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