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 + -
显示快捷键?