Explorar o código

Some error printing changes, removed ALSA global sequencer objects because they were not thread safe, various other updates suggested by Martin Koegler

Gary Scavone %!s(int64=11) %!d(string=hai) anos
pai
achega
a0d187b872
Modificáronse 13 ficheiros con 136 adicións e 136 borrados
  1. 1 1
      Makefile.in
  2. 113 101
      RtMidi.cpp
  3. 14 6
      RtMidi.h
  4. 1 1
      tests/cmidiin.cpp
  5. 0 4
      tests/cmidiin.dsp
  6. 2 2
      tests/midiout.cpp
  7. 0 4
      tests/midiout.dsp
  8. 1 1
      tests/midiprobe.cpp
  9. 0 4
      tests/midiprobe.dsp
  10. 2 2
      tests/qmidiin.cpp
  11. 0 4
      tests/qmidiin.dsp
  12. 2 2
      tests/sysextest.cpp
  13. 0 4
      tests/sysextest.dsp

+ 1 - 1
Makefile.in

@@ -66,7 +66,7 @@ distclean:
 	$(RM) -f $(LIBRARIES) @sharedname@ $(SHARED)*
 	$(RM) -f $(OBJECTS)
 	$(RM) -f *~
-	$(RM) -rf config.log config.status autom4te.cache Makefile rtmidi-config
+	$(RM) -rf config.log config.status autom4te.cache Makefile rtmidi-config $(LIBNAME).pc
 	cd tests && $(MAKE) distclean
 
 strip : 

+ 113 - 101
RtMidi.cpp

@@ -36,8 +36,6 @@
 */
 /**********************************************************************/
 
-// RtMidi: Version 2.1.0
-
 #include "RtMidi.h"
 #include <sstream>
 
@@ -45,6 +43,11 @@
 //  RtMidi Definitions
 //*********************************************************************//
 
+std::string RtMidi :: getVersion( void ) throw()
+{
+  return std::string( RTMIDI_VERSION );
+}
+
 void RtMidi :: getCompiledApi( std::vector<RtMidi::Api> &apis ) throw()
 {
   apis.clear();
@@ -71,7 +74,7 @@ void RtMidi :: getCompiledApi( std::vector<RtMidi::Api> &apis ) throw()
 #endif
 }
 
-void RtMidi :: error( RtMidiError::Type type, std::string errorString )
+void RtMidi :: error( RtMidiError::Type type, std::string &errorString )
 {
   if (type == RtMidiError::WARNING) {
     std::cerr << '\n' << errorString << "\n\n";
@@ -134,7 +137,8 @@ RtMidiIn :: RtMidiIn( RtMidi::Api api, const std::string clientName, unsigned in
 
     // No compiled support for specified API value.  Issue a debug
     // warning and continue as if no API was specified.
-    RtMidi::error( RtMidiError::WARNING, "RtMidiIn: no compiled support for specified API argument!" );
+    std::string errormsg = "RtMidiIn: no compiled support for specified API argument!";
+    RtMidi::error( RtMidiError::WARNING, errormsg );
   }
 
   // Iterate through the compiled APIs and return as soon as we find
@@ -152,12 +156,14 @@ RtMidiIn :: RtMidiIn( RtMidi::Api api, const std::string clientName, unsigned in
   // definition __RTMIDI_DUMMY__ is automatically defined if no
   // API-specific definitions are passed to the compiler. But just in
   // case something weird happens, we'll print out an error message.
-  RtMidi::error( RtMidiError::WARNING, "RtMidiIn: no compiled API support found ... critical error!!" );
+  std::string errormsg = "RtMidiIn: no compiled API support found ... critical error!!";
+  RtMidi::error( RtMidiError::UNSPECIFIED, errormsg );
 }
 
 RtMidiIn :: ~RtMidiIn() throw()
 {
-  delete rtapi_;
+  if ( rtapi_ )
+    delete rtapi_;
 }
 
 
@@ -208,7 +214,8 @@ RtMidiOut :: RtMidiOut( RtMidi::Api api, const std::string clientName )
 
     // No compiled support for specified API value.  Issue a debug
     // warning and continue as if no API was specified.
-    RtMidi::error( RtMidiError::WARNING, "RtMidiOut: no compiled support for specified API argument!" );
+    std::string errormsg = "RtMidiOut: no compiled support for specified API argument!";
+    RtMidi::error( RtMidiError::WARNING, errormsg );
   }
 
   // Iterate through the compiled APIs and return as soon as we find
@@ -226,12 +233,14 @@ RtMidiOut :: RtMidiOut( RtMidi::Api api, const std::string clientName )
   // definition __RTMIDI_DUMMY__ is automatically defined if no
   // API-specific definitions are passed to the compiler. But just in
   // case something weird happens, we'll print out an error message.
-  RtMidi::error( RtMidiError::WARNING, "RtMidiOut: no compiled API support found ... critical error!!" );
+  std::string errormsg = "RtMidiOut: no compiled API support found ... critical error!!";
+  RtMidi::error( RtMidiError::UNSPECIFIED, errormsg );
 }
 
 RtMidiOut :: ~RtMidiOut() throw()
 {
-  delete rtapi_;
+  if ( rtapi_ )
+    delete rtapi_;
 }
 
 //*********************************************************************//
