From d2530d10261f65c0e79541fc642092c178eec17c Mon Sep 17 00:00:00 2001 From: Gary Scavone Date: Fri, 14 Mar 2014 12:44:06 -0400 Subject: Updated OS-X sysex sending mechanism according to patch submitted by ptarabbia --- RtMidi.cpp | 62 ++++++++++++++++++++++++++--------------------------- doc/release.txt | 1 + tests/sysextest.cpp | 2 +- 3 files changed, 32 insertions(+), 33 deletions(-) diff --git a/RtMidi.cpp b/RtMidi.cpp index 18da68f..e6f507b 100644 --- a/RtMidi.cpp +++ b/RtMidi.cpp @@ -993,13 +993,9 @@ void MidiOutCore :: openVirtualPort( std::string portName ) data->endpoint = endpoint; } -static char *sysexBuffer = 0; - -static void sysexCompletionProc( MIDISysexSendRequest * /*sreq*/ ) +static void sysexCompletionProc( MIDISysexSendRequest *sreq ) { - //std::cout << "Completed SysEx send\n"; - delete sysexBuffer; - sysexBuffer = 0; + free( sreq ); } void MidiOutCore :: sendMessage( std::vector *message ) @@ -1021,32 +1017,34 @@ void MidiOutCore :: sendMessage( std::vector *message ) if ( message->at(0) == 0xF0 ) { - while ( sysexBuffer != 0 ) usleep( 1000 ); // sleep 1 ms - - sysexBuffer = new char[nBytes]; - if ( sysexBuffer == NULL ) { - errorString_ = "MidiOutCore::sendMessage: error allocating sysex message memory!"; - error( RtMidiError::MEMORY_ERROR, errorString_ ); - return; - } - - // Copy data to buffer. - for ( unsigned int i=0; iat(i); - - data->sysexreq.destination = data->destinationId; - data->sysexreq.data = (Byte *)sysexBuffer; - data->sysexreq.bytesToSend = nBytes; - data->sysexreq.complete = 0; - data->sysexreq.completionProc = sysexCompletionProc; - data->sysexreq.completionRefCon = &(data->sysexreq); - - result = MIDISendSysex( &(data->sysexreq) ); - if ( result != noErr ) { - errorString_ = "MidiOutCore::sendMessage: error sending MIDI to virtual destinations."; - error( RtMidiError::WARNING, errorString_ ); - return; - } - return; + // Apple's fantastic API requires us to free the allocated data in + // the completion callback but trashes the pointer and size before + // we get a chance to free it!! This is a somewhat ugly hack + // submitted by ptarabbia that puts the sysex buffer data right at + // the end of the MIDISysexSendRequest structure. This solution + // does not require that we wait for a previous sysex buffer to be + // sent before sending a new one, which was the old way we did it. + MIDISysexSendRequest *newRequest = (MIDISysexSendRequest *) malloc(sizeof(struct MIDISysexSendRequest) + nBytes); + char * sysexBuffer = ((char *) newRequest) + sizeof(struct MIDISysexSendRequest); + + // Copy data to buffer. + for ( unsigned int i=0; iat(i); + + newRequest->destination = data->destinationId; + newRequest->data = (Byte *)sysexBuffer; + newRequest->bytesToSend = nBytes; + newRequest->complete = 0; + newRequest->completionProc = sysexCompletionProc; + newRequest->completionRefCon = newRequest; + + result = MIDISendSysex(newRequest); + if ( result != noErr ) { + free( newRequest ); + errorString_ = "MidiOutCore::sendMessage: error sending MIDI to virtual destinations."; + error( RtMidiError::WARNING, errorString_ ); + return; + } + return; } else if ( nBytes > 3 ) { errorString_ = "MidiOutCore::sendMessage: message format problem ... not sysex but > 3 bytes?"; diff --git a/doc/release.txt b/doc/release.txt index 7eefe46..3d8b59a 100644 --- a/doc/release.txt +++ b/doc/release.txt @@ -13,6 +13,7 @@ v2.1.0: (?? 2014) - added custom error hook that allows the client to capture an RtMidi error outside of the RtMidi code - fix for portnames in Windows when UNICODE is defined - added RtMidi::isPortOpen function +- updated OS-X sysex sending mechanism (ptarabbia) v2.0.1: (26 July 2012) - small fixes for problems reported by Chris Arndt (scoping, preprocessor, and include) diff --git a/tests/sysextest.cpp b/tests/sysextest.cpp index 68b9a0d..39228ea 100644 --- a/tests/sysextest.cpp +++ b/tests/sysextest.cpp @@ -80,7 +80,7 @@ int main( int argc, char *argv[] ) midiout->sendMessage( &message ); SLEEP( 500 ); // pause a little - // Create a long sysex messages of numbered bytes and send it out. + // Create a long sysex message of numbered bytes and send it out. for ( int n=0; n<2; n++ ) { message.clear(); message.push_back( 240 ); -- cgit v1.2.3