diff data/midi/rtmidi/RtMidi.h @ 1527:710e6250a401 zoom

Merge from default branch
author Chris Cannam
date Mon, 17 Sep 2018 13:51:14 +0100
parents 08bbbd2023c4
children
line wrap: on
line diff
--- a/data/midi/rtmidi/RtMidi.h	Mon Dec 12 15:18:52 2016 +0000
+++ b/data/midi/rtmidi/RtMidi.h	Mon Sep 17 13:51:14 2018 +0100
@@ -8,7 +8,7 @@
     RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/
 
     RtMidi: realtime MIDI i/o C++ classes
-    Copyright (c) 2003-2009 Gary P. Scavone
+    Copyright (c) 2003-2016 Gary P. Scavone
 
     Permission is hereby granted, free of charge, to any person
     obtaining a copy of this software and associated documentation files
@@ -22,8 +22,9 @@
     included in all copies or substantial portions of the Software.
 
     Any person wishing to distribute modifications to the Software is
-    requested to send the modifications to the original developer so that
-    they can be incorporated into the canonical version.
+    asked to send the modifications to the original developer so that
+    they can be incorporated into the canonical version.  This is,
+    however, not a binding provision of this license.
 
     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
@@ -35,18 +36,108 @@
 */
 /**********************************************************************/
 
-// RtMidi: Version 1.0.8
+/*!
+  \file RtMidi.h
+ */
 
 #ifndef RTMIDI_H
 #define RTMIDI_H
 
-#include "RtError.h"
+#define RTMIDI_VERSION "2.1.1"
+
+#include <exception>
+#include <iostream>
 #include <string>
