changeset 565:3086876472dc

* rtmidi & activity updates
author Chris Cannam
date Tue, 24 Feb 2009 17:25:55 +0000
parents ecef2f1bec18
children e2281de2361c
files data/midi/MIDIInput.cpp data/midi/rtmidi/RtMidi.cpp data/midi/rtmidi/RtMidi.h
diffstat 3 files changed, 179 insertions(+), 114 deletions(-) [+]
line wrap: on
line diff
--- a/data/midi/MIDIInput.cpp	Tue Feb 24 11:39:45 2009 +0000
+++ b/data/midi/MIDIInput.cpp	Tue Feb 24 17:25:55 2009 +0000
@@ -24,7 +24,7 @@
     try {
         m_rtmidi = new RtMidiIn(name.toStdString());
         m_rtmidi->setCallback(staticCallback, this);
-        m_rtmidi->openPort();
+        m_rtmidi->openPort(0, tr("Input").toStdString());
     } catch (RtError e) {
         e.printMessage();
         delete m_rtmidi;
--- a/data/midi/rtmidi/RtMidi.cpp	Tue Feb 24 11:39:45 2009 +0000
+++ b/data/midi/rtmidi/RtMidi.cpp	Tue Feb 24 17:25:55 2009 +0000
@@ -8,7 +8,7 @@
     RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/
 
     RtMidi: realtime MIDI i/o C++ classes
-    Copyright (c) 2003-2007 Gary P. Scavone
+    Copyright (c) 2003-2009 Gary P. Scavone
 
     Permission is hereby granted, free of charge, to any person
     obtaining a copy of this software and associated documentation files
@@ -35,7 +35,7 @@
 */
 /**********************************************************************/
 
-// RtMidi: Version 1.0.7
+// RtMidi: Version 1.0.8
 
 #include "RtMidi.h"
 #include <sstream>
@@ -69,9 +69,9 @@
 //  Common RtMidiIn Definitions
 //*********************************************************************//
 
-RtMidiIn :: RtMidiIn(std::string name) : RtMidi()
+RtMidiIn :: RtMidiIn( const std::string clientName ) : RtMidi()
 {
-  this->initialize(name);
+  this->initialize( clientName );
 }
 
 void RtMidiIn :: setCallback( RtMidiCallback callback, void *userData )
@@ -144,9 +144,9 @@
 //  Common RtMidiOut Definitions
 //*********************************************************************//
 
-RtMidiOut :: RtMidiOut(std::string name) : RtMidi()
+RtMidiOut :: RtMidiOut( const std::string clientName ) : RtMidi()
 {
-  this->initialize(name);
+  this->initialize( clientName );
 }
 
 
@@ -187,20 +187,24 @@
   RtMidiIn::RtMidiInData *data = static_cast<RtMidiIn::RtMidiInData *> (procRef);
   CoreMidiData *apiData = static_cast<CoreMidiData *> (data->apiData);
 
-  bool continueSysex = false;
   unsigned char status;
   unsigned short nBytes, iByte, size;
   unsigned long long time;
-  RtMidiIn::MidiMessage message;
+
+  bool& continueSysex = data->continueSysex;
+  RtMidiIn::MidiMessage& message = data->message;
+
   const MIDIPacket *packet = &list->packet[0];
   for ( unsigned int i=0; i<list->numPackets; ++i ) {
 
     // My interpretation of the CoreMIDI documentation: all message
     // types, except sysex, are complete within a packet and there may
     // be several of them in a single packet.  Sysex messages can be
-    // broken across multiple packets but are bundled alone within a
-    // packet.  I'm assuming that sysex messages, if segmented, must
-    // be complete within the same MIDIPacketList.
+    // broken across multiple packets and PacketLists but are bundled
+    // alone within each packet (these packets do not contain other
+    // message types).  If sysex messages are split across multiple
+    // MIDIPacketLists, they must be handled by multiple calls to this
+    // function.
 
     nBytes = packet->length;
     if ( nBytes == 0 ) continue;
@@ -220,12 +224,13 @@
     iByte = 0;
     if ( continueSysex ) {
       // We have a continuing, segmented sysex message.
-      if ( !(data->ignoreFlags & 0x01) ) {
+      if ( !( data->ignoreFlags & 0x01 ) ) {
         // If we're not ignoring sysex messages, copy the entire packet.
         for ( unsigned int j=0; j<nBytes; j++ )
           message.bytes.push_back( packet->data[j] );
       }
-      if ( packet->data[nBytes] == 0xF7 ) continueSysex = false;
+      continueSysex = packet->data[nBytes-1] != 0xF7;
+
       if ( !continueSysex ) {
         // If not a continuing sysex message, invoke the user callback function or queue the message.
         if ( data->usingCallback && message.bytes.size() > 0 ) {
@@ -259,7 +264,7 @@
             iByte = nBytes;
           }
           else size = nBytes - iByte;
-          if ( packet->data[nBytes] == 0xF7 ) continueSysex = false;
+          continueSysex =  packet->data[nBytes-1] != 0xF7;
         }
         else if ( status < 0xF3 ) {
           if ( status == 0xF1 && (data->ignoreFlags & 0x02) ) {
@@ -311,13 +316,11 @@
   }
 }
 
-void RtMidiIn :: initialize(std::string name)
+void RtMidiIn :: initialize( const std::string& clientName )
 {
   // Set up our client.
   MIDIClientRef client;
-  OSStatus result = MIDIClientCreate
-    ( CFStringCreateWithBytes(0, (unsigned char *)name.data(),
-      name.size(), kCFStringEncodingUTF8, 0), NULL, NULL, &client );
+  OSStatus result = MIDIClientCreate( CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII ), NULL, NULL, &client );
   if ( result != noErr ) {
     errorString_ = "RtMidiIn::initialize: error creating OS-X MIDI client object.";
     error( RtError::DRIVER_ERROR );
@@ -331,7 +334,7 @@
   inputData_.apiData = (void *) data;
 }
 
-void RtMidiIn :: openPort( unsigned int portNumber )
+void RtMidiIn :: openPort( unsigned int portNumber, const std::string portName )
 {
   if ( connected_ ) {
     errorString_ = "RtMidiIn::openPort: a valid connection already exists!";
@@ -354,7 +357,9 @@
 
   MIDIPortRef port;
   CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
-  OSStatus result = MIDIInputPortCreate( data->client, CFSTR("MIDI Input Port"), midiInputCallback, (void *)&inputData_, &port );
+  OSStatus result = MIDIInputPortCreate( data->client, 
+                                         CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
+                                         midiInputCallback, (void *)&inputData_, &port );
   if ( result != noErr ) {
     MIDIClientDispose( data->client );
     errorString_ = "RtMidiIn::openPort: error creating OS-X MIDI input port.";
@@ -481,13 +486,11 @@
   return stringName;
 }
 
-void RtMidiOut :: initialize(std::string name)
+void RtMidiOut :: initialize( const std::string& clientName )
 {
   // Set up our client.
   MIDIClientRef client;
-  OSStatus result = MIDIClientCreate
-    ( CFStringCreateWithBytes(0, (unsigned char *)name.data(),
-      name.size(), kCFStringEncodingUTF8, 0), NULL, NULL, &client );
+  OSStatus result = MIDIClientCreate( CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII ), NULL, NULL, &client );
   if ( result != noErr ) {
     errorString_ = "RtMidiOut::initialize: error creating OS-X MIDI client object.";
     error( RtError::DRIVER_ERROR );
@@ -500,7 +503,7 @@
   apiData_ = (void *) data;
 }
 
-void RtMidiOut :: openPort( unsigned int portNumber )
+void RtMidiOut :: openPort( unsigned int portNumber, const std::string portName )
 {
   if ( connected_ ) {
     errorString_ = "RtMidiOut::openPort: a valid connection already exists!";
@@ -523,7 +526,9 @@
 
   MIDIPortRef port;
   CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
-  OSStatus result = MIDIOutputPortCreate( data->client, CFSTR("Virtual MIDI Output Port"), &port );
+  OSStatus result = MIDIOutputPortCreate( data->client, 
+                                          CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
+                                          &port );
   if ( result != noErr ) {
     MIDIClientDispose( data->client );
     errorString_ = "RtMidiOut::openPort: error creating OS-X MIDI output port.";
@@ -592,33 +597,59 @@
 
 void RtMidiOut :: sendMessage( std::vector<unsigned char> *message )
 {
+  // The CoreMidi documentation indicates a maximum PackList size of
+  // 64K, so we may need to break long sysex messages into pieces and
+  // send via separate lists.
   unsigned int nBytes = message->size();
-  // Pad the buffer for extra (unknown) structure data.
-  Byte buffer[nBytes+32];
-  MIDIPacketList *pktlist = (MIDIPacketList *) buffer;
-  MIDIPacket *curPacket = MIDIPacketListInit( pktlist );
+  if ( nBytes == 0 ) {
+    errorString_ = "RtMidiOut::sendMessage: no data in message argument!";      
+    error( RtError::WARNING );
+    return;
+  }
 
+  if ( nBytes > 3 && ( message->at(0) != 0xF0 ) ) {
+    errorString_ = "RtMidiOut::sendMessage: message format problem ... not sysex but > 3 bytes?";      
+    error( RtError::WARNING );
+    return;
+  }
+
+  unsigned int packetBytes, bytesLeft = nBytes;
+  unsigned int messageIndex = 0;
   MIDITimeStamp timeStamp = 0;
-  curPacket = MIDIPacketListAdd( pktlist, sizeof(buffer), curPacket, timeStamp, nBytes, &message->at(0) );
-
   CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
 
-  // Send to any destinations that may have connected to us.
-  OSStatus result;
-  if ( data->endpoint ) {
-    result = MIDIReceived( data->endpoint, pktlist );
-    if ( result != noErr ) {
-      errorString_ = "RtMidiOut::sendMessage: error sending MIDI to virtual destinations.";
-      error( RtError::WARNING );
+  while ( bytesLeft > 0 ) {
+
+    packetBytes = ( bytesLeft > 32736 ) ? 32736 : bytesLeft;
+    Byte buffer[packetBytes + 32]; // extra memory for other structure variables
+    MIDIPacketList *packetList = (MIDIPacketList *) buffer;
+    MIDIPacket *curPacket = MIDIPacketListInit( packetList );
+
+    curPacket = MIDIPacketListAdd( packetList, packetBytes+32, curPacket, timeStamp, packetBytes, (const Byte *) &message->at( messageIndex ) );
+    if ( !curPacket ) {
+      errorString_ = "RtMidiOut::sendMessage: could not allocate packet list";      
+      error( RtError::DRIVER_ERROR );
     }
-  }
+    messageIndex += packetBytes;
+    bytesLeft -= packetBytes;
 
-  // And send to an explicit destination port if we're connected.
-  if ( connected_ ) {
-    result = MIDISend( data->port, data->destinationId, pktlist );
-    if ( result != noErr ) {
-      errorString_ = "RtMidiOut::sendMessage: error sending MIDI message to port.";
-      error( RtError::WARNING );
+    // Send to any destinations that may have connected to us.
+    OSStatus result;
+    if ( data->endpoint ) {
+      result = MIDIReceived( data->endpoint, packetList );
+      if ( result != noErr ) {
+        errorString_ = "RtMidiOut::sendMessage: error sending MIDI to virtual destinations.";
+        error( RtError::WARNING );
+      }
+    }
+
+    // And send to an explicit destination port if we're connected.
+    if ( connected_ ) {
+      result = MIDISend( data->port, data->destinationId, packetList );
+      if ( result != noErr ) {
+        errorString_ = "RtMidiOut::sendMessage: error sending MIDI message to port.";
+        error( RtError::WARNING );
+      }
     }
   }
 }
@@ -717,7 +748,9 @@
 
     // This is a bit weird, but we now have to decode an ALSA MIDI
     // event (back) into MIDI bytes.  We'll ignore non-MIDI types.
-    message.bytes.clear();
+    if ( !continueSysex )
+      message.bytes.clear();
+
     switch ( ev->type ) {
 
 		case SND_SEQ_EVENT_PORT_SUBSCRIBED:
@@ -727,8 +760,15 @@
       break;
 
 		case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
+#if defined(__RTMIDI_DEBUG__)
       std::cerr << "RtMidiIn::alsaMidiHandler: port connection has closed!\n";
-      data->doInput = false;
+      // FIXME: this is called for all unsubscribe events, even ones
+      //not related to this particular connection.  As it stands, I
+      //see no data provided in the "source" and "dest" fields so
+      //there is nothing we can do about this at this time.
+      // std::cout << "sender = " << ev->source.client << ", dest = " << ev->dest.port << std::endl;
+#endif
+      //data->doInput = false;
       break;
 
     case SND_SEQ_EVENT_QFRAME: // MIDI time code
@@ -772,7 +812,7 @@
       else
         message.bytes.insert( message.bytes.end(), buffer, &buffer[nBytes] );
 
-      continueSysex = ( ev->type == SND_SEQ_EVENT_SYSEX && message.bytes.back() != 0xF7 );
+      continueSysex = ( ( ev->type == SND_SEQ_EVENT_SYSEX ) && ( message.bytes.back() != 0xF7 ) );
       if ( continueSysex )
         break;
 
@@ -798,7 +838,7 @@
     snd_seq_free_event(ev);
     if ( message.bytes.size() == 0 ) continue;
 
-    if ( data->usingCallback ) {
+    if ( data->usingCallback && !continueSysex ) {
       RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
       callback( message.timeStamp, &message.bytes, data->userData );
     }
@@ -817,10 +857,10 @@
   return 0;
 }
 
-void RtMidiIn :: initialize(std::string name)
+void RtMidiIn :: initialize( const std::string& clientName )
 {
   // Set up the ALSA sequencer client.
-	snd_seq_t *seq;
+  snd_seq_t *seq;
   int result = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK);
   if ( result < 0 ) {
     errorString_ = "RtMidiIn::initialize: error creating ALSA sequencer input client object.";
@@ -828,7 +868,7 @@
 	}
 
   // Set client name.
-  snd_seq_set_client_name(seq, name.c_str());
+  snd_seq_set_client_name( seq, clientName.c_str() );
 
   // Save our api-specific connection information.
   AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
@@ -864,7 +904,10 @@
 		snd_seq_port_info_set_client( pinfo, client );
 		snd_seq_port_info_set_port( pinfo, -1 );
 		while ( snd_seq_query_next_port( seq, pinfo ) >= 0 ) {
-      if ( !PORT_TYPE( pinfo, type ) )  continue;
+      unsigned int atyp = snd_seq_port_info_get_type( pinfo );
+      if ( ( atyp & SND_SEQ_PORT_TYPE_MIDI_GENERIC ) == 0 ) continue;
+      unsigned int caps = snd_seq_port_info_get_capability( pinfo );
+      if ( ( caps & type ) != type ) continue;
       if ( count == portNumber ) return 1;
       count++;
 		}
@@ -875,7 +918,7 @@
   return 0;
 }
 
-void RtMidiIn :: openPort( unsigned int portNumber )
+void RtMidiIn :: openPort( unsigned int portNumber, const std::string portName )
 {
   if ( connected_ ) {
     errorString_ = "RtMidiIn::openPort: a valid connection already exists!";
@@ -889,8 +932,8 @@
     error( RtError::NO_DEVICES_FOUND );
   }
 
-  snd_seq_port_info_t *pinfo;
-  snd_seq_port_info_alloca( &pinfo );
+	snd_seq_port_info_t *pinfo;
+	snd_seq_port_info_alloca( &pinfo );
   std::ostringstream ost;
   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
   if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) == 0 ) {
@@ -899,8 +942,6 @@
     error( RtError::INVALID_PARAMETER );
   }
 
-  char name[20];
-  sprintf(name, "Input %d", portNumber + 1);
 
   snd_seq_addr_t sender, receiver;
   sender.client = snd_seq_port_info_get_client( pinfo );
@@ -919,7 +960,7 @@
     snd_seq_port_info_set_timestamping(pinfo, 1);
     snd_seq_port_info_set_timestamp_real(pinfo, 1);    
     snd_seq_port_info_set_timestamp_queue(pinfo, data->queue_id);
-    snd_seq_port_info_set_name(pinfo, name);
+    snd_seq_port_info_set_name(pinfo,  portName.c_str() );
     data->vport = snd_seq_create_port(data->seq, pinfo);
   
     if ( data->vport < 0 ) {
@@ -1055,12 +1096,20 @@
 
 std::string RtMidiIn :: getPortName( unsigned int portNumber )
 {
-	snd_seq_port_info_t *pinfo;
-	snd_seq_port_info_alloca( &pinfo );
+  snd_seq_client_info_t *cinfo;
+  snd_seq_port_info_t *pinfo;
+  snd_seq_client_info_alloca( &cinfo );
+  snd_seq_port_info_alloca( &pinfo );
 
   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
   if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) ) {
-    std::string stringName = std::string( snd_seq_port_info_get_name( pinfo ) );
+    int cnum = snd_seq_port_info_get_client( pinfo );
+    snd_seq_get_any_client_info( data->seq, cnum, cinfo );
+    std::ostringstream os;
+    os << snd_seq_client_info_get_name( cinfo );
+    os << ":";
+    os << snd_seq_port_info_get_port( pinfo );
+    std::string stringName = os.str();
     return stringName;
   }
 
@@ -1086,12 +1135,20 @@
 
 std::string RtMidiOut :: getPortName( unsigned int portNumber )
 {
-	snd_seq_port_info_t *pinfo;
-	snd_seq_port_info_alloca( &pinfo );
+  snd_seq_client_info_t *cinfo;
+  snd_seq_port_info_t *pinfo;
+  snd_seq_client_info_alloca( &cinfo );
+  snd_seq_port_info_alloca( &pinfo );
 
   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
   if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) ) {
-    std::string stringName = std::string( snd_seq_port_info_get_name( pinfo ) );
+    int cnum = snd_seq_port_info_get_client(pinfo);
+    snd_seq_get_any_client_info( data->seq, cnum, cinfo );
+    std::ostringstream os;
+    os << snd_seq_client_info_get_name(cinfo);
+    os << ":";
+    os << snd_seq_port_info_get_port(pinfo);
+    std::string stringName = os.str();
     return stringName;
   }
 
@@ -1101,18 +1158,18 @@
   return 0;
 }
 
-void RtMidiOut :: initialize(std::string name)
+void RtMidiOut :: initialize( const std::string& clientName )
 {
   // Set up the ALSA sequencer client.
-	snd_seq_t *seq;
-  int result = snd_seq_open(&seq, "default", SND_SEQ_OPEN_OUTPUT, 0);
+  snd_seq_t *seq;
+  int result = snd_seq_open( &seq, "default", SND_SEQ_OPEN_OUTPUT, SND_SEQ_NONBLOCK );
   if ( result < 0 ) {
     errorString_ = "RtMidiOut::initialize: error creating ALSA sequencer client object.";
     error( RtError::DRIVER_ERROR );
 	}
 
   // Set client name.
-  snd_seq_set_client_name(seq, name.c_str());
+  snd_seq_set_client_name( seq, clientName.c_str() );
 
   // Save our api-specific connection information.
   AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
@@ -1137,7 +1194,7 @@
   apiData_ = (void *) data;
 }
 
-void RtMidiOut :: openPort( unsigned int portNumber )
+void RtMidiOut :: openPort( unsigned int portNumber, const std::string portName )
 {
   if ( connected_ ) {
     errorString_ = "RtMidiOut::openPort: a valid connection already exists!";
@@ -1151,8 +1208,8 @@
     error( RtError::NO_DEVICES_FOUND );
   }
 
-  snd_seq_port_info_t *pinfo;
-  snd_seq_port_info_alloca( &pinfo );
+	snd_seq_port_info_t *pinfo;
+	snd_seq_port_info_alloca( &pinfo );
   std::ostringstream ost;
   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
   if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) == 0 ) {
@@ -1166,11 +1223,8 @@
   receiver.port = snd_seq_port_info_get_port( pinfo );
   sender.client = snd_seq_client_id( data->seq );
 
-  char name[20];
-  sprintf(name, "Output %d", portNumber + 1);
-
   if ( data->vport < 0 ) {
-    data->vport = snd_seq_create_simple_port( data->seq, name,
+    data->vport = snd_seq_create_simple_port( data->seq, portName.c_str(),
                                               SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
                                               SND_SEQ_PORT_TYPE_MIDI_GENERIC );
     if ( data->vport < 0 ) {
@@ -1432,7 +1486,7 @@
   return 0;
 }
 
-void RtMidiIn :: initialize(std::string name)
+void RtMidiIn :: initialize( const std::string& /*clientName*/ )
 {
   // Initialize the Irix MIDI system.  At the moment, we will not
   // worry about a return value of zero (ports) because there is a
@@ -1445,7 +1499,7 @@
   inputData_.apiData = (void *) data;
 }
 
-void RtMidiIn :: openPort( unsigned int portNumber )
+void RtMidiIn :: openPort( unsigned int portNumber, const std::string /*portName*/ )
 {
   if ( connected_ ) {
     errorString_ = "RtMidiIn::openPort: a valid connection already exists!";
@@ -1573,7 +1627,7 @@
   return stringName;
 }
 
-void RtMidiOut :: initialize(std::string name)
+void RtMidiOut :: initialize( const std::string& /*clientName*/ )
 {
   // Initialize the Irix MIDI system.  At the moment, we will not
   // worry about a return value of zero (ports) because there is a
@@ -1585,7 +1639,7 @@
   apiData_ = (void *) data;
 }
 
-void RtMidiOut :: openPort( unsigned int portNumber )
+void RtMidiOut :: openPort( unsigned int portNumber, const std::string /*portName*/ )
 {
   if ( connected_ ) {
     errorString_ = "RtMidiOut::openPort: a valid connection already exists!";
@@ -1763,21 +1817,31 @@
     unsigned char *ptr = (unsigned char *) &midiMessage;
     for ( int i=0; i<nBytes; i++ ) apiData->message.bytes.push_back( *ptr++ );
   }
-  else if ( !(data->ignoreFlags & 0x01) ) {
-    // Sysex message and we're not ignoring it
-    MIDIHDR *sysex = ( MIDIHDR *) midiMessage;
-    for ( int i=0; i<(int)sysex->dwBytesRecorded; i++ )
-      apiData->message.bytes.push_back( sysex->lpData[i] );
+  else { // Sysex message ( MIM_LONGDATA )
+    MIDIHDR *sysex = ( MIDIHDR *) midiMessage; 
+    if ( !( data->ignoreFlags & 0x01 ) ) {  
+      // Sysex message and we're not ignoring it
+      for ( int i=0; i<(int)sysex->dwBytesRecorded; i++ )
+        apiData->message.bytes.push_back( sysex->lpData[i] );
+    }
 
-    // When the callback has to be unaffected (application closes), 
-    // it seems WinMM calls it with an empty sysex to de-queue the buffer
-    // If the buffer is requeued afer that message, the PC suddenly reboots
-    // after one or two minutes (JB).
+    // The WinMM API requires that the sysex buffer be requeued after
+    // input of each sysex message.  Even if we are ignoring sysex
+    // messages, we still need to requeue the buffer in case the user
+    // decides to not ignore sysex messages in the future.  However,
+    // it seems that WinMM calls this function with an empty sysex
+    // buffer when an application closes and in this case, we should
+    // avoid requeueing it, else the computer suddenly reboots after
+    // one or two minutes.
     if ( apiData->sysexBuffer->dwBytesRecorded > 0 ) {
+      //if ( sysex->dwBytesRecorded > 0 ) {
       MMRESULT result = midiInAddBuffer( apiData->inHandle, apiData->sysexBuffer, sizeof(MIDIHDR) );
       if ( result != MMSYSERR_NOERROR )
         std::cerr << "\nRtMidiIn::midiInputCallback: error sending sysex to Midi device!!\n\n";
+
+      if ( data->ignoreFlags & 0x01 ) return;
     }
+    else return;
   }
 
   if ( data->usingCallback ) {
@@ -1792,13 +1856,11 @@
       std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
   }
 
-  // Clear the vector for the next input message.  Note that doing
-  // this here allows our code to work for sysex messages which are
-  // segmented across multiple buffers.
+  // Clear the vector for the next input message.
   apiData->message.bytes.clear();
 }
 
-void RtMidiIn :: initialize(std::string name)
+void RtMidiIn :: initialize( const std::string& /*clientName*/ )
 {
   // We'll issue a warning here if no devices are available but not
   // throw an error since the user can plugin something later.
@@ -1815,7 +1877,7 @@
   data->message.bytes.clear();  // needs to be empty for first input message
 }
 
-void RtMidiIn :: openPort( unsigned int portNumber )
+void RtMidiIn :: openPort( unsigned int portNumber, const std::string /*portName*/ )
 {
   if ( connected_ ) {
     errorString_ = "RtMidiIn::openPort: a valid connection already exists!";
@@ -1849,8 +1911,8 @@
 
   // Allocate and init the sysex buffer.
   data->sysexBuffer = (MIDIHDR*) new char[ sizeof(MIDIHDR) ];
-  data->sysexBuffer->lpData = new char[1024];
-  data->sysexBuffer->dwBufferLength = 1024;
+  data->sysexBuffer->lpData = new char[ RT_SYSEX_BUFFER_SIZE ];
+  data->sysexBuffer->dwBufferLength = RT_SYSEX_BUFFER_SIZE;
   data->sysexBuffer->dwFlags = 0;
 
   result = midiInPrepareHeader( data->inHandle, data->sysexBuffer, sizeof(MIDIHDR) );
@@ -1979,7 +2041,7 @@
   return stringName;
 }
 
-void RtMidiOut :: initialize(std::string name)
+void RtMidiOut :: initialize( const std::string& /*clientName*/ )
 {
   // We'll issue a warning here if no devices are available but not
   // throw an error since the user can plug something in later.
@@ -1994,7 +2056,7 @@
   apiData_ = (void *) data;
 }
 
-void RtMidiOut :: openPort( unsigned int portNumber )
+void RtMidiOut :: openPort( unsigned int portNumber, const std::string /*portName*/ )
 {
   if ( connected_ ) {
     errorString_ = "RtMidiOut::openPort: a valid connection already exists!";
--- a/data/midi/rtmidi/RtMidi.h	Tue Feb 24 11:39:45 2009 +0000
+++ b/data/midi/rtmidi/RtMidi.h	Tue Feb 24 17:25:55 2009 +0000
@@ -8,7 +8,7 @@
     RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/
 
     RtMidi: realtime MIDI i/o C++ classes
-    Copyright (c) 2003-2007 Gary P. Scavone
+    Copyright (c) 2003-2009 Gary P. Scavone
 
     Permission is hereby granted, free of charge, to any person
     obtaining a copy of this software and associated documentation files
@@ -35,7 +35,7 @@
 */
 /**********************************************************************/
 
-// RtMidi: Version 1.0.7
+// RtMidi: Version 1.0.8
 
 #ifndef RTMIDI_H
 #define RTMIDI_H
@@ -48,7 +48,7 @@
  public:
 
   //! Pure virtual openPort() function.
-  virtual void openPort( unsigned int portNumber = 0 ) = 0;
+  virtual void openPort( unsigned int portNumber = 0, const std::string portName = std::string( "RtMidi" ) ) = 0;
 
   //! Pure virtual openVirtualPort() function.
   virtual void openVirtualPort( const std::string portName = std::string( "RtMidi" ) ) = 0;
@@ -91,7 +91,7 @@
     to open a virtual input port to which other MIDI software clients
     can connect.
 
-    by Gary P. Scavone, 2003-2004.
+    by Gary P. Scavone, 2003-2008.
 */
 /**********************************************************************/
 
@@ -105,11 +105,11 @@
   //! User callback function type definition.
   typedef void (*RtMidiCallback)( double timeStamp, std::vector<unsigned char> *message, void *userData);
 
-  //! Default constructor.
+  //! Default constructor that allows an optional client name.
   /*!
       An exception will be thrown if a MIDI system initialization error occurs.
   */
-  RtMidiIn(std::string inputName = std::string("RtMidi Input Client"));
+  RtMidiIn( const std::string clientName = std::string( "RtMidi Input Client") );
 
   //! If a MIDI connection is still open, it will be closed by the destructor.
   ~RtMidiIn();
@@ -119,7 +119,7 @@
       An optional port number greater than 0 can be specified.
       Otherwise, the default or first port found is opened.
   */
-  void openPort( unsigned int portNumber = 0 );
+  void openPort( unsigned int portNumber = 0, const std::string Portname = std::string( "RtMidi Input" ) );
 
   //! Create a virtual input port, with optional name, to allow software connections (OS X and ALSA only).
   /*!
@@ -200,6 +200,7 @@
   // the MIDI input handling function or thread.
   struct RtMidiInData {
     std::queue<MidiMessage> queue;
+    MidiMessage message;
     unsigned int queueLimit;
     unsigned char ignoreFlags;
     bool doInput;
@@ -208,16 +209,18 @@
     bool usingCallback;
     void *userCallback;
     void *userData;
+    bool continueSysex;
 
     // Default constructor.
     RtMidiInData()
       : queueLimit(1024), ignoreFlags(7), doInput(false), firstMessage(true),
-        apiData(0), usingCallback(false), userCallback(0), userData(0) {}
+        apiData(0), usingCallback(false), userCallback(0), userData(0),
+        continueSysex(false) {}
   };
 
  private:
 
-  void initialize(std::string name);
+  void initialize( const std::string& clientName );
   RtMidiInData inputData_;
 
 };
@@ -232,7 +235,7 @@
     the connection.  Create multiple instances of this class to
     connect to more than one MIDI device at the same time.
 
-    by Gary P. Scavone, 2003-2004.
+    by Gary P. Scavone, 2003-2008.
 */
 /**********************************************************************/
 
@@ -240,11 +243,11 @@
 {
  public:
 
-  //! Default constructor.
+  //! Default constructor that allows an optional client name.
   /*!
       An exception will be thrown if a MIDI system initialization error occurs.
   */
-  RtMidiOut(std::string outputName = "RtMidi Output Client");
+  RtMidiOut( const std::string clientName = std::string( "RtMidi Output Client" ) );
 
   //! The destructor closes any open MIDI connections.
   ~RtMidiOut();
@@ -256,7 +259,7 @@
       exception is thrown if an error occurs while attempting to make
       the port connection.
   */
-  void openPort( unsigned int portNumber = 0 );
+  void openPort( unsigned int portNumber = 0, const std::string portName = std::string( "RtMidi Output" ) );
 
   //! Close an open MIDI connection (if one exists).
   void closePort();
@@ -290,7 +293,7 @@
 
  private:
 
-  void initialize(std::string name);
+  void initialize( const std::string& clientName );
 };
 
 #endif