1 /**********************************************************************/
2 /*! \class RtMidi
3     \brief An abstract base class for realtime MIDI input/output.
4 
5     This class implements some common functionality for the realtime
6     MIDI input/output subclasses RtMidiIn and RtMidiOut.
7 
8     RtMidi GitHub site: https://github.com/thestk/rtmidi
9     RtMidi WWW site: http://www.music.mcgill.ca/~gary/rtmidi/
10 
11     RtMidi: realtime MIDI i/o C++ classes
12     Copyright (c) 2003-2019 Gary P. Scavone
13 
14     Permission is hereby granted, free of charge, to any person
15     obtaining a copy of this software and associated documentation files
16     (the "Software"), to deal in the Software without restriction,
17     including without limitation the rights to use, copy, modify, merge,
18     publish, distribute, sublicense, and/or sell copies of the Software,
19     and to permit persons to whom the Software is furnished to do so,
20     subject to the following conditions:
21 
22     The above copyright notice and this permission notice shall be
23     included in all copies or substantial portions of the Software.
24 
25     Any person wishing to distribute modifications to the Software is
26     asked to send the modifications to the original developer so that
27     they can be incorporated into the canonical version.  This is,
28     however, not a binding provision of this license.
29 
30     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
33     IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
34     ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
35     CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
36     WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 */
38 /**********************************************************************/
39 
40 #include "RtMidi.h"
41 #include <sstream>
42 
43 #if defined(__MACOSX_CORE__)
44   #if TARGET_OS_IPHONE
45     #define AudioGetCurrentHostTime CAHostTimeBase::GetCurrentTime
46     #define AudioConvertHostTimeToNanos CAHostTimeBase::ConvertToNanos
47   #endif
48 #endif
49 
50 // Default for Windows is to add an identifier to the port names; this
51 // flag can be defined (e.g. in your project file) to disable this behaviour.
52 //#define RTMIDI_DO_NOT_ENSURE_UNIQUE_PORTNAMES
53 
54 // **************************************************************** //
55 //
56 // MidiInApi and MidiOutApi subclass prototypes.
57 //
58 // **************************************************************** //
59 
60 #if !defined(__LINUX_ALSA__) && !defined(__UNIX_JACK__) && !defined(__MACOSX_CORE__) && !defined(__WINDOWS_MM__)
61   #define __RTMIDI_DUMMY__
62 #endif
63 
64 #if defined(__MACOSX_CORE__)
65 
66 class MidiInCore: public MidiInApi
67 {
68  public:
69   MidiInCore( const std::string &clientName, unsigned int queueSizeLimit );
70   ~MidiInCore( void );
getCurrentApi(void)71   RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; };
72   void openPort( unsigned int portNumber, const std::string &portName );
73   void openVirtualPort( const std::string &portName );
74   void closePort( void );
75   void setClientName( const std::string &clientName );
76   void setPortName( const std::string &portName );
77   unsigned int getPortCount( void );
78   std::string getPortName( unsigned int portNumber );
79 
80  protected:
81   void initialize( const std::string& clientName );
82 };
83 
84 class MidiOutCore: public MidiOutApi
85 {
86  public:
87   MidiOutCore( const std::string &clientName );
88   ~MidiOutCore( void );
getCurrentApi(void)89   RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; };
90   void openPort( unsigned int portNumber, const std::string &portName );
91   void openVirtualPort( const std::string &portName );
92   void closePort( void );
93   void setClientName( const std::string &clientName );
94   void setPortName( const std::string &portName );
95   unsigned int getPortCount( void );
96   std::string getPortName( unsigned int portNumber );
97   void sendMessage( const unsigned char *message, size_t size );
98 
99  protected:
100   void initialize( const std::string& clientName );
101 };
102 
103 #endif
104 
105 #if defined(__UNIX_JACK__)
106 
107 class MidiInJack: public MidiInApi
108 {
109  public:
110   MidiInJack( const std::string &clientName, unsigned int queueSizeLimit );
111   ~MidiInJack( void );
getCurrentApi(void)112   RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; };
113   void openPort( unsigned int portNumber, const std::string &portName );
114   void openVirtualPort( const std::string &portName );
115   void closePort( void );
116   void setClientName( const std::string &clientName );
117   void setPortName( const std::string &portName);
118   unsigned int getPortCount( void );
119   std::string getPortName( unsigned int portNumber );
120 
121  protected:
122   std::string clientName;
123 
124   void connect( void );
125   void initialize( const std::string& clientName );
126 };
127 
128 class MidiOutJack: public MidiOutApi
129 {
130  public:
131   MidiOutJack( const std::string &clientName );
132   ~MidiOutJack( void );
getCurrentApi(void)133   RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; };
134   void openPort( unsigned int portNumber, const std::string &portName );
135   void openVirtualPort( const std::string &portName );
136   void closePort( void );
137   void setClientName( const std::string &clientName );
138   void setPortName( const std::string &portName);
139   unsigned int getPortCount( void );
140   std::string getPortName( unsigned int portNumber );
141   void sendMessage( const unsigned char *message, size_t size );
142 
143  protected:
144   std::string clientName;
145 
146   void connect( void );
147   void initialize( const std::string& clientName );
148 };
149 
150 #endif
151 
152 #if defined(__LINUX_ALSA__)
153 
154 class MidiInAlsa: public MidiInApi
155 {
156  public:
157   MidiInAlsa( const std::string &clientName, unsigned int queueSizeLimit );
158   ~MidiInAlsa( void );
getCurrentApi(void)159   RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; };
160   void openPort( unsigned int portNumber, const std::string &portName );
161   void openVirtualPort( const std::string &portName );
162   void closePort( void );
163   void setClientName( const std::string &clientName );
164   void setPortName( const std::string &portName);
165   unsigned int getPortCount( void );
166   std::string getPortName( unsigned int portNumber );
167 
168  protected:
169   void initialize( const std::string& clientName );
170 };
171 
172 class MidiOutAlsa: public MidiOutApi
173 {
174  public:
175   MidiOutAlsa( const std::string &clientName );
176   ~MidiOutAlsa( void );
getCurrentApi(void)177   RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; };
178   void openPort( unsigned int portNumber, const std::string &portName );
179   void openVirtualPort( const std::string &portName );
180   void closePort( void );
181   void setClientName( const std::string &clientName );
182   void setPortName( const std::string &portName );
183   unsigned int getPortCount( void );
184   std::string getPortName( unsigned int portNumber );
185   void sendMessage( const unsigned char *message, size_t size );
186 
187  protected:
188   void initialize( const std::string& clientName );
189 };
190 
191 #endif
192 
193 #if defined(__WINDOWS_MM__)
194 
195 class MidiInWinMM: public MidiInApi
196 {
197  public:
198   MidiInWinMM( const std::string &clientName, unsigned int queueSizeLimit );
199   ~MidiInWinMM( void );
getCurrentApi(void)200   RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; };
201   void openPort( unsigned int portNumber, const std::string &portName );
202   void openVirtualPort( const std::string &portName );
203   void closePort( void );
204   void setClientName( const std::string &clientName );
205   void setPortName( const std::string &portName );
206   unsigned int getPortCount( void );
207   std::string getPortName( unsigned int portNumber );
208 
209  protected:
210   void initialize( const std::string& clientName );
211 };
212 
213 class MidiOutWinMM: public MidiOutApi
214 {
215  public:
216   MidiOutWinMM( const std::string &clientName );
217   ~MidiOutWinMM( void );
getCurrentApi(void)218   RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; };
219   void openPort( unsigned int portNumber, const std::string &portName );
220   void openVirtualPort( const std::string &portName );
221   void closePort( void );
222   void setClientName( const std::string &clientName );
223   void setPortName( const std::string &portName );
224   unsigned int getPortCount( void );
225   std::string getPortName( unsigned int portNumber );
226   void sendMessage( const unsigned char *message, size_t size );
227 
228  protected:
229   void initialize( const std::string& clientName );
230 };
231 
232 #endif
233 
234 #if defined(__RTMIDI_DUMMY__)
235 
236 class MidiInDummy: public MidiInApi
237 {
238  public:
MidiInDummy(const std::string &,unsigned int queueSizeLimit)239  MidiInDummy( const std::string &/*clientName*/, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit ) { errorString_ = "MidiInDummy: This class provides no functionality."; error( RtMidiError::WARNING, errorString_ ); }
getCurrentApi(void)240   RtMidi::Api getCurrentApi( void ) { return RtMidi::RTMIDI_DUMMY; }
openPort(unsigned int,const std::string &)241   void openPort( unsigned int /*portNumber*/, const std::string &/*portName*/ ) {}
openVirtualPort(const std::string &)242   void openVirtualPort( const std::string &/*portName*/ ) {}
closePort(void)243   void closePort( void ) {}
setClientName(const std::string &)244   void setClientName( const std::string &/*clientName*/ ) {};
setPortName(const std::string &)245   void setPortName( const std::string &/*portName*/ ) {};
getPortCount(void)246   unsigned int getPortCount( void ) { return 0; }
getPortName(unsigned int)247   std::string getPortName( unsigned int /*portNumber*/ ) { return ""; }
248 
249  protected:
initialize(const std::string &)250   void initialize( const std::string& /*clientName*/ ) {}
251 };
252 
253 class MidiOutDummy: public MidiOutApi
254 {
255  public:
MidiOutDummy(const std::string &)256   MidiOutDummy( const std::string &/*clientName*/ ) { errorString_ = "MidiOutDummy: This class provides no functionality."; error( RtMidiError::WARNING, errorString_ ); }
getCurrentApi(void)257   RtMidi::Api getCurrentApi( void ) { return RtMidi::RTMIDI_DUMMY; }
openPort(unsigned int,const std::string &)258   void openPort( unsigned int /*portNumber*/, const std::string &/*portName*/ ) {}
openVirtualPort(const std::string &)259   void openVirtualPort( const std::string &/*portName*/ ) {}
closePort(void)260   void closePort( void ) {}
setClientName(const std::string &)261   void setClientName( const std::string &/*clientName*/ ) {};
setPortName(const std::string &)262   void setPortName( const std::string &/*portName*/ ) {};
getPortCount(void)263   unsigned int getPortCount( void ) { return 0; }
getPortName(unsigned int)264   std::string getPortName( unsigned int /*portNumber*/ ) { return ""; }
sendMessage(const unsigned char *,size_t)265   void sendMessage( const unsigned char * /*message*/, size_t /*size*/ ) {}
266 
267  protected:
initialize(const std::string &)268   void initialize( const std::string& /*clientName*/ ) {}
269 };
270 
271 #endif
272 
273 //*********************************************************************//
274 //  RtMidi Definitions
275 //*********************************************************************//
276 
RtMidi()277 RtMidi :: RtMidi()
278   : rtapi_(0)
279 {
280 }
281 
~RtMidi()282 RtMidi :: ~RtMidi()
283 {
284   delete rtapi_;
285   rtapi_ = 0;
286 }
287 
getVersion(void)288 std::string RtMidi :: getVersion( void ) throw()
289 {
290   return std::string( RTMIDI_VERSION );
291 }
292 
293 // Define API names and display names.
294 // Must be in same order as API enum.
295 extern "C" {
296 const char* rtmidi_api_names[][2] = {
297   { "unspecified" , "Unknown" },
298   { "core"        , "CoreMidi" },
299   { "alsa"        , "ALSA" },
300   { "jack"        , "Jack" },
301   { "winmm"       , "Windows MultiMedia" },
302   { "dummy"       , "Dummy" },
303 };
304 const unsigned int rtmidi_num_api_names =
305   sizeof(rtmidi_api_names)/sizeof(rtmidi_api_names[0]);
306 
307 // The order here will control the order of RtMidi's API search in
308 // the constructor.
309 extern "C" const RtMidi::Api rtmidi_compiled_apis[] = {
310 #if defined(__MACOSX_CORE__)
311   RtMidi::MACOSX_CORE,
312 #endif
313 #if defined(__LINUX_ALSA__)
314   RtMidi::LINUX_ALSA,
315 #endif
316 #if defined(__UNIX_JACK__)
317   RtMidi::UNIX_JACK,
318 #endif
319 #if defined(__WINDOWS_MM__)
320   RtMidi::WINDOWS_MM,
321 #endif
322 #if defined(__RTMIDI_DUMMY__)
323   RtMidi::RTMIDI_DUMMY,
324 #endif
325   RtMidi::UNSPECIFIED,
326 };
327 extern "C" const unsigned int rtmidi_num_compiled_apis =
328   sizeof(rtmidi_compiled_apis)/sizeof(rtmidi_compiled_apis[0])-1;
329 }
330 
331 // This is a compile-time check that rtmidi_num_api_names == RtMidi::NUM_APIS.
332 // If the build breaks here, check that they match.
StaticAssert()333 template<bool b> class StaticAssert { private: StaticAssert() {} };
StaticAssert()334 template<> class StaticAssert<true>{ public: StaticAssert() {} };
StaticAssertions()335 class StaticAssertions { StaticAssertions() {
336   StaticAssert<rtmidi_num_api_names == RtMidi::NUM_APIS>();
337 }};
338 
getCompiledApi(std::vector<RtMidi::Api> & apis)339 void RtMidi :: getCompiledApi( std::vector<RtMidi::Api> &apis ) throw()
340 {
341   apis = std::vector<RtMidi::Api>(rtmidi_compiled_apis,
342                                   rtmidi_compiled_apis + rtmidi_num_compiled_apis);
343 }
344 
getApiName(RtMidi::Api api)345 std::string RtMidi :: getApiName( RtMidi::Api api )
346 {
347   if (api < 0 || api >= RtMidi::NUM_APIS)
348     return "";
349   return rtmidi_api_names[api][0];
350 }
351 
getApiDisplayName(RtMidi::Api api)352 std::string RtMidi :: getApiDisplayName( RtMidi::Api api )
353 {
354   if (api < 0 || api >= RtMidi::NUM_APIS)
355     return "Unknown";
356   return rtmidi_api_names[api][1];
357 }
358 
getCompiledApiByName(const std::string & name)359 RtMidi::Api RtMidi :: getCompiledApiByName( const std::string &name )
360 {
361   unsigned int i=0;
362   for (i = 0; i < rtmidi_num_compiled_apis; ++i)
363     if (name == rtmidi_api_names[rtmidi_compiled_apis[i]][0])
364       return rtmidi_compiled_apis[i];
365   return RtMidi::UNSPECIFIED;
366 }
367 
setClientName(const std::string & clientName)368 void RtMidi :: setClientName( const std::string &clientName )
369 {
370   rtapi_->setClientName( clientName );
371 }
372 
setPortName(const std::string & portName)373 void RtMidi :: setPortName( const std::string &portName )
374 {
375   rtapi_->setPortName( portName );
376 }
377 
378 
379 //*********************************************************************//
380 //  RtMidiIn Definitions
381 //*********************************************************************//
382 
openMidiApi(RtMidi::Api api,const std::string & clientName,unsigned int queueSizeLimit)383 void RtMidiIn :: openMidiApi( RtMidi::Api api, const std::string &clientName, unsigned int queueSizeLimit )
384 {
385   delete rtapi_;
386   rtapi_ = 0;
387 
388 #if defined(__UNIX_JACK__)
389   if ( api == UNIX_JACK )
390     rtapi_ = new MidiInJack( clientName, queueSizeLimit );
391 #endif
392 #if defined(__LINUX_ALSA__)
393   if ( api == LINUX_ALSA )
394     rtapi_ = new MidiInAlsa( clientName, queueSizeLimit );
395 #endif
396 #if defined(__WINDOWS_MM__)
397   if ( api == WINDOWS_MM )
398     rtapi_ = new MidiInWinMM( clientName, queueSizeLimit );
399 #endif
400 #if defined(__MACOSX_CORE__)
401   if ( api == MACOSX_CORE )
402     rtapi_ = new MidiInCore( clientName, queueSizeLimit );
403 #endif
404 #if defined(__RTMIDI_DUMMY__)
405   if ( api == RTMIDI_DUMMY )
406     rtapi_ = new MidiInDummy( clientName, queueSizeLimit );
407 #endif
408 }
409 
RtMidiIn(RtMidi::Api api,const std::string & clientName,unsigned int queueSizeLimit)410 RTMIDI_DLL_PUBLIC RtMidiIn :: RtMidiIn( RtMidi::Api api, const std::string &clientName, unsigned int queueSizeLimit )
411   : RtMidi()
412 {
413   if ( api != UNSPECIFIED ) {
414     // Attempt to open the specified API.
415     openMidiApi( api, clientName, queueSizeLimit );
416     if ( rtapi_ ) return;
417 
418     // No compiled support for specified API value.  Issue a warning
419     // and continue as if no API was specified.
420     std::cerr << "\nRtMidiIn: no compiled support for specified API argument!\n\n" << std::endl;
421   }
422 
423   // Iterate through the compiled APIs and return as soon as we find
424   // one with at least one port or we reach the end of the list.
425   std::vector< RtMidi::Api > apis;
426   getCompiledApi( apis );
427   for ( unsigned int i=0; i<apis.size(); i++ ) {
428     openMidiApi( apis[i], clientName, queueSizeLimit );
429     if ( rtapi_ && rtapi_->getPortCount() ) break;
430   }
431 
432   if ( rtapi_ ) return;
433 
434   // It should not be possible to get here because the preprocessor
435   // definition __RTMIDI_DUMMY__ is automatically defined if no
436   // API-specific definitions are passed to the compiler. But just in
437   // case something weird happens, we'll throw an error.
438   std::string errorText = "RtMidiIn: no compiled API support found ... critical error!!";
439   throw( RtMidiError( errorText, RtMidiError::UNSPECIFIED ) );
440 }
441 
~RtMidiIn()442 RtMidiIn :: ~RtMidiIn() throw()
443 {
444 }
445 
446 
447 //*********************************************************************//
448 //  RtMidiOut Definitions
449 //*********************************************************************//
450 
openMidiApi(RtMidi::Api api,const std::string & clientName)451 void RtMidiOut :: openMidiApi( RtMidi::Api api, const std::string &clientName )
452 {
453   delete rtapi_;
454   rtapi_ = 0;
455 
456 #if defined(__UNIX_JACK__)
457   if ( api == UNIX_JACK )
458     rtapi_ = new MidiOutJack( clientName );
459 #endif
460 #if defined(__LINUX_ALSA__)
461   if ( api == LINUX_ALSA )
462     rtapi_ = new MidiOutAlsa( clientName );
463 #endif
464 #if defined(__WINDOWS_MM__)
465   if ( api == WINDOWS_MM )
466     rtapi_ = new MidiOutWinMM( clientName );
467 #endif
468 #if defined(__MACOSX_CORE__)
469   if ( api == MACOSX_CORE )
470     rtapi_ = new MidiOutCore( clientName );
471 #endif
472 #if defined(__RTMIDI_DUMMY__)
473   if ( api == RTMIDI_DUMMY )
474     rtapi_ = new MidiOutDummy( clientName );
475 #endif
476 }
477 
RtMidiOut(RtMidi::Api api,const std::string & clientName)478 RTMIDI_DLL_PUBLIC RtMidiOut :: RtMidiOut( RtMidi::Api api, const std::string &clientName)
479 {
480   if ( api != UNSPECIFIED ) {
481     // Attempt to open the specified API.
482     openMidiApi( api, clientName );
483     if ( rtapi_ ) return;
484 
485     // No compiled support for specified API value.  Issue a warning
486     // and continue as if no API was specified.
487     std::cerr << "\nRtMidiOut: no compiled support for specified API argument!\n\n" << std::endl;
488   }
489 
490   // Iterate through the compiled APIs and return as soon as we find
491   // one with at least one port or we reach the end of the list.
492   std::vector< RtMidi::Api > apis;
493   getCompiledApi( apis );
494   for ( unsigned int i=0; i<apis.size(); i++ ) {
495     openMidiApi( apis[i], clientName );
496     if ( rtapi_ && rtapi_->getPortCount() ) break;
497   }
498 
499   if ( rtapi_ ) return;
500 
501   // It should not be possible to get here because the preprocessor
502   // definition __RTMIDI_DUMMY__ is automatically defined if no
503   // API-specific definitions are passed to the compiler. But just in
504   // case something weird happens, we'll thrown an error.
505   std::string errorText = "RtMidiOut: no compiled API support found ... critical error!!";
506   throw( RtMidiError( errorText, RtMidiError::UNSPECIFIED ) );
507 }
508 
~RtMidiOut()509 RtMidiOut :: ~RtMidiOut() throw()
510 {
511 }
512 
513 //*********************************************************************//
514 //  Common MidiApi Definitions
515 //*********************************************************************//
516 
MidiApi(void)517 MidiApi :: MidiApi( void )
518   : apiData_( 0 ), connected_( false ), errorCallback_(0), firstErrorOccurred_(false), errorCallbackUserData_(0)
519 {
520 }
521 
~MidiApi(void)522 MidiApi :: ~MidiApi( void )
523 {
524 }
525 
setErrorCallback(RtMidiErrorCallback errorCallback,void * userData=0)526 void MidiApi :: setErrorCallback( RtMidiErrorCallback errorCallback, void *userData = 0 )
527 {
528     errorCallback_ = errorCallback;
529     errorCallbackUserData_ = userData;
530 }
531 
error(RtMidiError::Type type,std::string errorString)532 void MidiApi :: error( RtMidiError::Type type, std::string errorString )
533 {
534   if ( errorCallback_ ) {
535 
536     if ( firstErrorOccurred_ )
537       return;
538 
539     firstErrorOccurred_ = true;
540     const std::string errorMessage = errorString;
541 
542     errorCallback_( type, errorMessage, errorCallbackUserData_ );
543     firstErrorOccurred_ = false;
544     return;
545   }
546 
547   if ( type == RtMidiError::WARNING ) {
548     std::cerr << '\n' << errorString << "\n\n";
549   }
550   else if ( type == RtMidiError::DEBUG_WARNING ) {
551 #if defined(__RTMIDI_DEBUG__)
552     std::cerr << '\n' << errorString << "\n\n";
553 #endif
554   }
555   else {
556     std::cerr << '\n' << errorString << "\n\n";
557     throw RtMidiError( errorString, type );
558   }
559 }
560 
561 //*********************************************************************//
562 //  Common MidiInApi Definitions
563 //*********************************************************************//
564 
MidiInApi(unsigned int queueSizeLimit)565 MidiInApi :: MidiInApi( unsigned int queueSizeLimit )
566   : MidiApi()
567 {
568   // Allocate the MIDI queue.
569   inputData_.queue.ringSize = queueSizeLimit;
570   if ( inputData_.queue.ringSize > 0 )
571     inputData_.queue.ring = new MidiMessage[ inputData_.queue.ringSize ];
572 }
573 
~MidiInApi(void)574 MidiInApi :: ~MidiInApi( void )
575 {
576   // Delete the MIDI queue.
577   if ( inputData_.queue.ringSize > 0 ) delete [] inputData_.queue.ring;
578 }
579 
setCallback(RtMidiIn::RtMidiCallback callback,void * userData)580 void MidiInApi :: setCallback( RtMidiIn::RtMidiCallback callback, void *userData )
581 {
582   if ( inputData_.usingCallback ) {
583     errorString_ = "MidiInApi::setCallback: a callback function is already set!";
584     error( RtMidiError::WARNING, errorString_ );
585     return;
586   }
587 
588   if ( !callback ) {
589     errorString_ = "RtMidiIn::setCallback: callback function value is invalid!";
590     error( RtMidiError::WARNING, errorString_ );
591     return;
592   }
593 
594   inputData_.userCallback = callback;
595   inputData_.userData = userData;
596   inputData_.usingCallback = true;
597 }
598 
cancelCallback()599 void MidiInApi :: cancelCallback()
600 {
601   if ( !inputData_.usingCallback ) {
602     errorString_ = "RtMidiIn::cancelCallback: no callback function was set!";
603     error( RtMidiError::WARNING, errorString_ );
604     return;
605   }
606 
607   inputData_.userCallback = 0;
608   inputData_.userData = 0;
609   inputData_.usingCallback = false;
610 }
611 
ignoreTypes(bool midiSysex,bool midiTime,bool midiSense)612 void MidiInApi :: ignoreTypes( bool midiSysex, bool midiTime, bool midiSense )
613 {
614   inputData_.ignoreFlags = 0;
615   if ( midiSysex ) inputData_.ignoreFlags = 0x01;
616   if ( midiTime ) inputData_.ignoreFlags |= 0x02;
617   if ( midiSense ) inputData_.ignoreFlags |= 0x04;
618 }
619 
getMessage(std::vector<unsigned char> * message)620 double MidiInApi :: getMessage( std::vector<unsigned char> *message )
621 {
622   message->clear();
623 
624   if ( inputData_.usingCallback ) {
625     errorString_ = "RtMidiIn::getNextMessage: a user callback is currently set for this port.";
626     error( RtMidiError::WARNING, errorString_ );
627     return 0.0;
628   }
629 
630   double timeStamp;
631   if ( !inputData_.queue.pop( message, &timeStamp ) )
632     return 0.0;
633 
634   return timeStamp;
635 }
636 
size(unsigned int * __back,unsigned int * __front)637 unsigned int MidiInApi::MidiQueue::size( unsigned int *__back,
638                                          unsigned int *__front )
639 {
640   // Access back/front members exactly once and make stack copies for
641   // size calculation
642   unsigned int _back = back, _front = front, _size;
643   if ( _back >= _front )
644     _size = _back - _front;
645   else
646     _size = ringSize - _front + _back;
647 
648   // Return copies of back/front so no new and unsynchronized accesses
649   // to member variables are needed.
650   if ( __back ) *__back = _back;
651   if ( __front ) *__front = _front;
652   return _size;
653 }
654 
655 // As long as we haven't reached our queue size limit, push the message.
push(const MidiInApi::MidiMessage & msg)656 bool MidiInApi::MidiQueue::push( const MidiInApi::MidiMessage& msg )
657 {
658   // Local stack copies of front/back
659   unsigned int _back, _front, _size;
660 
661   // Get back/front indexes exactly once and calculate current size
662   _size = size( &_back, &_front );
663 
664   if ( _size < ringSize-1 )
665   {
666     ring[_back] = msg;
667     back = (back+1)%ringSize;
668     return true;
669   }
670 
671   return false;
672 }
673 
pop(std::vector<unsigned char> * msg,double * timeStamp)674 bool MidiInApi::MidiQueue::pop( std::vector<unsigned char> *msg, double* timeStamp )
675 {
676   // Local stack copies of front/back
677   unsigned int _back, _front, _size;
678 
679   // Get back/front indexes exactly once and calculate current size
680   _size = size( &_back, &_front );
681 
682   if ( _size == 0 )
683     return false;
684 
685   // Copy queued message to the vector pointer argument and then "pop" it.
686   msg->assign( ring[_front].bytes.begin(), ring[_front].bytes.end() );
687   *timeStamp = ring[_front].timeStamp;
688 
689   // Update front
690   front = (front+1)%ringSize;
691   return true;
692 }
693 
694 //*********************************************************************//
695 //  Common MidiOutApi Definitions
696 //*********************************************************************//
697 
MidiOutApi(void)698 MidiOutApi :: MidiOutApi( void )
699   : MidiApi()
700 {
701 }
702 
~MidiOutApi(void)703 MidiOutApi :: ~MidiOutApi( void )
704 {
705 }
706 
707 // *************************************************** //
708 //
709 // OS/API-specific methods.
710 //
711 // *************************************************** //
712 
713 #if defined(__MACOSX_CORE__)
714 
715 // The CoreMIDI API is based on the use of a callback function for
716 // MIDI input.  We convert the system specific time stamps to delta
717 // time values.
718 
719 // OS-X CoreMIDI header files.
720 #include <CoreMIDI/CoreMIDI.h>
721 #include <CoreAudio/HostTime.h>
722 #include <CoreServices/CoreServices.h>
723 
724 // A structure to hold variables related to the CoreMIDI API
725 // implementation.
726 struct CoreMidiData {
727   MIDIClientRef client;
728   MIDIPortRef port;
729   MIDIEndpointRef endpoint;
730   MIDIEndpointRef destinationId;
731   unsigned long long lastTime;
732   MIDISysexSendRequest sysexreq;
733 };
734 
735 //*********************************************************************//
736 //  API: OS-X
737 //  Class Definitions: MidiInCore
738 //*********************************************************************//
739 
midiInputCallback(const MIDIPacketList * list,void * procRef,void *)740 static void midiInputCallback( const MIDIPacketList *list, void *procRef, void */*srcRef*/ )
741 {
742   MidiInApi::RtMidiInData *data = static_cast<MidiInApi::RtMidiInData *> (procRef);
743   CoreMidiData *apiData = static_cast<CoreMidiData *> (data->apiData);
744 
745   unsigned char status;
746   unsigned short nBytes, iByte, size;
747   unsigned long long time;
748 
749   bool& continueSysex = data->continueSysex;
750   MidiInApi::MidiMessage& message = data->message;
751 
752   const MIDIPacket *packet = &list->packet[0];
753   for ( unsigned int i=0; i<list->numPackets; ++i ) {
754 
755     // My interpretation of the CoreMIDI documentation: all message
756     // types, except sysex, are complete within a packet and there may
757     // be several of them in a single packet.  Sysex messages can be
758     // broken across multiple packets and PacketLists but are bundled
759     // alone within each packet (these packets do not contain other
760     // message types).  If sysex messages are split across multiple
761     // MIDIPacketLists, they must be handled by multiple calls to this
762     // function.
763 
764     nBytes = packet->length;
765     if ( nBytes == 0 ) {
766       packet = MIDIPacketNext( packet );
767       continue;
768     }
769 
770     // Calculate time stamp.
771     if ( data->firstMessage ) {
772       message.timeStamp = 0.0;
773       data->firstMessage = false;
774     }
775     else {
776       time = packet->timeStamp;
777       if ( time == 0 ) { // this happens when receiving asynchronous sysex messages
778         time = AudioGetCurrentHostTime();
779       }
780       time -= apiData->lastTime;
781       time = AudioConvertHostTimeToNanos( time );
782       if ( !continueSysex )
783         message.timeStamp = time * 0.000000001;
784     }
785 
786     // Track whether any non-filtered messages were found in this
787     // packet for timestamp calculation
788     bool foundNonFiltered = false;
789 
790     iByte = 0;
791     if ( continueSysex ) {
792       // We have a continuing, segmented sysex message.
793       if ( !( data->ignoreFlags & 0x01 ) ) {
794         // If we're not ignoring sysex messages, copy the entire packet.
795         for ( unsigned int j=0; j<nBytes; ++j )
796           message.bytes.push_back( packet->data[j] );
797       }
798       continueSysex = packet->data[nBytes-1] != 0xF7;
799 
800       if ( !( data->ignoreFlags & 0x01 ) && !continueSysex ) {
801         // If not a continuing sysex message, invoke the user callback function or queue the message.
802         if ( data->usingCallback ) {
803           RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
804           callback( message.timeStamp, &message.bytes, data->userData );
805         }
806         else {
807           // As long as we haven't reached our queue size limit, push the message.
808           if ( !data->queue.push( message ) )
809             std::cerr << "\nMidiInCore: message queue limit reached!!\n\n";
810         }
811         message.bytes.clear();
812       }
813     }
814     else {
815       while ( iByte < nBytes ) {
816         size = 0;
817         // We are expecting that the next byte in the packet is a status byte.
818         status = packet->data[iByte];
819         if ( !(status & 0x80) ) break;
820         // Determine the number of bytes in the MIDI message.
821         if ( status < 0xC0 ) size = 3;
822         else if ( status < 0xE0 ) size = 2;
823         else if ( status < 0xF0 ) size = 3;
824         else if ( status == 0xF0 ) {
825           // A MIDI sysex
826           if ( data->ignoreFlags & 0x01 ) {
827             size = 0;
828             iByte = nBytes;
829           }
830           else size = nBytes - iByte;
831           continueSysex = packet->data[nBytes-1] != 0xF7;
832         }
833         else if ( status == 0xF1 ) {
834           // A MIDI time code message
835           if ( data->ignoreFlags & 0x02 ) {
836             size = 0;
837             iByte += 2;
838           }
839           else size = 2;
840         }
841         else if ( status == 0xF2 ) size = 3;
842         else if ( status == 0xF3 ) size = 2;
843         else if ( status == 0xF8 && ( data->ignoreFlags & 0x02 ) ) {
844           // A MIDI timing tick message and we're ignoring it.
845           size = 0;
846           iByte += 1;
847         }
848         else if ( status == 0xFE && ( data->ignoreFlags & 0x04 ) ) {
849           // A MIDI active sensing message and we're ignoring it.
850           size = 0;
851           iByte += 1;
852         }
853         else size = 1;
854 
855         // Copy the MIDI data to our vector.
856         if ( size ) {
857           foundNonFiltered = true;
858           message.bytes.assign( &packet->data[iByte], &packet->data[iByte+size] );
859           if ( !continueSysex ) {
860             // If not a continuing sysex message, invoke the user callback function or queue the message.
861             if ( data->usingCallback ) {
862               RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
863               callback( message.timeStamp, &message.bytes, data->userData );
864             }
865             else {
866               // As long as we haven't reached our queue size limit, push the message.
867               if ( !data->queue.push( message ) )
868                 std::cerr << "\nMidiInCore: message queue limit reached!!\n\n";
869             }
870             message.bytes.clear();
871           }
872           iByte += size;
873         }
874       }
875     }
876 
877     // Save the time of the last non-filtered message
878     if ( foundNonFiltered ) {
879       apiData->lastTime = packet->timeStamp;
880       if ( apiData->lastTime == 0 ) { // this happens when receiving asynchronous sysex messages
881         apiData->lastTime = AudioGetCurrentHostTime();
882       }
883     }
884 
885     packet = MIDIPacketNext(packet);
886   }
887 }
888 
MidiInCore(const std::string & clientName,unsigned int queueSizeLimit)889 MidiInCore :: MidiInCore( const std::string &clientName, unsigned int queueSizeLimit )
890   : MidiInApi( queueSizeLimit )
891 {
892   MidiInCore::initialize( clientName );
893 }
894 
~MidiInCore(void)895 MidiInCore :: ~MidiInCore( void )
896 {
897   // Close a connection if it exists.
898   MidiInCore::closePort();
899 
900   // Cleanup.
901   CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
902   MIDIClientDispose( data->client );
903   if ( data->endpoint ) MIDIEndpointDispose( data->endpoint );
904   delete data;
905 }
906 
initialize(const std::string & clientName)907 void MidiInCore :: initialize( const std::string& clientName )
908 {
909   // Set up our client.
910   MIDIClientRef client;
911   CFStringRef name = CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII );
912   OSStatus result = MIDIClientCreate(name, NULL, NULL, &client );
913   if ( result != noErr ) {
914     std::ostringstream ost;
915     ost << "MidiInCore::initialize: error creating OS-X MIDI client object (" << result << ").";
916     errorString_ = ost.str();
917     error( RtMidiError::DRIVER_ERROR, errorString_ );
918     return;
919   }
920 
921   // Save our api-specific connection information.
922   CoreMidiData *data = (CoreMidiData *) new CoreMidiData;
923   data->client = client;
924   data->endpoint = 0;
925   apiData_ = (void *) data;
926   inputData_.apiData = (void *) data;
927   CFRelease( name );
928 }
929 
openPort(unsigned int portNumber,const std::string & portName)930 void MidiInCore :: openPort( unsigned int portNumber, const std::string &portName )
931 {
932   if ( connected_ ) {
933     errorString_ = "MidiInCore::openPort: a valid connection already exists!";
934     error( RtMidiError::WARNING, errorString_ );
935     return;
936   }
937 
938   CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
939   unsigned int nSrc = MIDIGetNumberOfSources();
940   if ( nSrc < 1 ) {
941     errorString_ = "MidiInCore::openPort: no MIDI input sources found!";
942     error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
943     return;
944   }
945 
946   if ( portNumber >= nSrc ) {
947     std::ostringstream ost;
948     ost << "MidiInCore::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
949     errorString_ = ost.str();
950     error( RtMidiError::INVALID_PARAMETER, errorString_ );
951     return;
952   }
953 
954   MIDIPortRef port;
955   CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
956   CFStringRef portNameRef = CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII );
957   OSStatus result = MIDIInputPortCreate( data->client,
958                                          portNameRef,
959                                          midiInputCallback, (void *)&inputData_, &port );
960   CFRelease( portNameRef );
961 
962   if ( result != noErr ) {
963     MIDIClientDispose( data->client );
964     errorString_ = "MidiInCore::openPort: error creating OS-X MIDI input port.";
965     error( RtMidiError::DRIVER_ERROR, errorString_ );
966     return;
967   }
968 
969   // Get the desired input source identifier.
970   MIDIEndpointRef endpoint = MIDIGetSource( portNumber );
971   if ( endpoint == 0 ) {
972     MIDIPortDispose( port );
973     MIDIClientDispose( data->client );
974     errorString_ = "MidiInCore::openPort: error getting MIDI input source reference.";
975     error( RtMidiError::DRIVER_ERROR, errorString_ );
976     return;
977   }
978 
979   // Make the connection.
980   result = MIDIPortConnectSource( port, endpoint, NULL );
981   if ( result != noErr ) {
982     MIDIPortDispose( port );
983     MIDIClientDispose( data->client );
984     errorString_ = "MidiInCore::openPort: error connecting OS-X MIDI input port.";
985     error( RtMidiError::DRIVER_ERROR, errorString_ );
986     return;
987   }
988 
989   // Save our api-specific port information.
990   data->port = port;
991 
992   connected_ = true;
993 }
994 
openVirtualPort(const std::string & portName)995 void MidiInCore :: openVirtualPort( const std::string &portName )
996 {
997   CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
998 
999   // Create a virtual MIDI input destination.
1000   MIDIEndpointRef endpoint;
1001   CFStringRef portNameRef = CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII );
1002   OSStatus result = MIDIDestinationCreate( data->client,
1003                                            portNameRef,
1004                                            midiInputCallback, (void *)&inputData_, &endpoint );
1005   CFRelease( portNameRef );
1006 
1007   if ( result != noErr ) {
1008     errorString_ = "MidiInCore::openVirtualPort: error creating virtual OS-X MIDI destination.";
1009     error( RtMidiError::DRIVER_ERROR, errorString_ );
1010     return;
1011   }
1012 
1013   // Save our api-specific connection information.
1014   data->endpoint = endpoint;
1015 }
1016 
closePort(void)1017 void MidiInCore :: closePort( void )
1018 {
1019   CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
1020 
1021   if ( data->endpoint ) {
1022     MIDIEndpointDispose( data->endpoint );
1023     data->endpoint = 0;
1024   }
1025 
1026   if ( data->port ) {
1027     MIDIPortDispose( data->port );
1028     data->port = 0;
1029   }
1030 
1031   connected_ = false;
1032 }
1033 
setClientName(const std::string &)1034 void MidiInCore :: setClientName ( const std::string& )
1035 {
1036 
1037   errorString_ = "MidiInCore::setClientName: this function is not implemented for the MACOSX_CORE API!";
1038   error( RtMidiError::WARNING, errorString_ );
1039 
1040 }
1041 
setPortName(const std::string &)1042 void MidiInCore :: setPortName ( const std::string& )
1043 {
1044 
1045   errorString_ = "MidiInCore::setPortName: this function is not implemented for the MACOSX_CORE API!";
1046   error( RtMidiError::WARNING, errorString_ );
1047 
1048 }
1049 
getPortCount()1050 unsigned int MidiInCore :: getPortCount()
1051 {
1052   CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
1053   return MIDIGetNumberOfSources();
1054 }
1055 
1056 // This function was submitted by Douglas Casey Tucker and apparently
1057 // derived largely from PortMidi.
EndpointName(MIDIEndpointRef endpoint,bool isExternal)1058 CFStringRef EndpointName( MIDIEndpointRef endpoint, bool isExternal )
1059 {
1060   CFMutableStringRef result = CFStringCreateMutable( NULL, 0 );
1061   CFStringRef str;
1062 
1063   // Begin with the endpoint's name.
1064   str = NULL;
1065   MIDIObjectGetStringProperty( endpoint, kMIDIPropertyName, &str );
1066   if ( str != NULL ) {
1067     CFStringAppend( result, str );
1068     CFRelease( str );
1069   }
1070 
1071   MIDIEntityRef entity = 0;
1072   MIDIEndpointGetEntity( endpoint, &entity );
1073   if ( entity == 0 )
1074     // probably virtual
1075     return result;
1076 
1077   if ( CFStringGetLength( result ) == 0 ) {
1078     // endpoint name has zero length -- try the entity
1079     str = NULL;
1080     MIDIObjectGetStringProperty( entity, kMIDIPropertyName, &str );
1081     if ( str != NULL ) {
1082       CFStringAppend( result, str );
1083       CFRelease( str );
1084     }
1085   }
1086   // now consider the device's name
1087   MIDIDeviceRef device = 0;
1088   MIDIEntityGetDevice( entity, &device );
1089   if ( device == 0 )
1090     return result;
1091 
1092   str = NULL;
1093   MIDIObjectGetStringProperty( device, kMIDIPropertyName, &str );
1094   if ( CFStringGetLength( result ) == 0 ) {
1095       CFRelease( result );
1096       return str;
1097   }
1098   if ( str != NULL ) {
1099     // if an external device has only one entity, throw away
1100     // the endpoint name and just use the device name
1101     if ( isExternal && MIDIDeviceGetNumberOfEntities( device ) < 2 ) {
1102       CFRelease( result );
1103       return str;
1104     } else {
1105       if ( CFStringGetLength( str ) == 0 ) {
1106         CFRelease( str );
1107         return result;
1108       }
1109       // does the entity name already start with the device name?
1110       // (some drivers do this though they shouldn't)
1111       // if so, do not prepend
1112       if ( CFStringCompareWithOptions( result, /* endpoint name */
1113                                        str /* device name */,
1114                                        CFRangeMake(0, CFStringGetLength( str ) ), 0 ) != kCFCompareEqualTo ) {
1115         // prepend the device name to the entity name
1116         if ( CFStringGetLength( result ) > 0 )
1117           CFStringInsert( result, 0, CFSTR(" ") );
1118 
1119         CFStringInsert( result, 0, str );
1120       }
1121       CFRelease( str );
1122     }
1123   }
1124   return result;
1125 }
1126 
1127 // This function was submitted by Douglas Casey Tucker and apparently
1128 // derived largely from PortMidi.
ConnectedEndpointName(MIDIEndpointRef endpoint)1129 static CFStringRef ConnectedEndpointName( MIDIEndpointRef endpoint )
1130 {
1131   CFMutableStringRef result = CFStringCreateMutable( NULL, 0 );
1132   CFStringRef str;
1133   OSStatus err;
1134   int i;
1135 
1136   // Does the endpoint have connections?
1137   CFDataRef connections = NULL;
1138   int nConnected = 0;
1139   bool anyStrings = false;
1140   err = MIDIObjectGetDataProperty( endpoint, kMIDIPropertyConnectionUniqueID, &connections );
1141   if ( connections != NULL ) {
1142     // It has connections, follow them
1143     // Concatenate the names of all connected devices
1144     nConnected = CFDataGetLength( connections ) / sizeof(MIDIUniqueID);
1145     if ( nConnected ) {
1146       const SInt32 *pid = (const SInt32 *)(CFDataGetBytePtr(connections));
1147       for ( i=0; i<nConnected; ++i, ++pid ) {
1148         MIDIUniqueID id = EndianS32_BtoN( *pid );
1149         MIDIObjectRef connObject;
1150         MIDIObjectType connObjectType;
1151         err = MIDIObjectFindByUniqueID( id, &connObject, &connObjectType );
1152         if ( err == noErr ) {
1153           if ( connObjectType == kMIDIObjectType_ExternalSource  ||
1154                connObjectType == kMIDIObjectType_ExternalDestination ) {
1155             // Connected to an external device's endpoint (10.3 and later).
1156             str = EndpointName( (MIDIEndpointRef)(connObject), true );
1157           } else {
1158             // Connected to an external device (10.2) (or something else, catch-
1159             str = NULL;
1160             MIDIObjectGetStringProperty( connObject, kMIDIPropertyName, &str );
1161           }
1162           if ( str != NULL ) {
1163             if ( anyStrings )
1164               CFStringAppend( result, CFSTR(", ") );
1165             else
1166               anyStrings = true;
1167             CFStringAppend( result, str );
1168             CFRelease( str );
1169           }
1170         }
1171       }
1172     }
1173     CFRelease( connections );
1174   }
1175   if ( anyStrings )
1176     return result;
1177 
1178   CFRelease( result );
1179 
1180   // Here, either the endpoint had no connections, or we failed to obtain names
1181   return EndpointName( endpoint, false );
1182 }
1183 
getPortName(unsigned int portNumber)1184 std::string MidiInCore :: getPortName( unsigned int portNumber )
1185 {
1186   CFStringRef nameRef;
1187   MIDIEndpointRef portRef;
1188   char name[128];
1189 
1190   std::string stringName;
1191   CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
1192   if ( portNumber >= MIDIGetNumberOfSources() ) {
1193     std::ostringstream ost;
1194     ost << "MidiInCore::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
1195     errorString_ = ost.str();
1196     error( RtMidiError::WARNING, errorString_ );
1197     return stringName;
1198   }
1199 
1200   portRef = MIDIGetSource( portNumber );
1201   nameRef = ConnectedEndpointName( portRef );
1202   CFStringGetCString( nameRef, name, sizeof(name), kCFStringEncodingUTF8 );
1203   CFRelease( nameRef );
1204 
1205   return stringName = name;
1206 }
1207 
1208 //*********************************************************************//
1209 //  API: OS-X
1210 //  Class Definitions: MidiOutCore
1211 //*********************************************************************//
1212 
MidiOutCore(const std::string & clientName)1213 MidiOutCore :: MidiOutCore( const std::string &clientName )
1214   : MidiOutApi()
1215 {
1216   MidiOutCore::initialize( clientName );
1217 }
1218 
~MidiOutCore(void)1219 MidiOutCore :: ~MidiOutCore( void )
1220 {
1221   // Close a connection if it exists.
1222   MidiOutCore::closePort();
1223 
1224   // Cleanup.
1225   CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
1226   MIDIClientDispose( data->client );
1227   if ( data->endpoint ) MIDIEndpointDispose( data->endpoint );
1228   delete data;
1229 }
1230 
initialize(const std::string & clientName)1231 void MidiOutCore :: initialize( const std::string& clientName )
1232 {
1233   // Set up our client.
1234   MIDIClientRef client;
1235   CFStringRef name = CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII );
1236   OSStatus result = MIDIClientCreate(name, NULL, NULL, &client );
1237   if ( result != noErr ) {
1238     std::ostringstream ost;
1239     ost << "MidiInCore::initialize: error creating OS-X MIDI client object (" << result << ").";
1240     errorString_ = ost.str();
1241     error( RtMidiError::DRIVER_ERROR, errorString_ );
1242     return;
1243   }
1244 
1245   // Save our api-specific connection information.
1246   CoreMidiData *data = (CoreMidiData *) new CoreMidiData;
1247   data->client = client;
1248   data->endpoint = 0;
1249   apiData_ = (void *) data;
1250   CFRelease( name );
1251 }
1252 
getPortCount()1253 unsigned int MidiOutCore :: getPortCount()
1254 {
1255   CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
1256   return MIDIGetNumberOfDestinations();
1257 }
1258 
getPortName(unsigned int portNumber)1259 std::string MidiOutCore :: getPortName( unsigned int portNumber )
1260 {
1261   CFStringRef nameRef;
1262   MIDIEndpointRef portRef;
1263   char name[128];
1264 
1265   std::string stringName;
1266   CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
1267   if ( portNumber >= MIDIGetNumberOfDestinations() ) {
1268     std::ostringstream ost;
1269     ost << "MidiOutCore::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
1270     errorString_ = ost.str();
1271     error( RtMidiError::WARNING, errorString_ );
1272     return stringName;
1273   }
1274 
1275   portRef = MIDIGetDestination( portNumber );
1276   nameRef = ConnectedEndpointName(portRef);
1277   CFStringGetCString( nameRef, name, sizeof(name), kCFStringEncodingUTF8 );
1278   CFRelease( nameRef );
1279 
1280   return stringName = name;
1281 }
1282 
openPort(unsigned int portNumber,const std::string & portName)1283 void MidiOutCore :: openPort( unsigned int portNumber, const std::string &portName )
1284 {
1285   if ( connected_ ) {
1286     errorString_ = "MidiOutCore::openPort: a valid connection already exists!";
1287     error( RtMidiError::WARNING, errorString_ );
1288     return;
1289   }
1290 
1291   CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
1292   unsigned int nDest = MIDIGetNumberOfDestinations();
1293   if (nDest < 1) {
1294     errorString_ = "MidiOutCore::openPort: no MIDI output destinations found!";
1295     error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
1296     return;
1297   }
1298 
1299   if ( portNumber >= nDest ) {
1300     std::ostringstream ost;
1301     ost << "MidiOutCore::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
1302     errorString_ = ost.str();
1303     error( RtMidiError::INVALID_PARAMETER, errorString_ );
1304     return;
1305   }
1306 
1307   MIDIPortRef port;
1308   CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
1309   CFStringRef portNameRef = CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII );
1310   OSStatus result = MIDIOutputPortCreate( data->client, portNameRef, &port );
1311   CFRelease( portNameRef );
1312   if ( result != noErr ) {
1313     MIDIClientDispose( data->client );
1314     errorString_ = "MidiOutCore::openPort: error creating OS-X MIDI output port.";
1315     error( RtMidiError::DRIVER_ERROR, errorString_ );
1316     return;
1317   }
1318 
1319   // Get the desired output port identifier.
1320   MIDIEndpointRef destination = MIDIGetDestination( portNumber );
1321   if ( destination == 0 ) {
1322     MIDIPortDispose( port );
1323     MIDIClientDispose( data->client );
1324     errorString_ = "MidiOutCore::openPort: error getting MIDI output destination reference.";
1325     error( RtMidiError::DRIVER_ERROR, errorString_ );
1326     return;
1327   }
1328 
1329   // Save our api-specific connection information.
1330   data->port = port;
1331   data->destinationId = destination;
1332   connected_ = true;
1333 }
1334 
closePort(void)1335 void MidiOutCore :: closePort( void )
1336 {
1337   CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
1338 
1339   if ( data->endpoint ) {
1340     MIDIEndpointDispose( data->endpoint );
1341     data->endpoint = 0;
1342   }
1343 
1344   if ( data->port ) {
1345     MIDIPortDispose( data->port );
1346     data->port = 0;
1347   }
1348 
1349   connected_ = false;
1350 }
1351 
setClientName(const std::string &)1352 void MidiOutCore :: setClientName ( const std::string& )
1353 {
1354 
1355   errorString_ = "MidiOutCore::setClientName: this function is not implemented for the MACOSX_CORE API!";
1356   error( RtMidiError::WARNING, errorString_ );
1357 
1358 }
1359 
setPortName(const std::string &)1360 void MidiOutCore :: setPortName ( const std::string& )
1361 {
1362 
1363   errorString_ = "MidiOutCore::setPortName: this function is not implemented for the MACOSX_CORE API!";
1364   error( RtMidiError::WARNING, errorString_ );
1365 
1366 }
1367 
openVirtualPort(const std::string & portName)1368 void MidiOutCore :: openVirtualPort( const std::string &portName )
1369 {
1370   CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
1371 
1372   if ( data->endpoint ) {
1373     errorString_ = "MidiOutCore::openVirtualPort: a virtual output port already exists!";
1374     error( RtMidiError::WARNING, errorString_ );
1375     return;
1376   }
1377 
1378   // Create a virtual MIDI output source.
1379   MIDIEndpointRef endpoint;
1380   CFStringRef portNameRef = CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII );
1381   OSStatus result = MIDISourceCreate( data->client, portNameRef, &endpoint );
1382   CFRelease( portNameRef );
1383 
1384   if ( result != noErr ) {
1385     errorString_ = "MidiOutCore::initialize: error creating OS-X virtual MIDI source.";
1386     error( RtMidiError::DRIVER_ERROR, errorString_ );
1387     return;
1388   }
1389 
1390   // Save our api-specific connection information.
1391   data->endpoint = endpoint;
1392 }
1393 
sendMessage(const unsigned char * message,size_t size)1394 void MidiOutCore :: sendMessage( const unsigned char *message, size_t size )
1395 {
1396   // We use the MIDISendSysex() function to asynchronously send sysex
1397   // messages.  Otherwise, we use a single CoreMidi MIDIPacket.
1398   unsigned int nBytes = static_cast<unsigned int> (size);
1399   if ( nBytes == 0 ) {
1400     errorString_ = "MidiOutCore::sendMessage: no data in message argument!";
1401     error( RtMidiError::WARNING, errorString_ );
1402     return;
1403   }
1404 
1405   MIDITimeStamp timeStamp = AudioGetCurrentHostTime();
1406   CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
1407   OSStatus result;
1408 
1409   if ( message[0] != 0xF0 && nBytes > 3 ) {
1410     errorString_ = "MidiOutCore::sendMessage: message format problem ... not sysex but > 3 bytes?";
1411     error( RtMidiError::WARNING, errorString_ );
1412     return;
1413   }
1414 
1415   Byte buffer[nBytes+(sizeof( MIDIPacketList ))];
1416   ByteCount listSize = sizeof( buffer );
1417   MIDIPacketList *packetList = (MIDIPacketList*)buffer;
1418   MIDIPacket *packet = MIDIPacketListInit( packetList );
1419 
1420   ByteCount remainingBytes = nBytes;
1421   while ( remainingBytes && packet ) {
1422     ByteCount bytesForPacket = remainingBytes > 65535 ? 65535 : remainingBytes; // 65535 = maximum size of a MIDIPacket
1423     const Byte* dataStartPtr = (const Byte *) &message[nBytes - remainingBytes];
1424     packet = MIDIPacketListAdd( packetList, listSize, packet, timeStamp, bytesForPacket, dataStartPtr );
1425     remainingBytes -= bytesForPacket;
1426   }
1427 
1428   if ( !packet ) {
1429     errorString_ = "MidiOutCore::sendMessage: could not allocate packet list";
1430     error( RtMidiError::DRIVER_ERROR, errorString_ );
1431     return;
1432   }
1433 
1434   // Send to any destinations that may have connected to us.
1435   if ( data->endpoint ) {
1436     result = MIDIReceived( data->endpoint, packetList );
1437     if ( result != noErr ) {
1438       errorString_ = "MidiOutCore::sendMessage: error sending MIDI to virtual destinations.";
1439       error( RtMidiError::WARNING, errorString_ );
1440     }
1441   }
1442 
1443   // And send to an explicit destination port if we're connected.
1444   if ( connected_ ) {
1445     result = MIDISend( data->port, data->destinationId, packetList );
1446     if ( result != noErr ) {
1447       errorString_ = "MidiOutCore::sendMessage: error sending MIDI message to port.";
1448       error( RtMidiError::WARNING, errorString_ );
1449     }
1450   }
1451 }
1452 
1453 #endif  // __MACOSX_CORE__
1454 
1455 
1456 //*********************************************************************//
1457 //  API: LINUX ALSA SEQUENCER
1458 //*********************************************************************//
1459 
1460 // API information found at:
1461 //   - http://www.alsa-project.org/documentation.php#Library
1462 
1463 #if defined(__LINUX_ALSA__)
1464 
1465 // The ALSA Sequencer API is based on the use of a callback function for
1466 // MIDI input.
1467 //
1468 // Thanks to Pedro Lopez-Cabanillas for help with the ALSA sequencer
1469 // time stamps and other assorted fixes!!!
1470 
1471 // If you don't need timestamping for incoming MIDI events, define the
1472 // preprocessor definition AVOID_TIMESTAMPING to save resources
1473 // associated with the ALSA sequencer queues.
1474 
1475 #include <pthread.h>
1476 #include <sys/time.h>
1477 
1478 // ALSA header file.
1479 #include <alsa/asoundlib.h>
1480 
1481 // A structure to hold variables related to the ALSA API
1482 // implementation.
1483 struct AlsaMidiData {
1484   snd_seq_t *seq;
1485   unsigned int portNum;
1486   int vport;
1487   snd_seq_port_subscribe_t *subscription;
1488   snd_midi_event_t *coder;
1489   unsigned int bufferSize;
1490   unsigned char *buffer;
1491   pthread_t thread;
1492   pthread_t dummy_thread_id;
1493   snd_seq_real_time_t lastTime;
1494   int queue_id; // an input queue is needed to get timestamped events
1495   int trigger_fds[2];
1496 };
1497 
1498 #define PORT_TYPE( pinfo, bits ) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
1499 
1500 //*********************************************************************//
1501 //  API: LINUX ALSA
1502 //  Class Definitions: MidiInAlsa
1503 //*********************************************************************//
1504 
alsaMidiHandler(void * ptr)1505 static void *alsaMidiHandler( void *ptr )
1506 {
1507   MidiInApi::RtMidiInData *data = static_cast<MidiInApi::RtMidiInData *> (ptr);
1508   AlsaMidiData *apiData = static_cast<AlsaMidiData *> (data->apiData);
1509 
1510   long nBytes;
1511   double time;
1512   bool continueSysex = false;
1513   bool doDecode = false;
1514   MidiInApi::MidiMessage message;
1515   int poll_fd_count;
1516   struct pollfd *poll_fds;
1517 
1518   snd_seq_event_t *ev;
1519   int result;
1520   apiData->bufferSize = 32;
1521   result = snd_midi_event_new( 0, &apiData->coder );
1522   if ( result < 0 ) {
1523     data->doInput = false;
1524     std::cerr << "\nMidiInAlsa::alsaMidiHandler: error initializing MIDI event parser!\n\n";
1525     return 0;
1526   }
1527   unsigned char *buffer = (unsigned char *) malloc( apiData->bufferSize );
1528   if ( buffer == NULL ) {
1529     data->doInput = false;
1530     snd_midi_event_free( apiData->coder );
1531     apiData->coder = 0;
1532     std::cerr << "\nMidiInAlsa::alsaMidiHandler: error initializing buffer memory!\n\n";
1533     return 0;
1534   }
1535   snd_midi_event_init( apiData->coder );
1536   snd_midi_event_no_status( apiData->coder, 1 ); // suppress running status messages
1537 
1538   poll_fd_count = snd_seq_poll_descriptors_count( apiData->seq, POLLIN ) + 1;
1539   poll_fds = (struct pollfd*)alloca( poll_fd_count * sizeof( struct pollfd ));
1540   snd_seq_poll_descriptors( apiData->seq, poll_fds + 1, poll_fd_count - 1, POLLIN );
1541   poll_fds[0].fd = apiData->trigger_fds[0];
1542   poll_fds[0].events = POLLIN;
1543 
1544   while ( data->doInput ) {
1545 
1546     if ( snd_seq_event_input_pending( apiData->seq, 1 ) == 0 ) {
1547       // No data pending
1548       if ( poll( poll_fds, poll_fd_count, -1) >= 0 ) {
1549         if ( poll_fds[0].revents & POLLIN ) {
1550           bool dummy;
1551           int res = read( poll_fds[0].fd, &dummy, sizeof(dummy) );
1552           (void) res;
1553         }
1554       }
1555       continue;
1556     }
1557 
1558     // If here, there should be data.
1559     result = snd_seq_event_input( apiData->seq, &ev );
1560     if ( result == -ENOSPC ) {
1561       std::cerr << "\nMidiInAlsa::alsaMidiHandler: MIDI input buffer overrun!\n\n";
1562       continue;
1563     }
1564     else if ( result <= 0 ) {
1565       std::cerr << "\nMidiInAlsa::alsaMidiHandler: unknown MIDI input error!\n";
1566       perror("System reports");
1567       continue;
1568     }
1569 
1570     // This is a bit weird, but we now have to decode an ALSA MIDI
1571     // event (back) into MIDI bytes.  We'll ignore non-MIDI types.
1572     if ( !continueSysex ) message.bytes.clear();
1573 
1574     doDecode = false;
1575     switch ( ev->type ) {
1576 
1577     case SND_SEQ_EVENT_PORT_SUBSCRIBED:
1578 #if defined(__RTMIDI_DEBUG__)
1579       std::cout << "MidiInAlsa::alsaMidiHandler: port connection made!\n";
1580 #endif
1581       break;
1582 
1583     case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
1584 #if defined(__RTMIDI_DEBUG__)
1585       std::cerr << "MidiInAlsa::alsaMidiHandler: port connection has closed!\n";
1586       std::cout << "sender = " << (int) ev->data.connect.sender.client << ":"
1587                 << (int) ev->data.connect.sender.port
1588                 << ", dest = " << (int) ev->data.connect.dest.client << ":"
1589                 << (int) ev->data.connect.dest.port
1590                 << std::endl;
1591 #endif
1592       break;
1593 
1594     case SND_SEQ_EVENT_QFRAME: // MIDI time code
1595       if ( !( data->ignoreFlags & 0x02 ) ) doDecode = true;
1596       break;
1597 
1598     case SND_SEQ_EVENT_TICK: // 0xF9 ... MIDI timing tick
1599       if ( !( data->ignoreFlags & 0x02 ) ) doDecode = true;
1600       break;
1601 
1602     case SND_SEQ_EVENT_CLOCK: // 0xF8 ... MIDI timing (clock) tick
1603       if ( !( data->ignoreFlags & 0x02 ) ) doDecode = true;
1604       break;
1605 
1606     case SND_SEQ_EVENT_SENSING: // Active sensing
1607       if ( !( data->ignoreFlags & 0x04 ) ) doDecode = true;
1608       break;
1609 
1610     case SND_SEQ_EVENT_SYSEX:
1611       if ( (data->ignoreFlags & 0x01) ) break;
1612       if ( ev->data.ext.len > apiData->bufferSize ) {
1613         apiData->bufferSize = ev->data.ext.len;
1614         free( buffer );
1615         buffer = (unsigned char *) malloc( apiData->bufferSize );
1616         if ( buffer == NULL ) {
1617           data->doInput = false;
1618           std::cerr << "\nMidiInAlsa::alsaMidiHandler: error resizing buffer memory!\n\n";
1619           break;
1620         }
1621       }
1622       doDecode = true;
1623       break;
1624 
1625     default:
1626       doDecode = true;
1627     }
1628 
1629     if ( doDecode ) {
1630 
1631       nBytes = snd_midi_event_decode( apiData->coder, buffer, apiData->bufferSize, ev );
1632       if ( nBytes > 0 ) {
1633         // The ALSA sequencer has a maximum buffer size for MIDI sysex
1634         // events of 256 bytes.  If a device sends sysex messages larger
1635         // than this, they are segmented into 256 byte chunks.  So,
1636         // we'll watch for this and concatenate sysex chunks into a
1637         // single sysex message if necessary.
1638         if ( !continueSysex )
1639           message.bytes.assign( buffer, &buffer[nBytes] );
1640         else
1641           message.bytes.insert( message.bytes.end(), buffer, &buffer[nBytes] );
1642 
1643         continueSysex = ( ( ev->type == SND_SEQ_EVENT_SYSEX ) && ( message.bytes.back() != 0xF7 ) );
1644         if ( !continueSysex ) {
1645 
1646           // Calculate the time stamp:
1647           message.timeStamp = 0.0;
1648 
1649           // Method 1: Use the system time.
1650           //(void)gettimeofday(&tv, (struct timezone *)NULL);
1651           //time = (tv.tv_sec * 1000000) + tv.tv_usec;
1652 
1653           // Method 2: Use the ALSA sequencer event time data.
1654           // (thanks to Pedro Lopez-Cabanillas!).
1655 
1656           // Using method from:
1657           // https://www.gnu.org/software/libc/manual/html_node/Elapsed-Time.html
1658 
1659           // Perform the carry for the later subtraction by updating y.
1660           // Temp var y is timespec because computation requires signed types,
1661           // while snd_seq_real_time_t has unsigned types.
1662           snd_seq_real_time_t &x( ev->time.time );
1663           struct timespec y;
1664           y.tv_nsec = apiData->lastTime.tv_nsec;
1665           y.tv_sec = apiData->lastTime.tv_sec;
1666           if ( x.tv_nsec < y.tv_nsec ) {
1667               int nsec = (y.tv_nsec - (int)x.tv_nsec) / 1000000000 + 1;
1668               y.tv_nsec -= 1000000000 * nsec;
1669               y.tv_sec += nsec;
1670           }
1671           if ( x.tv_nsec - y.tv_nsec > 1000000000 ) {
1672               int nsec = ((int)x.tv_nsec - y.tv_nsec) / 1000000000;
1673               y.tv_nsec += 1000000000 * nsec;
1674               y.tv_sec -= nsec;
1675           }
1676 
1677           // Compute the time difference.
1678           time = (int)x.tv_sec - y.tv_sec + ((int)x.tv_nsec - y.tv_nsec)*1e-9;
1679 
1680           apiData->lastTime = ev->time.time;
1681 
1682           if ( data->firstMessage == true )
1683             data->firstMessage = false;
1684           else
1685             message.timeStamp = time;
1686         }
1687         else {
1688 #if defined(__RTMIDI_DEBUG__)
1689           std::cerr << "\nMidiInAlsa::alsaMidiHandler: event parsing error or not a MIDI event!\n\n";
1690 #endif
1691         }
1692       }
1693     }
1694 
1695     snd_seq_free_event( ev );
1696     if ( message.bytes.size() == 0 || continueSysex ) continue;
1697 
1698     if ( data->usingCallback ) {
1699       RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
1700       callback( message.timeStamp, &message.bytes, data->userData );
1701     }
1702     else {
1703       // As long as we haven't reached our queue size limit, push the message.
1704       if ( !data->queue.push( message ) )
1705         std::cerr << "\nMidiInAlsa: message queue limit reached!!\n\n";
1706     }
1707   }
1708 
1709   if ( buffer ) free( buffer );
1710   snd_midi_event_free( apiData->coder );
1711   apiData->coder = 0;
1712   apiData->thread = apiData->dummy_thread_id;
1713   return 0;
1714 }
1715 
MidiInAlsa(const std::string & clientName,unsigned int queueSizeLimit)1716 MidiInAlsa :: MidiInAlsa( const std::string &clientName, unsigned int queueSizeLimit )
1717   : MidiInApi( queueSizeLimit )
1718 {
1719   MidiInAlsa::initialize( clientName );
1720 }
1721 
~MidiInAlsa()1722 MidiInAlsa :: ~MidiInAlsa()
1723 {
1724   // Close a connection if it exists.
1725   MidiInAlsa::closePort();
1726 
1727   // Shutdown the input thread.
1728   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1729   if ( inputData_.doInput ) {
1730     inputData_.doInput = false;
1731     int res = write( data->trigger_fds[1], &inputData_.doInput, sizeof( inputData_.doInput ) );
1732     (void) res;
1733     if ( !pthread_equal(data->thread, data->dummy_thread_id) )
1734       pthread_join( data->thread, NULL );
1735   }
1736 
1737   // Cleanup.
1738   close ( data->trigger_fds[0] );
1739   close ( data->trigger_fds[1] );
1740   if ( data->vport >= 0 ) snd_seq_delete_port( data->seq, data->vport );
1741 #ifndef AVOID_TIMESTAMPING
1742   snd_seq_free_queue( data->seq, data->queue_id );
1743 #endif
1744   snd_seq_close( data->seq );
1745   delete data;
1746 }
1747 
initialize(const std::string & clientName)1748 void MidiInAlsa :: initialize( const std::string& clientName )
1749 {
1750   // Set up the ALSA sequencer client.
1751   snd_seq_t *seq;
1752   int result = snd_seq_open( &seq, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK );
1753   if ( result < 0 ) {
1754     errorString_ = "MidiInAlsa::initialize: error creating ALSA sequencer client object.";
1755     error( RtMidiError::DRIVER_ERROR, errorString_ );
1756     return;
1757   }
1758 
1759   // Set client name.
1760   snd_seq_set_client_name( seq, clientName.c_str() );
1761 
1762   // Save our api-specific connection information.
1763   AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
1764   data->seq = seq;
1765   data->portNum = -1;
1766   data->vport = -1;
1767   data->subscription = 0;
1768   data->dummy_thread_id = pthread_self();
1769   data->thread = data->dummy_thread_id;
1770   data->trigger_fds[0] = -1;
1771   data->trigger_fds[1] = -1;
1772   apiData_ = (void *) data;
1773   inputData_.apiData = (void *) data;
1774 
1775   if ( pipe(data->trigger_fds) == -1 ) {
1776     errorString_ = "MidiInAlsa::initialize: error creating pipe objects.";
1777     error( RtMidiError::DRIVER_ERROR, errorString_ );
1778     return;
1779   }
1780 
1781   // Create the input queue
1782 #ifndef AVOID_TIMESTAMPING
1783   data->queue_id = snd_seq_alloc_named_queue( seq, "RtMidi Queue" );
1784   // Set arbitrary tempo (mm=100) and resolution (240)
1785   snd_seq_queue_tempo_t *qtempo;
1786   snd_seq_queue_tempo_alloca( &qtempo );
1787   snd_seq_queue_tempo_set_tempo( qtempo, 600000 );
1788   snd_seq_queue_tempo_set_ppq( qtempo, 240 );
1789   snd_seq_set_queue_tempo( data->seq, data->queue_id, qtempo );
1790   snd_seq_drain_output( data->seq );
1791 #endif
1792 }
1793 
1794 // This function is used to count or get the pinfo structure for a given port number.
portInfo(snd_seq_t * seq,snd_seq_port_info_t * pinfo,unsigned int type,int portNumber)1795 unsigned int portInfo( snd_seq_t *seq, snd_seq_port_info_t *pinfo, unsigned int type, int portNumber )
1796 {
1797   snd_seq_client_info_t *cinfo;
1798   int client;
1799   int count = 0;
1800   snd_seq_client_info_alloca( &cinfo );
1801 
1802   snd_seq_client_info_set_client( cinfo, -1 );
1803   while ( snd_seq_query_next_client( seq, cinfo ) >= 0 ) {
1804     client = snd_seq_client_info_get_client( cinfo );
1805     if ( client == 0 ) continue;
1806     // Reset query info
1807     snd_seq_port_info_set_client( pinfo, client );
1808     snd_seq_port_info_set_port( pinfo, -1 );
1809     while ( snd_seq_query_next_port( seq, pinfo ) >= 0 ) {
1810       unsigned int atyp = snd_seq_port_info_get_type( pinfo );
1811       if ( ( ( atyp & SND_SEQ_PORT_TYPE_MIDI_GENERIC ) == 0 ) &&
1812            ( ( atyp & SND_SEQ_PORT_TYPE_SYNTH ) == 0 ) &&
1813            ( ( atyp & SND_SEQ_PORT_TYPE_APPLICATION ) == 0 ) ) continue;
1814 
1815       unsigned int caps = snd_seq_port_info_get_capability( pinfo );
1816       if ( ( caps & type ) != type ) continue;
1817       if ( count == portNumber ) return 1;
1818       ++count;
1819     }
1820   }
1821 
1822   // If a negative portNumber was used, return the port count.
1823   if ( portNumber < 0 ) return count;
1824   return 0;
1825 }
1826 
getPortCount()1827 unsigned int MidiInAlsa :: getPortCount()
1828 {
1829   snd_seq_port_info_t *pinfo;
1830   snd_seq_port_info_alloca( &pinfo );
1831 
1832   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1833   return portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, -1 );
1834 }
1835 
getPortName(unsigned int portNumber)1836 std::string MidiInAlsa :: getPortName( unsigned int portNumber )
1837 {
1838   snd_seq_client_info_t *cinfo;
1839   snd_seq_port_info_t *pinfo;
1840   snd_seq_client_info_alloca( &cinfo );
1841   snd_seq_port_info_alloca( &pinfo );
1842 
1843   std::string stringName;
1844   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1845   if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) ) {
1846     int cnum = snd_seq_port_info_get_client( pinfo );
1847     snd_seq_get_any_client_info( data->seq, cnum, cinfo );
1848     std::ostringstream os;
1849     os << snd_seq_client_info_get_name( cinfo );
1850     os << ":";
1851     os << snd_seq_port_info_get_name( pinfo );
1852     os << " ";                                    // These lines added to make sure devices are listed
1853     os << snd_seq_port_info_get_client( pinfo );  // with full portnames added to ensure individual device names
1854     os << ":";
1855     os << snd_seq_port_info_get_port( pinfo );
1856     stringName = os.str();
1857     return stringName;
1858   }
1859 
1860   // If we get here, we didn't find a match.
1861   errorString_ = "MidiInAlsa::getPortName: error looking for port name!";
1862   error( RtMidiError::WARNING, errorString_ );
1863   return stringName;
1864 }
1865 
openPort(unsigned int portNumber,const std::string & portName)1866 void MidiInAlsa :: openPort( unsigned int portNumber, const std::string &portName )
1867 {
1868   if ( connected_ ) {
1869     errorString_ = "MidiInAlsa::openPort: a valid connection already exists!";
1870     error( RtMidiError::WARNING, errorString_ );
1871     return;
1872   }
1873 
1874   unsigned int nSrc = this->getPortCount();
1875   if ( nSrc < 1 ) {
1876     errorString_ = "MidiInAlsa::openPort: no MIDI input sources found!";
1877     error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
1878     return;
1879   }
1880 
1881   snd_seq_port_info_t *src_pinfo;
1882   snd_seq_port_info_alloca( &src_pinfo );
1883   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1884   if ( portInfo( data->seq, src_pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) == 0 ) {
1885     std::ostringstream ost;
1886     ost << "MidiInAlsa::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
1887     errorString_ = ost.str();
1888     error( RtMidiError::INVALID_PARAMETER, errorString_ );
1889     return;
1890   }
1891 
1892   snd_seq_addr_t sender, receiver;
1893   sender.client = snd_seq_port_info_get_client( src_pinfo );
1894   sender.port = snd_seq_port_info_get_port( src_pinfo );
1895   receiver.client = snd_seq_client_id( data->seq );
1896 
1897   snd_seq_port_info_t *pinfo;
1898   snd_seq_port_info_alloca( &pinfo );
1899   if ( data->vport < 0 ) {
1900     snd_seq_port_info_set_client( pinfo, 0 );
1901     snd_seq_port_info_set_port( pinfo, 0 );
1902     snd_seq_port_info_set_capability( pinfo,
1903                                       SND_SEQ_PORT_CAP_WRITE |
1904                                       SND_SEQ_PORT_CAP_SUBS_WRITE );
1905     snd_seq_port_info_set_type( pinfo,
1906                                 SND_SEQ_PORT_TYPE_MIDI_GENERIC |
1907                                 SND_SEQ_PORT_TYPE_APPLICATION );
1908     snd_seq_port_info_set_midi_channels(pinfo, 16);
1909 #ifndef AVOID_TIMESTAMPING
1910     snd_seq_port_info_set_timestamping( pinfo, 1 );
1911     snd_seq_port_info_set_timestamp_real( pinfo, 1 );
1912     snd_seq_port_info_set_timestamp_queue( pinfo, data->queue_id );
1913 #endif
1914     snd_seq_port_info_set_name( pinfo,  portName.c_str() );
1915     data->vport = snd_seq_create_port( data->seq, pinfo );
1916 
1917     if ( data->vport < 0 ) {
1918       errorString_ = "MidiInAlsa::openPort: ALSA error creating input port.";
1919       error( RtMidiError::DRIVER_ERROR, errorString_ );
1920       return;
1921     }
1922     data->vport = snd_seq_port_info_get_port( pinfo );
1923   }
1924 
1925   receiver.port = data->vport;
1926 
1927   if ( !data->subscription ) {
1928     // Make subscription
1929     if ( snd_seq_port_subscribe_malloc( &data->subscription ) < 0 ) {
1930       errorString_ = "MidiInAlsa::openPort: ALSA error allocation port subscription.";
1931       error( RtMidiError::DRIVER_ERROR, errorString_ );
1932       return;
1933     }
1934     snd_seq_port_subscribe_set_sender( data->subscription, &sender );
1935     snd_seq_port_subscribe_set_dest( data->subscription, &receiver );
1936     if ( snd_seq_subscribe_port( data->seq, data->subscription ) ) {
1937       snd_seq_port_subscribe_free( data->subscription );
1938       data->subscription = 0;
1939       errorString_ = "MidiInAlsa::openPort: ALSA error making port connection.";
1940       error( RtMidiError::DRIVER_ERROR, errorString_ );
1941       return;
1942     }
1943   }
1944 
1945   if ( inputData_.doInput == false ) {
1946     // Start the input queue
1947 #ifndef AVOID_TIMESTAMPING
1948     snd_seq_start_queue( data->seq, data->queue_id, NULL );
1949     snd_seq_drain_output( data->seq );
1950 #endif
1951     // Start our MIDI input thread.
1952     pthread_attr_t attr;
1953     pthread_attr_init( &attr );
1954     pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
1955     pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
1956 
1957     inputData_.doInput = true;
1958     int err = pthread_create( &data->thread, &attr, alsaMidiHandler, &inputData_ );
1959     pthread_attr_destroy( &attr );
1960     if ( err ) {
1961       snd_seq_unsubscribe_port( data->seq, data->subscription );
1962       snd_seq_port_subscribe_free( data->subscription );
1963       data->subscription = 0;
1964       inputData_.doInput = false;
1965       errorString_ = "MidiInAlsa::openPort: error starting MIDI input thread!";
1966       error( RtMidiError::THREAD_ERROR, errorString_ );
1967       return;
1968     }
1969   }
1970 
1971   connected_ = true;
1972 }
1973 
openVirtualPort(const std::string & portName)1974 void MidiInAlsa :: openVirtualPort( const std::string &portName )
1975 {
1976   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1977   if ( data->vport < 0 ) {
1978     snd_seq_port_info_t *pinfo;
1979     snd_seq_port_info_alloca( &pinfo );
1980     snd_seq_port_info_set_capability( pinfo,
1981                                       SND_SEQ_PORT_CAP_WRITE |
1982                                       SND_SEQ_PORT_CAP_SUBS_WRITE );
1983     snd_seq_port_info_set_type( pinfo,
1984                                 SND_SEQ_PORT_TYPE_MIDI_GENERIC |
1985                                 SND_SEQ_PORT_TYPE_APPLICATION );
1986     snd_seq_port_info_set_midi_channels( pinfo, 16 );
1987 #ifndef AVOID_TIMESTAMPING
1988     snd_seq_port_info_set_timestamping( pinfo, 1 );
1989     snd_seq_port_info_set_timestamp_real( pinfo, 1 );
1990     snd_seq_port_info_set_timestamp_queue( pinfo, data->queue_id );
1991 #endif
1992     snd_seq_port_info_set_name( pinfo, portName.c_str() );
1993     data->vport = snd_seq_create_port( data->seq, pinfo );
1994 
1995     if ( data->vport < 0 ) {
1996       errorString_ = "MidiInAlsa::openVirtualPort: ALSA error creating virtual port.";
1997       error( RtMidiError::DRIVER_ERROR, errorString_ );
1998       return;
1999     }
2000     data->vport = snd_seq_port_info_get_port( pinfo );
2001   }
2002 
2003   if ( inputData_.doInput == false ) {
2004     // Wait for old thread to stop, if still running
2005     if ( !pthread_equal( data->thread, data->dummy_thread_id ) )
2006       pthread_join( data->thread, NULL );
2007 
2008     // Start the input queue
2009 #ifndef AVOID_TIMESTAMPING
2010     snd_seq_start_queue( data->seq, data->queue_id, NULL );
2011     snd_seq_drain_output( data->seq );
2012 #endif
2013     // Start our MIDI input thread.
2014     pthread_attr_t attr;
2015     pthread_attr_init( &attr );
2016     pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
2017     pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
2018 
2019     inputData_.doInput = true;
2020     int err = pthread_create( &data->thread, &attr, alsaMidiHandler, &inputData_ );
2021     pthread_attr_destroy( &attr );
2022     if ( err ) {
2023       if ( data->subscription ) {
2024         snd_seq_unsubscribe_port( data->seq, data->subscription );
2025         snd_seq_port_subscribe_free( data->subscription );
2026         data->subscription = 0;
2027       }
2028       inputData_.doInput = false;
2029       errorString_ = "MidiInAlsa::openPort: error starting MIDI input thread!";
2030       error( RtMidiError::THREAD_ERROR, errorString_ );
2031       return;
2032     }
2033   }
2034 }
2035 
closePort(void)2036 void MidiInAlsa :: closePort( void )
2037 {
2038   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
2039 
2040   if ( connected_ ) {
2041     if ( data->subscription ) {
2042       snd_seq_unsubscribe_port( data->seq, data->subscription );
2043       snd_seq_port_subscribe_free( data->subscription );
2044       data->subscription = 0;
2045     }
2046     // Stop the input queue
2047 #ifndef AVOID_TIMESTAMPING
2048     snd_seq_stop_queue( data->seq, data->queue_id, NULL );
2049     snd_seq_drain_output( data->seq );
2050 #endif
2051     connected_ = false;
2052   }
2053 
2054   // Stop thread to avoid triggering the callback, while the port is intended to be closed
2055   if ( inputData_.doInput ) {
2056     inputData_.doInput = false;
2057     int res = write( data->trigger_fds[1], &inputData_.doInput, sizeof( inputData_.doInput ) );
2058     (void) res;
2059     if ( !pthread_equal( data->thread, data->dummy_thread_id ) )
2060       pthread_join( data->thread, NULL );
2061   }
2062 }
2063 
setClientName(const std::string & clientName)2064 void MidiInAlsa :: setClientName( const std::string &clientName )
2065 {
2066 
2067   AlsaMidiData *data = static_cast<AlsaMidiData *> ( apiData_ );
2068   snd_seq_set_client_name( data->seq, clientName.c_str() );
2069 
2070 }
2071 
setPortName(const std::string & portName)2072 void MidiInAlsa :: setPortName( const std::string &portName )
2073 {
2074   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
2075   snd_seq_port_info_t *pinfo;
2076   snd_seq_port_info_alloca( &pinfo );
2077   snd_seq_get_port_info( data->seq, data->vport, pinfo );
2078   snd_seq_port_info_set_name( pinfo, portName.c_str() );
2079   snd_seq_set_port_info( data->seq, data->vport, pinfo );
2080 }
2081 
2082 //*********************************************************************//
2083 //  API: LINUX ALSA
2084 //  Class Definitions: MidiOutAlsa
2085 //*********************************************************************//
2086 
MidiOutAlsa(const std::string & clientName)2087 MidiOutAlsa :: MidiOutAlsa( const std::string &clientName ) : MidiOutApi()
2088 {
2089   MidiOutAlsa::initialize( clientName );
2090 }
2091 
~MidiOutAlsa()2092 MidiOutAlsa :: ~MidiOutAlsa()
2093 {
2094   // Close a connection if it exists.
2095   MidiOutAlsa::closePort();
2096 
2097   // Cleanup.
2098   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
2099   if ( data->vport >= 0 ) snd_seq_delete_port( data->seq, data->vport );
2100   if ( data->coder ) snd_midi_event_free( data->coder );
2101   if ( data->buffer ) free( data->buffer );
2102   snd_seq_close( data->seq );
2103   delete data;
2104 }
2105 
initialize(const std::string & clientName)2106 void MidiOutAlsa :: initialize( const std::string& clientName )
2107 {
2108   // Set up the ALSA sequencer client.
2109   snd_seq_t *seq;
2110   int result1 = snd_seq_open( &seq, "default", SND_SEQ_OPEN_OUTPUT, SND_SEQ_NONBLOCK );
2111   if ( result1 < 0 ) {
2112     errorString_ = "MidiOutAlsa::initialize: error creating ALSA sequencer client object.";
2113     error( RtMidiError::DRIVER_ERROR, errorString_ );
2114     return;
2115   }
2116 
2117   // Set client name.
2118   snd_seq_set_client_name( seq, clientName.c_str() );
2119 
2120   // Save our api-specific connection information.
2121   AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
2122   data->seq = seq;
2123   data->portNum = -1;
2124   data->vport = -1;
2125   data->bufferSize = 32;
2126   data->coder = 0;
2127   data->buffer = 0;
2128   int result = snd_midi_event_new( data->bufferSize, &data->coder );
2129   if ( result < 0 ) {
2130     delete data;
2131     errorString_ = "MidiOutAlsa::initialize: error initializing MIDI event parser!\n\n";
2132     error( RtMidiError::DRIVER_ERROR, errorString_ );
2133     return;
2134   }
2135   data->buffer = (unsigned char *) malloc( data->bufferSize );
2136   if ( data->buffer == NULL ) {
2137     delete data;
2138     errorString_ = "MidiOutAlsa::initialize: error allocating buffer memory!\n\n";
2139     error( RtMidiError::MEMORY_ERROR, errorString_ );
2140     return;
2141   }
2142   snd_midi_event_init( data->coder );
2143   apiData_ = (void *) data;
2144 }
2145 
getPortCount()2146 unsigned int MidiOutAlsa :: getPortCount()
2147 {
2148   snd_seq_port_info_t *pinfo;
2149   snd_seq_port_info_alloca( &pinfo );
2150 
2151   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
2152   return portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, -1 );
2153 }
2154 
getPortName(unsigned int portNumber)2155 std::string MidiOutAlsa :: getPortName( unsigned int portNumber )
2156 {
2157   snd_seq_client_info_t *cinfo;
2158   snd_seq_port_info_t *pinfo;
2159   snd_seq_client_info_alloca( &cinfo );
2160   snd_seq_port_info_alloca( &pinfo );
2161 
2162   std::string stringName;
2163   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
2164   if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) ) {
2165     int cnum = snd_seq_port_info_get_client( pinfo );
2166     snd_seq_get_any_client_info( data->seq, cnum, cinfo );
2167     std::ostringstream os;
2168     os << snd_seq_client_info_get_name( cinfo );
2169     os << ":";
2170     os << snd_seq_port_info_get_name( pinfo );
2171     os << " ";                                    // These lines added to make sure devices are listed
2172     os << snd_seq_port_info_get_client( pinfo );  // with full portnames added to ensure individual device names
2173     os << ":";
2174     os << snd_seq_port_info_get_port( pinfo );
2175     stringName = os.str();
2176     return stringName;
2177   }
2178 
2179   // If we get here, we didn't find a match.
2180   errorString_ = "MidiOutAlsa::getPortName: error looking for port name!";
2181   error( RtMidiError::WARNING, errorString_ );
2182   return stringName;
2183 }
2184 
openPort(unsigned int portNumber,const std::string & portName)2185 void MidiOutAlsa :: openPort( unsigned int portNumber, const std::string &portName )
2186 {
2187   if ( connected_ ) {
2188     errorString_ = "MidiOutAlsa::openPort: a valid connection already exists!";
2189     error( RtMidiError::WARNING, errorString_ );
2190     return;
2191   }
2192 
2193   unsigned int nSrc = this->getPortCount();
2194   if ( nSrc < 1 ) {
2195     errorString_ = "MidiOutAlsa::openPort: no MIDI output sources found!";
2196     error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
2197     return;
2198   }
2199 
2200   snd_seq_port_info_t *pinfo;
2201   snd_seq_port_info_alloca( &pinfo );
2202   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
2203   if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) == 0 ) {
2204     std::ostringstream ost;
2205     ost << "MidiOutAlsa::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
2206     errorString_ = ost.str();
2207     error( RtMidiError::INVALID_PARAMETER, errorString_ );
2208     return;
2209   }
2210 
2211   snd_seq_addr_t sender, receiver;
2212   receiver.client = snd_seq_port_info_get_client( pinfo );
2213   receiver.port = snd_seq_port_info_get_port( pinfo );
2214   sender.client = snd_seq_client_id( data->seq );
2215 
2216   if ( data->vport < 0 ) {
2217     data->vport = snd_seq_create_simple_port( data->seq, portName.c_str(),
2218                                               SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
2219                                               SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_APPLICATION );
2220     if ( data->vport < 0 ) {
2221       errorString_ = "MidiOutAlsa::openPort: ALSA error creating output port.";
2222       error( RtMidiError::DRIVER_ERROR, errorString_ );
2223       return;
2224     }
2225   }
2226 
2227   sender.port = data->vport;
2228 
2229   // Make subscription
2230   if ( snd_seq_port_subscribe_malloc( &data->subscription ) < 0 ) {
2231     snd_seq_port_subscribe_free( data->subscription );
2232     errorString_ = "MidiOutAlsa::openPort: error allocating port subscription.";
2233     error( RtMidiError::DRIVER_ERROR, errorString_ );
2234     return;
2235   }
2236   snd_seq_port_subscribe_set_sender( data->subscription, &sender );
2237   snd_seq_port_subscribe_set_dest( data->subscription, &receiver );
2238   snd_seq_port_subscribe_set_time_update( data->subscription, 1 );
2239   snd_seq_port_subscribe_set_time_real( data->subscription, 1 );
2240   if ( snd_seq_subscribe_port( data->seq, data->subscription ) ) {
2241     snd_seq_port_subscribe_free( data->subscription );
2242     errorString_ = "MidiOutAlsa::openPort: ALSA error making port connection.";
2243     error( RtMidiError::DRIVER_ERROR, errorString_ );
2244     return;
2245   }
2246 
2247   connected_ = true;
2248 }
2249 
closePort(void)2250 void MidiOutAlsa :: closePort( void )
2251 {
2252   if ( connected_ ) {
2253     AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
2254     snd_seq_unsubscribe_port( data->seq, data->subscription );
2255     snd_seq_port_subscribe_free( data->subscription );
2256     data->subscription = 0;
2257     connected_ = false;
2258   }
2259 }
2260 
setClientName(const std::string & clientName)2261 void MidiOutAlsa :: setClientName( const std::string &clientName )
2262 {
2263 
2264     AlsaMidiData *data = static_cast<AlsaMidiData *> ( apiData_ );
2265     snd_seq_set_client_name( data->seq, clientName.c_str() );
2266 
2267 }
2268 
setPortName(const std::string & portName)2269 void MidiOutAlsa :: setPortName( const std::string &portName )
2270 {
2271   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
2272   snd_seq_port_info_t *pinfo;
2273   snd_seq_port_info_alloca( &pinfo );
2274   snd_seq_get_port_info( data->seq, data->vport, pinfo );
2275   snd_seq_port_info_set_name( pinfo, portName.c_str() );
2276   snd_seq_set_port_info( data->seq, data->vport, pinfo );
2277 }
2278 
openVirtualPort(const std::string & portName)2279 void MidiOutAlsa :: openVirtualPort( const std::string &portName )
2280 {
2281   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
2282   if ( data->vport < 0 ) {
2283     data->vport = snd_seq_create_simple_port( data->seq, portName.c_str(),
2284                                               SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
2285                                               SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_APPLICATION );
2286 
2287     if ( data->vport < 0 ) {
2288       errorString_ = "MidiOutAlsa::openVirtualPort: ALSA error creating virtual port.";
2289       error( RtMidiError::DRIVER_ERROR, errorString_ );
2290     }
2291   }
2292 }
2293 
sendMessage(const unsigned char * message,size_t size)2294 void MidiOutAlsa :: sendMessage( const unsigned char *message, size_t size )
2295 {
2296   int result;
2297   AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
2298   unsigned int nBytes = static_cast<unsigned int> (size);
2299   if ( nBytes > data->bufferSize ) {
2300     data->bufferSize = nBytes;
2301     result = snd_midi_event_resize_buffer( data->coder, nBytes );
2302     if ( result != 0 ) {
2303       errorString_ = "MidiOutAlsa::sendMessage: ALSA error resizing MIDI event buffer.";
2304       error( RtMidiError::DRIVER_ERROR, errorString_ );
2305       return;
2306     }
2307     free (data->buffer);
2308     data->buffer = (unsigned char *) malloc( data->bufferSize );
2309     if ( data->buffer == NULL ) {
2310       errorString_ = "MidiOutAlsa::initialize: error allocating buffer memory!\n\n";
2311       error( RtMidiError::MEMORY_ERROR, errorString_ );
2312       return;
2313     }
2314   }
2315 
2316   snd_seq_event_t ev;
2317   snd_seq_ev_clear( &ev );
2318   snd_seq_ev_set_source( &ev, data->vport );
2319   snd_seq_ev_set_subs( &ev );
2320   snd_seq_ev_set_direct( &ev );
2321   for ( unsigned int i=0; i<nBytes; ++i ) data->buffer[i] = message[i];
2322   result = snd_midi_event_encode( data->coder, data->buffer, (long)nBytes, &ev );
2323   if ( result < (int)nBytes ) {
2324     errorString_ = "MidiOutAlsa::sendMessage: event parsing error!";
2325     error( RtMidiError::WARNING, errorString_ );
2326     return;
2327   }
2328 
2329   // Send the event.
2330   result = snd_seq_event_output( data->seq, &ev );
2331   if ( result < 0 ) {
2332     errorString_ = "MidiOutAlsa::sendMessage: error sending MIDI message to port.";
2333     error( RtMidiError::WARNING, errorString_ );
2334     return;
2335   }
2336   snd_seq_drain_output( data->seq );
2337 }
2338 
2339 #endif // __LINUX_ALSA__
2340 
2341 
2342 //*********************************************************************//
2343 //  API: Windows Multimedia Library (MM)
2344 //*********************************************************************//
2345 
2346 // API information deciphered from:
2347 //  - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_midi_reference.asp
2348 
2349 // Thanks to Jean-Baptiste Berruchon for the sysex code.
2350 
2351 #if defined(__WINDOWS_MM__)
2352 
2353 // The Windows MM API is based on the use of a callback function for
2354 // MIDI input.  We convert the system specific time stamps to delta
2355 // time values.
2356 
2357 // Windows MM MIDI header files.
2358 #include <windows.h>
2359 #include <mmsystem.h>
2360 
2361 // Convert a null-terminated wide string or ANSI-encoded string to UTF-8.
ConvertToUTF8(const TCHAR * str)2362 static std::string ConvertToUTF8(const TCHAR *str)
2363 {
2364   std::string u8str;
2365   const WCHAR *wstr = L"";
2366 #if defined( UNICODE ) || defined( _UNICODE )
2367   wstr = str;
2368 #else
2369   // Convert from ANSI encoding to wide string
2370   int wlength = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
2371   std::wstring wstrtemp;
2372   if ( wlength )
2373   {
2374     wstrtemp.assign( wlength - 1, 0 );
2375     MultiByteToWideChar( CP_ACP, 0, str, -1, &wstrtemp[0], wlength );
2376     wstr = &wstrtemp[0];
2377   }
2378 #endif
2379   // Convert from wide string to UTF-8
2380   int length = WideCharToMultiByte( CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL );
2381   if ( length )
2382   {
2383     u8str.assign( length - 1, 0 );
2384     length = WideCharToMultiByte( CP_UTF8, 0, wstr, -1, &u8str[0], length, NULL, NULL );
2385   }
2386   return u8str;
2387 }
2388 
2389 #define  RT_SYSEX_BUFFER_SIZE 1024
2390 #define  RT_SYSEX_BUFFER_COUNT 4
2391 
2392 // A structure to hold variables related to the CoreMIDI API
2393 // implementation.
2394 struct WinMidiData {
2395   HMIDIIN inHandle;    // Handle to Midi Input Device
2396   HMIDIOUT outHandle;  // Handle to Midi Output Device
2397   DWORD lastTime;
2398   MidiInApi::MidiMessage message;
2399   LPMIDIHDR sysexBuffer[RT_SYSEX_BUFFER_COUNT];
2400   CRITICAL_SECTION _mutex; // [Patrice] see https://groups.google.com/forum/#!topic/mididev/6OUjHutMpEo
2401 };
2402 
2403 //*********************************************************************//
2404 //  API: Windows MM
2405 //  Class Definitions: MidiInWinMM
2406 //*********************************************************************//
2407 
midiInputCallback(HMIDIIN,UINT inputStatus,DWORD_PTR instancePtr,DWORD_PTR midiMessage,DWORD timestamp)2408 static void CALLBACK midiInputCallback( HMIDIIN /*hmin*/,
2409                                         UINT inputStatus,
2410                                         DWORD_PTR instancePtr,
2411                                         DWORD_PTR midiMessage,
2412                                         DWORD timestamp )
2413 {
2414   if ( inputStatus != MIM_DATA && inputStatus != MIM_LONGDATA && inputStatus != MIM_LONGERROR ) return;
2415 
2416   //MidiInApi::RtMidiInData *data = static_cast<MidiInApi::RtMidiInData *> (instancePtr);
2417   MidiInApi::RtMidiInData *data = (MidiInApi::RtMidiInData *)instancePtr;
2418   WinMidiData *apiData = static_cast<WinMidiData *> (data->apiData);
2419 
2420   // Calculate time stamp.
2421   if ( data->firstMessage == true ) {
2422     apiData->message.timeStamp = 0.0;
2423     data->firstMessage = false;
2424   }
2425   else apiData->message.timeStamp = (double) ( timestamp - apiData->lastTime ) * 0.001;
2426 
2427   if ( inputStatus == MIM_DATA ) { // Channel or system message
2428 
2429     // Make sure the first byte is a status byte.
2430     unsigned char status = (unsigned char) (midiMessage & 0x000000FF);
2431     if ( !(status & 0x80) ) return;
2432 
2433     // Determine the number of bytes in the MIDI message.
2434     unsigned short nBytes = 1;
2435     if ( status < 0xC0 ) nBytes = 3;
2436     else if ( status < 0xE0 ) nBytes = 2;
2437     else if ( status < 0xF0 ) nBytes = 3;
2438     else if ( status == 0xF1 ) {
2439       if ( data->ignoreFlags & 0x02 ) return;
2440       else nBytes = 2;
2441     }
2442     else if ( status == 0xF2 ) nBytes = 3;
2443     else if ( status == 0xF3 ) nBytes = 2;
2444     else if ( status == 0xF8 && ( data->ignoreFlags & 0x02 ) ) {
2445       // A MIDI timing tick message and we're ignoring it.
2446       return;
2447     }
2448     else if ( status == 0xFE && ( data->ignoreFlags & 0x04 ) ) {
2449       // A MIDI active sensing message and we're ignoring it.
2450       return;
2451     }
2452 
2453     // Copy bytes to our MIDI message.
2454     unsigned char *ptr = (unsigned char *) &midiMessage;
2455     for ( int i=0; i<nBytes; ++i ) apiData->message.bytes.push_back( *ptr++ );
2456   }
2457   else { // Sysex message ( MIM_LONGDATA or MIM_LONGERROR )
2458     MIDIHDR *sysex = ( MIDIHDR *) midiMessage;
2459     if ( !( data->ignoreFlags & 0x01 ) && inputStatus != MIM_LONGERROR ) {
2460       // Sysex message and we're not ignoring it
2461       for ( int i=0; i<(int)sysex->dwBytesRecorded; ++i )
2462         apiData->message.bytes.push_back( sysex->lpData[i] );
2463     }
2464 
2465     // The WinMM API requires that the sysex buffer be requeued after
2466     // input of each sysex message.  Even if we are ignoring sysex
2467     // messages, we still need to requeue the buffer in case the user
2468     // decides to not ignore sysex messages in the future.  However,
2469     // it seems that WinMM calls this function with an empty sysex
2470     // buffer when an application closes and in this case, we should
2471     // avoid requeueing it, else the computer suddenly reboots after
2472     // one or two minutes.
2473     if ( apiData->sysexBuffer[sysex->dwUser]->dwBytesRecorded > 0 ) {
2474       //if ( sysex->dwBytesRecorded > 0 ) {
2475       EnterCriticalSection( &(apiData->_mutex) );
2476       MMRESULT result = midiInAddBuffer( apiData->inHandle, apiData->sysexBuffer[sysex->dwUser], sizeof(MIDIHDR) );
2477       LeaveCriticalSection( &(apiData->_mutex) );
2478       if ( result != MMSYSERR_NOERROR )
2479         std::cerr << "\nRtMidiIn::midiInputCallback: error sending sysex to Midi device!!\n\n";
2480 
2481       if ( data->ignoreFlags & 0x01 ) return;
2482     }
2483     else return;
2484   }
2485 
2486   // Save the time of the last non-filtered message
2487   apiData->lastTime = timestamp;
2488 
2489   if ( data->usingCallback ) {
2490     RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
2491     callback( apiData->message.timeStamp, &apiData->message.bytes, data->userData );
2492   }
2493   else {
2494     // As long as we haven't reached our queue size limit, push the message.
2495     if ( !data->queue.push( apiData->message ) )
2496       std::cerr << "\nMidiInWinMM: message queue limit reached!!\n\n";
2497   }
2498 
2499   // Clear the vector for the next input message.
2500   apiData->message.bytes.clear();
2501 }
2502 
MidiInWinMM(const std::string & clientName,unsigned int queueSizeLimit)2503 MidiInWinMM :: MidiInWinMM( const std::string &clientName, unsigned int queueSizeLimit )
2504   : MidiInApi( queueSizeLimit )
2505 {
2506   MidiInWinMM::initialize( clientName );
2507 }
2508 
~MidiInWinMM()2509 MidiInWinMM :: ~MidiInWinMM()
2510 {
2511   // Close a connection if it exists.
2512   MidiInWinMM::closePort();
2513 
2514   WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2515   DeleteCriticalSection( &(data->_mutex) );
2516 
2517   // Cleanup.
2518   delete data;
2519 }
2520 
initialize(const std::string &)2521 void MidiInWinMM :: initialize( const std::string& /*clientName*/ )
2522 {
2523   // We'll issue a warning here if no devices are available but not
2524   // throw an error since the user can plugin something later.
2525   unsigned int nDevices = midiInGetNumDevs();
2526   if ( nDevices == 0 ) {
2527     errorString_ = "MidiInWinMM::initialize: no MIDI input devices currently available.";
2528     error( RtMidiError::WARNING, errorString_ );
2529   }
2530 
2531   // Save our api-specific connection information.
2532   WinMidiData *data = (WinMidiData *) new WinMidiData;
2533   apiData_ = (void *) data;
2534   inputData_.apiData = (void *) data;
2535   data->message.bytes.clear();  // needs to be empty for first input message
2536 
2537   if ( !InitializeCriticalSectionAndSpinCount( &(data->_mutex), 0x00000400 ) ) {
2538     errorString_ = "MidiInWinMM::initialize: InitializeCriticalSectionAndSpinCount failed.";
2539     error( RtMidiError::WARNING, errorString_ );
2540   }
2541 }
2542 
openPort(unsigned int portNumber,const std::string &)2543 void MidiInWinMM :: openPort( unsigned int portNumber, const std::string &/*portName*/ )
2544 {
2545   if ( connected_ ) {
2546     errorString_ = "MidiInWinMM::openPort: a valid connection already exists!";
2547     error( RtMidiError::WARNING, errorString_ );
2548     return;
2549   }
2550 
2551   unsigned int nDevices = midiInGetNumDevs();
2552   if (nDevices == 0) {
2553     errorString_ = "MidiInWinMM::openPort: no MIDI input sources found!";
2554     error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
2555     return;
2556   }
2557 
2558   if ( portNumber >= nDevices ) {
2559     std::ostringstream ost;
2560     ost << "MidiInWinMM::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
2561     errorString_ = ost.str();
2562     error( RtMidiError::INVALID_PARAMETER, errorString_ );
2563     return;
2564   }
2565 
2566   WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2567   MMRESULT result = midiInOpen( &data->inHandle,
2568                                 portNumber,
2569                                 (DWORD_PTR)&midiInputCallback,
2570                                 (DWORD_PTR)&inputData_,
2571                                 CALLBACK_FUNCTION );
2572   if ( result != MMSYSERR_NOERROR ) {
2573     errorString_ = "MidiInWinMM::openPort: error creating Windows MM MIDI input port.";
2574     error( RtMidiError::DRIVER_ERROR, errorString_ );
2575     return;
2576   }
2577 
2578   // Allocate and init the sysex buffers.
2579   for ( int i=0; i<RT_SYSEX_BUFFER_COUNT; ++i ) {
2580     data->sysexBuffer[i] = (MIDIHDR*) new char[ sizeof(MIDIHDR) ];
2581     data->sysexBuffer[i]->lpData = new char[ RT_SYSEX_BUFFER_SIZE ];
2582     data->sysexBuffer[i]->dwBufferLength = RT_SYSEX_BUFFER_SIZE;
2583     data->sysexBuffer[i]->dwUser = i; // We use the dwUser parameter as buffer indicator
2584     data->sysexBuffer[i]->dwFlags = 0;
2585 
2586     result = midiInPrepareHeader( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) );
2587     if ( result != MMSYSERR_NOERROR ) {
2588       midiInClose( data->inHandle );
2589       data->inHandle = 0;
2590       errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port (PrepareHeader).";
2591       error( RtMidiError::DRIVER_ERROR, errorString_ );
2592       return;
2593     }
2594 
2595     // Register the buffer.
2596     result = midiInAddBuffer( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) );
2597     if ( result != MMSYSERR_NOERROR ) {
2598       midiInClose( data->inHandle );
2599       data->inHandle = 0;
2600       errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port (AddBuffer).";
2601       error( RtMidiError::DRIVER_ERROR, errorString_ );
2602       return;
2603     }
2604   }
2605 
2606   result = midiInStart( data->inHandle );
2607   if ( result != MMSYSERR_NOERROR ) {
2608     midiInClose( data->inHandle );
2609     data->inHandle = 0;
2610     errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port.";
2611     error( RtMidiError::DRIVER_ERROR, errorString_ );
2612     return;
2613   }
2614 
2615   connected_ = true;
2616 }
2617 
openVirtualPort(const std::string &)2618 void MidiInWinMM :: openVirtualPort( const std::string &/*portName*/ )
2619 {
2620   // This function cannot be implemented for the Windows MM MIDI API.
2621   errorString_ = "MidiInWinMM::openVirtualPort: cannot be implemented in Windows MM MIDI API!";
2622   error( RtMidiError::WARNING, errorString_ );
2623 }
2624 
closePort(void)2625 void MidiInWinMM :: closePort( void )
2626 {
2627   if ( connected_ ) {
2628     WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2629     EnterCriticalSection( &(data->_mutex) );
2630     midiInReset( data->inHandle );
2631     midiInStop( data->inHandle );
2632 
2633     for ( int i=0; i<RT_SYSEX_BUFFER_COUNT; ++i ) {
2634       int result = midiInUnprepareHeader(data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR));
2635       delete [] data->sysexBuffer[i]->lpData;
2636       delete [] data->sysexBuffer[i];
2637       if ( result != MMSYSERR_NOERROR ) {
2638         midiInClose( data->inHandle );
2639         data->inHandle = 0;
2640         errorString_ = "MidiInWinMM::openPort: error closing Windows MM MIDI input port (midiInUnprepareHeader).";
2641         error( RtMidiError::DRIVER_ERROR, errorString_ );
2642         return;
2643       }
2644     }
2645 
2646     midiInClose( data->inHandle );
2647     data->inHandle = 0;
2648     connected_ = false;
2649     LeaveCriticalSection( &(data->_mutex) );
2650   }
2651 }
2652 
setClientName(const std::string &)2653 void MidiInWinMM :: setClientName ( const std::string& )
2654 {
2655 
2656   errorString_ = "MidiInWinMM::setClientName: this function is not implemented for the WINDOWS_MM API!";
2657   error( RtMidiError::WARNING, errorString_ );
2658 
2659 }
2660 
setPortName(const std::string &)2661 void MidiInWinMM :: setPortName ( const std::string& )
2662 {
2663 
2664   errorString_ = "MidiInWinMM::setPortName: this function is not implemented for the WINDOWS_MM API!";
2665   error( RtMidiError::WARNING, errorString_ );
2666 
2667 }
2668 
getPortCount()2669 unsigned int MidiInWinMM :: getPortCount()
2670 {
2671   return midiInGetNumDevs();
2672 }
2673 
getPortName(unsigned int portNumber)2674 std::string MidiInWinMM :: getPortName( unsigned int portNumber )
2675 {
2676   std::string stringName;
2677   unsigned int nDevices = midiInGetNumDevs();
2678   if ( portNumber >= nDevices ) {
2679     std::ostringstream ost;
2680     ost << "MidiInWinMM::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
2681     errorString_ = ost.str();
2682     error( RtMidiError::WARNING, errorString_ );
2683     return stringName;
2684   }
2685 
2686   MIDIINCAPS deviceCaps;
2687   midiInGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIINCAPS));
2688   stringName = ConvertToUTF8( deviceCaps.szPname );
2689 
2690   // Next lines added to add the portNumber to the name so that
2691   // the device's names are sure to be listed with individual names
2692   // even when they have the same brand name
2693 #ifndef RTMIDI_DO_NOT_ENSURE_UNIQUE_PORTNAMES
2694   std::ostringstream os;
2695   os << " ";
2696   os << portNumber;
2697   stringName += os.str();
2698 #endif
2699 
2700   return stringName;
2701 }
2702 
2703 //*********************************************************************//
2704 //  API: Windows MM
2705 //  Class Definitions: MidiOutWinMM
2706 //*********************************************************************//
2707 
MidiOutWinMM(const std::string & clientName)2708 MidiOutWinMM :: MidiOutWinMM( const std::string &clientName ) : MidiOutApi()
2709 {
2710   MidiOutWinMM::initialize( clientName );
2711 }
2712 
~MidiOutWinMM()2713 MidiOutWinMM :: ~MidiOutWinMM()
2714 {
2715   // Close a connection if it exists.
2716   MidiOutWinMM::closePort();
2717 
2718   // Cleanup.
2719   WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2720   delete data;
2721 }
2722 
initialize(const std::string &)2723 void MidiOutWinMM :: initialize( const std::string& /*clientName*/ )
2724 {
2725   // We'll issue a warning here if no devices are available but not
2726   // throw an error since the user can plug something in later.
2727   unsigned int nDevices = midiOutGetNumDevs();
2728   if ( nDevices == 0 ) {
2729     errorString_ = "MidiOutWinMM::initialize: no MIDI output devices currently available.";
2730     error( RtMidiError::WARNING, errorString_ );
2731   }
2732 
2733   // Save our api-specific connection information.
2734   WinMidiData *data = (WinMidiData *) new WinMidiData;
2735   apiData_ = (void *) data;
2736 }
2737 
getPortCount()2738 unsigned int MidiOutWinMM :: getPortCount()
2739 {
2740   return midiOutGetNumDevs();
2741 }
2742 
getPortName(unsigned int portNumber)2743 std::string MidiOutWinMM :: getPortName( unsigned int portNumber )
2744 {
2745   std::string stringName;
2746   unsigned int nDevices = midiOutGetNumDevs();
2747   if ( portNumber >= nDevices ) {
2748     std::ostringstream ost;
2749     ost << "MidiOutWinMM::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
2750     errorString_ = ost.str();
2751     error( RtMidiError::WARNING, errorString_ );
2752     return stringName;
2753   }
2754 
2755   MIDIOUTCAPS deviceCaps;
2756   midiOutGetDevCaps( portNumber, &deviceCaps, sizeof( MIDIOUTCAPS ) );
2757   stringName = ConvertToUTF8( deviceCaps.szPname );
2758 
2759   // Next lines added to add the portNumber to the name so that
2760   // the device's names are sure to be listed with individual names
2761   // even when they have the same brand name
2762   std::ostringstream os;
2763 #ifndef RTMIDI_DO_NOT_ENSURE_UNIQUE_PORTNAMES
2764   os << " ";
2765   os << portNumber;
2766   stringName += os.str();
2767 #endif
2768 
2769   return stringName;
2770 }
2771 
openPort(unsigned int portNumber,const std::string &)2772 void MidiOutWinMM :: openPort( unsigned int portNumber, const std::string &/*portName*/ )
2773 {
2774   if ( connected_ ) {
2775     errorString_ = "MidiOutWinMM::openPort: a valid connection already exists!";
2776     error( RtMidiError::WARNING, errorString_ );
2777     return;
2778   }
2779 
2780   unsigned int nDevices = midiOutGetNumDevs();
2781   if ( nDevices < 1 ) {
2782     errorString_ = "MidiOutWinMM::openPort: no MIDI output destinations found!";
2783     error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
2784     return;
2785   }
2786 
2787   if ( portNumber >= nDevices ) {
2788     std::ostringstream ost;
2789     ost << "MidiOutWinMM::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
2790     errorString_ = ost.str();
2791     error( RtMidiError::INVALID_PARAMETER, errorString_ );
2792     return;
2793   }
2794 
2795   WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2796   MMRESULT result = midiOutOpen( &data->outHandle,
2797                                  portNumber,
2798                                  (DWORD)NULL,
2799                                  (DWORD)NULL,
2800                                  CALLBACK_NULL );
2801   if ( result != MMSYSERR_NOERROR ) {
2802     errorString_ = "MidiOutWinMM::openPort: error creating Windows MM MIDI output port.";
2803     error( RtMidiError::DRIVER_ERROR, errorString_ );
2804     return;
2805   }
2806 
2807   connected_ = true;
2808 }
2809 
closePort(void)2810 void MidiOutWinMM :: closePort( void )
2811 {
2812   if ( connected_ ) {
2813     WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2814     midiOutReset( data->outHandle );
2815     midiOutClose( data->outHandle );
2816     data->outHandle = 0;
2817     connected_ = false;
2818   }
2819 }
2820 
setClientName(const std::string &)2821 void MidiOutWinMM :: setClientName ( const std::string& )
2822 {
2823 
2824   errorString_ = "MidiOutWinMM::setClientName: this function is not implemented for the WINDOWS_MM API!";
2825   error( RtMidiError::WARNING, errorString_ );
2826 
2827 }
2828 
setPortName(const std::string &)2829 void MidiOutWinMM :: setPortName ( const std::string& )
2830 {
2831 
2832   errorString_ = "MidiOutWinMM::setPortName: this function is not implemented for the WINDOWS_MM API!";
2833   error( RtMidiError::WARNING, errorString_ );
2834 
2835 }
2836 
openVirtualPort(const std::string &)2837 void MidiOutWinMM :: openVirtualPort( const std::string &/*portName*/ )
2838 {
2839   // This function cannot be implemented for the Windows MM MIDI API.
2840   errorString_ = "MidiOutWinMM::openVirtualPort: cannot be implemented in Windows MM MIDI API!";
2841   error( RtMidiError::WARNING, errorString_ );
2842 }
2843 
sendMessage(const unsigned char * message,size_t size)2844 void MidiOutWinMM :: sendMessage( const unsigned char *message, size_t size )
2845 {
2846   if ( !connected_ ) return;
2847 
2848   unsigned int nBytes = static_cast<unsigned int>(size);
2849   if ( nBytes == 0 ) {
2850     errorString_ = "MidiOutWinMM::sendMessage: message argument is empty!";
2851     error( RtMidiError::WARNING, errorString_ );
2852     return;
2853   }
2854 
2855   MMRESULT result;
2856   WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2857   if ( message[0] == 0xF0 ) { // Sysex message
2858 
2859     // Allocate buffer for sysex data.
2860     char *buffer = (char *) malloc( nBytes );
2861     if ( buffer == NULL ) {
2862       errorString_ = "MidiOutWinMM::sendMessage: error allocating sysex message memory!";
2863       error( RtMidiError::MEMORY_ERROR, errorString_ );
2864       return;
2865     }
2866 
2867     // Copy data to buffer.
2868     for ( unsigned int i=0; i<nBytes; ++i ) buffer[i] = message[i];
2869 
2870     // Create and prepare MIDIHDR structure.
2871     MIDIHDR sysex;
2872     sysex.lpData = (LPSTR) buffer;
2873     sysex.dwBufferLength = nBytes;
2874     sysex.dwFlags = 0;
2875     result = midiOutPrepareHeader( data->outHandle,  &sysex, sizeof( MIDIHDR ) );
2876     if ( result != MMSYSERR_NOERROR ) {
2877       free( buffer );
2878       errorString_ = "MidiOutWinMM::sendMessage: error preparing sysex header.";
2879       error( RtMidiError::DRIVER_ERROR, errorString_ );
2880       return;
2881     }
2882 
2883     // Send the message.
2884     result = midiOutLongMsg( data->outHandle, &sysex, sizeof( MIDIHDR ) );
2885     if ( result != MMSYSERR_NOERROR ) {
2886       free( buffer );
2887       errorString_ = "MidiOutWinMM::sendMessage: error sending sysex message.";
2888       error( RtMidiError::DRIVER_ERROR, errorString_ );
2889       return;
2890     }
2891 
2892     // Unprepare the buffer and MIDIHDR.
2893     while ( MIDIERR_STILLPLAYING == midiOutUnprepareHeader( data->outHandle, &sysex, sizeof ( MIDIHDR ) ) ) Sleep( 1 );
2894     free( buffer );
2895   }
2896   else { // Channel or system message.
2897 
2898     // Make sure the message size isn't too big.
2899     if ( nBytes > 3 ) {
2900       errorString_ = "MidiOutWinMM::sendMessage: message size is greater than 3 bytes (and not sysex)!";
2901       error( RtMidiError::WARNING, errorString_ );
2902       return;
2903     }
2904 
2905     // Pack MIDI bytes into double word.
2906     DWORD packet;
2907     unsigned char *ptr = (unsigned char *) &packet;
2908     for ( unsigned int i=0; i<nBytes; ++i ) {
2909       *ptr = message[i];
2910       ++ptr;
2911     }
2912 
2913     // Send the message immediately.
2914     result = midiOutShortMsg( data->outHandle, packet );
2915     if ( result != MMSYSERR_NOERROR ) {
2916       errorString_ = "MidiOutWinMM::sendMessage: error sending MIDI message.";
2917       error( RtMidiError::DRIVER_ERROR, errorString_ );
2918     }
2919   }
2920 }
2921 
2922 #endif  // __WINDOWS_MM__
2923 
2924 
2925 //*********************************************************************//
2926 //  API: UNIX JACK
2927 //
2928 //  Written primarily by Alexander Svetalkin, with updates for delta
2929 //  time by Gary Scavone, April 2011.
2930 //
2931 //  *********************************************************************//
2932 
2933 #if defined(__UNIX_JACK__)
2934 
2935 // JACK header files
2936 #include <jack/jack.h>
2937 #include <jack/midiport.h>
2938 #include <jack/ringbuffer.h>
2939 #ifdef HAVE_SEMAPHORE
2940   #include <semaphore.h>
2941 #endif
2942 
2943 #define JACK_RINGBUFFER_SIZE 16384 // Default size for ringbuffer
2944 
2945 struct JackMidiData {
2946   jack_client_t *client;
2947   jack_port_t *port;
2948   jack_ringbuffer_t *buffSize;
2949   jack_ringbuffer_t *buffMessage;
2950   jack_time_t lastTime;
2951 #ifdef HAVE_SEMAPHORE
2952   sem_t sem_cleanup;
2953   sem_t sem_needpost;
2954 #endif
2955   MidiInApi :: RtMidiInData *rtMidiIn;
2956   };
2957 
2958 //*********************************************************************//
2959 //  API: JACK
2960 //  Class Definitions: MidiInJack
2961 //*********************************************************************//
2962 
jackProcessIn(jack_nframes_t nframes,void * arg)2963 static int jackProcessIn( jack_nframes_t nframes, void *arg )
2964 {
2965   JackMidiData *jData = (JackMidiData *) arg;
2966   MidiInApi :: RtMidiInData *rtData = jData->rtMidiIn;
2967   jack_midi_event_t event;
2968   jack_time_t time;
2969 
2970   // Is port created?
2971   if ( jData->port == NULL ) return 0;
2972 
2973   void *buff = jack_port_get_buffer( jData->port, nframes );
2974   bool& continueSysex = rtData->continueSysex;
2975   unsigned char& ignoreFlags = rtData->ignoreFlags;
2976 
2977   // We have midi events in buffer
2978   int evCount = jack_midi_get_event_count( buff );
2979   for (int j = 0; j < evCount; j++) {
2980     MidiInApi::MidiMessage& message = rtData->message;
2981     jack_midi_event_get( &event, buff, j );
2982 
2983     // Compute the delta time.
2984     time = jack_get_time();
2985     if ( rtData->firstMessage == true ) {
2986       message.timeStamp = 0.0;
2987       rtData->firstMessage = false;
2988     } else
2989       message.timeStamp = ( time - jData->lastTime ) * 0.000001;
2990 
2991     jData->lastTime = time;
2992 
2993     if ( !continueSysex )
2994       message.bytes.clear();
2995 
2996     if ( !( ( continueSysex || event.buffer[0] == 0xF0 ) && ( ignoreFlags & 0x01 ) ) ) {
2997       // Unless this is a (possibly continued) SysEx message and we're ignoring SysEx,
2998       // copy the event buffer into the MIDI message struct.
2999       for ( unsigned int i = 0; i < event.size; i++ )
3000         message.bytes.push_back( event.buffer[i] );
3001     }
3002 
3003     switch ( event.buffer[0] ) {
3004       case 0xF0:
3005         // Start of a SysEx message
3006         continueSysex = event.buffer[event.size - 1] != 0xF7;
3007         if ( ignoreFlags & 0x01 ) continue;
3008         break;
3009       case 0xF1:
3010       case 0xF8:
3011         // MIDI Time Code or Timing Clock message
3012         if ( ignoreFlags & 0x02 ) continue;
3013         break;
3014       case 0xFE:
3015         // Active Sensing message
3016         if ( ignoreFlags & 0x04 ) continue;
3017         break;
3018       default:
3019         if ( continueSysex ) {
3020           // Continuation of a SysEx message
3021           continueSysex = event.buffer[event.size - 1] != 0xF7;
3022           if ( ignoreFlags & 0x01 ) continue;
3023         }
3024         // All other MIDI messages
3025     }
3026 
3027     if ( !continueSysex ) {
3028       // If not a continuation of a SysEx message,
3029       // invoke the user callback function or queue the message.
3030       if ( rtData->usingCallback ) {
3031         RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) rtData->userCallback;
3032         callback( message.timeStamp, &message.bytes, rtData->userData );
3033       }
3034       else {
3035         // As long as we haven't reached our queue size limit, push the message.
3036         if ( !rtData->queue.push( message ) )
3037           std::cerr << "\nMidiInJack: message queue limit reached!!\n\n";
3038       }
3039     }
3040   }
3041 
3042   return 0;
3043 }
3044 
MidiInJack(const std::string & clientName,unsigned int queueSizeLimit)3045 MidiInJack :: MidiInJack( const std::string &clientName, unsigned int queueSizeLimit )
3046   : MidiInApi( queueSizeLimit )
3047 {
3048   MidiInJack::initialize( clientName );
3049 }
3050 
initialize(const std::string & clientName)3051 void MidiInJack :: initialize( const std::string& clientName )
3052 {
3053   JackMidiData *data = new JackMidiData;
3054   apiData_ = (void *) data;
3055 
3056   data->rtMidiIn = &inputData_;
3057   data->port = NULL;
3058   data->client = NULL;
3059   this->clientName = clientName;
3060 
3061   connect();
3062 }
3063 
connect()3064 void MidiInJack :: connect()
3065 {
3066   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3067   if ( data->client )
3068     return;
3069 
3070   // Initialize JACK client
3071   if (( data->client = jack_client_open( clientName.c_str(), JackNoStartServer, NULL )) == 0) {
3072     errorString_ = "MidiInJack::initialize: JACK server not running?";
3073     error( RtMidiError::WARNING, errorString_ );
3074     return;
3075   }
3076 
3077   jack_set_process_callback( data->client, jackProcessIn, data );
3078   jack_activate( data->client );
3079 }
3080 
~MidiInJack()3081 MidiInJack :: ~MidiInJack()
3082 {
3083   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3084   MidiInJack::closePort();
3085 
3086   if ( data->client )
3087     jack_client_close( data->client );
3088   delete data;
3089 }
3090 
openPort(unsigned int portNumber,const std::string & portName)3091 void MidiInJack :: openPort( unsigned int portNumber, const std::string &portName )
3092 {
3093   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3094 
3095   connect();
3096 
3097   // Creating new port
3098   if ( data->port == NULL )
3099     data->port = jack_port_register( data->client, portName.c_str(),
3100                                      JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0 );
3101 
3102   if ( data->port == NULL ) {
3103     errorString_ = "MidiInJack::openPort: JACK error creating port";
3104     error( RtMidiError::DRIVER_ERROR, errorString_ );
3105     return;
3106   }
3107 
3108   // Connecting to the output
3109   std::string name = getPortName( portNumber );
3110   jack_connect( data->client, name.c_str(), jack_port_name( data->port ) );
3111 
3112   connected_ = true;
3113 }
3114 
openVirtualPort(const std::string & portName)3115 void MidiInJack :: openVirtualPort( const std::string &portName )
3116 {
3117   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3118 
3119   connect();
3120   if ( data->port == NULL )
3121     data->port = jack_port_register( data->client, portName.c_str(),
3122                                      JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0 );
3123 
3124   if ( data->port == NULL ) {
3125     errorString_ = "MidiInJack::openVirtualPort: JACK error creating virtual port";
3126     error( RtMidiError::DRIVER_ERROR, errorString_ );
3127   }
3128 }
3129 
getPortCount()3130 unsigned int MidiInJack :: getPortCount()
3131 {
3132   int count = 0;
3133   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3134   connect();
3135   if ( !data->client )
3136     return 0;
3137 
3138   // List of available ports
3139   const char **ports = jack_get_ports( data->client, NULL, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput );
3140 
3141   if ( ports == NULL ) return 0;
3142   while ( ports[count] != NULL )
3143     count++;
3144 
3145   free( ports );
3146 
3147   return count;
3148 }
3149 
getPortName(unsigned int portNumber)3150 std::string MidiInJack :: getPortName( unsigned int portNumber )
3151 {
3152   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3153   std::string retStr( "" );
3154 
3155   connect();
3156 
3157   // List of available ports
3158   const char **ports = jack_get_ports( data->client, NULL,
3159                                        JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput );
3160 
3161   // Check port validity
3162   if ( ports == NULL ) {
3163     errorString_ = "MidiInJack::getPortName: no ports available!";
3164     error( RtMidiError::WARNING, errorString_ );
3165     return retStr;
3166   }
3167 
3168   unsigned int i;
3169   for ( i=0; i<portNumber && ports[i]; i++ ) {}
3170   if ( i < portNumber || !ports[portNumber] ) {
3171     std::ostringstream ost;
3172     ost << "MidiInJack::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
3173     errorString_ = ost.str();
3174     error( RtMidiError::WARNING, errorString_ );
3175   }
3176   else retStr.assign( ports[portNumber] );
3177 
3178   jack_free( ports );
3179   return retStr;
3180 }
3181 
closePort()3182 void MidiInJack :: closePort()
3183 {
3184   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3185 
3186   if ( data->port == NULL ) return;
3187   jack_port_unregister( data->client, data->port );
3188   data->port = NULL;
3189 
3190   connected_ = false;
3191 }
3192 
setClientName(const std::string &)3193 void MidiInJack:: setClientName( const std::string& )
3194 {
3195 
3196   errorString_ = "MidiInJack::setClientName: this function is not implemented for the UNIX_JACK API!";
3197   error( RtMidiError::WARNING, errorString_ );
3198 
3199 }
3200 
setPortName(const std::string & portName)3201 void MidiInJack :: setPortName( const std::string &portName )
3202 {
3203   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3204 #ifdef JACK_HAS_PORT_RENAME
3205   jack_port_rename( data->client, data->port, portName.c_str() );
3206 #else
3207   jack_port_set_name( data->port, portName.c_str() );
3208 #endif
3209 }
3210 
3211 //*********************************************************************//
3212 //  API: JACK
3213 //  Class Definitions: MidiOutJack
3214 //*********************************************************************//
3215 
3216 // Jack process callback
jackProcessOut(jack_nframes_t nframes,void * arg)3217 static int jackProcessOut( jack_nframes_t nframes, void *arg )
3218 {
3219   JackMidiData *data = (JackMidiData *) arg;
3220   jack_midi_data_t *midiData;
3221   int space;
3222 
3223   // Is port created?
3224   if ( data->port == NULL ) return 0;
3225 
3226   void *buff = jack_port_get_buffer( data->port, nframes );
3227   jack_midi_clear_buffer( buff );
3228 
3229   while ( jack_ringbuffer_read_space( data->buffSize ) > 0 ) {
3230     jack_ringbuffer_read( data->buffSize, (char *) &space, (size_t) sizeof( space ) );
3231     midiData = jack_midi_event_reserve( buff, 0, space );
3232 
3233     jack_ringbuffer_read( data->buffMessage, (char *) midiData, (size_t) space );
3234   }
3235 
3236 #ifdef HAVE_SEMAPHORE
3237   if ( !sem_trywait( &data->sem_needpost ) )
3238     sem_post( &data->sem_cleanup );
3239 #endif
3240 
3241   return 0;
3242 }
3243 
MidiOutJack(const std::string & clientName)3244 MidiOutJack :: MidiOutJack( const std::string &clientName ) : MidiOutApi()
3245 {
3246   MidiOutJack::initialize( clientName );
3247 }
3248 
initialize(const std::string & clientName)3249 void MidiOutJack :: initialize( const std::string& clientName )
3250 {
3251   JackMidiData *data = new JackMidiData;
3252   apiData_ = (void *) data;
3253 
3254   data->port = NULL;
3255   data->client = NULL;
3256 #ifdef HAVE_SEMAPHORE
3257   sem_init( &data->sem_cleanup, 0, 0 );
3258   sem_init( &data->sem_needpost, 0, 0 );
3259 #endif
3260   this->clientName = clientName;
3261 
3262   connect();
3263 }
3264 
connect()3265 void MidiOutJack :: connect()
3266 {
3267   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3268   if ( data->client )
3269     return;
3270 
3271   // Initialize output ringbuffers
3272   data->buffSize = jack_ringbuffer_create( JACK_RINGBUFFER_SIZE );
3273   data->buffMessage = jack_ringbuffer_create( JACK_RINGBUFFER_SIZE );
3274 
3275   // Initialize JACK client
3276   if ( ( data->client = jack_client_open( clientName.c_str(), JackNoStartServer, NULL ) ) == 0 ) {
3277     errorString_ = "MidiOutJack::initialize: JACK server not running?";
3278     error( RtMidiError::WARNING, errorString_ );
3279     return;
3280   }
3281 
3282   jack_set_process_callback( data->client, jackProcessOut, data );
3283   jack_activate( data->client );
3284 }
3285 
~MidiOutJack()3286 MidiOutJack :: ~MidiOutJack()
3287 {
3288   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3289   MidiOutJack::closePort();
3290 
3291   // Cleanup
3292   jack_ringbuffer_free( data->buffSize );
3293   jack_ringbuffer_free( data->buffMessage );
3294   if ( data->client ) {
3295     jack_client_close( data->client );
3296   }
3297 
3298 #ifdef HAVE_SEMAPHORE
3299   sem_destroy( &data->sem_cleanup );
3300   sem_destroy( &data->sem_needpost );
3301 #endif
3302 
3303   delete data;
3304 }
3305 
openPort(unsigned int portNumber,const std::string & portName)3306 void MidiOutJack :: openPort( unsigned int portNumber, const std::string &portName )
3307 {
3308   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3309 
3310   connect();
3311 
3312   // Creating new port
3313   if ( data->port == NULL )
3314     data->port = jack_port_register( data->client, portName.c_str(),
3315                                      JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0 );
3316 
3317   if ( data->port == NULL ) {
3318     errorString_ = "MidiOutJack::openPort: JACK error creating port";
3319     error( RtMidiError::DRIVER_ERROR, errorString_ );
3320     return;
3321   }
3322 
3323   // Connecting to the output
3324   std::string name = getPortName( portNumber );
3325   jack_connect( data->client, jack_port_name( data->port ), name.c_str() );
3326 
3327   connected_ = true;
3328 }
3329 
openVirtualPort(const std::string & portName)3330 void MidiOutJack :: openVirtualPort( const std::string &portName )
3331 {
3332   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3333 
3334   connect();
3335   if ( data->port == NULL )
3336     data->port = jack_port_register( data->client, portName.c_str(),
3337                                      JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0 );
3338 
3339   if ( data->port == NULL ) {
3340     errorString_ = "MidiOutJack::openVirtualPort: JACK error creating virtual port";
3341     error( RtMidiError::DRIVER_ERROR, errorString_ );
3342   }
3343 }
3344 
getPortCount()3345 unsigned int MidiOutJack :: getPortCount()
3346 {
3347   int count = 0;
3348   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3349   connect();
3350   if ( !data->client )
3351     return 0;
3352 
3353   // List of available ports
3354   const char **ports = jack_get_ports( data->client, NULL,
3355                                        JACK_DEFAULT_MIDI_TYPE, JackPortIsInput );
3356 
3357   if ( ports == NULL ) return 0;
3358   while ( ports[count] != NULL )
3359     count++;
3360 
3361   free( ports );
3362 
3363   return count;
3364 }
3365 
getPortName(unsigned int portNumber)3366 std::string MidiOutJack :: getPortName( unsigned int portNumber )
3367 {
3368   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3369   std::string retStr("");
3370 
3371   connect();
3372 
3373   // List of available ports
3374   const char **ports = jack_get_ports( data->client, NULL,
3375                                        JACK_DEFAULT_MIDI_TYPE, JackPortIsInput );
3376 
3377   // Check port validity
3378   if ( ports == NULL ) {
3379     errorString_ = "MidiOutJack::getPortName: no ports available!";
3380     error( RtMidiError::WARNING, errorString_ );
3381     return retStr;
3382   }
3383 
3384   if ( ports[portNumber] == NULL ) {
3385     std::ostringstream ost;
3386     ost << "MidiOutJack::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
3387     errorString_ = ost.str();
3388     error( RtMidiError::WARNING, errorString_ );
3389   }
3390   else retStr.assign( ports[portNumber] );
3391 
3392   free( ports );
3393   return retStr;
3394 }
3395 
closePort()3396 void MidiOutJack :: closePort()
3397 {
3398   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3399 
3400   if ( data->port == NULL ) return;
3401 
3402 #ifdef HAVE_SEMAPHORE
3403   struct timespec ts;
3404   if ( clock_gettime( CLOCK_REALTIME, &ts ) != -1 ) {
3405     ts.tv_sec += 1; // wait max one second
3406     sem_post( &data->sem_needpost );
3407     sem_timedwait( &data->sem_cleanup, &ts );
3408   }
3409 #endif
3410 
3411   jack_port_unregister( data->client, data->port );
3412   data->port = NULL;
3413 
3414   connected_ = false;
3415 }
3416 
setClientName(const std::string &)3417 void MidiOutJack:: setClientName( const std::string& )
3418 {
3419 
3420   errorString_ = "MidiOutJack::setClientName: this function is not implemented for the UNIX_JACK API!";
3421   error( RtMidiError::WARNING, errorString_ );
3422 
3423 }
3424 
setPortName(const std::string & portName)3425 void MidiOutJack :: setPortName( const std::string &portName )
3426 {
3427   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3428 #ifdef JACK_HAS_PORT_RENAME
3429   jack_port_rename( data->client, data->port, portName.c_str() );
3430 #else
3431   jack_port_set_name( data->port, portName.c_str() );
3432 #endif
3433 }
3434 
sendMessage(const unsigned char * message,size_t size)3435 void MidiOutJack :: sendMessage( const unsigned char *message, size_t size )
3436 {
3437   int nBytes = static_cast<int>(size);
3438   JackMidiData *data = static_cast<JackMidiData *> (apiData_);
3439 
3440   // Write full message to buffer
3441   jack_ringbuffer_write( data->buffMessage, ( const char * ) message, nBytes );
3442   jack_ringbuffer_write( data->buffSize, ( char * ) &nBytes, sizeof( nBytes ) );
3443 }
3444 
3445 #endif  // __UNIX_JACK__
3446