+#include <vector>
+
+/************************************************************************/
+/*! \class RtMidiError
+    \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 RtMidi documentation to know
+    which methods can throw an RtMidiError.
+*/
+/************************************************************************/
+
+class RtMidiError : public std::exception
+{
+ public:
+  //! Defined RtMidiError types.
+  enum Type {
+    WARNING,           /*!< A non-critical error. */
+    DEBUG_WARNING,     /*!< A non-critical error which might be useful for debugging. */
+    UNSPECIFIED,       /*!< The default, unspecified error type. */
+    NO_DEVICES_FOUND,  /*!< No devices found on system. */
+    INVALID_DEVICE,    /*!< An invalid device ID was specified. */
+    MEMORY_ERROR,      /*!< An error occured during memory allocation. */
+    INVALID_PARAMETER, /*!< An invalid parameter was specified to a function. */
+    INVALID_USE,       /*!< The function was called incorrectly. */
+    DRIVER_ERROR,      /*!< A system driver error occured. */
+    SYSTEM_ERROR,      /*!< A system error occured. */
+    THREAD_ERROR       /*!< A thread error occured. */
+  };
+
+  //! The constructor.
+  RtMidiError( const std::string& message, Type type = RtMidiError::UNSPECIFIED ) throw() : message_(message), type_(type) {}
+ 
+  //! The destructor.
+  virtual ~RtMidiError( void ) throw() {}
+
+  //! Prints thrown error message to stderr.
+  virtual void printMessage( void ) const throw() { std::cerr << '\n' << message_ << "\n\n"; }
+
+  //! Returns the thrown error message type.
+  virtual const Type& getType(void) const throw() { return type_; }
+
+  //! Returns the thrown error message string.
+  virtual const std::string& getMessage(void) const throw() { return message_; }
+
+  //! Returns the thrown error message as a c-style string.
+  virtual const char* what( void ) const throw() { return message_.c_str(); }
+
+ protected:
+  std::string message_;
+  Type type_;
+};
+
+//! RtMidi error callback function prototype.
+/*!
+    \param type Type of error.
+    \param errorText Error description.
+
+    Note that class behaviour is undefined after a critical error (not
+    a warning) is reported.
+ */
+typedef void (*RtMidiErrorCallback)( RtMidiError::Type type, const std::string &errorText, void *userData );
+
+class MidiApi;
 
 class RtMidi
 {
  public:
 
+  //! MIDI API specifier arguments.
+  enum Api {
+    UNSPECIFIED,    /*!< Search for a working compiled API. */
+    MACOSX_CORE,    /*!< Macintosh OS-X Core Midi API. */
+    LINUX_ALSA,     /*!< The Advanced Linux Sound Architecture API. */
+    UNIX_JACK,      /*!< The JACK Low-Latency MIDI Server API. */
+    WINDOWS_MM,     /*!< The Microsoft Multimedia MIDI API. */
+    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
+    the enumerated list values.  Note that there can be more than one
+    API compiled for certain operating systems.
+  */
+  static void getCompiledApi( std::vector<RtMidi::Api> &apis ) throw();
+
   //! Pure virtual openPort() function.
   virtual void openPort( unsigned int portNumber = 0, const std::string portName = std::string( "RtMidi" ) ) = 0;
 
@@ -62,19 +153,22 @@
   //! Pure virtual closePort() function.
   virtual void closePort( void ) = 0;
 
+  //! Returns true if a port is open and false if not.
+  virtual bool isPortOpen( void ) const = 0;
+
+  //! Set an error callback function to be invoked when an error has occured.
+  /*!
+    The callback function will be called whenever an error has occured. It is best
+    to set the error callback function before opening a port.
+  */
+  virtual void setErrorCallback( RtMidiErrorCallback errorCallback = NULL, void *userData = 0 ) = 0;
+
  protected:
 
   RtMidi();
-  virtual ~RtMidi() {};
+  virtual ~RtMidi();
 
-  // A basic error reporting function for internal use in the RtMidi
-  // subclasses.  The behavior of this function can be modified to
-  // suit specific needs.
-  void error( RtError::Type type );
-
-  void *apiData_;
-  bool connected_;
-  std::string errorString_;
+  MidiApi *rtapi_;
 };
 
 /**********************************************************************/
@@ -87,16 +181,27 @@
     retrieval using the getMessage() function or immediately passed to
     a user-specified callback function.  Create multiple instances of
     this class to connect to more than one MIDI device at the same
-    time.  With the OS-X and Linux ALSA MIDI APIs, it is also possible
-    to open a virtual input port to which other MIDI software clients
-    can connect.
+    time.  With the OS-X, Linux ALSA, and JACK MIDI APIs, it is also
+    possible to open a virtual input port to which other MIDI software
+    clients can connect.
 
-    by Gary P. Scavone, 2003-2008.
+    by Gary P. Scavone, 2003-2014.
 */
 /**********************************************************************/
 
-#include <vector>
-#include <queue>
+// **************************************************************** //
+//
+// RtMidiIn and RtMidiOut class declarations.
+//
+// RtMidiIn / RtMidiOut are "controllers" used to select an available
+// MIDI input or output interface.  They present common APIs for the
+// user to call but all functionality is implemented by the classes
+// MidiInApi, MidiOutApi and their subclasses.  RtMidiIn and RtMidiOut
+// each create an instance of a MidiInApi or MidiOutApi subclass based
+// on the user's API choice.  If no choice is made, they attempt to
+// make a "logical" API selection.
+//
+// **************************************************************** //
 
 class RtMidiIn : public RtMidi
 {
@@ -105,123 +210,122 @@
   //! User callback function type definition.
   typedef void (*RtMidiCallback)( double timeStamp, std::vector<unsigned char> *message, void *userData);
 
-  //! Default constructor that allows an optional client name.
+  //! Default constructor that allows an optional api, client name and queue size.
   /*!
-      An exception will be thrown if a MIDI system initialization error occurs.
+    An exception will be thrown if a MIDI system initialization
+    error occurs.  The queue size defines the maximum number of
+    messages that can be held in the MIDI queue (when not using a
+    callback function).  If the queue size limit is reached,
+    incoming messages will be ignored.
+
+    If no API argument is specified and multiple API support has been
+    compiled, the default order of use is ALSA, JACK (Linux) and CORE,
+    JACK (OS-X).
+
+    \param api        An optional API id can be specified.
+    \param clientName An optional client name can be specified. This
+                      will be used to group the ports that are created
+                      by the application.
+    \param queueSizeLimit An optional size of the MIDI input queue can be specified.
   */
-  RtMidiIn( const std::string clientName = std::string( "RtMidi Input Client") );
+  RtMidiIn( RtMidi::Api api=UNSPECIFIED,
+            const std::string clientName = std::string( "RtMidi Input Client"),
+            unsigned int queueSizeLimit = 100 );
 
   //! If a MIDI connection is still open, it will be closed by the destructor.
-  ~RtMidiIn();
+  ~RtMidiIn ( void ) throw();
 
-  //! Open a MIDI input connection.
+  //! Returns the MIDI API specifier for the current instance of RtMidiIn.
+  RtMidi::Api getCurrentApi( void ) throw();
+
+  //! Open a MIDI input connection given by enumeration number.
   /*!
-      An optional port number greater than 0 can be specified.
-      Otherwise, the default or first port found is opened.
+    \param portNumber An optional port number greater than 0 can be specified.
+                      Otherwise, the default or first port found is opened.
+    \param portName An optional name for the application port that is used to connect to portId can be specified.
   */
-  void openPort( unsigned int portNumber = 0, const std::string Portname = std::string( "RtMidi Input" ) );
+  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).
+  //! Create a virtual input port, with optional name, to allow software connections (OS X, JACK and ALSA only).
   /*!
-      This function creates a virtual MIDI input port to which other
-      software applications can connect.  This type of functionality
-      is currently only supported by the Macintosh OS-X and Linux ALSA
-      APIs (the function does nothing for the other APIs).
+    This function creates a virtual MIDI input port to which other
+    software applications can connect.  This type of functionality
+    is currently only supported by the Macintosh OS-X, any JACK,
+    and Linux ALSA APIs (the function returns an error for the other APIs).
+
+    \param portName An optional name for the application port that is
+                    used to connect to portId can be specified.
   */
   void openVirtualPort( const std::string portName = std::string( "RtMidi Input" ) );
 
   //! Set a callback function to be invoked for incoming MIDI messages.
   /*!
-      The callback function will be called whenever an incoming MIDI
-      message is received.  While not absolutely necessary, it is best
-      to set the callback function before opening a MIDI port to avoid
-      leaving some messages in the queue.
+    The callback function will be called whenever an incoming MIDI
+    message is received.  While not absolutely necessary, it is best
+    to set the callback function before opening a MIDI port to avoid
+    leaving some messages in the queue.
+
+    \param callback A callback function must be given.
+    \param userData Optionally, a pointer to additional data can be
+                    passed to the callback function whenever it is called.
   */
   void setCallback( RtMidiCallback callback, void *userData = 0 );
 
   //! Cancel use of the current callback function (if one exists).
   /*!
-      Subsequent incoming MIDI messages will be written to the queue
-      and can be retrieved with the \e getMessage function.
+    Subsequent incoming MIDI messages will be written to the queue
+    and can be retrieved with the \e getMessage function.
   */
   void cancelCallback();
 
   //! Close an open MIDI connection (if one exists).
   void closePort( void );
 
+  //! Returns true if a port is open and false if not.
+  virtual bool isPortOpen() const;
+
   //! Return the number of available MIDI input ports.
+  /*!
+    \return This function returns the number of MIDI ports of the selected API.
+  */
   unsigned int getPortCount();
 
   //! Return a string identifier for the specified MIDI input port number.
   /*!
-      An exception is thrown if an invalid port specifier is provided.
+    \return The name of the port with the given Id is returned.
+    \retval An empty string is returned if an invalid port specifier is provided.
   */
   std::string getPortName( unsigned int portNumber = 0 );
 
-  //! Set the maximum number of MIDI messages to be saved in the queue.
-  /*!
-      If the queue size limit is reached, incoming messages will be
-      ignored.  The default limit is 1024.
-  */
-  void setQueueSizeLimit( unsigned int queueSize );
-
   //! Specify whether certain MIDI message types should be queued or ignored during input.
   /*!
-      By default, MIDI timing and active sensing messages are ignored
-      during message input because of their relative high data rates.
-      MIDI sysex messages are ignored by default as well.  Variable
-      values of "true" imply that the respective message type will be
-      ignored.
+    By default, MIDI timing and active sensing messages are ignored
+    during message input because of their relative high data rates.
+    MIDI sysex messages are ignored by default as well.  Variable
+    values of "true" imply that the respective message type will be
+    ignored.
   */
   void ignoreTypes( bool midiSysex = true, bool midiTime = true, bool midiSense = true );
 
   //! Fill the user-provided vector with the data bytes for the next available MIDI message in the input queue and return the event delta-time in seconds.
   /*!
-      This function returns immediately whether a new message is
-      available or not.  A valid message is indicated by a non-zero
-      vector size.  An exception is thrown if an error occurs during
-      message retrieval or an input connection was not previously
-      established.
+    This function returns immediately whether a new message is
+    available or not.  A valid message is indicated by a non-zero
+    vector size.  An exception is thrown if an error occurs during
+    message retrieval or an input connection was not previously
+    established.
   */
   double getMessage( std::vector<unsigned char> *message );
 
-  // A MIDI structure used internally by the class to store incoming
-  // messages.  Each message represents one and only one MIDI message.
-  struct MidiMessage { 
-    std::vector<unsigned char> bytes; 
-    double timeStamp;
+  //! Set an error callback function to be invoked when an error has occured.
+  /*!
+    The callback function will be called whenever an error has occured. It is best
+    to set the error callback function before opening a port.
+  */
+  virtual void setErrorCallback( RtMidiErrorCallback errorCallback = NULL, void *userData = 0 );
 
-    // Default constructor.
-    MidiMessage()
-      :bytes(3), timeStamp(0.0) {}
-  };
-
-  // The RtMidiInData structure is used to pass private class data to
-  // the MIDI input handling function or thread.
-  struct RtMidiInData {
-    std::queue<MidiMessage> queue;
-    MidiMessage message;
-    unsigned int queueLimit;
-    unsigned char ignoreFlags;
-    bool doInput;
-    bool firstMessage;
-    void *apiData;
-    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),
-        continueSysex(false) {}
-  };
-
- private:
-
-  void initialize( const std::string& clientName );
-  RtMidiInData inputData_;
+ protected:
+  void openMidiApi( RtMidi::Api api, const std::string clientName, unsigned int queueSizeLimit );
 
 };
 
