views:

204

answers:

2

As a side project, I am implementing a MIDI matrix to interconnect a number of MIDI keyboards with sound sources. The key requirement here is to echo MIDI data received on an input port to a selected output port.

Having created the necessary P/Invoke declarations & wrappers, I notice that the Win32 MIDI documentation for MidiInProc states: "Applications should not call any multimedia functions from inside the callback function, as doing so can cause a deadlock".

Given that it is unsafe to call midiOutShortMsg from within a MidiInProc, my current solution is to write MIDI data to a queue and set an event. A worker thread waits on the event and calls midiOutShortMsg. The general idea is this:-

static void InputCallback( int hMidiIn, uint wMsg, uint dwInstance, uint dwParam1, uint dwParam2 )
{
    if( wMsg == MM_MIM_DATA )
    {
        data.EnQueue( dwParam1 );    //data is a Queue<uint>
        dataReady.Set();      //dataReady is AutoResetEvent
    }
}


void ThreadProc
{
    while( !_done )
    {
        dataReady.WaitOne();
        midiOutShortMsg( hMidiOut, data.DeQueue() );
    }
}

However, whilst this has been working fine in testing, there appears to be a window of opportunity between the call to dataReady.Set() and InputCallBack returning during which preemption could allow the worker thread to call midiOutShortMsg (albeit in another thread).

Is this approach safe?

+1  A: 

Your question might be a bit domain-specific for StackOverflow. If no one here answers it, check out: http://groups.google.com/group/mididev?hl=en&amp;lnk=

MusiGenesis
Thanks. looks like a useful resource.
MikeJ-UK
Just don't tell them I sent you. I tend to bad-mouth MIDI at every opportunity (I spent years on a MIDI app, so I feel I'm entitled). :)
MusiGenesis
+2  A: 

Looks safe to me: even if your two threads are running at the same time, it's still only the worker thread that might block, so this won't deadlock your input callback.

redtuna
I second that. A deadlock only occurs if a thread waits for itself to finish - which it can't because it's waiting. In this case, the thread is waiting for another thread.
configurator