使用Windows MIDI API时遇到问题(播放时无回调)

Pib*_*ben 3 c windows midi

我有一个USB连接的MIDI键盘.它在其他应用程序中工作正常.但是,在我自己的程序中却没有.midiInOpen()调用通过,我得到一个回调(从打开设备)但我在播放键盘时没有得到任何回调.

通过使用midiInGetDevCaps(),我可以看到我正在使用正确的设备.

有任何想法吗?其他(商业)应用程序是否可以使用其他API?

static void CALLBACK myFunc(HMIDIIN handle, UINT uMsg,
                            DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) {
   printf("Callback!"\n);
}

int main() {

   unsigned long result;
   HMIDIIN       inHandle;

   result = midiInOpen(&inHandle, 0, (DWORD)myFunc, 0, CALLBACK_FUNCTION);
   if (result)
   {
      printf("There was an error opening MIDI\n");
   }

   while(1) { Sleep(1); }
}
Run Code Online (Sandbox Code Playgroud)

sea*_*n e 6

你需要打电话给midiInstart.您还需要提取消息.如果您正在调用Sleep而不是服务输入,那么什么都不会发生.

这里有一些关于Windows MIDI教程.

这是我为Win MIDI输入编写的类(WinMidiIn)的摘录(删除了大量错误处理,类成员类型可以从它们传递给params的调用中推断出来):

{
    MMRESULT res = ::midiInOpen(&mMidiIn, mDeviceIdx, (DWORD_PTR)MidiInCallbackProc, (DWORD_PTR)this, 
        CALLBACK_FUNCTION | MIDI_IO_STATUS);
    if (MMSYSERR_NOERROR != res)
        return;

    const int kDataBufLen = 512;
    int idx;
    for (idx = 0; idx < MIDIHDR_CNT; ++idx)
    {
        mMidiHdrs[idx].lpData = (LPSTR) ::malloc(kDataBufLen);
        mMidiHdrs[idx].dwBufferLength = kDataBufLen;

        res = ::midiInPrepareHeader(mMidiIn, &mMidiHdrs[idx], (UINT)sizeof(MIDIHDR));
        res = ::midiInAddBuffer(mMidiIn, &mMidiHdrs[idx], sizeof(MIDIHDR));
    }

    res = ::midiInStart(mMidiIn);

    for (;;)
    {
        DWORD result;
        MSG msg;

        // Read all of the messages in this next loop, 
        // removing each message as we read it.
        while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            // If it is a quit message, exit.
            if (msg.message == WM_QUIT)
                break;

            // Otherwise, dispatch the message.
            ::DispatchMessage(&msg);
        }

        // Wait for any message sent or posted to this queue 
        // or for one of the passed handles be set to signaled.
        result = ::MsgWaitForMultipleObjects(1, &mDoneEvent, FALSE, INFINITE, QS_ALLINPUT);

        // The result tells us the type of event we have.
        if (result == (WAIT_OBJECT_0 + 1))
        {
            // New messages have arrived. 
            // Continue to the top of the always while loop to 
            // dispatch them and resume waiting.
            continue;
        }
        else if (WAIT_TIMEOUT == result)
            continue;
        else if (WAIT_OBJECT_0 == result)
            break; // done event fired
        else
            break; // ??
    }

    res = ::midiInReset(mMidiIn);

    for (idx = 0; idx < MIDIHDR_CNT; ++idx)
    {
        res = ::midiInUnprepareHeader(mMidiIn, &mMidiHdrs[idx], (UINT)sizeof(MIDIHDR));
        ::free(mMidiHdrs[idx].lpData);
        mMidiHdrs[idx].lpData = NULL;
    }

    res = ::midiInClose(mMidiIn);
    mMidiIn = NULL;
}



void CALLBACK 
MidiInCallbackProc(HMIDIIN hmi, 
                          UINT wMsg, 
                          DWORD dwInstance, 
                          DWORD dwParam1, 
                          DWORD dwParam2)
{
    MMRESULT res;
    LPMIDIHDR hdr;
    WinMidiIn * _this = (WinMidiIn *) dwInstance;

    switch (wMsg)
    {
    case MIM_DATA:
        //  dwParam1 is the midi event with status in the low byte of the low word
        //  dwParam2 is the event time in ms since the start of midi in
        // data: LOBYTE(dwParam1), HIBYTE(dwParam1), LOBYTE(HIWORD(dwParam1))
        break;
    case MIM_ERROR:
        break;
    case MIM_LONGDATA:
        //  dwParam1 is the lpMidiHdr
        //  dwParam2 is the event time in ms since the start of midi in
        hdr = (LPMIDIHDR) dwParam1;
        // sysex: (byte*)hdr->lpData, (int)hdr->dwBytesRecorded
        res = ::midiInAddBuffer(_this->mMidiIn, hdr, sizeof(MIDIHDR));
        break;
    case MIM_LONGERROR:
        hdr = (LPMIDIHDR) dwParam1;
        res = ::midiInAddBuffer(_this->mMidiIn, hdr, sizeof(MIDIHDR));
        break;
    }
}
Run Code Online (Sandbox Code Playgroud)