@@ -233,9 +337,11 @@
     output.  It allows one to probe available MIDI output ports, to
     connect to one such port, and to send MIDI bytes immediately over
     the connection.  Create multiple instances of this class to
-    connect to more than one MIDI device at the same time.
+    connect to more than one MIDI device at the same time.  With the
+    OS-X, Linux ALSA and JACK MIDI APIs, it is also possible to open a
+    virtual port to which other MIDI software clients can connect.
 
-    by Gary P. Scavone, 2003-2008.
+    by Gary P. Scavone, 2003-2014.
 */
 /**********************************************************************/
 
@@ -245,12 +351,20 @@
 
   //! Default constructor that allows an optional client name.
   /*!
-      An exception will be thrown if a MIDI system initialization error occurs.
+    An exception will be thrown if a MIDI system initialization error occurs.
+
+    If no API argument is specified and multiple API support has been
+    compiled, the default order of use is ALSA, JACK (Linux) and CORE,
+    JACK (OS-X).
   */
-  RtMidiOut( const std::string clientName = std::string( "RtMidi Output Client" ) );
+  RtMidiOut( RtMidi::Api api=UNSPECIFIED,
+             const std::string clientName = std::string( "RtMidi Output Client") );
 
   //! The destructor closes any open MIDI connections.
