📄 midistrm.cpp
字号:
//-----------------------------------------------------------------------------
// Copyright (c) Wolfson Microelectronics plc. All rights reserved.
//
// This software as well as any related documentation is furnished under
// license and may only be used or copied in accordance with the terms of the
// license. The information in this file is furnished for informational use
// only, is subject to change without notice, and should not be construed as
// a commitment by Wolfson Microelectronics plc. Wolfson Microelectronics plc
// assumes no responsibility or liability for any errors or inaccuracies that
// may appear in this document or any software that may be provided in
// association with this document.
//
// Except as permitted by such license, no part of this document may be
// reproduced, stored in a retrieval system, or transmitted in any form or by
// any means without the express written consent of Wolfson Microelectronics plc.
//
// $Id: midistrm.cpp 2719 2006-02-08 13:13:48Z ian $
//
// This file contains the code specific to MIDI streams for the WaveDev2
// driver for Wolfson codecs.
//
// Warning:
// This driver is specifically written for Wolfson Audio Codecs. It is
// not a general audio CODEC device driver.
//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
// -----------------------------------------------------------------------------
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// -----------------------------------------------------------------------------
#include "wavemain.h"
void CMidiStream::GainChange()
{
PLIST_ENTRY pListEntry;
CMidiNote *pCNote;
pListEntry = m_NoteList.Flink;
while (pListEntry != &m_NoteList)
{
// Get a pointer to the stream context
pCNote = CONTAINING_RECORD(pListEntry,CMidiNote,m_Link);
pCNote->GainChange();
pListEntry = pListEntry->Flink;
}
}
DWORD CMidiStream::MapNoteGain(DWORD NoteGain, DWORD Channel)
{
DWORD TotalGain = NoteGain & 0xFFFF;
DWORD StreamGain = m_dwGain;
if (Channel==1)
{
StreamGain >>= 16;
}
StreamGain &= 0xFFFF;
TotalGain *= StreamGain; // Calc. aggregate gain
TotalGain += 0xFFFF; // Force to round up
TotalGain >>= 16;
return MapGain(TotalGain, Channel);
}
HRESULT CMidiStream::Open(DeviceContext *pDeviceContext, LPWAVEOPENDESC lpWOD, DWORD dwFlags)
{
HRESULT Result;
LPWAVEFORMAT_MIDI pwfxmidi = (LPWAVEFORMAT_MIDI) lpWOD->lpFormat;
if (pwfxmidi->wfx.cbSize!=WAVEFORMAT_MIDI_EXTRASIZE)
{
return E_FAIL;
}
// Add all notes to free list
InitializeListHead(&m_NoteList);
InitializeListHead(&m_FreeList);
for (int i=0;i<NUMNOTES;i++)
{
InsertTailList(&m_FreeList,&m_MidiNote[i].m_Link);
}
m_NumChannels = pDeviceContext->NumChannels();
Result = StreamContext::Open(pDeviceContext, lpWOD, dwFlags);
if ( Result != MMSYSERR_NOERROR )
{
goto end;
}
m_USecPerQuarterNote = pwfxmidi->USecPerQuarterNote;
m_TicksPerQuarterNote = pwfxmidi->TicksPerQuarterNote;
UpdateTempo();
m_DeltaSampleCount=0;
//
// Initialise the pitches for this stream - based on the device
// sample rate.
//
CMidiNote::InitialisePitchTable( m_PitchTable, pDeviceContext->SampleRate() );
// Note: Output streams should be initialized in the run state.
Run();
end:
return Result;
}
DWORD CMidiStream::Reset()
{
DWORD dwResult = StreamContext::Reset();
if (dwResult==MMSYSERR_NOERROR)
{
AllNotesOff(0);
// Note: Output streams should be reset to the run state.
Run();
}
return dwResult;
}
DWORD CMidiStream::Close()
{
DWORD dwResult = StreamContext::Close();
if (dwResult==MMSYSERR_NOERROR)
{
AllNotesOff(0);
}
return dwResult;
}
HRESULT CMidiStream::UpdateTempo()
{
if (m_USecPerQuarterNote==0)
{
m_USecPerQuarterNote = 500000; // If not specified, assume 500000usec = 1/2 sec per quarter note
}
if (m_TicksPerQuarterNote==0)
{
m_TicksPerQuarterNote = 96; // If not specified, assume 96 ticks/quarter note
}
UINT64 Num = SampleRate();
Num *= m_USecPerQuarterNote;
UINT64 Den = 1000000;
Den *= m_TicksPerQuarterNote;
UINT64 SamplesPerTick = Num/Den;
m_SamplesPerTick = (UINT32)SamplesPerTick;
return S_OK;
}
// Return the delta # of samples until the next midi event
// or 0 if no midi events are left in the queue
UINT32 CMidiStream::ProcessMidiStream()
{
WAVEFORMAT_MIDI_MESSAGE *pMsg;
WAVEFORMAT_MIDI_MESSAGE *pMsgEnd;
UINT32 ThisMidiEventDelta;
// Process all midi messages up to and including the current sample
pMsg = (WAVEFORMAT_MIDI_MESSAGE *)m_lpCurrData;
pMsgEnd = (WAVEFORMAT_MIDI_MESSAGE *)m_lpCurrDataEnd;
for (;;)
{
if (pMsg>=pMsgEnd)
{
pMsg = (WAVEFORMAT_MIDI_MESSAGE *)GetNextBuffer();
if (!pMsg)
{
DEBUGMSG(ZONE_VERBOSE, (TEXT("CMidiStream::ProcessMidiStream no more events\r\n")));
return 0;
}
pMsgEnd = (WAVEFORMAT_MIDI_MESSAGE *)m_lpCurrDataEnd;
}
_try
{
ThisMidiEventDelta = DeltaTicksToSamples(pMsg->DeltaTicks);
if (ThisMidiEventDelta > m_DeltaSampleCount)
{
m_lpCurrData = (PBYTE)pMsg;
INT32 Delta = ThisMidiEventDelta-m_DeltaSampleCount;
DEBUGMSG(ZONE_VERBOSE, (TEXT("CMidiStream::ProcessMidiStream next event @delta %d\r\n"),Delta));
return Delta;
}
DEBUGMSG(ZONE_VERBOSE, (TEXT("CMidiStream::ProcessMidiStream sending midi message 0x%x\r\n"),pMsg->MidiMsg));
InternalMidiMessage(pMsg->MidiMsg);
m_DeltaSampleCount=0;
pMsg++;
}
_except (EXCEPTION_EXECUTE_HANDLER)
{
RETAILMSG(ZONE_ALWAYS, (TEXT("EXCEPTION IN IST for midi stream 0x%x, buffer 0x%x!!!!\r\n"), this, m_lpCurrData));
pMsg = pMsgEnd; // Pretend we finished reading the application buffer
}
}
}
PBYTE CMidiStream::Render(PBYTE pBuffer, PBYTE pBufferEnd, PBYTE pBufferLast)
{
DEBUGMSG(ZONE_VERBOSE, (TEXT("Entering CMidiStream::Render, pBuffer=0x%x, current delta = %d\r\n"), pBuffer, m_DeltaSampleCount));
// If we're not running, or we don't have any buffers queued and the note list is empty,
// just return
if ( (!m_bRunning) || (!StillPlaying() && IsListEmpty(&m_NoteList)) )
{
DEBUGMSG(ZONE_VERBOSE, (TEXT("CMidiStream::Render nothing to do\r\n")));
return pBuffer;
}
while (pBuffer<pBufferEnd)
{
// Process pending midi messages and get relative sample # of next midi event
UINT32 NextMidiEvent;
NextMidiEvent = ProcessMidiStream();
PBYTE pBufferEndEvent; // Where to stop on this pass
// If NextMidiEvent returns 0, it means there are no more midi messages left in the queue.
if (NextMidiEvent==0)
{
// Just process the rest of this buffer
pBufferEndEvent=pBufferEnd;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -