windows-nt/Source/XPSP1/NT/multimedia/media/midimap/modfix.c
2020-09-26 16:20:57 +08:00

989 lines
26 KiB
C

/**********************************************************************
Copyright (c) 1992-1999 Microsoft Corporation
modfix.c
DESCRIPTION:
Fixed code for doing output mapping. KEEP THE SIZE OF THIS CODE
TO A MINIMUM!
HISTORY:
02/22/94 [jimge] created.
*********************************************************************/
#pragma warning(disable:4704)
#include "preclude.h"
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <mmddk.h>
#include "idf.h"
#include "midimap.h"
#include "debug.h"
extern HANDLE hMutexRefCnt; // Located in DRVPROC.C
extern HANDLE hMutexConfig; // Located in DRVPROC.C
#define MSG_UNKNOWN 0
#define MSG_SHORT 1
#define MSG_LONG 2
INT FNLOCAL MapEvent (
BYTE * pStatus,
DWORD dwBuffSize,
DWORD * pSkipBytes,
DWORD * pShortMsg);
DWORD FNLOCAL modMapLongMsg (
PINSTANCE pinstance,
LPMIDIHDR lpmh);
/***************************************************************************
@doc internal
@api int | modMessage | Exported entry point for MIDI out messages.
This function conforms to the definition in the MM DDK.
@parm UINT | uid | Device ID within driver to open. For mapper, this
should always be zero.
@parm UINT | umsg | Message to process. This should be one of the
#define'd MODM_xxx messages.
@parm DWORD | dwUser | Points to a DWORD where the driver (us) can
save instance data. This will store the near pointer to our
instance. On every other message, this will contain the instance
data.
@parm DWORD | dwParam1 | Message specific parameters.
@parm DWORD | dwParam2 | Message specific parameters.
@comm This function MUST be in a fixed segment since short messages
are allowed to be sent at interrupt time.
@rdesc | MMSYSERR_xxx.
***************************************************************************/
DWORD FNEXPORT modMessage(
UINT uid,
UINT umsg,
DWORD_PTR dwUser,
DWORD_PTR dwParam1,
DWORD_PTR dwParam2)
{
BYTE bs;
PINSTANCE pinstance;
// UINT uDeviceID;
PPORT pport;
MMRESULT mmrc;
MMRESULT mmrc2;
DWORD dwResult;
if (0 != uid)
{
DPF(1, TEXT ("Mapper called with non-zero uid!"));
return MMSYSERR_BADDEVICEID;
}
pinstance = (PINSTANCE)(UINT_PTR)(dwUser);
switch(umsg)
{
case MODM_GETDEVCAPS:
return modGetDevCaps((LPMIDIOUTCAPS)dwParam1,
(DWORD)dwParam2);
case MODM_OPEN:
return modOpen((PDWORD_PTR)dwUser,
(LPMIDIOPENDESC)dwParam1,
(DWORD)dwParam2);
case MODM_CLOSE:
return modClose((PINSTANCE)dwUser);
case MODM_DATA:
assert(NULL != pinstance);
// In cooked mode, don't allow non-status short messages.
// Otherwise (packed mode) maintain running status.
//
// TESTTEST -- Make sure running status works properly in
// MIDI_IO_PACKED - essential for backwards compatibility!!!
//
bs = MSG_STATUS(dwParam1);
if (pinstance->fdwOpen & MIDI_IO_COOKED)
{
bs = MSG_STATUS(dwParam1);
if (!IS_STATUS(bs))
{
DPF(1, TEXT ("Non-status short msg while opened in MIDI_IO_COOKED!"));
return MMSYSERR_INVALPARAM;
}
}
else
{
// Track running status
//
if (IS_STATUS(bs))
{
// Do not use real-time messages as the status
// byte of the next message.
if (!IS_REAL_TIME(bs))
{
pinstance->bRunningStatus = bs;
}
}
else
dwParam1 = (dwParam1 << 8) | (pinstance->bRunningStatus);
}
return MapSingleEvent((PINSTANCE)dwUser,
(DWORD)dwParam1,
MSE_F_SENDEVENT,
NULL);
case MODM_LONGDATA:
assert(NULL != pinstance);
// return modLongMsg(pinstance, (LPMIDIHDR)dwParam1);
return modMapLongMsg (pinstance, (LPMIDIHDR)dwParam1);
case MODM_PREPARE:
assert(NULL != pinstance);
return modPrepare((LPMIDIHDR)dwParam1);
case MODM_UNPREPARE:
assert(NULL != pinstance);
return modUnprepare((LPMIDIHDR)dwParam1);
case MODM_GETVOLUME:
if (!IS_ALLOWVOLUME)
return MMSYSERR_NOTSUPPORTED;
*(LPDWORD)dwParam1 = gdwVolume;
return MMSYSERR_NOERROR;
case MODM_SETVOLUME:
if (!IS_ALLOWVOLUME)
return MMSYSERR_NOTSUPPORTED;
gdwVolume = (DWORD)dwParam1;
if (ghMidiStrm)
return midiOutSetVolume((HMIDIOUT)ghMidiStrm, (DWORD)dwParam1);
return modSetVolume((DWORD)dwParam1);
case MODM_PROPERTIES:
assert(NULL != pinstance);
return midiStreamProperty(ghMidiStrm, (LPVOID)dwParam1, (DWORD)dwParam2);
case MODM_STRMDATA:
assert(NULL != pinstance);
return MapCookedBuffer(pinstance, (LPMIDIHDR)dwParam1);
case MODM_RESET:
assert(NULL != pinstance);
if (ghMidiStrm)
return midiOutReset((HMIDIOUT)ghMidiStrm);
mmrc = MMSYSERR_NOERROR;
for (pport = gpportList; pport; pport=pport->pNext)
if (MMSYSERR_NOERROR != (mmrc2 =
midiOutReset(pport->hmidi)))
mmrc = mmrc2;
return mmrc;
case MODM_GETPOS:
assert(NULL != pinstance);
return modGetPosition((PINSTANCE)pinstance,
(LPMMTIME)dwParam1,
(DWORD)dwParam2 /* cbmmtime */);
case MODM_PAUSE:
assert(NULL != pinstance);
return midiStreamPause(ghMidiStrm);
case MODM_RESTART:
assert(NULL != pinstance);
return midiStreamRestart(ghMidiStrm);
case MODM_STOP:
assert(NULL != pinstance);
return midiStreamStop(ghMidiStrm);
case MODM_CACHEPATCHES:
assert(NULL != pinstance);
if (!IS_ALLOWCACHE)
return MMSYSERR_NOTSUPPORTED;
if (ghMidiStrm)
return midiOutCachePatches(
(HMIDIOUT)ghMidiStrm, // hmidi
HIWORD(dwParam2), // wBank
(WORD FAR *)dwParam1, // lpPatchArray
LOWORD(dwParam2)); // wFlags
mmrc = MMSYSERR_NOERROR;
for (pport = gpportList; pport; pport=pport->pNext)
if (MMSYSERR_NOERROR != (mmrc2 =
midiOutCachePatches(
pport->hmidi, // hmidi
HIWORD(dwParam2), // wBank
(WORD FAR *)dwParam1, // lpPatchArray
LOWORD(dwParam2))) && // wFlags
MMSYSERR_NOTSUPPORTED != mmrc2)
mmrc = mmrc2;
return mmrc;
case MODM_CACHEDRUMPATCHES:
assert(NULL != pinstance);
if (!IS_ALLOWCACHE)
return MMSYSERR_NOTSUPPORTED;
if (ghMidiStrm)
return midiOutCacheDrumPatches(
(HMIDIOUT)ghMidiStrm, // hmidi
HIWORD(dwParam2), // wBank
(WORD FAR *)dwParam1, // lpKeyArray
LOWORD(dwParam2)); // wFlags
mmrc = MMSYSERR_NOERROR;
for (pport = gpportList; pport; pport=pport->pNext)
if (MMSYSERR_NOERROR != (mmrc2 =
midiOutCacheDrumPatches(
pport->hmidi, // hmidi
HIWORD(dwParam2), // wBank
(WORD FAR *)dwParam1, // lpKeyArray
LOWORD(dwParam2))) && // wFlags
MMSYSERR_NOTSUPPORTED != mmrc2)
mmrc = mmrc2;
return mmrc;
case DRVM_MAPPER_RECONFIGURE:
DPF(2, TEXT ("DRV_RECONFIGURE"));
// Prevent Synchronization problems during Configuration
if (NULL != hMutexConfig) WaitForSingleObject (hMutexConfig, INFINITE);
dwResult = UpdateInstruments(TRUE, (DWORD)dwParam2);
if (NULL != hMutexConfig) ReleaseMutex (hMutexConfig);
return dwResult;
}
return MMSYSERR_NOTSUPPORTED;
}
/***************************************************************************
@doc internal
@api void | modmCallback | Callback for completion of sending of
long messages. This function conforms to the definition in the SDK.
@parm HMIDIOUT | hmo | The MMSYSTEM handle of the device which
complete sending.
@parm WORD | wmsg | Contains a MOM_xxx code signifying what event
occurred. We only care about MOM_DONE.
@parm DWORD | dwInstance | DWORD of instance data given at open time;
this contains the PPORT which owns the handle.
@parm DWORD | dwParam1 | Message specific parameters. For MOM_DONE,
this contains a far pointer to the header which completed.
@parm DWORD | dwParam2 | Message specific parameters. Contains
nothinf for MOM_DONE.
@comm This function MUST be in a fixed segment since the driver
may call it at interrupt time.
***************************************************************************/
void CALLBACK _loadds modmCallback(
HMIDIOUT hmo,
WORD wmsg,
DWORD_PTR dwInstance,
DWORD_PTR dwParam1,
DWORD_PTR dwParam2)
{
LPMIDIHDR lpmhShadow;
LPMIDIHDR lpmhUser;
PINSTANCE pinstance;
PSHADOWBLOCK psb;
LPMIDIHDR31 lpmh31;
BOOL fNeedCB = FALSE;
lpmhShadow = (LPMIDIHDR)dwParam1;
if (wmsg == MOM_DONE && lpmhShadow)
{
DPF(1, TEXT ("Callback: MOM_DONE"));
pinstance = (PINSTANCE)(UINT_PTR)lpmhShadow->dwReserved[MH_MAPINST];
lpmhUser = (LPMIDIHDR)lpmhShadow->dwReserved[MH_SHADOWEE];
if (ghMidiStrm)
fNeedCB = TRUE;
else
{
lpmh31 = (LPMIDIHDR31)lpmhUser;
psb = (PSHADOWBLOCK)(UINT_PTR)lpmh31->reserved;
if (0 == --psb->cRefCnt && !(lpmh31->dwFlags & MHDR_SENDING))
fNeedCB = TRUE;
}
if (fNeedCB)
{
DPF(1, TEXT ("Callback: Propogating"));
lpmhUser->dwFlags |= MHDR_DONE;
lpmhUser->dwFlags &= ~MHDR_INQUEUE;
DriverCallback(
pinstance->dwCallback,
HIWORD(pinstance->fdwOpen),
(HANDLE)pinstance->hmidi,
MM_MOM_DONE,
pinstance->dwInstance,
(DWORD_PTR)lpmhUser,
0L);
}
}
else if (wmsg == MOM_POSITIONCB && lpmhShadow)
{
pinstance = (PINSTANCE)(UINT_PTR)lpmhShadow->dwReserved[MH_MAPINST];
lpmhUser = (LPMIDIHDR)lpmhShadow->dwReserved[MH_SHADOWEE];
if (!ghMidiStrm)
{
DPF(0, TEXT ("Got MOM_POSITIONCB on non-stream handle?"));
return;
}
lpmhUser->dwOffset = lpmhShadow->dwOffset;
DriverCallback(
pinstance->dwCallback,
HIWORD(pinstance->fdwOpen),
(HANDLE)pinstance->hmidi,
MM_MOM_POSITIONCB,
pinstance->dwInstance,
(DWORD_PTR)lpmhUser,
0L);
}
}
/***************************************************************************
@doc internal
@api DWORD | MapSingleEvent | Map and possibly send a short message.
@parm PINSTANCE | pinstance | Pointer to an open instance.
@parm DWORD | dwData | Contains the short message to transmit.
@parm DWORD | fdwFlags | One of the the following values:
@flag MSE_F_SENDEVENT | Send the event to the physical channel
@flag MSE_F_RETURNEVENT | Return the event to be re-packed into
a buffer.
@comm Running status should be taken care of before we get
called.
@rdesc | Some MMSYSERR_xxx code if MSE_F_SENDEVENT; otherwise the
mapped event if no error, 0L on error.
***************************************************************************/
DWORD FNGLOBAL MapSingleEvent(
PINSTANCE pinstance,
DWORD dwData,
DWORD fdwFlags,
DWORD BSTACK * pdwStreamID)
{
BYTE bMsg;
BYTE bChan;
BYTE b1;
BYTE b2;
PCHANNEL pchannel;
MMRESULT mmr;
BOOL frtm; // isrealtimemessage.
// Extract message type and channel number.
//
bMsg = MSG_STATUS(dwData);
frtm = IS_REAL_TIME(bMsg);
bChan = MSG_CHAN(bMsg);
bMsg = MSG_EVENT(bMsg);
// Ignore sysex messages.
// (MIDI_SYSEX == bMsg) will also eliminate real time
// messages. Therefore real-time messages are special cased
//
if (MIDI_SYSEX == bMsg && !frtm)
return !(fdwFlags & MSE_F_RETURNEVENT) ? MMSYSERR_NOERROR : (((DWORD)MEVT_NOP)<<24);
if (NULL == (pchannel = gapChannel[bChan]))
return !(fdwFlags & MSE_F_RETURNEVENT) ? MMSYSERR_NOERROR : (((DWORD)MEVT_NOP)<<24);
bChan = (BYTE)pchannel->uChannel;
if (pdwStreamID)
*pdwStreamID = pchannel->dwStreamID;
switch(bMsg)
{
case MIDI_NOTEOFF:
case MIDI_NOTEON:
b1 = MSG_PARM1(dwData);
b2 = MSG_PARM2(dwData);
if (NULL != pchannel->pbKeyMap)
b1 = pchannel->pbKeyMap[b1];
dwData = MSG_PACK2(bMsg|bChan, b1, b2);
break;
case MIDI_POLYPRESSURE:
case MIDI_CONTROLCHANGE:
case MIDI_PITCHBEND:
b1 = MSG_PARM1(dwData);
b2 = MSG_PARM2(dwData);
dwData = MSG_PACK2(bMsg|bChan, b1, b2);
break;
case MIDI_PROGRAMCHANGE:
b1 = MSG_PARM1(dwData);
if (NULL != pchannel->pbPatchMap)
b1 = pchannel->pbPatchMap[b1];
dwData = MSG_PACK1(bMsg|bChan, b1);
break;
}
if (!(fdwFlags & MSE_F_RETURNEVENT))
{
if (dwData)
{
if (ghMidiStrm)
mmr = midiOutShortMsg((HMIDIOUT)ghMidiStrm, dwData);
else
mmr = midiOutShortMsg(pchannel->pport->hmidi, dwData);
if (MMSYSERR_NOERROR != mmr)
{
DPF(1, TEXT ("midiOutShortMsg(%04X, %08lX) -> %u"), (WORD)(pchannel->pport->hmidi), dwData, (UINT)mmr);
}
}
return mmr;
}
else
return dwData;
}
/***************************************************************************
@doc internal
@api DWORD | modLongMsg | Handle MODM_LONGDATA in compatibility mode.
@parm LPMIDIHDR | lpmh | The header to broadcast.
@comm Propogate the header across all drivers. <f modmCallback> handles
counting the returning callbacks and making sure the caller only gets
one.
@rdesc | Some MMSYSERR_xxx code if MSE_F_SENDEVENT; otherwise the
mapped event if no error, 0L on error.
***************************************************************************/
DWORD FNLOCAL modLongMsg(
PINSTANCE pinstance,
LPMIDIHDR lpmh)
{
WORD wIntStat;
LPMIDIHDR lpmhWork;
PPORT pport;
MMRESULT mmrc = MMSYSERR_NOERROR;
BOOL fNeedCB = FALSE;
LPMIDIHDR31 lpmh31 = (LPMIDIHDR31)lpmh;
PSHADOWBLOCK psb;
if (ghMidiStrm)
psb = (PSHADOWBLOCK)(UINT_PTR)lpmh->dwReserved[MH_SHADOW];
else
psb = (PSHADOWBLOCK)(UINT_PTR)lpmh31->reserved;
lpmhWork = psb->lpmhShadow;
lpmhWork->dwReserved[MH_MAPINST] = (DWORD_PTR)pinstance;
if (ghMidiStrm)
{
lpmhWork->dwBufferLength = lpmh->dwBufferLength;
return midiOutLongMsg((HMIDIOUT)ghMidiStrm,
lpmhWork,
sizeof(*lpmhWork));
}
lpmh->dwFlags |= MHDR_SENDING;
psb->cRefCnt = 0;
DPF(1, TEXT ("LongMsg: User hdr %p Shadow %p"), lpmh, lpmhWork);
for (pport = gpportList; pport; pport=pport->pNext, lpmhWork++)
{
lpmhWork->dwBufferLength = lpmh->dwBufferLength;
mmrc = midiOutLongMsg(pport->hmidi, lpmhWork, sizeof(*lpmhWork));
if (MMSYSERR_NOERROR != mmrc)
{
// Don't turn off MHDR_SENDING; this will prevent any callbacks
// from being propogated to the user.
return mmrc;
}
++psb->cRefCnt;
}
// Wait for synchronization object
WaitForSingleObject (hMutexRefCnt, INFINITE);
// Do we need to do callback
if (0 == psb->cRefCnt)
fNeedCB = TRUE;
// Release synchronization object
ReleaseMutex (hMutexRefCnt);
if (fNeedCB)
{
lpmh->dwFlags |= MHDR_DONE;
DriverCallback(
pinstance->dwCallback,
HIWORD(pinstance->fdwOpen),
(HANDLE)pinstance->hmidi,
MM_MOM_DONE,
pinstance->dwInstance,
(DWORD_PTR)lpmh,
0L);
}
return MMSYSERR_NOERROR;
}
/***************************************************************************
@doc internal
@api DWORD | modMapLongMsg | Handle MODM_LONGDATA in compatibility mode.
@parm LPMIDIHDR | lpmh | The header to broadcast.
@comm if a SYSEXE event Propogate the header across all drivers.
<f modmCallback> handles counting the returning callbacks and making sure the caller only gets
one. Otherwise, parse the Long Message into a bunch of short messages
and Map each one individually.
@rdesc | Some MMSYSERR_xxx code if MSE_F_SENDEVENT; otherwise the
mapped event if no error, 0L on error.
***************************************************************************/
DWORD FNLOCAL modMapLongMsg (
PINSTANCE pinstance,
LPMIDIHDR lpmh)
{
WORD wIntStat;
LPMIDIHDR lpmhWork;
PPORT pport;
MMRESULT mmrc = MMSYSERR_NOERROR;
BOOL fNeedCB = FALSE;
LPMIDIHDR31 lpmh31 = (LPMIDIHDR31)lpmh;
PSHADOWBLOCK psb;
LPBYTE pbData; // Pointer to Data
BYTE bMsg;
UINT uMessageLength;
LPBYTE pbTrans; // Pointer to Translation Buffer
DWORD dwCurr;
DWORD dwLength;
DWORD dwMsg;
DWORD dwBuffLen;
INT rMsg;
// Get Shadow Block
if (ghMidiStrm)
psb = (PSHADOWBLOCK)(UINT_PTR)lpmh->dwReserved[MH_SHADOW];
else
psb = (PSHADOWBLOCK)(UINT_PTR)lpmh31->reserved;
lpmhWork = psb->lpmhShadow;
lpmhWork->dwReserved[MH_MAPINST] = (DWORD_PTR)pinstance;
// Check for MIDI streaming
if (ghMidiStrm)
{
lpmhWork->dwBufferLength = lpmh->dwBufferLength;
return midiOutLongMsg((HMIDIOUT)ghMidiStrm,
lpmhWork,
sizeof(*lpmhWork));
}
lpmh->dwFlags |= MHDR_SENDING;
psb->cRefCnt = 0;
DPF(1, TEXT ("MapLongMsg: User hdr %p Shadow %p"), lpmh, lpmhWork);
pbData = lpmhWork->lpData;
bMsg = MSG_EVENT(*pbData);
if (MIDI_SYSEX == bMsg)
{
// Broadcast SYSEX message to all active ports
for (pport = gpportList; pport; pport=pport->pNext, lpmhWork++)
{
lpmhWork->dwBufferLength = lpmh->dwBufferLength;
mmrc = midiOutLongMsg(pport->hmidi, lpmhWork, sizeof(*lpmhWork));
if (MMSYSERR_NOERROR != mmrc)
{
// Don't turn off MHDR_SENDING; this will prevent any callbacks
// from being propogated to the user.
return mmrc;
}
++psb->cRefCnt;
}
}
else
{
// Parse and Translate list of Short messages
dwBuffLen = lpmh->dwBufferLength;
// Grow Translation buffer to at least this size
if (!GrowTransBuffer (pinstance, dwBuffLen))
{
// That didn't work !!!
// Default to Broadcast messages to all active ports
for (pport = gpportList; pport; pport=pport->pNext, lpmhWork++)
{
lpmhWork->dwBufferLength = lpmh->dwBufferLength;
mmrc = midiOutLongMsg(pport->hmidi, lpmhWork, sizeof(*lpmhWork));
if (MMSYSERR_NOERROR != mmrc)
{
// Don't turn off MHDR_SENDING; this will prevent any callbacks
// from being propogated to the user.
return mmrc;
}
++psb->cRefCnt;
}
}
else
{
// Copy buffer to translation buffer
pbTrans = AccessTransBuffer (pinstance);
CopyMemory (pbTrans, pbData, dwBuffLen);
// Parse translation buffer
dwCurr = 0L;
while (dwBuffLen)
{
// Map Event
rMsg = MapEvent (&pbTrans[dwCurr], dwBuffLen, &dwLength, &dwMsg);
switch (rMsg)
{
case MSG_SHORT:
// Send Short Message
MapSingleEvent(pinstance,
dwMsg,
MSE_F_SENDEVENT,
NULL);
dwCurr += dwLength;
break;
case MSG_LONG:
//
// Note: For completeness, we should probably broadcast
// this, but for now assume that there are no embedded
// SYSEX messages in the buffer and skip any we encounter
//
dwCurr += dwLength;
break;
default:
dwCurr += dwLength;
break;
}
dwBuffLen -= dwLength;
} // End While
// Release Translation Buffer
ReleaseTransBuffer (pinstance);
}
}
// Wait for synchronization object
WaitForSingleObject (hMutexRefCnt, INFINITE);
// Do we need to do callback
if (0 == psb->cRefCnt)
fNeedCB = TRUE;
// Release synchronization object
ReleaseMutex (hMutexRefCnt);
if (fNeedCB)
{
lpmh->dwFlags |= MHDR_DONE;
DriverCallback(
pinstance->dwCallback,
HIWORD(pinstance->fdwOpen),
(HANDLE)pinstance->hmidi,
MM_MOM_DONE,
pinstance->dwInstance,
(DWORD_PTR)lpmh,
0L);
}
return MMSYSERR_NOERROR;
} // End modMapLongMsg
// returns length of various MIDI messages in bytes
INT FNLOCAL MapEvent (
BYTE * pStatus,
DWORD dwBuffSize,
DWORD * pSkipBytes,
DWORD * pShortMsg)
{
INT fResult = MSG_SHORT;
BYTE bMsg = 0;
BYTE bParam1 = 0;
BYTE bParam2 = 0;
bMsg = *pStatus;
*pSkipBytes = 0;
// Mask Off Channel bits
switch (bMsg & 0xF0)
{
case MIDI_NOTEOFF:
case MIDI_NOTEON:
case MIDI_POLYPRESSURE:
case MIDI_CONTROLCHANGE:
bParam1 = *(pStatus+1);
bParam2 = *(pStatus+2);
*pShortMsg = MSG_PACK2(bMsg,bParam1,bParam2);
*pSkipBytes = 3;
break;
case MIDI_PROGRAMCHANGE:
case MIDI_CHANPRESSURE:
bParam1 = *(pStatus+1);
*pShortMsg = MSG_PACK1(bMsg,bParam1);
*pSkipBytes = 2;
break;
case MIDI_PITCHBEND:
bParam1 = *(pStatus+1);
bParam2 = *(pStatus+2);
*pShortMsg = MSG_PACK2(bMsg,bParam1,bParam2);
*pSkipBytes = 3;
break;
case MIDI_SYSEX:
// It's a system message
// Keep counting system messages until
// We don't find any more
fResult = MSG_LONG;
*pSkipBytes = 0;
while (((bMsg & 0xF0) == 0xF0) &&
(*pSkipBytes < dwBuffSize))
{
switch (bMsg)
{
case MIDI_SYSEX:
// Find end of SysEx message
*pSkipBytes ++;
while ((*pSkipBytes < dwBuffSize) &&
(pStatus[*pSkipBytes] != MIDI_SYSEXEND))
{
*pSkipBytes++;
}
break;
case MIDI_QFRAME:
*pSkipBytes += 2;
break;
case MIDI_SONGPOINTER:
*pSkipBytes += 3;
break;
case MIDI_SONGSELECT:
*pSkipBytes += 2;
break;
case MIDI_F4: // Undefined message
case MIDI_F5: // Undefined message
case MIDI_TUNEREQUEST:
case MIDI_SYSEXEND: // Not really a message, but skip it
case MIDI_TIMINGCLOCK:
case MIDI_F9: // Undefined Message
case MIDI_START:
case MIDI_CONTINUE:
case MIDI_STOP:
case MIDI_FD: // Undefined Message
case MIDI_ACTIVESENSING:
case MIDI_META: // Is this how handle this message ?!?
*pSkipBytes += 1;
break;
} // End Switch
if (*pSkipBytes < dwBuffSize)
bMsg = pStatus[*pSkipBytes];
} // End While
break;
default:
// Unknown just increment skip count
fResult = MSG_UNKNOWN;
*pSkipBytes = 1;
break;
} // End switch
// Truncate to end of buffer
if (*pSkipBytes > dwBuffSize)
*pSkipBytes = dwBuffSize;
return fResult;
} // End MapEvent
// Create Translation buffer
BOOL FNGLOBAL InitTransBuffer (PINSTANCE pinstance)
{
if (!pinstance)
return FALSE;
InitializeCriticalSection (& (pinstance->csTrans));
EnterCriticalSection (&(pinstance->csTrans));
pinstance->pTranslate = NULL;
pinstance->cbTransSize = 0;
LeaveCriticalSection (&(pinstance->csTrans));
return TRUE;
} // End InitTransBuffer
// Cleanup Translation Buffer
BOOL FNGLOBAL CleanupTransBuffer (PINSTANCE pinstance)
{
if (!pinstance)
return FALSE;
EnterCriticalSection (&(pinstance->csTrans));
if (pinstance->pTranslate)
{
LocalFree((HLOCAL)(pinstance->pTranslate));
pinstance->pTranslate = NULL;
pinstance->cbTransSize = 0L;
}
LeaveCriticalSection (&(pinstance->csTrans));
DeleteCriticalSection (&(pinstance->csTrans));
return TRUE;
} // End CleanupTransBuffer
// Get Pointer to translation buffer
LPBYTE AccessTransBuffer (PINSTANCE pinstance)
{
if (!pinstance)
return NULL;
EnterCriticalSection (&(pinstance->csTrans));
return pinstance->pTranslate;
} // End AccessTransBuffer
// Release pointer to translation buffer
void FNGLOBAL ReleaseTransBuffer (PINSTANCE pinstance)
{
if (!pinstance)
return;
LeaveCriticalSection (&(pinstance->csTrans));
} // End ReleaseTransBuffer
// Resize Translation buffer
BOOL FNGLOBAL GrowTransBuffer (PINSTANCE pinstance, DWORD cbNewSize)
{
LPBYTE pNew;
if (!pinstance)
return FALSE;
EnterCriticalSection (&(pinstance->csTrans));
// Do we even need to grow buffer
if (cbNewSize > pinstance->cbTransSize)
{
pNew = (LPBYTE)LocalAlloc(LPTR, cbNewSize);
if (!pNew)
{
LeaveCriticalSection (&(pinstance->csTrans));
return FALSE;
}
// Remove old translation buffer, if any
if (pinstance->pTranslate)
LocalFree ((HLOCAL)(pinstance->pTranslate));
// Assign new buffer
pinstance->pTranslate = pNew;
pinstance->cbTransSize = cbNewSize;
}
LeaveCriticalSection (&(pinstance->csTrans));
return TRUE;
} // End GrowTransBuffer