-  ~RtMidiOut();
+  ~RtMidiOut( void ) throw();
+
+  //! Returns the MIDI API specifier for the current instance of RtMidiOut.
+  RtMidi::Api getCurrentApi( void ) throw();
 
   //! Open a MIDI output connection.
   /*!
@@ -262,25 +376,28 @@
   void openPort( unsigned int portNumber = 0, const std::string portName = std::string( "RtMidi Output" ) );
 
   //! Close an open MIDI connection (if one exists).
-  void closePort();
+  void closePort( void );
 
-  //! Create a virtual output port, with optional name, to allow software connections (OS X and ALSA only).
+  //! Returns true if a port is open and false if not.
+  virtual bool isPortOpen() const;
+
+  //! Create a virtual output port, with optional name, to allow software connections (OS X, JACK and ALSA only).
   /*!
       This function creates a virtual MIDI output port to which other
       software applications can connect.  This type of functionality
-      is currently only supported by the Macintosh OS-X and Linux ALSA
-      APIs (the function does nothing with the other APIs).  An
-      exception is thrown if an error occurs while attempting to create
-      the virtual port.
+      is currently only supported by the Macintosh OS-X, Linux ALSA
+      and JACK APIs (the function does nothing with the other APIs).
+      An exception is thrown if an error occurs while attempting to
+      create the virtual port.
   */
   void openVirtualPort( const std::string portName = std::string( "RtMidi Output" ) );
 
   //! Return the number of available MIDI output ports.