@@ -363,7 +372,7 @@ struct CoreMidiData {
 //  Class Definitions: MidiInCore
 //*********************************************************************//
 
-void midiInputCallback( const MIDIPacketList *list, void *procRef, void *srcRef )
+static void midiInputCallback( const MIDIPacketList *list, void *procRef, void *srcRef )
 {
   MidiInApi::RtMidiInData *data = static_cast<MidiInApi::RtMidiInData *> (procRef);
   CoreMidiData *apiData = static_cast<CoreMidiData *> (data->apiData);
@@ -563,8 +572,8 @@ void MidiInCore :: openPort( unsigned int portNumber, const std::string portName
     RtMidi::error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
   }
 
-  std::ostringstream ost;
   if ( portNumber >= nSrc ) {
+    std::ostringstream ost;
     ost << "MidiInCore::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
     errorString_ = ost.str();
     RtMidi::error( RtMidiError::INVALID_PARAMETER, errorString_ );
@@ -653,7 +662,7 @@ CFStringRef EndpointName( MIDIEndpointRef endpoint, bool isExternal )
     CFRelease( str );
   }
 
-  MIDIEntityRef entity = NULL;
+  MIDIEntityRef entity = 0;
   MIDIEndpointGetEntity( endpoint, &entity );
   if ( entity == 0 )
     // probably virtual
@@ -766,16 +775,15 @@ std::string MidiInCore :: getPortName( unsigned int portNumber )
 {
   CFStringRef nameRef;
   MIDIEndpointRef portRef;
-  std::ostringstream ost;
   char name[128];
 
   std::string stringName;
   CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
   if ( portNumber >= MIDIGetNumberOfSources() ) {
+    std::ostringstream ost;
     ost << "MidiInCore::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
     errorString_ = ost.str();
     RtMidi::error( RtMidiError::WARNING, errorString_ );
-    //RtMidi::error( RtMidiError::INVALID_PARAMETER, errorString_ );
     return stringName;
   }
 
@@ -836,17 +844,16 @@ std::string MidiOutCore :: getPortName( unsigned int portNumber )
 {
   CFStringRef nameRef;
   MIDIEndpointRef portRef;
-  std::ostringstream ost;
   char name[128];
 
   std::string stringName;
   CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
   if ( portNumber >= MIDIGetNumberOfDestinations() ) {
+    std::ostringstream ost;
     ost << "MidiOutCore::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
     errorString_ = ost.str();
     RtMidi::error( RtMidiError::WARNING, errorString_ );
     return stringName;
-    //RtMidi::error( RtMidiError::INVALID_PARAMETER, errorString_ );
   }
 
   portRef = MIDIGetDestination( portNumber );
@@ -872,8 +879,8 @@ void MidiOutCore :: openPort( unsigned int portNumber, const std::string portNam
     RtMidi::error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
   }
 
-  std::ostringstream ost;
   if ( portNumber >= nDest ) {
+    std::ostringstream ost;
     ost << "MidiOutCore::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
     errorString_ = ost.str();
     RtMidi::error( RtMidiError::INVALID_PARAMETER, errorString_ );
@@ -938,9 +945,9 @@ void MidiOutCore :: openVirtualPort( std::string portName )
   data->endpoint = endpoint;
 }
 
-char *sysexBuffer = 0;
+static char *sysexBuffer = 0;
 
-void sysexCompletionProc( MIDISysexSendRequest * sreq )
+static void sysexCompletionProc( MIDISysexSendRequest * sreq )
 {
   //std::cout << "Completed SysEx send\n";
  delete sysexBuffer;
@@ -1053,17 +1060,6 @@ void MidiOutCore :: sendMessage( std::vector<unsigned char> *message )
 // ALSA header file.
 #include <alsa/asoundlib.h>
 
-// Global sequencer instance created when first In/Out object is
-// created, then destroyed when last In/Out is deleted.
-static snd_seq_t *s_seq = NULL;
-
-// Variable to keep track of how many ports are open.
-static unsigned int s_numPorts = 0;
-
-// The client name to use when creating the sequencer, which is
-// currently set on the first call to createSequencer.
-static std::string s_clientName = "RtMidi Client";
-
 // A structure to hold variables related to the ALSA API
 // implementation.
 struct AlsaMidiData {
@@ -1083,44 +1079,12 @@ struct AlsaMidiData {
 
 #define PORT_TYPE( pinfo, bits ) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
 
-snd_seq_t* createSequencer( const std::string& clientName )
-{
-  // Set up the ALSA sequencer client.
-  if ( s_seq == NULL ) {
-    int result = snd_seq_open(&s_seq, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK);
-    if ( result < 0 ) {
-      s_seq = NULL;
-    }
-    else {
-      // Set client name, use current name if given string is empty.
-      if ( clientName != "" ) {
-        s_clientName = clientName;
-      }
-      snd_seq_set_client_name( s_seq, s_clientName.c_str() );
-    }
-  }
-
-  // Increment port count.
-  s_numPorts++;
-
-  return s_seq;
-}
-
-void freeSequencer ( void )
-{
-  s_numPorts--;
-  if ( s_numPorts == 0 && s_seq != NULL ) {
-    snd_seq_close( s_seq );
-    s_seq = NULL;
-  }
-}
-
 //*********************************************************************//
 //  API: LINUX ALSA
 //  Class Definitions: MidiInAlsa
 //*********************************************************************//
 
-extern "C" void *alsaMidiHandler( void *ptr )
+static void *alsaMidiHandler( void *ptr )
 {
   MidiInApi::RtMidiInData *data = static_cast<MidiInApi::RtMidiInData *> (ptr);
   AlsaMidiData *apiData = static_cast<AlsaMidiData *> (data->apiData);
@@ -1334,19 +1298,23 @@ MidiInAlsa :: ~MidiInAlsa()
 #ifndef AVOID_TIMESTAMPING
   snd_seq_free_queue( data->seq, data->queue_id );
 #endif
-  freeSequencer();
+  snd_seq_close( data->seq );
   delete data;
 }
 
 void MidiInAlsa :: initialize( const std::string& clientName )
 {
-  snd_seq_t* seq = createSequencer( clientName );
-  if ( seq == NULL ) {
-    s_seq = NULL;
+  // Set up the ALSA sequencer client.
+  snd_seq_t *seq;
+  int result = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK);
+  if ( result < 0 ) {
     errorString_ = "MidiInAlsa::initialize: error creating ALSA sequencer client object.";
     RtMidi::error( RtMidiError::DRIVER_ERROR, errorString_ );
   }
 
+  // Set client name.
+  snd_seq_set_client_name( seq, clientName.c_str() );
+
   // Save our api-specific connection information.
   AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
   data->seq = seq;
@@ -1367,7 +1335,7 @@ void MidiInAlsa :: initialize( const std::string& clientName )
 
   // Create the input queue
 #ifndef AVOID_TIMESTAMPING
-  data->queue_id = snd_seq_alloc_named_queue(s_seq, "RtMidi Queue");
+  data->queue_id = snd_seq_alloc_named_queue(seq, "RtMidi Queue");
   // Set arbitrary tempo (mm=100) and resolution (240)
   snd_seq_queue_tempo_t *qtempo;
   snd_seq_queue_tempo_alloca(&qtempo);
@@ -1443,7 +1411,6 @@ std::string MidiInAlsa :: getPortName( unsigned int portNumber )
   errorString_ = "MidiInAlsa::getPortName: error looking for port name!";
   RtMidi::error( RtMidiError::WARNING, errorString_ );
   return stringName;
-  //RtMidi::error( RtMidiError::INVALID_PARAMETER, errorString_ );
 }
 
 void MidiInAlsa :: openPort( unsigned int portNumber, const std::string portName )
@@ -1462,9 +1429,9 @@ void MidiInAlsa :: openPort( unsigned int portNumber, const std::string portName
 
   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 ) {
+    std::ostringstream ost;
     ost << "MidiInAlsa::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
     errorString_ = ost.str();
     RtMidi::error( RtMidiError::INVALID_PARAMETER, errorString_ );
@@ -1652,19 +1619,23 @@ MidiOutAlsa :: ~MidiOutAlsa()
   if ( data->vport >= 0 ) snd_seq_delete_port( data->seq, data->vport );
   if ( data->coder ) snd_midi_event_free( data->coder );
   if ( data->buffer ) free( data->buffer );
-  freeSequencer();
+  snd_seq_close( data->seq );
   delete data;
 }
 
 void MidiOutAlsa :: initialize( const std::string& clientName )
 {
-  snd_seq_t* seq = createSequencer( clientName );
-  if ( seq == NULL ) {
-    s_seq = NULL;
+  // Set up the ALSA sequencer client.
+  snd_seq_t *seq;
+  int result1 = snd_seq_open( &seq, "default", SND_SEQ_OPEN_OUTPUT, SND_SEQ_NONBLOCK );
+  if ( result1 < 0 ) {
     errorString_ = "MidiOutAlsa::initialize: error creating ALSA sequencer client object.";
     RtMidi::error( RtMidiError::DRIVER_ERROR, errorString_ );
 	}
 
+  // Set client name.
+  snd_seq_set_client_name( seq, clientName.c_str() );
+
   // Save our api-specific connection information.
   AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
   data->seq = seq;
@@ -1712,6 +1683,8 @@ std::string MidiOutAlsa :: getPortName( unsigned int portNumber )
     snd_seq_get_any_client_info( data->seq, cnum, cinfo );
     std::ostringstream os;
     os << snd_seq_client_info_get_name(cinfo);
+    os << " ";                                    // These lines added to make sure devices are listed
+    os << snd_seq_port_info_get_client( pinfo );  // with full portnames added to ensure individual device names
     os << ":";
     os << snd_seq_port_info_get_port(pinfo);
     stringName = os.str();
@@ -1741,9 +1714,9 @@ void MidiOutAlsa :: openPort( unsigned int portNumber, const std::string portNam
 
 	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 ) {
+    std::ostringstream ost;
     ost << "MidiOutAlsa::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
     errorString_ = ost.str();
     RtMidi::error( RtMidiError::INVALID_PARAMETER, errorString_ );
@@ -2035,8 +2008,8 @@ void MidiInWinMM :: openPort( unsigned int portNumber, const std::string /*portN
     RtMidi::error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
   }
 
-  std::ostringstream ost;
   if ( portNumber >= nDevices ) {
+    std::ostringstream ost;
     ost << "MidiInWinMM::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
     errorString_ = ost.str();
     RtMidi::error( RtMidiError::INVALID_PARAMETER, errorString_ );
@@ -2130,7 +2103,6 @@ std::string MidiInWinMM :: getPortName( unsigned int portNumber )
     std::ostringstream ost;
     ost << "MidiInWinMM::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
     errorString_ = ost.str();
-    //RtMidi::error( RtMidiError::INVALID_PARAMETER, errorString_ );
     RtMidi::error( RtMidiError::WARNING, errorString_ );
     return stringName;
   }
@@ -2205,7 +2177,6 @@ std::string MidiOutWinMM :: getPortName( unsigned int portNumber )
     std::ostringstream ost;
     ost << "MidiOutWinMM::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
     errorString_ = ost.str();
-    //RtMidi::error( RtMidiError::INVALID_PARAMETER, errorString_ );
     RtMidi::error( RtMidiError::WARNING, errorString_ );
     return stringName;
   }
@@ -2238,8 +2209,8 @@ void MidiOutWinMM :: openPort( unsigned int portNumber, const std::string /*port
     RtMidi::error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
   }
 
-  std::ostringstream ost;
   if ( portNumber >= nDevices ) {
+    std::ostringstream ost;
     ost << "MidiOutWinMM::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
     errorString_ = ost.str();
     RtMidi::error( RtMidiError::INVALID_PARAMETER, errorString_ );
@@ -3054,7 +3025,7 @@ struct WindowsKsData
 // Class Definitions: MidiInWinKS
 // *********************************************************************//
 
-DWORD WINAPI midiKsInputThread(VOID* pUser)
+static DWORD WINAPI midiKsInputThread(VOID* pUser)
 {
   MidiInApi::RtMidiInData* data = static_cast<MidiInApi::RtMidiInData*>(pUser);
   WindowsKsData* apiData = static_cast<WindowsKsData*>(data->apiData);
@@ -3410,7 +3381,7 @@ struct JackMidiData {
 //  Class Definitions: MidiInJack
 //*********************************************************************//
 
-int jackProcessIn( jack_nframes_t nframes, void *arg )
+static int jackProcessIn( jack_nframes_t nframes, void *arg )
 {
   JackMidiData *jData = (JackMidiData *) arg;
   MidiInApi :: RtMidiInData *rtData = jData->rtMidiIn;
@@ -3423,13 +3394,13 @@ int jackProcessIn( jack_nframes_t nframes, void *arg )
 
   // We have midi events in buffer
   int evCount = jack_midi_get_event_count( buff );
-  if ( evCount > 0 ) {
+  for (int j = 0; j < evCount; j++) {
     MidiInApi::MidiMessage message;
     message.bytes.clear();
 
-    jack_midi_event_get( &event, buff, 0 );
+    jack_midi_event_get( &event, buff, j );
 
-    for (unsigned int i = 0; i < event.size; i++ )
+    for ( unsigned int i = 0; i < event.size; i++ )
       message.bytes.push_back( event.buffer[i] );
 
     // Compute the delta time.
@@ -3473,16 +3444,27 @@ void MidiInJack :: initialize( const std::string& clientName )
   JackMidiData *data = new JackMidiData;
   apiData_ = (void *) data;
 
+  data->rtMidiIn = &inputData_;
+  data->port = NULL;
+  data->client = NULL;
+  this->clientName = clientName;
+
+  connect();
+}
+
+void MidiInJack :: connect()
+{
+  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
+  if ( data->client )
+    return;
+
   // Initialize JACK client
-  if (( data->client = jack_client_open( clientName.c_str(), JackNullOption, NULL )) == 0) {
+  if (( data->client = jack_client_open( clientName.c_str(), JackNoStartServer, NULL )) == 0) {
     errorString_ = "MidiInJack::initialize: JACK server not running?";
-    RtMidi::error( RtMidiError::DRIVER_ERROR, errorString_ );
+    RtMidi::error( RtError::WARNING, errorString_ );
     return;
   }
 
-  data->rtMidiIn = &inputData_;
-  data->port = NULL;
-
   jack_set_process_callback( data->client, jackProcessIn, data );
   jack_activate( data->client );
 }
@@ -3492,13 +3474,17 @@ MidiInJack :: ~MidiInJack()
   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
   closePort();
 
-  jack_client_close( data->client );
+  if ( data->client )
+    jack_client_close( data->client );
+  delete data;
 }
 
 void MidiInJack :: openPort( unsigned int portNumber, const std::string portName )
 {
   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
 
+  connect();
+
   // Creating new port
   if ( data->port == NULL)
     data->port = jack_port_register( data->client, portName.c_str(),
@@ -3518,6 +3504,7 @@ void MidiInJack :: openVirtualPort( const std::string portName )
 {
   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
 
+  connect();
   if ( data->port == NULL )
     data->port = jack_port_register( data->client, portName.c_str(),
                                      JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0 );
@@ -3532,6 +3519,9 @@ unsigned int MidiInJack :: getPortCount()
 {
   int count = 0;
   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
+  connect();
+  if ( !data->client )
+    return 0;
 
   // List of available ports
   const char **ports = jack_get_ports( data->client, NULL, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput );
@@ -3548,9 +3538,10 @@ unsigned int MidiInJack :: getPortCount()
 std::string MidiInJack :: getPortName( unsigned int portNumber )
 {
   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
-  std::ostringstream ost;
   std::string retStr("");
 
+  connect();
+
   // List of available ports
   const char **ports = jack_get_ports( data->client, NULL,
                                        JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput );
@@ -3563,6 +3554,7 @@ std::string MidiInJack :: getPortName( unsigned int portNumber )
   }
 
   if ( ports[portNumber] == NULL ) {
+    std::ostringstream ost;
     ost << "MidiInJack::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
     errorString_ = ost.str();
     RtMidi::error( RtMidiError::WARNING, errorString_ );
@@ -3589,7 +3581,7 @@ void MidiInJack :: closePort()
 //*********************************************************************//
 
 // Jack process callback
-int jackProcessOut( jack_nframes_t nframes, void *arg )
+static int jackProcessOut( jack_nframes_t nframes, void *arg )
 {
   JackMidiData *data = (JackMidiData *) arg;
   jack_midi_data_t *midiData;
@@ -3619,13 +3611,25 @@ MidiOutJack :: MidiOutJack( const std::string clientName ) : MidiOutApi()
 void MidiOutJack :: initialize( const std::string& clientName )
 {
   JackMidiData *data = new JackMidiData;
+  apiData_ = (void *) data;
 
   data->port = NULL;
+  data->client = NULL;
+  this->clientName = clientName;
+
+  connect();
+}
+
+void MidiOutJack :: connect()
+{
+  JackMidiData *data = static_cast<JackMidiData *> (apiData_);
+  if ( data->client )
+    return;
 
   // Initialize JACK client
-  if (( data->client = jack_client_open( clientName.c_str(), JackNullOption, NULL )) == 0) {
+  if (( data->client = jack_client_open( clientName.c_str(), JackNoStartServer, NULL )) == 0) {
     errorString_ = "MidiOutJack::initialize: JACK server not running?";
-    RtMidi::error( RtMidiError::DRIVER_ERROR, errorString_ );
+    RtMidi::error( RtMidiError::WARNING, errorString_ );
     return;
   }
 
@@ -3633,8 +3637,6 @@ void MidiOutJack :: initialize( const std::string& clientName )
   data->buffSize = jack_ringbuffer_create( JACK_RINGBUFFER_SIZE );
   data->buffMessage = jack_ringbuffer_create( JACK_RINGBUFFER_SIZE );
   jack_activate( data->client );
-
-  apiData_ = (void *) data;
 }
 
 MidiOutJack :: ~MidiOutJack()
@@ -3642,10 +3644,12 @@ MidiOutJack :: ~MidiOutJack()
   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
   closePort();
 
-  // Cleanup
-  jack_client_close( data->client );
-  jack_ringbuffer_free( data->buffSize );
-  jack_ringbuffer_free( data->buffMessage );
+  if ( data->client ) {
+    // Cleanup
+    jack_client_close( data->client );
+    jack_ringbuffer_free( data->buffSize );
+    jack_ringbuffer_free( data->buffMessage );
+  }
 
   delete data;
 }
@@ -3654,6 +3658,8 @@ void MidiOutJack :: openPort( unsigned int portNumber, const std::string portNam
 {
   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
 
+  connect();
+
   // Creating new port
   if ( data->port == NULL )
     data->port = jack_port_register( data->client, portName.c_str(),
@@ -3673,6 +3679,7 @@ void MidiOutJack :: openVirtualPort( const std::string portName )
 {
   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
 
+  connect();
   if ( data->port == NULL )
     data->port = jack_port_register( data->client, portName.c_str(),
       JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0 );
@@ -3687,6 +3694,9 @@ unsigned int MidiOutJack :: getPortCount()
 {
   int count = 0;
   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
+  connect();
+  if ( !data->client )
+    return 0;
 
   // List of available ports
   const char **ports = jack_get_ports( data->client, NULL,
@@ -3704,9 +3714,10 @@ unsigned int MidiOutJack :: getPortCount()
 std::string MidiOutJack :: getPortName( unsigned int portNumber )
 {
   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
-  std::ostringstream ost;
   std::string retStr("");
 
+  connect();
+
   // List of available ports
   const char **ports = jack_get_ports( data->client, NULL,
     JACK_DEFAULT_MIDI_TYPE, JackPortIsInput );
@@ -3719,6 +3730,7 @@ std::string MidiOutJack :: getPortName( unsigned int portNumber )
   }
 
   if ( ports[portNumber] == NULL) {
+    std::ostringstream ost;
     ost << "MidiOutJack::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
     errorString_ = ost.str();
     RtMidi::error( RtMidiError::WARNING, errorString_ );

+ 14 - 6
RtMidi.h

@@ -40,11 +40,11 @@
   \file RtMidi.h
  */
 
-// RtMidi: Version 2.1.0
-
 #ifndef RTMIDI_H
 #define RTMIDI_H
 
+#define RTMIDI_VERSION "2.1.0pre"
+
 #include <exception>
 #include <iostream>
 #include <string>
@@ -55,9 +55,8 @@
     \brief Exception handling class for RtMidi.
 
     The RtMidiError class is quite simple but it does allow errors to be
-    "caught" by RtMidiError::Type. See the RtAudio and RtMidi
-    documentation to know which methods can throw an RtMidiError.
-
+    "caught" by RtMidiError::Type. See the RtMidi documentation to know
+    which methods can throw an RtMidiError.
 */
 /************************************************************************/
 
@@ -117,6 +116,9 @@ class RtMidi
     RTMIDI_DUMMY    /*!< A compilable but non-functional API. */
   };
 
+  //! A static function to determine the current RtMidi version.
+  static std::string getVersion( void ) throw();
+
   //! A static function to determine the available compiled MIDI APIs.
   /*!
     The values returned in the std::vector can be compared against
@@ -141,7 +143,7 @@ class RtMidi
   virtual void closePort( void ) = 0;
 
   //! A basic error reporting function for RtMidi classes.
-  static void error( RtMidiError::Type type, std::string errorString );
+  static void error( RtMidiError::Type type, std::string &errorString );
 
  protected:
 
@@ -520,6 +522,9 @@ class MidiInCore: public MidiInApi
   std::string getPortName( unsigned int portNumber );
 
  protected:
+  std::string clientName;
+
+  void connect( void );
   void initialize( const std::string& clientName );
 };
 
@@ -537,6 +542,9 @@ class MidiOutCore: public MidiOutApi
   void sendMessage( std::vector<unsigned char> *message );
 
  protected:
+  std::string clientName;
+
+  void connect( void );
   void initialize( const std::string& clientName );
 };
 

+ 1 - 1
tests/cmidiin.cpp

@@ -60,7 +60,7 @@ int main( int argc, char *argv[] )
     char input;
     std::cin.get(input);
 
-  } catch ( RtError &error ) {
+  } catch ( RtMidiError &error ) {
     error.printMessage();
   }
 

+ 0 - 4
tests/cmidiin.dsp

@@ -99,10 +99,6 @@ SOURCE=..\RtMidi.cpp
 # PROP Default_Filter "h;hpp;hxx;hm;inl"
 # Begin Source File
 
-SOURCE=..\RtError.h
-# End Source File
-# Begin Source File
-
 SOURCE=..\RtMidi.h
 # End Source File
 # End Group

+ 2 - 2
tests/midiout.cpp

@@ -33,7 +33,7 @@ int main( int argc, char *argv[] )
   try {
     midiout = new RtMidiOut();
   }
-  catch ( RtError &error ) {
+  catch ( RtMidiError &error ) {
     error.printMessage();
     exit( EXIT_FAILURE );
   }
@@ -42,7 +42,7 @@ int main( int argc, char *argv[] )
   try {
     if ( chooseMidiPort( midiout ) == false ) goto cleanup;
   }
-  catch ( RtError &error ) {
+  catch ( RtMidiError &error ) {
     error.printMessage();
     goto cleanup;
   }

+ 0 - 4
tests/midiout.dsp

@@ -99,10 +99,6 @@ SOURCE=..\RtMidi.cpp
 # PROP Default_Filter "h;hpp;hxx;hm;inl"
 # Begin Source File
 
-SOURCE=..\RtError.h
-# End Source File
-# Begin Source File
-
 SOURCE=..\RtMidi.h
 # End Source File
 # End Group

+ 1 - 1
tests/midiprobe.cpp

@@ -61,7 +61,7 @@ int main()
     }
     std::cout << std::endl;
 
-  } catch ( RtError &error ) {
+  } catch ( RtMidiError &error ) {
     error.printMessage();
   }
 

+ 0 - 4
tests/midiprobe.dsp

@@ -99,10 +99,6 @@ SOURCE=..\RtMidi.cpp
 # PROP Default_Filter "h;hpp;hxx;hm;inl"
 # Begin Source File
 
-SOURCE=..\RtError.h
-# End Source File
-# Begin Source File
-
 SOURCE=..\RtMidi.h
 # End Source File
 # End Group

+ 2 - 2
tests/qmidiin.cpp

@@ -46,7 +46,7 @@ int main( int argc, char *argv[] )
   try {
     midiin = new RtMidiIn();
   }
-  catch ( RtError &error ) {
+  catch ( RtMidiError &error ) {
     error.printMessage();
     exit( EXIT_FAILURE );
   }
@@ -64,7 +64,7 @@ int main( int argc, char *argv[] )
   try {
     midiin->openPort( port );
   }
-  catch ( RtError &error ) {
+  catch ( RtMidiError &error ) {
     error.printMessage();
     goto cleanup;
   }

+ 0 - 4
tests/qmidiin.dsp

@@ -99,10 +99,6 @@ SOURCE=..\RtMidi.cpp
 # PROP Default_Filter "h;hpp;hxx;hm;inl"
 # Begin Source File
 
-SOURCE=..\RtError.h
-# End Source File
-# Begin Source File
-
 SOURCE=..\RtMidi.h
 # End Source File
 # End Group

+ 2 - 2
tests/sysextest.cpp

@@ -56,7 +56,7 @@ int main( int argc, char *argv[] )
     midiout = new RtMidiOut();
     midiin = new RtMidiIn();
   }
-  catch ( RtError &error ) {
+  catch ( RtMidiError &error ) {
     error.printMessage();
     goto cleanup;
   }
@@ -69,7 +69,7 @@ int main( int argc, char *argv[] )
     if ( chooseMidiPort( midiin ) == false ) goto cleanup;
     if ( chooseMidiPort( midiout ) == false ) goto cleanup;
   }
-  catch ( RtError &error ) {
+  catch ( RtMidiError &error ) {
     error.printMessage();
     goto cleanup;
   }

+ 0 - 4
tests/sysextest.dsp

@@ -99,10 +99,6 @@ SOURCE=.\sysextest.cpp
 # PROP Default_Filter "h;hpp;hxx;hm;inl"
 # Begin Source File
 
-SOURCE=..\RtError.h
-# End Source File
-# Begin Source File
-
 SOURCE=..\RtMidi.h
 # End Source File
 # End Group