mididd.c
来自「Windows NT声卡驱动VXD」· C语言 代码 · 共 1,581 行 · 第 1/4 页
C
1,581 行
case MODM_GETVOLUME:
D2(("MODM_GETVOLUME"));
//pOutClient = (PMIDIALLOC)dwUser;
//pOutClient->AuxParam.GetSetData.pData = *(PBYTE *)&dwParam1;
//pOutClient->AuxParam.GetSetData.DataLen = sizeof(DWORD);
//pOutClient->AuxParam.GetSetData.Function = IOCTL_MIDI_GET_VOLUME;
//return midiThreadCall(MidiThreadGetData, pOutClient);
return sndGetData(MidiOutDevice, id, sizeof(DWORD),
(PBYTE)dwParam1, IOCTL_MIDI_GET_VOLUME);
case MODM_CACHEPATCHES:
D2(("MODM_CACHEPATCHES"));
pOutClient = (PMIDIALLOC)dwUser;
{
MIDI_DD_CACHE_PATCHES AppData;
DWORD BytesReturned;
AppData.Bank = HIWORD(dwParam2);
AppData.Flags = LOWORD(dwParam2);
memcpy(AppData.Patches, (PVOID)dwParam1, sizeof(AppData.Patches));
return DeviceIoControl(
pOutClient->hDev,
IOCTL_MIDI_CACHE_PATCHES,
(PVOID)&AppData,
sizeof(AppData),
NULL,
0,
&BytesReturned,
NULL) ?
MMSYSERR_NOERROR :
sndTranslateStatus();
}
case MODM_CACHEDRUMPATCHES:
D2(("MODM_CACHEDRUMPATCHES"));
pOutClient = (PMIDIALLOC)dwUser;
{
MIDI_DD_CACHE_DRUM_PATCHES AppData;
DWORD BytesReturned;
AppData.Patch = HIWORD(dwParam2);
AppData.Flags = LOWORD(dwParam2);
memcpy(AppData.DrumPatches, (PVOID)dwParam1,
sizeof(AppData.DrumPatches));
return DeviceIoControl(
pOutClient->hDev,
IOCTL_MIDI_CACHE_DRUM_PATCHES,
(PVOID)&AppData,
sizeof(AppData),
NULL,
0,
&BytesReturned,
NULL) ?
MMSYSERR_NOERROR :
sndTranslateStatus();
}
default:
return MMSYSERR_NOTSUPPORTED;
}
//
// Should not get here
//
WinAssert(0);
return MMSYSERR_NOTSUPPORTED;
}
/***********************************************************************
UTILITY ROUTINES PORTED DIRECTLY FROM WIN 3.1
***********************************************************************/
/****************************************************************************
* @doc INTERNAL
*
* @api int | modMIDIlength | Get the length of a short midi message.
*
* @parm DWORD | dwMessage | The message.
*
* @rdesc Returns the length of the message.
***************************************************************************/
STATIC int modMIDIlength(PMIDIALLOC pClient, BYTE b)
{
if (b >= 0xF8) { // system realtime
/* for realtime messages, leave running status untouched */
return 1; // write one byte
}
switch (b) {
case 0xF0: case 0xF4: case 0xF5: case 0xF6: case 0xF7:
pClient->l = 1;
return pClient->l;
case 0xF1: case 0xF3:
pClient->l = 2;
return pClient->l;
case 0xF2:
pClient->l = 3;
return pClient->l;
}
switch (b & 0xF0) {
case 0x80: case 0x90: case 0xA0: case 0xB0: case 0xE0:
pClient->l = 3;
return pClient->l;
case 0xC0: case 0xD0:
pClient->l = 2;
return pClient->l;
}
return (pClient->l - 1); // uses previous value if data byte (running status)
}
/****************************************************************************
* @doc INTERNAL
*
* @api void | midBufferWrite | This function writes a byte into the long
* message buffer. If the buffer is full or a SYSEX_ERROR or
* end-of-sysex byte is received, the buffer is marked as 'done' and
* it's owner is called back.
*
* @parm BYTE | byte | The byte received.
*
* @rdesc There is no return value
***************************************************************************/
STATIC void midBufferWrite(PMIDIALLOC pClient, BYTE byte)
{
LPMIDIHDR lpmh;
UINT msg;
// if no buffers, nothing happens
if (pClient->lpMIQueue == NULL)
return;
lpmh = pClient->lpMIQueue;
if (byte == SYSEX_ERROR) {
D2(("sysexerror"));
msg = MIM_LONGERROR;
}
else {
D2(("bufferwrite"));
msg = MIM_LONGDATA;
*((LPSTR)(lpmh->lpData) + pClient->Mid->dwCurData++) = byte;
}
// if end of sysex, buffer full or error, send them back the buffer
if ((byte == SYSEX_ERROR) || (byte == 0xF7) || (pClient->Mid->dwCurData >= lpmh->dwBufferLength)) {
D2(("bufferdone"));
pClient->lpMIQueue = pClient->lpMIQueue->lpNext;
lpmh->dwBytesRecorded = pClient->Mid->dwCurData;
pClient->Mid->dwCurData = 0L;
lpmh->dwFlags |= MHDR_DONE;
lpmh->dwFlags &= ~MHDR_INQUEUE;
midiCallback(pClient, msg, (DWORD)lpmh, pClient->Mid->dwMsgTime);
}
return;
}
/****************************************************************************
* @doc INTERNAL
*
* @api void | midByteRec | This function constructs the complete midi
* messages from the individual bytes received and passes the message
* to the client via his callback.
*
* @parm WORD | word | The byte received is in the low order byte.
*
* @rdesc There is no return value
*
* @comm Note that currently running status isn't turned off on errors.
***************************************************************************/
STATIC void midByteRec(PMIDIALLOC pClient, BYTE byte)
{
if (!pClient->Mid->fMidiInStarted)
return;
// if it's a system realtime message, send it
// this does not affect running status or any current message
if (byte >= 0xF8) {
D2((" rt"));
midiCallback(pClient, MIM_DATA, (DWORD)byte, pClient->Mid->dwCurTime);
}
// else if it's a system common message
else if (byte >= 0xF0) {
if (pClient->Mid->fSysex) { // if we're in a sysex
pClient->Mid->fSysex = FALSE; // status byte during sysex ends it
if (byte == 0xF7)
{
midBufferWrite(pClient, 0xF7); // write in long message buffer
return;
}
else
midBufferWrite(pClient, SYSEX_ERROR); // secret code indicating error
}
if (pClient->Mid->dwMsg) { // throw away any incomplete short data
midiCallback(pClient, MIM_ERROR, pClient->Mid->dwMsg, pClient->Mid->dwMsgTime);
pClient->Mid->dwMsg = 0L;
}
pClient->Mid->status = 0; // kill running status
pClient->Mid->dwMsgTime = pClient->Mid->dwCurTime; // save timestamp
switch(byte) {
case 0xF0:
D2((" F0"));
pClient->Mid->fSysex = TRUE;
midBufferWrite(pClient, 0xF0);
break;
case 0xF7:
D2((" F7"));
if (!pClient->Mid->fSysex)
midiCallback(pClient, MIM_ERROR, (DWORD)byte, pClient->Mid->dwMsgTime);
// else already took care of it above
break;
case 0xF4: // system common, no data bytes
case 0xF5:
case 0xF6:
D2((" status0"));
midiCallback(pClient, MIM_DATA, (DWORD)byte, pClient->Mid->dwMsgTime);
pClient->Mid->bBytePos = 0;
break;
case 0xF1: // system common, one data byte
case 0xF3:
D2((" status1"));
pClient->Mid->dwMsg |= byte;
pClient->Mid->bBytesLeft = 1;
pClient->Mid->bBytePos = 1;
break;
case 0xF2: // system common, two data bytes
D2((" status2"));
pClient->Mid->dwMsg |= byte;
pClient->Mid->bBytesLeft = 2;
pClient->Mid->bBytePos = 1;
break;
}
}
// else if it's a channel message
else if (byte >= 0x80) {
if (pClient->Mid->fSysex) { // if we're in a sysex
pClient->Mid->fSysex = FALSE; // status byte during sysex ends it
midBufferWrite(pClient, SYSEX_ERROR); // secret code indicating error
}
if (pClient->Mid->dwMsg) { // throw away any incomplete data
midiCallback(pClient, MIM_ERROR, pClient->Mid->dwMsg, pClient->Mid->dwMsgTime);
pClient->Mid->dwMsg = 0L;
}
pClient->Mid->status = byte; // save for running status
pClient->Mid->dwMsgTime = pClient->Mid->dwCurTime; // save timestamp
pClient->Mid->dwMsg |= byte;
pClient->Mid->bBytePos = 1;
switch(byte & 0xF0) {
case 0xC0: // channel message, one data byte
case 0xD0:
D2((" status1"));
pClient->Mid->bBytesLeft = 1;
break;
case 0x80: // channel message, two data bytes
case 0x90:
case 0xA0:
case 0xB0:
case 0xE0:
D2((" status2"));
pClient->Mid->bBytesLeft = 2;
break;
}
}
// else if it's an expected data byte for a long message
else if (pClient->Mid->fSysex) {
D2((" sxdata"));
midBufferWrite(pClient, byte); // write in long message buffer
}
// else if it's an expected data byte for a short message
else if (pClient->Mid->bBytePos != 0) {
D2((" data"));
if ((pClient->Mid->status) && (pClient->Mid->bBytePos == 1)) { // if running status
pClient->Mid->dwMsg |= pClient->Mid->status;
pClient->Mid->dwMsgTime = pClient->Mid->dwCurTime; // save timestamp
}
pClient->Mid->dwMsg += (DWORD)byte << ((pClient->Mid->bBytePos++) * 8);
if (--pClient->Mid->bBytesLeft == 0) {
midiCallback(pClient, MIM_DATA, pClient->Mid->dwMsg, pClient->Mid->dwMsgTime);
pClient->Mid->dwMsg = 0L;
if (pClient->Mid->status) {
pClient->Mid->bBytesLeft = pClient->Mid->bBytePos - (BYTE)1;
pClient->Mid->bBytePos = 1;
}
else {
pClient->Mid->bBytePos = 0;
}
}
}
// else if it's an unexpected data byte
else {
D2((" baddata"));
midiCallback(pClient, MIM_ERROR, (DWORD)byte, pClient->Mid->dwMsgTime);
}
return;
}
/****************************************************************************
* @doc INTERNAL
*
* @api void | midFreeQ | Free all buffers in the MIQueue.
*
* @comm Currently this is only called after sending off any partially filled
* buffers, so all buffers here are empty. The timestamp value is 0 in
* this case.
*
* @rdesc There is no return value.
***************************************************************************/
STATIC void midFreeQ(PMIDIALLOC pClient)
{
LPMIDIHDR lpH, lpN;
lpH = pClient->lpMIQueue; // point to top of the queue
pClient->lpMIQueue = NULL; // mark the queue as empty
pClient->Mid->dwCurData = 0L;
while (lpH) {
lpN = lpH->lpNext;
lpH->dwFlags |= MHDR_DONE;
lpH->dwFlags &= ~MHDR_INQUEUE;
lpH->dwBytesRecorded = 0;
midiCallback(pClient, MIM_LONGDATA, (DWORD)lpH,
pClient->Mid->dwCurTime);
lpH = lpN;
}
}
/****************************************************************************
* @doc INTERNAL
*
* @api void | midSendPartBuffer | This function is called from midStop().
* It looks at the buffer at the head of the queue and, if it contains
* any data, marks it as done as sends it back to the client.
*
* @rdesc The return value is the number of bytes transfered. A value of zero
* indicates that there was no more data in the input queue.
***************************************************************************/
STATIC void midSendPartBuffer(PMIDIALLOC pClient)
{
LPMIDIHDR lpH;
if (pClient->lpMIQueue && pClient->Mid->dwCurData) {
lpH = pClient->lpMIQueue;
pClient->lpMIQueue = pClient->lpMIQueue->lpNext;
lpH->dwFlags |= MHDR_DONE;
lpH->dwFlags &= ~MHDR_INQUEUE;
pClient->Mid->dwCurData = 0L;
midiCallback(pClient, MIM_LONGERROR, (DWORD)lpH,
pClient->Mid->dwMsgTime);
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?