-  unsigned int getPortCount();
+  unsigned int getPortCount( void );
 
   //! Return a string identifier for the specified MIDI port type and number.
   /*!
-      An exception is thrown if an invalid port specifier is provided.
+      An empty string is returned if an invalid port specifier is provided.
   */
   std::string getPortName( unsigned int portNumber = 0 );
 
@@ -291,9 +408,356 @@
   */
   void sendMessage( std::vector<unsigned char> *message );
 
- private:
+  //! Set an error callback function to be invoked when an error has occured.
+  /*!
+    The callback function will be called whenever an error has occured. It is best
+    to set the error callback function before opening a port.
+  */
+  virtual void setErrorCallback( RtMidiErrorCallback errorCallback = NULL, void *userData = 0 );
 
+ protected:
+  void openMidiApi( RtMidi::Api api, const std::string clientName );
+};
+
+
+// **************************************************************** //
+//
+// MidiInApi / MidiOutApi class declarations.
+//
+// Subclasses of MidiInApi and MidiOutApi contain all API- and
+// OS-specific code necessary to fully implement the RtMidi API.
+//
+// Note that MidiInApi and MidiOutApi are abstract base classes and
+// cannot be explicitly instantiated.  RtMidiIn and RtMidiOut will
+// create instances of a MidiInApi or MidiOutApi subclass.
+//
+// **************************************************************** //
+
+class MidiApi
+{
+ public:
+
+  MidiApi();
+  virtual ~MidiApi();
+  virtual RtMidi::Api getCurrentApi( void ) = 0;
+  virtual void openPort( unsigned int portNumber, const std::string portName ) = 0;
+  virtual void openVirtualPort( const std::string portName ) = 0;
+  virtual void closePort( void ) = 0;
+
+  virtual unsigned int getPortCount( void ) = 0;
+  virtual std::string getPortName( unsigned int portNumber ) = 0;
+
+  inline bool isPortOpen() const { return connected_; }
+  void setErrorCallback( RtMidiErrorCallback errorCallback, void *userData );
+
+  //! A basic error reporting function for RtMidi classes.
+  void error( RtMidiError::Type type, std::string errorString );
+
+protected:
+  virtual void initialize( const std::string& clientName ) = 0;
+
+  void *apiData_;
+  bool connected_;
+  std::string errorString_;
+  RtMidiErrorCallback errorCallback_;
+  bool firstErrorOccurred_;
+  void *errorCallbackUserData_;
+};
+
+class MidiInApi : public MidiApi
+{
+ public:
+
+  MidiInApi( unsigned int queueSizeLimit );
+  virtual ~MidiInApi( void );
+  void setCallback( RtMidiIn::RtMidiCallback callback, void *userData );
+  void cancelCallback( void );
+  virtual void ignoreTypes( bool midiSysex, bool midiTime, bool midiSense );
+  double getMessage( std::vector<unsigned char> *message );
+
+  // A MIDI structure used internally by the class to store incoming
+  // messages.  Each message represents one and only one MIDI message.
+  struct MidiMessage { 
+    std::vector<unsigned char> bytes; 
+    double timeStamp;
+
+    // Default constructor.
+  MidiMessage()
+  :bytes(0), timeStamp(0.0) {}
+  };
+
+  struct MidiQueue {
+    unsigned int front;
+    unsigned int back;
+    unsigned int size;
+    unsigned int ringSize;
+    MidiMessage *ring;
+
+    // Default constructor.
+  MidiQueue()
+  :front(0), back(0), size(0), ringSize(0) {}
+  };
+
+  // The RtMidiInData structure is used to pass private class data to
+  // the MIDI input handling function or thread.
+  struct RtMidiInData {
+    MidiQueue queue;
+    MidiMessage message;
+    unsigned char ignoreFlags;
+    bool doInput;
+    bool firstMessage;
+    void *apiData;
+    bool usingCallback;
+    RtMidiIn::RtMidiCallback userCallback;
+    void *userData;
+    bool continueSysex;
+
+    // Default constructor.
+  RtMidiInData()
+  : ignoreFlags(7), doInput(false), firstMessage(true),
+      apiData(0), usingCallback(false), userCallback(0), userData(0),
+      continueSysex(false) {}
+  };
+
+ protected:
+  RtMidiInData inputData_;
+};
+
+class MidiOutApi : public MidiApi
+{
+ public:
+
+  MidiOutApi( void );
+  virtual ~MidiOutApi( void );
+  virtual void sendMessage( std::vector<unsigned char> *message ) = 0;
+};
+
+// **************************************************************** //
+//
+// Inline RtMidiIn and RtMidiOut definitions.
+//
+// **************************************************************** //
+
+inline RtMidi::Api RtMidiIn :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); }
+inline void RtMidiIn :: openPort( unsigned int portNumber, const std::string portName ) { rtapi_->openPort( portNumber, portName ); }
+inline void RtMidiIn :: openVirtualPort( const std::string portName ) { rtapi_->openVirtualPort( portName ); }
+inline void RtMidiIn :: closePort( void ) { rtapi_->closePort(); }
+inline bool RtMidiIn :: isPortOpen() const { return rtapi_->isPortOpen(); }
+inline void RtMidiIn :: setCallback( RtMidiCallback callback, void *userData ) { ((MidiInApi *)rtapi_)->setCallback( callback, userData ); }
+inline void RtMidiIn :: cancelCallback( void ) { ((MidiInApi *)rtapi_)->cancelCallback(); }
+inline unsigned int RtMidiIn :: getPortCount( void ) { return rtapi_->getPortCount(); }
+inline std::string RtMidiIn :: getPortName( unsigned int portNumber ) { return rtapi_->getPortName( portNumber ); }
+inline void RtMidiIn :: ignoreTypes( bool midiSysex, bool midiTime, bool midiSense ) { ((MidiInApi *)rtapi_)->ignoreTypes( midiSysex, midiTime, midiSense ); }
+inline double RtMidiIn :: getMessage( std::vector<unsigned char> *message ) { return ((MidiInApi *)rtapi_)->getMessage( message ); }
+inline void RtMidiIn :: setErrorCallback( RtMidiErrorCallback errorCallback, void *userData ) { rtapi_->setErrorCallback(errorCallback, userData); }
+
+inline RtMidi::Api RtMidiOut :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); }
+inline void RtMidiOut :: openPort( unsigned int portNumber, const std::string portName ) { rtapi_->openPort( portNumber, portName ); }
+inline void RtMidiOut :: openVirtualPort( const std::string portName ) { rtapi_->openVirtualPort( portName ); }
+inline void RtMidiOut :: closePort( void ) { rtapi_->closePort(); }
+inline bool RtMidiOut :: isPortOpen() const { return rtapi_->isPortOpen(); }
+inline unsigned int RtMidiOut :: getPortCount( void ) { return rtapi_->getPortCount(); }
+inline std::string RtMidiOut :: getPortName( unsigned int portNumber ) { return rtapi_->getPortName( portNumber ); }
+inline void RtMidiOut :: sendMessage( std::vector<unsigned char> *message ) { ((MidiOutApi *)rtapi_)->sendMessage( message ); }
+inline void RtMidiOut :: setErrorCallback( RtMidiErrorCallback errorCallback, void *userData ) { rtapi_->setErrorCallback(errorCallback, userData); }
+
+// **************************************************************** //
+//
+// MidiInApi and MidiOutApi subclass prototypes.
+//
+// **************************************************************** //
+
+#if !defined(__LINUX_ALSA__) && !defined(__UNIX_JACK__) && !defined(__MACOSX_CORE__) && !defined(__WINDOWS_MM__)
+  #define __RTMIDI_DUMMY__
+#endif
+
+#if defined(__MACOSX_CORE__)
+
+class MidiInCore: public MidiInApi
+{
+ public:
+  MidiInCore( const std::string clientName, unsigned int queueSizeLimit );
+  ~MidiInCore( void );
+  RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; };
+  void openPort( unsigned int portNumber, const std::string portName );
+  void openVirtualPort( const std::string portName );
+  void closePort( void );
+  unsigned int getPortCount( void );
+  std::string getPortName( unsigned int portNumber );
+
+ protected:
+  void initialize( const std::string& clientName );
+};
+
+class MidiOutCore: public MidiOutApi
+{
+ public:
+  MidiOutCore( const std::string clientName );
+  ~MidiOutCore( void );
+  RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; };
+  void openPort( unsigned int portNumber, const std::string portName );
+  void openVirtualPort( const std::string portName );
+  void closePort( void );
+  unsigned int getPortCount( void );
+  std::string getPortName( unsigned int portNumber );
+  void sendMessage( std::vector<unsigned char> *message );
+
+ protected:
   void initialize( const std::string& clientName );
 };
 
 #endif
