just started using RtMIDI in Xcode to prototype up some MIDI stuff. It's working fine but hit a stumbling block.
Using the example midiout.cpp without modifying anything:
- If I send MIDI events to an already existing MIDI port, all events are sent ok.
- If I send MIDI events to a created virtual port, all events except sysex events are sent.
Having a look in the library code, all MIDI events except sysex are sent (on OSX) using the os call MIDIReceived. Sysex events are sent using MIDISendSysex. This is as it should be.
Now, no errors are thrown, everything is being executed as it should, the MIDISendSysex call is not failing - just that no sysex events arrive at the destination. They just disappear into a black hole!
Anybody else come across this or have any help, suggestions, workarounds?
Thanks,
(Xcode 4.6.2, OSX 10.9.1, using MIDIMonitor & MIDIPipe to monitor the traffic on MIDI ports, both show same results of sysex events not arriving on virtual ports from midiout.cpp)
Ok, here's the sendMessage routing that's doing the actual sending:
void MidiOutCore :: sendMessage( std::vector *message )
{
// ------------------------------------------------------------------------
// We use the MIDISendSysex() function to asynchronously send sysex
// messages. Otherwise, we use a single CoreMidi MIDIPacket.
// ------------------------------------------------------------------------
// error handling code removed for brevity
MIDITimeStamp timeStamp = AudioGetCurrentHostTime();
CoreMidiData *data = static_cast (apiData_);
OSStatus result;
// ------------------------------------------------------------------------
// IF EVENT IS SYSEX
// ------------------------------------------------------------------------
if ( message->at(0) == 0xF0 ) { // sysex start byte
while ( sysexBuffer != 0 ) usleep( 1000 ); // sleep 1 ms
sysexBuffer = new char[nBytes];
// Copy data to buffer.
for ( unsigned int i=0; iat(i);
// build sysex request
data->sysexreq.destination = data->destinationId; // destinaiondId is valid endpointref
data->sysexreq.data = (Byte *)sysexBuffer;
data->sysexreq.bytesToSend = nBytes;
data->sysexreq.complete = 0;
data->sysexreq.completionProc = sysexCompletionProc;
data->sysexreq.completionRefCon = &(data->sysexreq);
// send the data
// this works when we are connected to a 'real' MIDI port/device, but fails on a virtual port
// destinationId is an endpointref and valid and id is good
// tried to use data->endpoint (also an endpointref with id) but doesn't send either
result = MIDISendSysex( &(data->sysexreq) );
return;
}
// ------------------------------------------------------------------------
// IF EVENT IS NOT SYSEX
// ------------------------------------------------------------------------
MIDIPacketList packetList;
MIDIPacket *packet = MIDIPacketListInit( &packetList );
packet = MIDIPacketListAdd( &packetList, sizeof(packetList), packet, timeStamp, nBytes, (const Byte *) &message->at( 0 ) );
// Send to any destinations that may have connected to us.
// this sends to virtual MIDI ports
if ( data->endpoint ) {
result = MIDIReceived( data->endpoint, &packetList );
if ( result != noErr ) {
errorString_ = "MidiOutCore::sendMessage: error sending MIDI to virtual destinations.";
RtMidi::error( RtError::WARNING, errorString_ );
}
}
// And send to an explicit destination port if we're connected.
// this sends to regular real MIDI devices we are connected to, not virtual ports
if ( connected_ ) {
result = MIDISend( data->port, data->destinationId, &packetList );
if ( result != noErr ) {
errorString_ = "MidiOutCore::sendMessage: error sending MIDI message to port.";
RtMidi::error( RtError::WARNING, errorString_ );
}
}
}