Проблема с использованием Windows MIDI API (без обратных вызовов при воспроизведении) - PullRequest
2 голосов
/ 20 апреля 2011

У меня подключена 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); }
}

Ответы [ 2 ]

5 голосов
/ 21 апреля 2011

Вам нужно позвонить midiInstart .Вам также нужно прокачать сообщения.Ничего не произойдет, если вы вызываете Sleep и не обслуживаете ввод.

Вот небольшой учебник по Windows MIDI .

Вот выдержка из класса( WinMidiIn ) Я написал для Win MIDI-ввода (удалена большая часть обработки ошибок, типы членов класса могут быть выведены из вызовов, которым они передаются как параметры):

{
    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;
    }
}
0 голосов
/ 24 июня 2015

Вы можете найти пример здесь https://gist.github.com/yoggy/1485181 Я выкладываю код здесь на случай, если ссылка станет мертвой

Возможно, вам не хватает midiInStart ()

#include <SDKDDKVer.h>

#include <Windows.h>

#include <stdio.h>
#include <conio.h>

#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")

void PrintMidiDevices()
{
    UINT nMidiDeviceNum;
    MIDIINCAPS caps;

    nMidiDeviceNum = midiInGetNumDevs();
    if (nMidiDeviceNum == 0) {
        fprintf(stderr, "midiInGetNumDevs() return 0...");
        return;
    }

    printf("== PrintMidiDevices() == \n");
    for (unsigned int i = 0; i < nMidiDeviceNum; ++i) {
        midiInGetDevCaps(i, &caps, sizeof(MIDIINCAPS));
        printf("\t%d : name = %s\n", i, caps.szPname);
    }
    printf("=====\n");
}

void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
    switch(wMsg) {
    case MIM_OPEN:
        printf("wMsg=MIM_OPEN\n");
        break;
    case MIM_CLOSE:
        printf("wMsg=MIM_CLOSE\n");
        break;
    case MIM_DATA:
        printf("wMsg=MIM_DATA, dwInstance=%08x, dwParam1=%08x, dwParam2=%08x\n", dwInstance, dwParam1, dwParam2);
        break;
    case MIM_LONGDATA:
        printf("wMsg=MIM_LONGDATA\n"); 
        break;
    case MIM_ERROR:
        printf("wMsg=MIM_ERROR\n");
        break;
    case MIM_LONGERROR:
        printf("wMsg=MIM_LONGERROR\n");
        break;
    case MIM_MOREDATA:
        printf("wMsg=MIM_MOREDATA\n");
        break;
    default:
        printf("wMsg = unknown\n");
        break;
    }
    return;
}

int main(int argc, char* argv[])
{
    HMIDIIN hMidiDevice = NULL;;
    DWORD nMidiPort = 0;
    UINT nMidiDeviceNum;
    MMRESULT rv;

    PrintMidiDevices();

    nMidiDeviceNum = midiInGetNumDevs();
    if (nMidiDeviceNum == 0) {
        fprintf(stderr, "midiInGetNumDevs() return 0...");
        return -1;
    }

    rv = midiInOpen(&hMidiDevice, nMidiPort, (DWORD)(void*)MidiInProc, 0, CALLBACK_FUNCTION);
    if (rv != MMSYSERR_NOERROR) {
        fprintf(stderr, "midiInOpen() failed...rv=%d", rv);
        return -1;
    }

    midiInStart(hMidiDevice);

    while(true) {
        if (!_kbhit()) {
            Sleep(100);
            continue;
        }
        int c = _getch();
        if (c == VK_ESCAPE) break;
        if (c == 'q') break;
    }

    midiInStop(hMidiDevice);
    midiInClose(hMidiDevice);
    hMidiDevice = NULL;

    return 0;
}
...