1 /************************** BEGIN RtMidi.h **************************/
2 /*
3  File: CAHostTimeBase.h
4  Abstract: Part of CoreAudio Utility Classes
5  Version: 1.0.3
6 
7  Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
8  Inc. ("Apple") in consideration of your agreement to the following
9  terms, and your use, installation, modification or redistribution of
10  this Apple software constitutes acceptance of these terms.  If you do
11  not agree with these terms, please do not use, install, modify or
12  redistribute this Apple software.
13 
14  In consideration of your agreement to abide by the following terms, and
15  subject to these terms, Apple grants you a personal, non-exclusive
16  license, under Apple's copyrights in this original Apple software (the
17  "Apple Software"), to use, reproduce, modify and redistribute the Apple
18  Software, with or without modifications, in source and/or binary forms;
19  provided that if you redistribute the Apple Software in its entirety and
20  without modifications, you must retain this notice and the following
21  text and disclaimers in all such redistributions of the Apple Software.
22  Neither the name, trademarks, service marks or logos of Apple Inc. may
23  be used to endorse or promote products derived from the Apple Software
24  without specific prior written permission from Apple.  Except as
25  expressly stated in this notice, no other rights or licenses, express or
26  implied, are granted by Apple herein, including but not limited to any
27  patent rights that may be infringed by your derivative works or by other
28  works in which the Apple Software may be incorporated.
29 
30  The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
31  MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
32  THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
33  FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
34  OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
35 
36  IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
37  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39  INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
40  MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
41  AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
42  STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
43  POSSIBILITY OF SUCH DAMAGE.
44 
45  Copyright (C) 2013 Apple Inc. All Rights Reserved.
46  */
47 
48 #if !defined(__CAHostTimeBase_h__)
49 #define __CAHostTimeBase_h__
50 
51 #ifdef __APPLE__
52 
53 //=============================================================================
54 //	Includes
55 //=============================================================================
56 
57 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
58 #include <CoreAudio/CoreAudioTypes.h>
59 #else
60 #include <CoreAudioTypes.h>
61 #endif
62 
63 #if TARGET_OS_MAC
64 #include <mach/mach_time.h>
65 #elif TARGET_OS_WIN32
66 #include <windows.h>
67 #else
68 #error	Unsupported operating system
69 #endif
70 
71 //=============================================================================
72 //	CAHostTimeBase
73 //
74 //	This class provides platform independent access to the host's time base.
75 //=============================================================================
76 
77 class CAHostTimeBase
78 {
79 
80 public:
81     static UInt64	ConvertToNanos(UInt64 inHostTime);
82     static UInt64	ConvertFromNanos(UInt64 inNanos);
83 
84     static UInt64	GetTheCurrentTime();
85 #if TARGET_OS_MAC
GetCurrentTime()86     static UInt64	GetCurrentTime() { return GetTheCurrentTime(); }
87 #endif
88     static UInt64	GetCurrentTimeInNanos();
89 
GetFrequency()90     static Float64	GetFrequency() { if(!sIsInited) { Initialize(); } return sFrequency; }
GetInverseFrequency()91     static Float64	GetInverseFrequency() { if(!sIsInited) { Initialize(); } return sInverseFrequency; }
GetMinimumDelta()92     static UInt32	GetMinimumDelta() { if(!sIsInited) { Initialize(); } return sMinDelta; }
93 
94     static UInt64	AbsoluteHostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime);
95     static SInt64	HostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime);
96 
97     static void     Initialize();
98 
99 private:
100 
101     static bool sIsInited;
102 
103     static Float64 sFrequency;
104     static Float64 sInverseFrequency;
105     static UInt32 sMinDelta;
106     static UInt32 sToNanosNumerator;
107     static UInt32 sToNanosDenominator;
108     static UInt32 sFromNanosNumerator;
109     static UInt32 sFromNanosDenominator;
110     static bool sUseMicroseconds;
111 #if Track_Host_TimeBase
112     static UInt64	sLastTime;
113 #endif
114 };
115 
GetTheCurrentTime()116 inline UInt64 CAHostTimeBase::GetTheCurrentTime()
117 {
118     UInt64 theTime = 0;
119 
120 #if TARGET_OS_MAC
121     theTime = mach_absolute_time();
122 
123 #elif TARGET_OS_WIN32
124     LARGE_INTEGER theValue;
125     QueryPerformanceCounter(&theValue);
126     theTime = *((UInt64*)&theValue);
127 #endif
128 
129 #if	Track_Host_TimeBase
130     if(sLastTime != 0)
131     {
132         if(theTime <= sLastTime)
133         {
134             DebugMessageN2("CAHostTimeBase::GetTheCurrentTime: the current time is earlier than the last time, now: %qd, then: %qd", theTime, sLastTime);
135         }
136         sLastTime = theTime;
137     }
138     else
139     {
140         sLastTime = theTime;
141     }
142 #endif
143 
144     return theTime;
145 }
146 
ConvertToNanos(UInt64 inHostTime)147 inline UInt64 CAHostTimeBase::ConvertToNanos(UInt64 inHostTime)
148 {
149     if(!sIsInited)
150     {
151         Initialize();
152     }
153 
154     Float64 theNumerator = static_cast<Float64>(sToNanosNumerator);
155     Float64 theDenominator = static_cast<Float64>(sToNanosDenominator);
156     Float64 theHostTime = static_cast<Float64>(inHostTime);
157 
158     Float64 thePartialAnswer = theHostTime / theDenominator;
159     Float64 theFloatAnswer = thePartialAnswer * theNumerator;
160     UInt64 theAnswer = static_cast<UInt64>(theFloatAnswer);
161 
162     return theAnswer;
163 }
164 
ConvertFromNanos(UInt64 inNanos)165 inline UInt64 CAHostTimeBase::ConvertFromNanos(UInt64 inNanos)
166 {
167     if(!sIsInited)
168     {
169         Initialize();
170     }
171 
172     Float64 theNumerator = static_cast<Float64>(sToNanosNumerator);
173     Float64 theDenominator = static_cast<Float64>(sToNanosDenominator);
174     Float64 theNanos = static_cast<Float64>(inNanos);
175 
176     Float64 thePartialAnswer = theNanos / theNumerator;
177     Float64 theFloatAnswer = thePartialAnswer * theDenominator;
178     UInt64 theAnswer = static_cast<UInt64>(theFloatAnswer);
179 
180     return theAnswer;
181 }
182 
GetCurrentTimeInNanos()183 inline UInt64 CAHostTimeBase::GetCurrentTimeInNanos()
184 {
185     return ConvertToNanos(GetTheCurrentTime());
186 }
187 
AbsoluteHostDeltaToNanos(UInt64 inStartTime,UInt64 inEndTime)188 inline UInt64 CAHostTimeBase::AbsoluteHostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime)
189 {
190     UInt64 theAnswer;
191 
192     if(inStartTime <= inEndTime)
193     {
194         theAnswer = inEndTime - inStartTime;
195     }
196     else
197     {
198         theAnswer = inStartTime - inEndTime;
199     }
200 
201     return ConvertToNanos(theAnswer);
202 }
203 
HostDeltaToNanos(UInt64 inStartTime,UInt64 inEndTime)204 inline SInt64 CAHostTimeBase::HostDeltaToNanos(UInt64 inStartTime, UInt64 inEndTime)
205 {
206     SInt64 theAnswer;
207     SInt64 theSign = 1;
208 
209     if(inStartTime <= inEndTime)
210     {
211         theAnswer = inEndTime - inStartTime;
212     }
213     else
214     {
215         theAnswer = inStartTime - inEndTime;
216         theSign = -1;
217     }
218 
219     return theSign * ConvertToNanos(theAnswer);
220 }
221 
222 #endif // __APPLE__
223 
224 #endif
225 
226 /**********************************************************************/
227 /*! \class RtMidi
228     \brief An abstract base class for realtime MIDI input/output.
229 
230     This class implements some common functionality for the realtime
231     MIDI input/output subclasses RtMidiIn and RtMidiOut.
232 
233     RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/
234 
235     RtMidi: realtime MIDI i/o C++ classes
236     Copyright (c) 2003-2017 Gary P. Scavone
237 
238     Permission is hereby granted, free of charge, to any person
239     obtaining a copy of this software and associated documentation files
240     (the "Software"), to deal in the Software without restriction,
241     including without limitation the rights to use, copy, modify, merge,
242     publish, distribute, sublicense, and/or sell copies of the Software,
243     and to permit persons to whom the Software is furnished to do so,
244     subject to the following conditions:
245 
246     The above copyright notice and this permission notice shall be
247     included in all copies or substantial portions of the Software.
248 
249     Any person wishing to distribute modifications to the Software is
250     asked to send the modifications to the original developer so that
251     they can be incorporated into the canonical version.  This is,
252     however, not a binding provision of this license.
253 
254     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
255     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
256     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
257     IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
258     ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
259     CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
260     WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
261 */
262 /**********************************************************************/
263 
264 /*!
265   \file RtMidi.h
266  */
267 
268 #ifndef RTMIDI_H
269 #define RTMIDI_H
270 
271 #define RTMIDI_VERSION "3.0.0"
272 
273 #include <exception>
274 #include <iostream>
275 #include <string>
276 #include <vector>
277 
278 #if __APPLE__
279 #define __MACOSX_CORE__ 1
280 //#define __UNIX_JACK__ 1
281 #endif
282 
283 #if __linux__
284 #define __LINUX_ALSA__ 1
285 #endif
286 
287 #if _WIN32
288 #define __WINDOWS_MM__ 1
289 #endif
290 
291 
292 /************************************************************************/
293 /*! \class RtMidiError
294     \brief Exception handling class for RtMidi.
295 
296     The RtMidiError class is quite simple but it does allow errors to be
297     "caught" by RtMidiError::Type. See the RtMidi documentation to know
298     which methods can throw an RtMidiError.
299 */
300 /************************************************************************/
301 
302 class RtMidiError : public std::exception
303 {
304  public:
305   //! Defined RtMidiError types.
306   enum Type {
307     WARNING,           /*!< A non-critical error. */
308     DEBUG_WARNING,     /*!< A non-critical error which might be useful for debugging. */
309     UNSPECIFIED,       /*!< The default, unspecified error type. */
310     NO_DEVICES_FOUND,  /*!< No devices found on system. */
311     INVALID_DEVICE,    /*!< An invalid device ID was specified. */
312     MEMORY_ERROR,      /*!< An error occured during memory allocation. */
313     INVALID_PARAMETER, /*!< An invalid parameter was specified to a function. */
314     INVALID_USE,       /*!< The function was called incorrectly. */
315     DRIVER_ERROR,      /*!< A system driver error occured. */
316     SYSTEM_ERROR,      /*!< A system error occured. */
317     THREAD_ERROR       /*!< A thread error occured. */
318   };
319 
320   //! The constructor.
throw()321   RtMidiError( const std::string& message, Type type = RtMidiError::UNSPECIFIED ) throw() : message_(message), type_(type) {}
322 
323   //! The destructor.
~RtMidiError(void)324   virtual ~RtMidiError( void ) throw() {}
325 
326   //! Prints thrown error message to stderr.
printMessage(void)327   virtual void printMessage( void ) const throw() { std::cerr << '\n' << message_ << "\n\n"; }
328 
329   //! Returns the thrown error message type.
getType(void)330   virtual const Type& getType(void) const throw() { return type_; }
331 
332   //! Returns the thrown error message string.
getMessage(void)333   virtual const std::string& getMessage(void) const throw() { return message_; }
334 
335   //! Returns the thrown error message as a c-style string.
what(void)336   virtual const char* what( void ) const throw() { return message_.c_str(); }
337 
338  protected:
339   std::string message_;
340   Type type_;
341 };
342 
343 //! RtMidi error callback function prototype.
344 /*!
345     \param type Type of error.
346     \param errorText Error description.
347 
348     Note that class behaviour is undefined after a critical error (not
349     a warning) is reported.
350  */
351 typedef void (*RtMidiErrorCallback)( RtMidiError::Type type, const std::string &errorText, void *userData );
352 
353 class MidiApi;
354 
355 class RtMidi
356 {
357  public:
358 
359   //! MIDI API specifier arguments.
360   enum Api {
361     UNSPECIFIED,    /*!< Search for a working compiled API. */
362     MACOSX_CORE,    /*!< Macintosh OS-X Core Midi API. */
363     LINUX_ALSA,     /*!< The Advanced Linux Sound Architecture API. */
364     UNIX_JACK,      /*!< The JACK Low-Latency MIDI Server API. */
365     WINDOWS_MM,     /*!< The Microsoft Multimedia MIDI API. */
366     RTMIDI_DUMMY    /*!< A compilable but non-functional API. */
367   };
368 
369   //! A static function to determine the current RtMidi version.
370   static std::string getVersion( void ) throw();
371 
372   //! A static function to determine the available compiled MIDI APIs.
373   /*!
374     The values returned in the std::vector can be compared against
375     the enumerated list values.  Note that there can be more than one
376     API compiled for certain operating systems.
377   */
378   static void getCompiledApi( std::vector<RtMidi::Api> &apis ) throw();
379 
380   //! Pure virtual openPort() function.
381   virtual void openPort( unsigned int portNumber = 0, const std::string &portName = std::string( "RtMidi" ) ) = 0;
382 
383   //! Pure virtual openVirtualPort() function.
384   virtual void openVirtualPort( const std::string &portName = std::string( "RtMidi" ) ) = 0;
385 
386   //! Pure virtual getPortCount() function.
387   virtual unsigned int getPortCount() = 0;
388 
389   //! Pure virtual getPortName() function.
390   virtual std::string getPortName( unsigned int portNumber = 0 ) = 0;
391 
392   //! Pure virtual closePort() function.
393   virtual void closePort( void ) = 0;
394 
395   //! Returns true if a port is open and false if not.
396   /*!
397       Note that this only applies to connections made with the openPort()
398       function, not to virtual ports.
399   */
400   virtual bool isPortOpen( void ) const = 0;
401 
402   //! Set an error callback function to be invoked when an error has occured.
403   /*!
404     The callback function will be called whenever an error has occured. It is best
405     to set the error callback function before opening a port.
406   */
407   virtual void setErrorCallback( RtMidiErrorCallback errorCallback = NULL, void *userData = 0 ) = 0;
408 
409  protected:
410 
411   RtMidi();
412   virtual ~RtMidi();
413 
414   MidiApi *rtapi_;
415 };
416 
417 /**********************************************************************/
418 /*! \class RtMidiIn
419     \brief A realtime MIDI input class.
420 
421     This class provides a common, platform-independent API for
422     realtime MIDI input.  It allows access to a single MIDI input
423     port.  Incoming MIDI messages are either saved to a queue for
424     retrieval using the getMessage() function or immediately passed to
425     a user-specified callback function.  Create multiple instances of
426     this class to connect to more than one MIDI device at the same
427     time.  With the OS-X, Linux ALSA, and JACK MIDI APIs, it is also
428     possible to open a virtual input port to which other MIDI software
429     clients can connect.
430 
431     by Gary P. Scavone, 2003-2017.
432 */
433 /**********************************************************************/
434 
435 // **************************************************************** //
436 //
437 // RtMidiIn and RtMidiOut class declarations.
438 //
439 // RtMidiIn / RtMidiOut are "controllers" used to select an available
440 // MIDI input or output interface.  They present common APIs for the
441 // user to call but all functionality is implemented by the classes
442 // MidiInApi, MidiOutApi and their subclasses.  RtMidiIn and RtMidiOut
443 // each create an instance of a MidiInApi or MidiOutApi subclass based
444 // on the user's API choice.  If no choice is made, they attempt to
445 // make a "logical" API selection.
446 //
447 // **************************************************************** //
448 
449 class RtMidiIn : public RtMidi
450 {
451  public:
452 
453   //! User callback function type definition.
454   typedef void (*RtMidiCallback)( double timeStamp, std::vector<unsigned char> *message, void *userData);
455 
456   //! Default constructor that allows an optional api, client name and queue size.
457   /*!
458     An exception will be thrown if a MIDI system initialization
459     error occurs.  The queue size defines the maximum number of
460     messages that can be held in the MIDI queue (when not using a
461     callback function).  If the queue size limit is reached,
462     incoming messages will be ignored.
463 
464     If no API argument is specified and multiple API support has been
465     compiled, the default order of use is ALSA, JACK (Linux) and CORE,
466     JACK (OS-X).
467 
468     \param api        An optional API id can be specified.
469     \param clientName An optional client name can be specified. This
470                       will be used to group the ports that are created
471                       by the application.
472     \param queueSizeLimit An optional size of the MIDI input queue can be specified.
473   */
474   RtMidiIn( RtMidi::Api api=UNSPECIFIED,
475             const std::string& clientName = "RtMidi Input Client",
476             unsigned int queueSizeLimit = 100 );
477 
478   //! If a MIDI connection is still open, it will be closed by the destructor.
479   ~RtMidiIn ( void ) throw();
480 
481   //! Returns the MIDI API specifier for the current instance of RtMidiIn.
482   RtMidi::Api getCurrentApi( void ) throw();
483 
484   //! Open a MIDI input connection given by enumeration number.
485   /*!
486     \param portNumber An optional port number greater than 0 can be specified.
487                       Otherwise, the default or first port found is opened.
488     \param portName An optional name for the application port that is used to connect to portId can be specified.
489   */
490   void openPort( unsigned int portNumber = 0, const std::string &portName = std::string( "RtMidi Input" ) );
491 
492   //! Create a virtual input port, with optional name, to allow software connections (OS X, JACK and ALSA only).
493   /*!
494     This function creates a virtual MIDI input port to which other
495     software applications can connect.  This type of functionality
496     is currently only supported by the Macintosh OS-X, any JACK,
497     and Linux ALSA APIs (the function returns an error for the other APIs).
498 
499     \param portName An optional name for the application port that is
500                     used to connect to portId can be specified.
501   */
502   void openVirtualPort( const std::string &portName = std::string( "RtMidi Input" ) );
503 
504   //! Set a callback function to be invoked for incoming MIDI messages.
505   /*!
506     The callback function will be called whenever an incoming MIDI
507     message is received.  While not absolutely necessary, it is best
508     to set the callback function before opening a MIDI port to avoid
509     leaving some messages in the queue.
510 
511     \param callback A callback function must be given.
512     \param userData Optionally, a pointer to additional data can be
513                     passed to the callback function whenever it is called.
514   */
515   void setCallback( RtMidiCallback callback, void *userData = 0 );
516 
517   //! Cancel use of the current callback function (if one exists).
518   /*!
519     Subsequent incoming MIDI messages will be written to the queue
520     and can be retrieved with the \e getMessage function.
521   */
522   void cancelCallback();
523 
524   //! Close an open MIDI connection (if one exists).
525   void closePort( void );
526 
527   //! Returns true if a port is open and false if not.
528   /*!
529       Note that this only applies to connections made with the openPort()
530       function, not to virtual ports.
531   */
532   virtual bool isPortOpen() const;
533 
534   //! Return the number of available MIDI input ports.
535   /*!
536     \return This function returns the number of MIDI ports of the selected API.
537   */
538   unsigned int getPortCount();
539 
540   //! Return a string identifier for the specified MIDI input port number.
541   /*!
542     \return The name of the port with the given Id is returned.
543     \retval An empty string is returned if an invalid port specifier
544             is provided. User code should assume a UTF-8 encoding.
545   */
546   std::string getPortName( unsigned int portNumber = 0 );
547 
548   //! Specify whether certain MIDI message types should be queued or ignored during input.
549   /*!
550     By default, MIDI timing and active sensing messages are ignored
551     during message input because of their relative high data rates.
552     MIDI sysex messages are ignored by default as well.  Variable
553     values of "true" imply that the respective message type will be
554     ignored.
555   */
556   void ignoreTypes( bool midiSysex = true, bool midiTime = true, bool midiSense = true );
557 
558   //! 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.
559   /*!
560     This function returns immediately whether a new message is
561     available or not.  A valid message is indicated by a non-zero
562     vector size.  An exception is thrown if an error occurs during
563     message retrieval or an input connection was not previously
564     established.
565   */
566   double getMessage( std::vector<unsigned char> *message );
567 
568   //! Set an error callback function to be invoked when an error has occured.
569   /*!
570     The callback function will be called whenever an error has occured. It is best
571     to set the error callback function before opening a port.
572   */
573   virtual void setErrorCallback( RtMidiErrorCallback errorCallback = NULL, void *userData = 0 );
574 
575  protected:
576   void openMidiApi( RtMidi::Api api, const std::string &clientName, unsigned int queueSizeLimit );
577 
578 };
579 
580 /**********************************************************************/
581 /*! \class RtMidiOut
582     \brief A realtime MIDI output class.
583 
584     This class provides a common, platform-independent API for MIDI
585     output.  It allows one to probe available MIDI output ports, to
586     connect to one such port, and to send MIDI bytes immediately over
587     the connection.  Create multiple instances of this class to
588     connect to more than one MIDI device at the same time.  With the
589     OS-X, Linux ALSA and JACK MIDI APIs, it is also possible to open a
590     virtual port to which other MIDI software clients can connect.
591 
592     by Gary P. Scavone, 2003-2017.
593 */
594 /**********************************************************************/
595 
596 class RtMidiOut : public RtMidi
597 {
598  public:
599 
600   //! Default constructor that allows an optional client name.
601   /*!
602     An exception will be thrown if a MIDI system initialization error occurs.
603 
604     If no API argument is specified and multiple API support has been
605     compiled, the default order of use is ALSA, JACK (Linux) and CORE,
606     JACK (OS-X).
607   */
608   RtMidiOut( RtMidi::Api api=UNSPECIFIED,
609              const std::string& clientName = "RtMidi Output Client" );
610 
611   //! The destructor closes any open MIDI connections.
612   ~RtMidiOut( void ) throw();
613 
614   //! Returns the MIDI API specifier for the current instance of RtMidiOut.
615   RtMidi::Api getCurrentApi( void ) throw();
616 
617   //! Open a MIDI output connection.
618   /*!
619       An optional port number greater than 0 can be specified.
620       Otherwise, the default or first port found is opened.  An
621       exception is thrown if an error occurs while attempting to make
622       the port connection.
623   */
624   void openPort( unsigned int portNumber = 0, const std::string &portName = std::string( "RtMidi Output" ) );
625 
626   //! Close an open MIDI connection (if one exists).
627   void closePort( void );
628 
629   //! Returns true if a port is open and false if not.
630   /*!
631       Note that this only applies to connections made with the openPort()
632       function, not to virtual ports.
633   */
634   virtual bool isPortOpen() const;
635 
636   //! Create a virtual output port, with optional name, to allow software connections (OS X, JACK and ALSA only).
637   /*!
638       This function creates a virtual MIDI output port to which other
639       software applications can connect.  This type of functionality
640       is currently only supported by the Macintosh OS-X, Linux ALSA
641       and JACK APIs (the function does nothing with the other APIs).
642       An exception is thrown if an error occurs while attempting to
643       create the virtual port.
644   */
645   void openVirtualPort( const std::string &portName = std::string( "RtMidi Output" ) );
646 
647   //! Return the number of available MIDI output ports.
648   unsigned int getPortCount( void );
649 
650   //! Return a string identifier for the specified MIDI port type and number.
651   /*!
652     \return The name of the port with the given Id is returned.
653     \retval An empty string is returned if an invalid port specifier
654             is provided. User code should assume a UTF-8 encoding.
655   */
656   std::string getPortName( unsigned int portNumber = 0 );
657 
658   //! Immediately send a single message out an open MIDI output port.
659   /*!
660       An exception is thrown if an error occurs during output or an
661       output connection was not previously established.
662   */
663   void sendMessage( const std::vector<unsigned char> *message );
664 
665   //! Immediately send a single message out an open MIDI output port.
666   /*!
667       An exception is thrown if an error occurs during output or an
668       output connection was not previously established.
669 
670       \param message A pointer to the MIDI message as raw bytes
671       \param size    Length of the MIDI message in bytes
672   */
673   void sendMessage( const unsigned char *message, size_t size );
674 
675   //! Set an error callback function to be invoked when an error has occured.
676   /*!
677     The callback function will be called whenever an error has occured. It is best
678     to set the error callback function before opening a port.
679   */
680   virtual void setErrorCallback( RtMidiErrorCallback errorCallback = NULL, void *userData = 0 );
681 
682  protected:
683   void openMidiApi( RtMidi::Api api, const std::string &clientName );
684 };
685 
686 
687 // **************************************************************** //
688 //
689 // MidiInApi / MidiOutApi class declarations.
690 //
691 // Subclasses of MidiInApi and MidiOutApi contain all API- and
692 // OS-specific code necessary to fully implement the RtMidi API.
693 //
694 // Note that MidiInApi and MidiOutApi are abstract base classes and
695 // cannot be explicitly instantiated.  RtMidiIn and RtMidiOut will
696 // create instances of a MidiInApi or MidiOutApi subclass.
697 //
698 // **************************************************************** //
699 
700 class MidiApi
701 {
702  public:
703 
704   MidiApi();
705   virtual ~MidiApi();
706   virtual RtMidi::Api getCurrentApi( void ) = 0;
707   virtual void openPort( unsigned int portNumber, const std::string &portName ) = 0;
708   virtual void openVirtualPort( const std::string &portName ) = 0;
709   virtual void closePort( void ) = 0;
710 
711   virtual unsigned int getPortCount( void ) = 0;
712   virtual std::string getPortName( unsigned int portNumber ) = 0;
713 
isPortOpen()714   inline bool isPortOpen() const { return connected_; }
715   void setErrorCallback( RtMidiErrorCallback errorCallback, void *userData );
716 
717   //! A basic error reporting function for RtMidi classes.
718   void error( RtMidiError::Type type, std::string errorString );
719 
720 protected:
721   virtual void initialize( const std::string& clientName ) = 0;
722 
723   void *apiData_;
724   bool connected_;
725   std::string errorString_;
726   RtMidiErrorCallback errorCallback_;
727   bool firstErrorOccurred_;
728   void *errorCallbackUserData_;
729 };
730 
731 class MidiInApi : public MidiApi
732 {
733  public:
734 
735   MidiInApi( unsigned int queueSizeLimit );
736   virtual ~MidiInApi( void );
737   void setCallback( RtMidiIn::RtMidiCallback callback, void *userData );
738   void cancelCallback( void );
739   virtual void ignoreTypes( bool midiSysex, bool midiTime, bool midiSense );
740   double getMessage( std::vector<unsigned char> *message );
741 
742   // A MIDI structure used internally by the class to store incoming
743   // messages.  Each message represents one and only one MIDI message.
744   struct MidiMessage {
745     std::vector<unsigned char> bytes;
746 
747     //! Time in seconds elapsed since the previous message
748     double timeStamp;
749 
750     // Default constructor.
MidiMessageMidiMessage751   MidiMessage()
752   :bytes(0), timeStamp(0.0) {}
753   };
754 
755   struct MidiQueue {
756     unsigned int front;
757     unsigned int back;
758     unsigned int ringSize;
759     MidiMessage *ring;
760 
761     // Default constructor.
MidiQueueMidiQueue762   MidiQueue()
763   :front(0), back(0), ringSize(0), ring(0) {}
764     bool push(const MidiMessage&);
765     bool pop(std::vector<unsigned char>*, double*);
766     unsigned int size(unsigned int *back=0,
767 		      unsigned int *front=0);
768   };
769 
770   // The RtMidiInData structure is used to pass private class data to
771   // the MIDI input handling function or thread.
772   struct RtMidiInData {
773     MidiQueue queue;
774     MidiMessage message;
775     unsigned char ignoreFlags;
776     bool doInput;
777     bool firstMessage;
778     void *apiData;
779     bool usingCallback;
780     RtMidiIn::RtMidiCallback userCallback;
781     void *userData;
782     bool continueSysex;
783 
784     // Default constructor.
RtMidiInDataRtMidiInData785   RtMidiInData()
786   : ignoreFlags(7), doInput(false), firstMessage(true),
787       apiData(0), usingCallback(false), userCallback(0), userData(0),
788       continueSysex(false) {}
789   };
790 
791  protected:
792   RtMidiInData inputData_;
793 };
794 
795 class MidiOutApi : public MidiApi
796 {
797  public:
798 
799   MidiOutApi( void );
800   virtual ~MidiOutApi( void );
801   virtual void sendMessage( const unsigned char *message, size_t size ) = 0;
802 };
803 
804 // **************************************************************** //
805 //
806 // Inline RtMidiIn and RtMidiOut definitions.
807 //
808 // **************************************************************** //
809 
getCurrentApi(void)810 inline RtMidi::Api RtMidiIn :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); }
openPort(unsigned int portNumber,const std::string & portName)811 inline void RtMidiIn :: openPort( unsigned int portNumber, const std::string &portName ) { rtapi_->openPort( portNumber, portName ); }
openVirtualPort(const std::string & portName)812 inline void RtMidiIn :: openVirtualPort( const std::string &portName ) { rtapi_->openVirtualPort( portName ); }
closePort(void)813 inline void RtMidiIn :: closePort( void ) { rtapi_->closePort(); }
isPortOpen()814 inline bool RtMidiIn :: isPortOpen() const { return rtapi_->isPortOpen(); }
setCallback(RtMidiCallback callback,void * userData)815 inline void RtMidiIn :: setCallback( RtMidiCallback callback, void *userData ) { ((MidiInApi *)rtapi_)->setCallback( callback, userData ); }
cancelCallback(void)816 inline void RtMidiIn :: cancelCallback( void ) { ((MidiInApi *)rtapi_)->cancelCallback(); }
getPortCount(void)817 inline unsigned int RtMidiIn :: getPortCount( void ) { return rtapi_->getPortCount(); }
getPortName(unsigned int portNumber)818 inline std::string RtMidiIn :: getPortName( unsigned int portNumber ) { return rtapi_->getPortName( portNumber ); }
ignoreTypes(bool midiSysex,bool midiTime,bool midiSense)819 inline void RtMidiIn :: ignoreTypes( bool midiSysex, bool midiTime, bool midiSense ) { ((MidiInApi *)rtapi_)->ignoreTypes( midiSysex, midiTime, midiSense ); }
getMessage(std::vector<unsigned char> * message)820 inline double RtMidiIn :: getMessage( std::vector<unsigned char> *message ) { return ((MidiInApi *)rtapi_)->getMessage( message ); }
setErrorCallback(RtMidiErrorCallback errorCallback,void * userData)821 inline void RtMidiIn :: setErrorCallback( RtMidiErrorCallback errorCallback, void *userData ) { rtapi_->setErrorCallback(errorCallback, userData); }
822 
getCurrentApi(void)823 inline RtMidi::Api RtMidiOut :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); }
openPort(unsigned int portNumber,const std::string & portName)824 inline void RtMidiOut :: openPort( unsigned int portNumber, const std::string &portName ) { rtapi_->openPort( portNumber, portName ); }
openVirtualPort(const std::string & portName)825 inline void RtMidiOut :: openVirtualPort( const std::string &portName ) { rtapi_->openVirtualPort( portName ); }
closePort(void)826 inline void RtMidiOut :: closePort( void ) { rtapi_->closePort(); }
isPortOpen()827 inline bool RtMidiOut :: isPortOpen() const { return rtapi_->isPortOpen(); }
getPortCount(void)828 inline unsigned int RtMidiOut :: getPortCount( void ) { return rtapi_->getPortCount(); }
getPortName(unsigned int portNumber)829 inline std::string RtMidiOut :: getPortName( unsigned int portNumber ) { return rtapi_->getPortName( portNumber ); }
sendMessage(const std::vector<unsigned char> * message)830 inline void RtMidiOut :: sendMessage( const std::vector<unsigned char> *message ) { ((MidiOutApi *)rtapi_)->sendMessage( &message->at(0), message->size() ); }
sendMessage(const unsigned char * message,size_t size)831 inline void RtMidiOut :: sendMessage( const unsigned char *message, size_t size ) { ((MidiOutApi *)rtapi_)->sendMessage( message, size ); }
setErrorCallback(RtMidiErrorCallback errorCallback,void * userData)832 inline void RtMidiOut :: setErrorCallback( RtMidiErrorCallback errorCallback, void *userData ) { rtapi_->setErrorCallback(errorCallback, userData); }
833 
834 // **************************************************************** //
835 //
836 // MidiInApi and MidiOutApi subclass prototypes.
837 //
838 // **************************************************************** //
839 
840 #if !defined(__LINUX_ALSA__) && !defined(__UNIX_JACK__) && !defined(__MACOSX_CORE__) && !defined(__WINDOWS_MM__)
841   #define __RTMIDI_DUMMY__
842 #endif
843 
844 #if defined(__MACOSX_CORE__)
845 
846 class MidiInCore: public MidiInApi
847 {
848  public:
849   MidiInCore( const std::string &clientName, unsigned int queueSizeLimit );
850   ~MidiInCore( void );
getCurrentApi(void)851   RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; };
852   void openPort( unsigned int portNumber, const std::string &portName );
853   void openVirtualPort( const std::string &portName );
854   void closePort( void );
855   unsigned int getPortCount( void );
856   std::string getPortName( unsigned int portNumber );
857 
858  protected:
859   void initialize( const std::string& clientName );
860 };
861 
862 class MidiOutCore: public MidiOutApi
863 {
864  public:
865   MidiOutCore( const std::string &clientName );
866   ~MidiOutCore( void );
getCurrentApi(void)867   RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; };
868   void openPort( unsigned int portNumber, const std::string &portName );
869   void openVirtualPort( const std::string &portName );
870   void closePort( void );
871   unsigned int getPortCount( void );
872   std::string getPortName( unsigned int portNumber );
873   void sendMessage( const unsigned char *message, size_t size );
874 
875  protected:
876   void initialize( const std::string& clientName );
877 };
878 
879 #endif
880 
881 #if defined(__UNIX_JACK__)
882 
883 class MidiInJack: public MidiInApi
884 {
885  public:
886   MidiInJack( const std::string &clientName, unsigned int queueSizeLimit );
887   ~MidiInJack( void );
getCurrentApi(void)888   RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; };
889   void openPort( unsigned int portNumber, const std::string &portName );
890   void openVirtualPort( const std::string &portName );
891   void closePort( void );
892   unsigned int getPortCount( void );
893   std::string getPortName( unsigned int portNumber );
894 
895  protected:
896   std::string clientName;
897 
898   void connect( void );
899   void initialize( const std::string& clientName );
900 };
901 
902 class MidiOutJack: public MidiOutApi
903 {
904  public:
905   MidiOutJack( const std::string &clientName );
906   ~MidiOutJack( void );
getCurrentApi(void)907   RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; };
908   void openPort( unsigned int portNumber, const std::string &portName );
909   void openVirtualPort( const std::string &portName );
910   void closePort( void );
911   unsigned int getPortCount( void );
912   std::string getPortName( unsigned int portNumber );
913   void sendMessage( const unsigned char *message, size_t size );
914 
915  protected:
916   std::string clientName;
917 
918   void connect( void );
919   void initialize( const std::string& clientName );
920 };
921 
922 #endif
923 
924 #if defined(__LINUX_ALSA__)
925 
926 class MidiInAlsa: public MidiInApi
927 {
928  public:
929   MidiInAlsa( const std::string &clientName, unsigned int queueSizeLimit );
930   ~MidiInAlsa( void );
getCurrentApi(void)931   RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; };
932   void openPort( unsigned int portNumber, const std::string &portName );
933   void openVirtualPort( const std::string &portName );
934   void closePort( void );
935   unsigned int getPortCount( void );
936   std::string getPortName( unsigned int portNumber );
937 
938  protected:
939   void initialize( const std::string& clientName );
940 };
941 
942 class MidiOutAlsa: public MidiOutApi
943 {
944  public:
945   MidiOutAlsa( const std::string &clientName );
946   ~MidiOutAlsa( void );
getCurrentApi(void)947   RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; };
948   void openPort( unsigned int portNumber, const std::string &portName );
949   void openVirtualPort( const std::string &portName );
950   void closePort( void );
951   unsigned int getPortCount( void );
952   std::string getPortName( unsigned int portNumber );
953   void sendMessage( const unsigned char *message, size_t size );
954 
955  protected:
956   void initialize( const std::string& clientName );
957 };
958 
959 #endif
960 
961 #if defined(__WINDOWS_MM__)
962 
963 class MidiInWinMM: public MidiInApi
964 {
965  public:
966   MidiInWinMM( const std::string &clientName, unsigned int queueSizeLimit );
967   ~MidiInWinMM( void );
getCurrentApi(void)968   RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; };
969   void openPort( unsigned int portNumber, const std::string &portName );
970   void openVirtualPort( const std::string &portName );
971   void closePort( void );
972   unsigned int getPortCount( void );
973   std::string getPortName( unsigned int portNumber );
974 
975  protected:
976   void initialize( const std::string& clientName );
977 };
978 
979 class MidiOutWinMM: public MidiOutApi
980 {
981  public:
982   MidiOutWinMM( const std::string &clientName );
983   ~MidiOutWinMM( void );
getCurrentApi(void)984   RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; };
985   void openPort( unsigned int portNumber, const std::string &portName );
986   void openVirtualPort( const std::string &portName );
987   void closePort( void );
988   unsigned int getPortCount( void );
989   std::string getPortName( unsigned int portNumber );
990   void sendMessage( const unsigned char *message, size_t size );
991 
992  protected:
993   void initialize( const std::string& clientName );
994 };
995 
996 #endif
997 
998 #if defined(__RTMIDI_DUMMY__)
999 
1000 class MidiInDummy: public MidiInApi
1001 {
1002  public:
MidiInDummy(const std::string &,unsigned int queueSizeLimit)1003  MidiInDummy( const std::string &/*clientName*/, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit ) { errorString_ = "MidiInDummy: This class provides no functionality."; error( RtMidiError::WARNING, errorString_ ); }
getCurrentApi(void)1004   RtMidi::Api getCurrentApi( void ) { return RtMidi::RTMIDI_DUMMY; }
openPort(unsigned int,const std::string &)1005   void openPort( unsigned int /*portNumber*/, const std::string &/*portName*/ ) {}
openVirtualPort(const std::string &)1006   void openVirtualPort( const std::string &/*portName*/ ) {}
closePort(void)1007   void closePort( void ) {}
getPortCount(void)1008   unsigned int getPortCount( void ) { return 0; }
getPortName(unsigned int)1009   std::string getPortName( unsigned int /*portNumber*/ ) { return ""; }
1010 
1011  protected:
initialize(const std::string &)1012   void initialize( const std::string& /*clientName*/ ) {}
1013 };
1014 
1015 class MidiOutDummy: public MidiOutApi
1016 {
1017  public:
MidiOutDummy(const std::string &)1018   MidiOutDummy( const std::string &/*clientName*/ ) { errorString_ = "MidiOutDummy: This class provides no functionality."; error( RtMidiError::WARNING, errorString_ ); }
getCurrentApi(void)1019   RtMidi::Api getCurrentApi( void ) { return RtMidi::RTMIDI_DUMMY; }
openPort(unsigned int,const std::string &)1020   void openPort( unsigned int /*portNumber*/, const std::string &/*portName*/ ) {}
openVirtualPort(const std::string &)1021   void openVirtualPort( const std::string &/*portName*/ ) {}
closePort(void)1022   void closePort( void ) {}
getPortCount(void)1023   unsigned int getPortCount( void ) { return 0; }
getPortName(unsigned int)1024   std::string getPortName( unsigned int /*portNumber*/ ) { return ""; }
sendMessage(const unsigned char *,size_t)1025   void sendMessage( const unsigned char * /*message*/, size_t /*size*/ ) {}
1026 
1027  protected:
initialize(const std::string &)1028   void initialize( const std::string& /*clientName*/ ) {}
1029 };
1030 
1031 #endif
1032 
1033 #endif
1034 /**************************  END  RtMidi.h **************************/
1035