mididd.c

来自「Windows NT声卡驱动VXD」· C语言 代码 · 共 1,581 行 · 第 1/4 页

C
1,581
字号
                            //
                            // Failed to add our buffer so give up and
                            // get our buffers back !
                            //
                            pClient->Mid->Bad = TRUE;
                            break;
                        }
                    }
                    //
                    // Set Device state.  By issuing state changes on THIS
                    // thread the calling thread can be sure that all Apc's
                    // generated by buffer completions will complete
                    // BEFORE this function completes.
                    //

                    pClient->AuxReturnCode =
                        midiSetState(pClient, pClient->AuxParam.State);

                    //
                    // If this failed then get our buffers back,
                    // otherwise set our new state
                    //
                    if (pClient->AuxReturnCode != MMSYSERR_NOERROR) {
                        pClient->Mid->Bad = TRUE;
                    } else {
                        pClient->Mid->fMidiInStarted = TRUE;
                    }
                } else {
                    //
                    // Already started or bad
                    //
                }
                break;

            case MIDI_DD_STOP:
                //
                // Set Device state.  By issuing state changes on THIS
                // thread the calling thread can be sure that all Apc's
                // generated by buffer completions will complete
                // BEFORE this function completes.
                //

                if (pClient->Mid->fMidiInStarted) {
                    pClient->Mid->fMidiInStarted = FALSE;

                    //
                    // RESET so we get our buffers back
                    //
                    pClient->AuxReturnCode =
                        midiSetState(pClient, MIDI_DD_RESET);
                        WinAssert(!pClient->Mid->DeviceQueue);

                    if (pClient->AuxReturnCode == MMSYSERR_NOERROR) {
                        midSendPartBuffer(pClient);
                    }
                }
                break;

            case MIDI_DD_RESET:
                //
                // Set Device state.  By issuing state changes on THIS
                // thread the calling thread can be sure that all Apc's
                // generated by buffer completions will complete
                // BEFORE this function completes.
                //

                if (pClient->Mid->fMidiInStarted) {
                    pClient->Mid->fMidiInStarted = FALSE;
                    pClient->AuxReturnCode =
                        midiSetState(pClient, pClient->AuxParam.State);
                        WinAssert(!pClient->Mid->DeviceQueue);

                    if (pClient->AuxReturnCode == MMSYSERR_NOERROR) {
                        pClient->Mid->Bad = FALSE; // Recovered !!
                        midSendPartBuffer(pClient);
                    }
                }
                //
                // We zero the input queue anyway - compatibility with
                // windows 3.1
                //
                midFreeQ(pClient);
                break;

            }
            break;

        case MidiThreadSetData:
            {
                pClient->AuxReturnCode =
                    sndSetHandleData(pClient->hDev,
                                     pClient->AuxParam.GetSetData.DataLen,
                                     pClient->AuxParam.GetSetData.pData,
                                     pClient->AuxParam.GetSetData.Function,
                                     pClient->Event);
            }
            break;

        case MidiThreadClose:
            //
            // Try to complete.
            // If we're completed all our buffers then we can.
            // otherwise we can't
            //
            if (pClient->lpMIQueue == NULL) {
                pClient->AuxReturnCode = MMSYSERR_NOERROR;
                Close = TRUE;
            } else {
                pClient->AuxReturnCode = MIDIERR_STILLPLAYING;
            }
            break;

        default:
            WinAssert(FALSE);   // Invalid call
            break;
        }
        //
        // Trap invalid callers
        //
        pClient->AuxFunction = MidiThreadInvalid;

                //
                // See if apcs completed
                //
                midiFlush(pClient);

        //
        // Release the caller
        //
        SetEvent(pClient->AuxEvent2);

        //
        // Complete ?
        //
        if (Close) {
            break;
        }
        //
        // Wait for more !
        //
        while (WaitForSingleObjectEx(pClient->AuxEvent1, INFINITE, TRUE) ==
                   WAIT_IO_COMPLETION) {
                        //
                        // Complete buffers whose Apcs ran
                        //
                        midiFlush(pClient);
        }
    }

    //
    // We've been asked to terminte
    //

    return 1;
}



