1 /**********************************************************************/
2 /*! \class RtMidi
3     \brief An abstract base class for realtime MIDI input/output.
4 
5     This class implements some common functionality for the realtime
6     MIDI input/output subclasses RtMidiIn and RtMidiOut.
7 
8     RtMidi GitHub site: https://github.com/thestk/rtmidi
9     RtMidi WWW site: http://www.music.mcgill.ca/~gary/rtmidi/
10 
11     RtMidi: realtime MIDI i/o C++ classes
12     Copyright (c) 2003-2021 Gary P. Scavone
13 
14     Permission is hereby granted, free of charge, to any person
15     obtaining a copy of this software and associated documentation files
16     (the "Software"), to deal in the Software without restriction,
17     including without limitation the rights to use, copy, modify, merge,
18     publish, distribute, sublicense, and/or sell copies of the Software,
19     and to permit persons to whom the Software is furnished to do so,
20     subject to the following conditions:
21 
22     The above copyright notice and this permission notice shall be
23     included in all copies or substantial portions of the Software.
24 
25     Any person wishing to distribute modifications to the Software is
26     asked to send the modifications to the original developer so that
27     they can be incorporated into the canonical version.  This is,
28     however, not a binding provision of this license.
29 
30     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
33     IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
34     ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
35     CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
36     WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 */
38 /**********************************************************************/
39 
40 /*!
41   \file RtMidi.h
42  */
43 
44 #ifndef RTMIDI_H
45 #define RTMIDI_H
46 
47 #if defined _WIN32 || defined __CYGWIN__
48   #if defined(RTMIDI_EXPORT)
49     #define RTMIDI_DLL_PUBLIC __declspec(dllexport)
50   #else
51     #define RTMIDI_DLL_PUBLIC
52   #endif
53 #else
54   #if __GNUC__ >= 4
55     #define RTMIDI_DLL_PUBLIC __attribute__( (visibility( "default" )) )
56   #else
57     #define RTMIDI_DLL_PUBLIC
58   #endif
59 #endif
60 
61 #define RTMIDI_VERSION "5.0.0"
62 
63 #include <exception>
64 #include <iostream>
65 #include <string>
66 #include <vector>
67 
68 
69 /************************************************************************/
70 /*! \class RtMidiError
71     \brief Exception handling class for RtMidi.
72 
73     The RtMidiError class is quite simple but it does allow errors to be
74     "caught" by RtMidiError::Type. See the RtMidi documentation to know
75     which methods can throw an RtMidiError.
76 */
77 /************************************************************************/
78 
79 class RTMIDI_DLL_PUBLIC RtMidiError : public std::exception
80 {
81  public:
82   //! Defined RtMidiError types.
83   enum Type {
84     WARNING,           /*!< A non-critical error. */
85     DEBUG_WARNING,     /*!< A non-critical error which might be useful for debugging. */
86     UNSPECIFIED,       /*!< The default, unspecified error type. */
87     NO_DEVICES_FOUND,  /*!< No devices found on system. */
88     INVALID_DEVICE,    /*!< An invalid device ID was specified. */
89     MEMORY_ERROR,      /*!< An error occured during memory allocation. */
90     INVALID_PARAMETER, /*!< An invalid parameter was specified to a function. */
91     INVALID_USE,       /*!< The function was called incorrectly. */
92     DRIVER_ERROR,      /*!< A system driver error occured. */
93     SYSTEM_ERROR,      /*!< A system error occured. */
94     THREAD_ERROR       /*!< A thread error occured. */
95   };
96 
97   //! The constructor.
98   RtMidiError( const std::string& message, Type type = RtMidiError::UNSPECIFIED ) throw()
99     : message_(message), type_(type) {}
100 
101   //! The destructor.
102   virtual ~RtMidiError( void ) throw() {}
103 
104   //! Prints thrown error message to stderr.
105   virtual void printMessage( void ) const throw() { std::cerr << '\n' << message_ << "\n\n"; }
106 
107   //! Returns the thrown error message type.
108   virtual const Type& getType( void ) const throw() { return type_; }
109 
110   //! Returns the thrown error message string.
111   virtual const std::string& getMessage( void ) const throw() { return message_; }
112 
113   //! Returns the thrown error message as a c-style string.
114   virtual const char* what( void ) const throw() { return message_.c_str(); }
115 
116  protected:
117   std::string message_;
118   Type type_;
119 };
120 
121 //! RtMidi error callback function prototype.
122 /*!
123     \param type Type of error.
124     \param errorText Error description.
125 
126     Note that class behaviour is undefined after a critical error (not
127     a warning) is reported.
128  */
129 typedef void (*RtMidiErrorCallback)( RtMidiError::Type type, const std::string &errorText, void *userData );
130 
131 class MidiApi;
132 
133 class RTMIDI_DLL_PUBLIC RtMidi
134 {
135  public:
136 
137      RtMidi(RtMidi&& other) noexcept;
138   //! MIDI API specifier arguments.
139   enum Api {
140     UNSPECIFIED,    /*!< Search for a working compiled API. */
141     MACOSX_CORE,    /*!< Macintosh OS-X CoreMIDI API. */
142     LINUX_ALSA,     /*!< The Advanced Linux Sound Architecture API. */
143     UNIX_JACK,      /*!< The JACK Low-Latency MIDI Server API. */
144     WINDOWS_MM,     /*!< The Microsoft Multimedia MIDI API. */
145     RTMIDI_DUMMY,   /*!< A compilable but non-functional API. */
146     WEB_MIDI_API,   /*!< W3C Web MIDI API. */
147     NUM_APIS        /*!< Number of values in this enum. */
148   };
149 
150   //! A static function to determine the current RtMidi version.
151   static std::string getVersion( void ) throw();
152 
153   //! A static function to determine the available compiled MIDI APIs.
154   /*!
155     The values returned in the std::vector can be compared against
156     the enumerated list values.  Note that there can be more than one
157     API compiled for certain operating systems.
158   */
159   static void getCompiledApi( std::vector<RtMidi::Api> &apis ) throw();
160 
161   //! Return the name of a specified compiled MIDI API.
162   /*!
163     This obtains a short lower-case name used for identification purposes.
164     This value is guaranteed to remain identical across library versions.
165     If the API is unknown, this function will return the empty string.
166   */
167   static std::string getApiName( RtMidi::Api api );
168 
169   //! Return the display name of a specified compiled MIDI API.
170   /*!
171     This obtains a long name used for display purposes.
172     If the API is unknown, this function will return the empty string.
173   */
174   static std::string getApiDisplayName( RtMidi::Api api );
175 
176   //! Return the compiled MIDI API having the given name.
177   /*!
178     A case insensitive comparison will check the specified name
179     against the list of compiled APIs, and return the one which
180     matches. On failure, the function returns UNSPECIFIED.
181   */
182   static RtMidi::Api getCompiledApiByName( const std::string &name );
183 
184   //! Pure virtual openPort() function.
185   virtual void openPort( unsigned int portNumber = 0, const std::string &portName = std::string( "RtMidi" ) ) = 0;
186 
187   //! Pure virtual openVirtualPort() function.
188   virtual void openVirtualPort( const std::string &portName = std::string( "RtMidi" ) ) = 0;
189 
190   //! Pure virtual getPortCount() function.
191   virtual unsigned int getPortCount() = 0;
192 
193   //! Pure virtual getPortName() function.
194   virtual std::string getPortName( unsigned int portNumber = 0 ) = 0;
195 
196   //! Pure virtual closePort() function.
197   virtual void closePort( void ) = 0;
198 
199   void setClientName( const std::string &clientName );
200   void setPortName( const std::string &portName );
201 
202   //! Returns true if a port is open and false if not.
203   /*!
204       Note that this only applies to connections made with the openPort()
205       function, not to virtual ports.
206   */
207   virtual bool isPortOpen( void ) const = 0;
208 
209   //! Set an error callback function to be invoked when an error has occured.
210   /*!
211     The callback function will be called whenever an error has occured. It is best
212     to set the error callback function before opening a port.
213   */
214   virtual void setErrorCallback( RtMidiErrorCallback errorCallback = NULL, void *userData = 0 ) = 0;
215 
216  protected:
217   RtMidi();
218   virtual ~RtMidi();
219   MidiApi *rtapi_;
220 
221   /* Make the class non-copyable */
222   RtMidi(RtMidi& other) = delete;
223   RtMidi& operator=(RtMidi& other) = delete;
224 };
225 
226 /**********************************************************************/
227 /*! \class RtMidiIn
228     \brief A realtime MIDI input class.
229 
230     This class provides a common, platform-independent API for
231     realtime MIDI input.  It allows access to a single MIDI input
232     port.  Incoming MIDI messages are either saved to a queue for
233     retrieval using the getMessage() function or immediately passed to
234     a user-specified callback function.  Create multiple instances of
235     this class to connect to more than one MIDI device at the same
236     time.  With the OS-X, Linux ALSA, and JACK MIDI APIs, it is also
237     possible to open a virtual input port to which other MIDI software
238     clients can connect.
239 */
240 /**********************************************************************/
241 
242 // **************************************************************** //
243 //
244 // RtMidiIn and RtMidiOut class declarations.
245 //
246 // RtMidiIn / RtMidiOut are "controllers" used to select an available
247 // MIDI input or output interface.  They present common APIs for the
248 // user to call but all functionality is implemented by the classes
249 // MidiInApi, MidiOutApi and their subclasses.  RtMidiIn and RtMidiOut
250 // each create an instance of a MidiInApi or MidiOutApi subclass based
251 // on the user's API choice.  If no choice is made, they attempt to
252 // make a "logical" API selection.
253 //
254 // **************************************************************** //
255 
256 class RTMIDI_DLL_PUBLIC RtMidiIn : public RtMidi
257 {
258  public:
259   //! User callback function type definition.
260   typedef void (*RtMidiCallback)( double timeStamp, std::vector<unsigned char> *message, void *userData );
261 
262   //! Default constructor that allows an optional api, client name and queue size.
263   /*!
264     An exception will be thrown if a MIDI system initialization
265     error occurs.  The queue size defines the maximum number of
266     messages that can be held in the MIDI queue (when not using a
267     callback function).  If the queue size limit is reached,
268     incoming messages will be ignored.
269 
270     If no API argument is specified and multiple API support has been
271     compiled, the default order of use is ALSA, JACK (Linux) and CORE,
272     JACK (OS-X).
273 
274     \param api        An optional API id can be specified.
275     \param clientName An optional client name can be specified. This
276                       will be used to group the ports that are created
277                       by the application.
278     \param queueSizeLimit An optional size of the MIDI input queue can be specified.
279   */
280   RtMidiIn( RtMidi::Api api=UNSPECIFIED,
281             const std::string& clientName = "RtMidi Input Client",
282             unsigned int queueSizeLimit = 100 );
283 
284   RtMidiIn(RtMidiIn&& other) noexcept : RtMidi(std::move(other)) { }
285 
286   //! If a MIDI connection is still open, it will be closed by the destructor.
287   ~RtMidiIn ( void ) throw();
288 
289   //! Returns the MIDI API specifier for the current instance of RtMidiIn.
290   RtMidi::Api getCurrentApi( void ) throw();
291 
292   //! Open a MIDI input connection given by enumeration number.
293   /*!
294     \param portNumber An optional port number greater than 0 can be specified.
295                       Otherwise, the default or first port found is opened.
296     \param portName An optional name for the application port that is used to connect to portId can be specified.
297   */
298   void openPort( unsigned int portNumber = 0, const std::string &portName = std::string( "RtMidi Input" ) );
299 
300   //! Create a virtual input port, with optional name, to allow software connections (OS X, JACK and ALSA only).
301   /*!
302     This function creates a virtual MIDI input port to which other
303     software applications can connect.  This type of functionality
304     is currently only supported by the Macintosh OS-X, any JACK,
305     and Linux ALSA APIs (the function returns an error for the other APIs).
306 
307     \param portName An optional name for the application port that is
308                     used to connect to portId can be specified.
309   */
310   void openVirtualPort( const std::string &portName = std::string( "RtMidi Input" ) );
311 
312   //! Set a callback function to be invoked for incoming MIDI messages.
313   /*!
314     The callback function will be called whenever an incoming MIDI
315     message is received.  While not absolutely necessary, it is best
316     to set the callback function before opening a MIDI port to avoid
317     leaving some messages in the queue.
318 
319     \param callback A callback function must be given.
320     \param userData Optionally, a pointer to additional data can be
321                     passed to the callback function whenever it is called.
322   */
323   void setCallback( RtMidiCallback callback, void *userData = 0 );
324 
325   //! Cancel use of the current callback function (if one exists).
326   /*!
327     Subsequent incoming MIDI messages will be written to the queue
328     and can be retrieved with the \e getMessage function.
329   */
330   void cancelCallback();
331 
332   //! Close an open MIDI connection (if one exists).
333   void closePort( void );
334 
335   //! Returns true if a port is open and false if not.
336   /*!
337       Note that this only applies to connections made with the openPort()
338       function, not to virtual ports.
339   */
340   virtual bool isPortOpen() const;
341 
342   //! Return the number of available MIDI input ports.
343   /*!
344     \return This function returns the number of MIDI ports of the selected API.
345   */
346   unsigned int getPortCount();
347 
348   //! Return a string identifier for the specified MIDI input port number.
349   /*!
350     \return The name of the port with the given Id is returned.
351     \retval An empty string is returned if an invalid port specifier
352             is provided. User code should assume a UTF-8 encoding.
353   */
354   std::string getPortName( unsigned int portNumber = 0 );
355 
356   //! Specify whether certain MIDI message types should be queued or ignored during input.
357   /*!
358     By default, MIDI timing and active sensing messages are ignored
359     during message input because of their relative high data rates.
360     MIDI sysex messages are ignored by default as well.  Variable
361     values of "true" imply that the respective message type will be
362     ignored.
363   */
364   void ignoreTypes( bool midiSysex = true, bool midiTime = true, bool midiSense = true );
365 
366   //! 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.
367   /*!
368     This function returns immediately whether a new message is
369     available or not.  A valid message is indicated by a non-zero
370     vector size.  An exception is thrown if an error occurs during
371     message retrieval or an input connection was not previously
372     established.
373   */
374   double getMessage( std::vector<unsigned char> *message );
375 
376   //! Set an error callback function to be invoked when an error has occured.
377   /*!
378     The callback function will be called whenever an error has occured. It is best
379     to set the error callback function before opening a port.
380   */
381   virtual void setErrorCallback( RtMidiErrorCallback errorCallback = NULL, void *userData = 0 );
382 
383   //! Set maximum expected incoming message size.
384   /*!
385     For APIs that require manual buffer management, it can be useful to set the buffer
386     size and buffer count when expecting to receive large SysEx messages.  Note that
387     currently this function has no effect when called after openPort().  The default
388     buffer size is 1024 with a count of 4 buffers, which should be sufficient for most
389     cases; as mentioned, this does not affect all API backends, since most either support
390     dynamically scalable buffers or take care of buffer handling themselves.  It is
391     principally intended for users of the Windows MM backend who must support receiving
392     especially large messages.
393   */
394   virtual void setBufferSize( unsigned int size, unsigned int count );
395 
396  protected:
397   void openMidiApi( RtMidi::Api api, const std::string &clientName, unsigned int queueSizeLimit );
398 };
399 
400 /**********************************************************************/
401 /*! \class RtMidiOut
402     \brief A realtime MIDI output class.
403 
404     This class provides a common, platform-independent API for MIDI
405     output.  It allows one to probe available MIDI output ports, to
406     connect to one such port, and to send MIDI bytes immediately over
407     the connection.  Create multiple instances of this class to
408     connect to more than one MIDI device at the same time.  With the
409     OS-X, Linux ALSA and JACK MIDI APIs, it is also possible to open a
410     virtual port to which other MIDI software clients can connect.
411 */
412 /**********************************************************************/
413 
414 class RTMIDI_DLL_PUBLIC RtMidiOut : public RtMidi
415 {
416  public:
417   //! Default constructor that allows an optional client name.
418   /*!
419     An exception will be thrown if a MIDI system initialization error occurs.
420 
421     If no API argument is specified and multiple API support has been
422     compiled, the default order of use is ALSA, JACK (Linux) and CORE,
423     JACK (OS-X).
424   */
425   RtMidiOut( RtMidi::Api api=UNSPECIFIED,
426              const std::string& clientName = "RtMidi Output Client" );
427 
428   RtMidiOut(RtMidiOut&& other) noexcept : RtMidi(std::move(other)) { }
429 
430   //! The destructor closes any open MIDI connections.
431   ~RtMidiOut( void ) throw();
432 
433   //! Returns the MIDI API specifier for the current instance of RtMidiOut.
434   RtMidi::Api getCurrentApi( void ) throw();
435 
436   //! Open a MIDI output connection.
437   /*!
438       An optional port number greater than 0 can be specified.
439       Otherwise, the default or first port found is opened.  An
440       exception is thrown if an error occurs while attempting to make
441       the port connection.
442   */
443   void openPort( unsigned int portNumber = 0, const std::string &portName = std::string( "RtMidi Output" ) );
444 
445   //! Close an open MIDI connection (if one exists).
446   void closePort( void );
447 
448   //! Returns true if a port is open and false if not.
449   /*!
450       Note that this only applies to connections made with the openPort()
451       function, not to virtual ports.
452   */
453   virtual bool isPortOpen() const;
454 
455   //! Create a virtual output port, with optional name, to allow software connections (OS X, JACK and ALSA only).
456   /*!
457       This function creates a virtual MIDI output port to which other
458       software applications can connect.  This type of functionality
459       is currently only supported by the Macintosh OS-X, Linux ALSA
460       and JACK APIs (the function does nothing with the other APIs).
461       An exception is thrown if an error occurs while attempting to
462       create the virtual port.
463   */
464   void openVirtualPort( const std::string &portName = std::string( "RtMidi Output" ) );
465 
466   //! Return the number of available MIDI output ports.
467   unsigned int getPortCount( void );
468 
469   //! Return a string identifier for the specified MIDI port type and number.
470   /*!
471     \return The name of the port with the given Id is returned.
472     \retval An empty string is returned if an invalid port specifier
473             is provided. User code should assume a UTF-8 encoding.
474   */
475   std::string getPortName( unsigned int portNumber = 0 );
476 
477   //! Immediately send a single message out an open MIDI output port.
478   /*!
479       An exception is thrown if an error occurs during output or an
480       output connection was not previously established.
481   */
482   void sendMessage( const std::vector<unsigned char> *message );
483 
484   //! Immediately send a single message out an open MIDI output port.
485   /*!
486       An exception is thrown if an error occurs during output or an
487       output connection was not previously established.
488 
489       \param message A pointer to the MIDI message as raw bytes
490       \param size    Length of the MIDI message in bytes
491   */
492   void sendMessage( const unsigned char *message, size_t size );
493 
494   //! Set an error callback function to be invoked when an error has occured.
495   /*!
496     The callback function will be called whenever an error has occured. It is best
497     to set the error callback function before opening a port.
498   */
499   virtual void setErrorCallback( RtMidiErrorCallback errorCallback = NULL, void *userData = 0 );
500 
501  protected:
502   void openMidiApi( RtMidi::Api api, const std::string &clientName );
503 };
504 
505 
506 // **************************************************************** //
507 //
508 // MidiInApi / MidiOutApi class declarations.
509 //
510 // Subclasses of MidiInApi and MidiOutApi contain all API- and
511 // OS-specific code necessary to fully implement the RtMidi API.
512 //
513 // Note that MidiInApi and MidiOutApi are abstract base classes and
514 // cannot be explicitly instantiated.  RtMidiIn and RtMidiOut will
515 // create instances of a MidiInApi or MidiOutApi subclass.
516 //
517 // **************************************************************** //
518 
519 class RTMIDI_DLL_PUBLIC MidiApi
520 {
521  public:
522 
523   MidiApi();
524   virtual ~MidiApi();
525   virtual RtMidi::Api getCurrentApi( void ) = 0;
526   virtual void openPort( unsigned int portNumber, const std::string &portName ) = 0;
527   virtual void openVirtualPort( const std::string &portName ) = 0;
528   virtual void closePort( void ) = 0;
529   virtual void setClientName( const std::string &clientName ) = 0;
530   virtual void setPortName( const std::string &portName ) = 0;
531 
532   virtual unsigned int getPortCount( void ) = 0;
533   virtual std::string getPortName( unsigned int portNumber ) = 0;
534 
535   inline bool isPortOpen() const { return connected_; }
536   void setErrorCallback( RtMidiErrorCallback errorCallback, void *userData );
537 
538   //! A basic error reporting function for RtMidi classes.
539   void error( RtMidiError::Type type, std::string errorString );
540 
541 protected:
542   virtual void initialize( const std::string& clientName ) = 0;
543 
544   void *apiData_;
545   bool connected_;
546   std::string errorString_;
547   RtMidiErrorCallback errorCallback_;
548   bool firstErrorOccurred_;
549   void *errorCallbackUserData_;
550 
551 };
552 
553 class RTMIDI_DLL_PUBLIC MidiInApi : public MidiApi
554 {
555  public:
556 
557   MidiInApi( unsigned int queueSizeLimit );
558   virtual ~MidiInApi( void );
559   void setCallback( RtMidiIn::RtMidiCallback callback, void *userData );
560   void cancelCallback( void );
561   virtual void ignoreTypes( bool midiSysex, bool midiTime, bool midiSense );
562   double getMessage( std::vector<unsigned char> *message );
563   virtual void setBufferSize( unsigned int size, unsigned int count );
564 
565   // A MIDI structure used internally by the class to store incoming
566   // messages.  Each message represents one and only one MIDI message.
567   struct MidiMessage {
568     std::vector<unsigned char> bytes;
569 
570     //! Time in seconds elapsed since the previous message
571     double timeStamp;
572 
573     // Default constructor.
574     MidiMessage()
575       : bytes(0), timeStamp(0.0) {}
576   };
577 
578   struct MidiQueue {
579     unsigned int front;
580     unsigned int back;
581     unsigned int ringSize;
582     MidiMessage *ring;
583 
584     // Default constructor.
585     MidiQueue()
586       : front(0), back(0), ringSize(0), ring(0) {}
587     bool push( const MidiMessage& );
588     bool pop( std::vector<unsigned char>*, double* );
589     unsigned int size( unsigned int *back=0, unsigned int *front=0 );
590   };
591 
592   // The RtMidiInData structure is used to pass private class data to
593   // the MIDI input handling function or thread.
594   struct RtMidiInData {
595     MidiQueue queue;
596     MidiMessage message;
597     unsigned char ignoreFlags;
598     bool doInput;
599     bool firstMessage;
600     void *apiData;
601     bool usingCallback;
602     RtMidiIn::RtMidiCallback userCallback;
603     void *userData;
604     bool continueSysex;
605     unsigned int bufferSize;
606     unsigned int bufferCount;
607 
608     // Default constructor.
609     RtMidiInData()
610       : ignoreFlags(7), doInput(false), firstMessage(true), apiData(0), usingCallback(false),
611         userCallback(0), userData(0), continueSysex(false), bufferSize(1024), bufferCount(4) {}
612   };
613 
614  protected:
615   RtMidiInData inputData_;
616 };
617 
618 class RTMIDI_DLL_PUBLIC MidiOutApi : public MidiApi
619 {
620  public:
621 
622   MidiOutApi( void );
623   virtual ~MidiOutApi( void );
624   virtual void sendMessage( const unsigned char *message, size_t size ) = 0;
625 };
626 
627 // **************************************************************** //
628 //
629 // Inline RtMidiIn and RtMidiOut definitions.
630 //
631 // **************************************************************** //
632 
633 inline RtMidi::Api RtMidiIn :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); }
634 inline void RtMidiIn :: openPort( unsigned int portNumber, const std::string &portName ) { rtapi_->openPort( portNumber, portName ); }
635 inline void RtMidiIn :: openVirtualPort( const std::string &portName ) { rtapi_->openVirtualPort( portName ); }
636 inline void RtMidiIn :: closePort( void ) { rtapi_->closePort(); }
637 inline bool RtMidiIn :: isPortOpen() const { return rtapi_->isPortOpen(); }
638 inline void RtMidiIn :: setCallback( RtMidiCallback callback, void *userData ) { static_cast<MidiInApi *>(rtapi_)->setCallback( callback, userData ); }
639 inline void RtMidiIn :: cancelCallback( void ) { static_cast<MidiInApi *>(rtapi_)->cancelCallback(); }
640 inline unsigned int RtMidiIn :: getPortCount( void ) { return rtapi_->getPortCount(); }
641 inline std::string RtMidiIn :: getPortName( unsigned int portNumber ) { return rtapi_->getPortName( portNumber ); }
642 inline void RtMidiIn :: ignoreTypes( bool midiSysex, bool midiTime, bool midiSense ) { static_cast<MidiInApi *>(rtapi_)->ignoreTypes( midiSysex, midiTime, midiSense ); }
643 inline double RtMidiIn :: getMessage( std::vector<unsigned char> *message ) { return static_cast<MidiInApi *>(rtapi_)->getMessage( message ); }
644 inline void RtMidiIn :: setErrorCallback( RtMidiErrorCallback errorCallback, void *userData ) { rtapi_->setErrorCallback(errorCallback, userData); }
645 inline void RtMidiIn :: setBufferSize( unsigned int size, unsigned int count ) { static_cast<MidiInApi *>(rtapi_)->setBufferSize(size, count); }
646 
647 inline RtMidi::Api RtMidiOut :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); }
648 inline void RtMidiOut :: openPort( unsigned int portNumber, const std::string &portName ) { rtapi_->openPort( portNumber, portName ); }
649 inline void RtMidiOut :: openVirtualPort( const std::string &portName ) { rtapi_->openVirtualPort( portName ); }
650 inline void RtMidiOut :: closePort( void ) { rtapi_->closePort(); }
651 inline bool RtMidiOut :: isPortOpen() const { return rtapi_->isPortOpen(); }
652 inline unsigned int RtMidiOut :: getPortCount( void ) { return rtapi_->getPortCount(); }
653 inline std::string RtMidiOut :: getPortName( unsigned int portNumber ) { return rtapi_->getPortName( portNumber ); }
654 inline void RtMidiOut :: sendMessage( const std::vector<unsigned char> *message ) { static_cast<MidiOutApi *>(rtapi_)->sendMessage( &message->at(0), message->size() ); }
655 inline void RtMidiOut :: sendMessage( const unsigned char *message, size_t size ) { static_cast<MidiOutApi *>(rtapi_)->sendMessage( message, size ); }
656 inline void RtMidiOut :: setErrorCallback( RtMidiErrorCallback errorCallback, void *userData ) { rtapi_->setErrorCallback(errorCallback, userData); }
657 
658 #endif
659