+
+#if defined(__UNIX_JACK__)
+
+class MidiInJack: public MidiInApi
+{
+ public:
+  MidiInJack( const std::string clientName, unsigned int queueSizeLimit );
+  ~MidiInJack( void );
+  RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; };
+  void openPort( unsigned int portNumber, const std::string portName );
+  void openVirtualPort( const std::string portName );
+  void closePort( void );
+  unsigned int getPortCount( void );
+  std::string getPortName( unsigned int portNumber );
+
+ protected:
+  std::string clientName;
+
+  void connect( void );
+  void initialize( const std::string& clientName );
+};
+
+class MidiOutJack: public MidiOutApi
+{
+ public:
+  MidiOutJack( const std::string clientName );
+  ~MidiOutJack( void );
+  RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; };
+  void openPort( unsigned int portNumber, const std::string portName );
+  void openVirtualPort( const std::string portName );
+  void closePort( void );
+  unsigned int getPortCount( void );
+  std::string getPortName( unsigned int portNumber );
+  void sendMessage( std::vector<unsigned char> *message );
+
+ protected:
+  std::string clientName;
+
+  void connect( void );
+  void initialize( const std::string& clientName );
+};
+
+#endif
+
+#if defined(__LINUX_ALSA__)
+
+class MidiInAlsa: public MidiInApi
+{
+ public:
+  MidiInAlsa( const std::string clientName, unsigned int queueSizeLimit );
+  ~MidiInAlsa( void );
+  RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; };
+  void openPort( unsigned int portNumber, const std::string portName );
+  void openVirtualPort( const std::string portName );
+  void closePort( void );
+  unsigned int getPortCount( void );
+  std::string getPortName( unsigned int portNumber );
+
+ protected:
+  void initialize( const std::string& clientName );
+};
+
+class MidiOutAlsa: public MidiOutApi
+{
+ public:
+  MidiOutAlsa( const std::string clientName );
+  ~MidiOutAlsa( void );
+  RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; };
+  void openPort( unsigned int portNumber, const std::string portName );
+  void openVirtualPort( const std::string portName );
+  void closePort( void );
+  unsigned int getPortCount( void );
+  std::string getPortName( unsigned int portNumber );
+  void sendMessage( std::vector<unsigned char> *message );
+
+ protected:
+  void initialize( const std::string& clientName );
+};
+
+#endif
+
+#if defined(__WINDOWS_MM__)
+
+class MidiInWinMM: public MidiInApi
+{
+ public:
+  MidiInWinMM( const std::string clientName, unsigned int queueSizeLimit );
+  ~MidiInWinMM( void );
+  RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; };
+  void openPort( unsigned int portNumber, const std::string portName );
+  void openVirtualPort( const std::string portName );
+  void closePort( void );
+  unsigned int getPortCount( void );
+  std::string getPortName( unsigned int portNumber );
+
+ protected:
+  void initialize( const std::string& clientName );
+};
+
+class MidiOutWinMM: public MidiOutApi
+{
+ public:
+  MidiOutWinMM( const std::string clientName );
+  ~MidiOutWinMM( void );
+  RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; };
+  void openPort( unsigned int portNumber, const std::string portName );
+  void openVirtualPort( const std::string portName );
+  void closePort( void );
+  unsigned int getPortCount( void );
+  std::string getPortName( unsigned int portNumber );
+  void sendMessage( std::vector<unsigned char> *message );
+
+ protected:
+  void initialize( const std::string& clientName );
+};
+
+#endif
+
+#if defined(__RTMIDI_DUMMY__)
+
+class MidiInDummy: public MidiInApi
+{
+ public:
+ MidiInDummy( const std::string /*clientName*/, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit ) { errorString_ = "MidiInDummy: This class provides no functionality."; error( RtMidiError::WARNING, errorString_ ); }
+  RtMidi::Api getCurrentApi( void ) { return RtMidi::RTMIDI_DUMMY; }
+  void openPort( unsigned int /*portNumber*/, const std::string /*portName*/ ) {}
+  void openVirtualPort( const std::string /*portName*/ ) {}
+  void closePort( void ) {}
+  unsigned int getPortCount( void ) { return 0; }
+  std::string getPortName( unsigned int /*portNumber*/ ) { return ""; }
+
+ protected:
+  void initialize( const std::string& /*clientName*/ ) {}
+};
+
+class MidiOutDummy: public MidiOutApi
+{
+ public:
+  MidiOutDummy( const std::string /*clientName*/ ) { errorString_ = "MidiOutDummy: This class provides no functionality."; error( RtMidiError::WARNING, errorString_ ); }
+  RtMidi::Api getCurrentApi( void ) { return RtMidi::RTMIDI_DUMMY; }
+  void openPort( unsigned int /*portNumber*/, const std::string /*portName*/ ) {}
+  void openVirtualPort( const std::string /*portName*/ ) {}
+  void closePort( void ) {}
+  unsigned int getPortCount( void ) { return 0; }
+  std::string getPortName( unsigned int /*portNumber*/ ) { return ""; }
+  void sendMessage( std::vector<unsigned char> * /*message*/ ) {}
+
+ protected:
+  void initialize( const std::string& /*clientName*/ ) {}
+};
+
+#endif
+
+#endif