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