Browse Source

Updated OS-X sysex sending mechanism according to patch submitted by ptarabbia

Gary Scavone 11 years ago
parent
commit
d2530d1026
3 changed files with 32 additions and 33 deletions
  1. 30 32
      RtMidi.cpp
  2. 1 0
      doc/release.txt
  3. 1 1
      tests/sysextest.cpp

+ 30 - 32
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<unsigned char> *message )
@@ -1021,32 +1017,34 @@ void MidiOutCore :: sendMessage( std::vector<unsigned char> *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; i<nBytes; ++i ) sysexBuffer[i] = message->at(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; i<nBytes; ++i ) sysexBuffer[i] = message->at(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?";

+ 1 - 0
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)

+ 1 - 1
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 );