/****************************************************************************
 * @doc INTERNAL
 *
 * @api void | midiCallback | This calls DriverCallback for a MIDIHDR.
 *
 * @parm PMIDIALLOC | pMidi | Pointer to midi device.
 *
 * @parm DWORD | msg | The message.
 *
 * @parm DWORD | dw1 | message DWORD (dw2 is always set to 0).
 *
 * @rdesc There is no return value.
 ***************************************************************************/
void midiCallback(PMIDIALLOC pMidi, DWORD msg, DWORD dw1, DWORD dw2)
{

    // invoke the callback function, if it exists.  dwFlags contains
    // midi driver specific flags in the LOWORD and generic driver
    // flags in the HIWORD

    if (pMidi->dwCallback)
        DriverCallback(pMidi->dwCallback,       // user's callback DWORD
                       HIWORD(pMidi->dwFlags),  // callback flags
                       (HDRVR)pMidi->hMidi,     // handle to the midi device
                       msg,                     // the message
                       pMidi->dwInstance,       // user's instance data
                       dw1,                     // first DWORD
                       dw2);                    // second DWORD
}



/****************************************************************************

    This function conforms to the standard Midi input driver message proc
    (midMessage), which is documented in mmddk.d.

****************************************************************************/
DWORD APIENTRY midMessage(DWORD id, DWORD msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
{
    PMIDIALLOC pInClient;

    switch (msg) {

        case MIDM_GETNUMDEVS:
            D2(("MIDM_GETNUMDEVS"));
            return 0;

        case MIDM_GETDEVCAPS:
            D2(("MIDM_GETDEVCAPS"));
            return midiGetDevCaps(id, MidiInDevice, (LPBYTE)dwParam1,
                                  (DWORD)dwParam2);

        case MIDM_OPEN:
            D2(("MIDM_OPEN"));
            return midiOpen(MidiInDevice, id, dwUser, dwParam1, dwParam2);

        case MIDM_CLOSE:
            D2(("MIDM_CLOSE"));
            pInClient = (PMIDIALLOC)dwUser;

            //
            // Call our task to see if it's ready to complete
            //
            if (midiThreadCall(MidiThreadClose, pInClient) != 0L) {
                return MIDIERR_STILLPLAYING;
            }

            //
            // Wait for our thread to terminate and close our device
            //
            WaitForSingleObject(pInClient->ThreadHandle, INFINITE);
            CloseHandle(pInClient->ThreadHandle);

            //
            // Tell the caller we're done
            //
            midiCallback(pInClient, MIM_CLOSE, 0L, 0L);

            midiCleanUp(pInClient);

            return MMSYSERR_NOERROR;

        case MIDM_ADDBUFFER:
            D2(("MIDM_ADDBUFFER"));

            // check if it's been prepared
            if (!(((LPMIDIHDR)dwParam1)->dwFlags & MHDR_PREPARED))
                return MIDIERR_UNPREPARED;

            WinAssert(!(((LPMIDIHDR)dwParam1)->dwFlags & MHDR_INQUEUE));

            // if it is already in our Q, then we cannot do this
            if ( ((LPMIDIHDR)dwParam1)->dwFlags & MHDR_INQUEUE )
                return ( MIDIERR_STILLPLAYING );

            // store the pointer to my MIDIALLOC structure in the midihdr
            pInClient = (PMIDIALLOC)dwUser;
            ((LPMIDIHDR)dwParam1)->reserved = (DWORD)(LPSTR)pInClient;

            return midiInWrite((LPMIDIHDR)dwParam1, pInClient);

        case MIDM_STOP:
            D2(("MIDM_PAUSE"));
            pInClient = (PMIDIALLOC)dwUser;
            pInClient->AuxParam.State = MIDI_DD_STOP;
            return midiThreadCall(MidiThreadSetState, pInClient);

        case MIDM_START:
            D2(("MIDM_RESTART"));
            pInClient = (PMIDIALLOC)dwUser;
            pInClient->AuxParam.State = MIDI_DD_RECORD;
            return midiThreadCall(MidiThreadSetState, pInClient);

        case MIDM_RESET:
            D2(("MIDM_RESET"));
            pInClient = (PMIDIALLOC)dwUser;
            pInClient->AuxParam.State = MIDI_DD_RESET;
            return midiThreadCall(MidiThreadSetState, pInClient);

        default:
            return MMSYSERR_NOTSUPPORTED;
    }

    //
    // Should not get here
    //

    WinAssert(0);
    return MMSYSERR_NOTSUPPORTED;
}

/****************************************************************************

    This function conforms to the standard Midi output driver message proc
    (modMessage), which is documented in mmddk.d.

****************************************************************************/
DWORD APIENTRY modMessage(DWORD id, DWORD msg, DWORD dwUser, DWORD dwParam1,
                          DWORD dwParam2)
{
    PMIDIALLOC pOutClient;

    switch (msg) {
    case MODM_GETNUMDEVS:
	return 0;
//        D2(("MODM_GETNUMDEVS"));
//        return sndGetNumDevs(MidiOutDevice);

    case MODM_GETDEVCAPS:
        D2(("MODM_GETDEVCAPS"));
        return midiGetDevCaps(id, MidiOutDevice, (LPBYTE)dwParam1,
                              (DWORD)dwParam2);

    case MODM_OPEN:
        D2(("MODM_OPEN"));
        return midiOpen(MidiOutDevice, id, dwUser, dwParam1, dwParam2);

    case MODM_CLOSE:
        D2(("MODM_CLOSE"));
        pOutClient = (PMIDIALLOC)dwUser;

        midiCallback(pOutClient, MOM_CLOSE, 0L, 0L);

        //
        // Close our device
        //
        midiCleanUp(pOutClient);

        return MMSYSERR_NOERROR;

    case MODM_DATA:
        D2(("MODM_DATA"));
        {
            int i;
            BYTE b[4];
            for (i = 0; i < 4; i ++) {
                b[i] = (BYTE)(dwParam1 % 256);
                dwParam1 /= 256;
            }
            return midiOutWrite(b, modMIDIlength((PMIDIALLOC)dwUser, b[0]),
                                (PMIDIALLOC)dwUser);
        }

    case MODM_LONGDATA:
        D2(("MODM_LONGDATA"));

        pOutClient = (PMIDIALLOC)dwUser;
        {
            LPMIDIHDR lpHdr;
            MMRESULT  mRet;

            //
            // check if it's been prepared
            //
            lpHdr = (LPMIDIHDR)dwParam1;
            if (!(lpHdr->dwFlags & MHDR_PREPARED)) {
                return MIDIERR_UNPREPARED;
            }

            //
            //
            //

            mRet = midiOutWrite(lpHdr->lpData, lpHdr->dwBufferLength,
                                pOutClient);

            // note that clearing the done bit or setting the inqueue bit
            // isn't necessary here since this function is synchronous -
            // the client will not get control back until it's done.

            lpHdr->dwFlags |= MHDR_DONE;

            // notify client

            if (mRet == MMSYSERR_NOERROR) {
                midiCallback(pOutClient, MOM_DONE, (DWORD)lpHdr, 0L);
            }

            return mRet;
        }


    case MODM_RESET:
        D2(("MODM_RESET"));
        return midiSetState((PMIDIALLOC)dwUser, MIDI_DD_RESET);


    case MODM_SETVOLUME:
        D2(("MODM_SETVOLUME"));
        //pOutClient = (PMIDIALLOC)dwUser;
        //pOutClient->AuxParam.GetSetData.pData = *(PBYTE *)&dwParam1;
        //pOutClient->AuxParam.GetSetData.DataLen = sizeof(DWORD);
        //pOutClient->AuxParam.GetSetData.Function = IOCTL_MIDI_SET_VOLUME;
        //return midiThreadCall(MidiThreadSetData, pOutClient);

        return sndSetData(MidiOutDevice, id, sizeof(DWORD),
                          (PBYTE)&dwParam1, IOCTL_MIDI_SET_VOLUME);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?