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