3
votes

I am trying to develop a C++ Windows application to process MIDI information coming from some MIDI device. The OS I am force to work with is Windows 8.1 64 bit. The development environment is Qt.

After having read tons of web pages I've found out that windows has a set of low level functions to handle MIDI data that allows to connect the windows MIDI driver with any application. These functions are described here http://msdn.microsoft.com/en-us/library/windows/desktop/dd757277(v=vs.85).aspx

The software I wrote so far works properly and I am able to process incoming MIDI short messages within my application. Nonetheless, when it comes to pass some buffer from the application to the driver and viceversa, the software fails and an exception is thrown about invalid memory address. By using the debugger I have discovered that the memory address is natively a 64 bits address but when the driver passes the address back to the application (actually to a callback) it is just 32 bits. And not just any 32 its, but exactly the lowe 32 bits of the original 64 bits address.

So, I am getting very confused and I have some questions: 1. Which is the Windows SDK I should be using ? And where can I find it ? (I am already using one but I am not sure it is the right one). 2. Ar ethere 64 bits windows MIDI functions ? And where can I find the documentation for them ? (I am already using some but they are under the big label of win32 API ...)

Thank you very much for your help.

Fabrizio

UPDATE #1.

This is a snippet of code concerning the callback function. The exception is thrown because the element BufferPtr->dwBytesRecorded is not accessible. The actual problem is that the windows data type DWORD is a typedef for an unsigned long but I believe that it should be a long long instead. In my mind if I was using the right 64 bits windows SDK this typedef should have been set correctly.

void CALLBACK MIDIInputDevice::MIDIProcessingCallback(HMIDIIN hMidiIn,UINT wMsg,DWORD_PTR dwInstance,DWORD dwParam1,DWORD dwParam2)
{
    MIDIInputDevice* ThisDevice;
    QString MessageStr;

    ThisDevice = (MIDIInputDevice*)dwInstance;
    switch (wMsg)
    {
        case MIM_LONGDATA:

            unsigned int ByteIndex;
            MIDIHDR* BufferPtr;

            BufferPtr = (MIDIHDR*)dwParam1;
            MessageStr = QString("Device #%1 - Long data: ")
                    .arg(ThisDevice->getIndex());
            for (ByteIndex = 0; ByteIndex < (BufferPtr->dwBytesRecorded)-1; ByteIndex++)
            {
                MessageStr.append(QString("%1:").arg(*((BufferPtr->lpData)+ByteIndex),2,16,QChar('0')));
            }
            MessageStr.append(QString("%1").arg(*((BufferPtr->lpData)+BufferPtr->dwBytesRecorded-1),2,16,QChar('0')));
            MessageStr.append(" - Time: %1 ms").arg(dwParam2);
            emit ThisDevice->talk(MessageStr);
            break;
...

This is the line of code where I am linking the callback to the driver.

LastResult = midiInOpen(&Handle,Index,(DWORD_PTR)(&MIDIInputDevice::MIDIProcessingCallback),(DWORD_PTR)(this),CALLBACK_FUNCTION | MIDI_IO_STATUS);
1
Can you include the exact function call where you set the callback, and your callback function? - All Workers Are Essential
Do you call midiInPrepareHeader before calling midiInAddBuffer to registering the buffer with the in port? - obiwanjacobi
Yes I do call midiInPrepareHeader before midiInAddBuffer and the system does not return any error. - Fabry

1 Answers

3
votes

You are already using the 64 bit interface. You are just using it wrongly. The problems are in your code. Here's the docs for the callback: http://msdn.microsoft.com/en-us/library/windows/desktop/dd798460.aspx

And here's the prototype for the callback:

void CALLBACK MidiInProc(
  HMIDIIN hMidiIn,
  UINT wMsg,
  DWORD_PTR dwInstance,
  DWORD_PTR dwParam1,
  DWORD_PTR dwParam2
);

Your mistake is to use the 32 bit type DWORD rather than the pointer sized DWORD_PTR. That is why the addresses are truncated.

I trust that MIDIProcessingCallback is a static member function.