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