Browse Source

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

Gary Scavone 11 năm trước cách đây
mục cha
commit
a0d187b872
13 tập tin đã thay đổi với 136 bổ sung136 xóa
  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