Cleanup
[carla.git] / source / modules / rtmidi / RtMidi.cpp
blobb9b3237326d0bfa5a3c7511d3fdd7dc41e195568
1 /**********************************************************************/
2 /*! \class RtMidi
3 \brief An abstract base class for realtime MIDI input/output.
5 This class implements some common functionality for the realtime
6 MIDI input/output subclasses RtMidiIn and RtMidiOut.
8 RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/
10 RtMidi: realtime MIDI i/o C++ classes
11 Copyright (c) 2003-2017 Gary P. Scavone
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:
21 The above copyright notice and this permission notice shall be
22 included in all copies or substantial portions of the Software.
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.
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.
37 /**********************************************************************/
39 #include "RtMidi.h"
40 #include <sstream>
42 #if defined(__MACOSX_CORE__)
43 #if TARGET_OS_IPHONE
44 #define AudioGetCurrentHostTime CAHostTimeBase::GetCurrentTime
45 #define AudioConvertHostTimeToNanos CAHostTimeBase::ConvertToNanos
46 #endif
47 #endif
49 // Default for Windows is to add an identifier to the port names; this
50 // flag can be defined (e.g. in your project file) to disable this behaviour.
51 //#define RTMIDI_DO_NOT_ENSURE_UNIQUE_PORTNAMES
53 //*********************************************************************//
54 // RtMidi Definitions
55 //*********************************************************************//
57 RtMidi :: RtMidi()
58 : rtapi_(0)
62 RtMidi :: ~RtMidi()
64 delete rtapi_;
65 rtapi_ = 0;
68 std::string RtMidi :: getVersion( void ) throw()
70 return std::string( RTMIDI_VERSION );
73 void RtMidi :: getCompiledApi( std::vector<RtMidi::Api> &apis ) throw()
75 apis.clear();
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
96 //*********************************************************************//
97 // RtMidiIn Definitions
98 //*********************************************************************//
100 void RtMidiIn :: openMidiApi( RtMidi::Api api, const std::string &clientName, unsigned int queueSizeLimit )
102 delete rtapi_;
103 rtapi_ = 0;
105 #if defined(__UNIX_JACK__)
106 if ( api == UNIX_JACK )
107 rtapi_ = new MidiInJack( clientName, queueSizeLimit );
108 #endif
109 #if defined(__LINUX_ALSA__)
110 if ( api == LINUX_ALSA )
111 rtapi_ = new MidiInAlsa( clientName, queueSizeLimit );
112 #endif
113 #if defined(__WINDOWS_MM__)
114 if ( api == WINDOWS_MM )
115 rtapi_ = new MidiInWinMM( clientName, queueSizeLimit );
116 #endif
117 #if defined(__MACOSX_CORE__)
118 if ( api == MACOSX_CORE )
119 rtapi_ = new MidiInCore( clientName, queueSizeLimit );
120 #endif
121 #if defined(__RTMIDI_DUMMY__)
122 if ( api == RTMIDI_DUMMY )
123 rtapi_ = new MidiInDummy( clientName, queueSizeLimit );
124 #endif
127 RTMIDI_DLL_PUBLIC RtMidiIn :: RtMidiIn( RtMidi::Api api, const std::string &clientName, unsigned int queueSizeLimit )
128 : RtMidi()
130 if ( api != UNSPECIFIED ) {
131 // Attempt to open the specified API.
132 openMidiApi( api, clientName, queueSizeLimit );
133 if ( rtapi_ ) return;
135 // No compiled support for specified API value. Issue a warning
136 // and continue as if no API was specified.
137 std::cerr << "\nRtMidiIn: no compiled support for specified API argument!\n\n" << std::endl;
140 // Iterate through the compiled APIs and return as soon as we find
141 // one with at least one port or we reach the end of the list.
142 std::vector< RtMidi::Api > apis;
143 getCompiledApi( apis );
144 for ( unsigned int i=0; i<apis.size(); i++ ) {
145 openMidiApi( apis[i], clientName, queueSizeLimit );
146 if ( rtapi_ && rtapi_->getPortCount() ) break;
149 if ( rtapi_ ) return;
151 // It should not be possible to get here because the preprocessor
152 // definition __RTMIDI_DUMMY__ is automatically defined if no
153 // API-specific definitions are passed to the compiler. But just in
154 // case something weird happens, we'll throw an error.
155 std::string errorText = "RtMidiIn: no compiled API support found ... critical error!!";
156 throw( RtMidiError( errorText, RtMidiError::UNSPECIFIED ) );
159 RtMidiIn :: ~RtMidiIn() throw()
164 //*********************************************************************//
165 // RtMidiOut Definitions
166 //*********************************************************************//
168 void RtMidiOut :: openMidiApi( RtMidi::Api api, const std::string &clientName )
170 delete rtapi_;
171 rtapi_ = 0;
173 #if defined(__UNIX_JACK__)
174 if ( api == UNIX_JACK )
175 rtapi_ = new MidiOutJack( clientName );
176 #endif
177 #if defined(__LINUX_ALSA__)
178 if ( api == LINUX_ALSA )
179 rtapi_ = new MidiOutAlsa( clientName );
180 #endif
181 #if defined(__WINDOWS_MM__)
182 if ( api == WINDOWS_MM )
183 rtapi_ = new MidiOutWinMM( clientName );
184 #endif
185 #if defined(__MACOSX_CORE__)
186 if ( api == MACOSX_CORE )
187 rtapi_ = new MidiOutCore( clientName );
188 #endif
189 #if defined(__RTMIDI_DUMMY__)
190 if ( api == RTMIDI_DUMMY )
191 rtapi_ = new MidiOutDummy( clientName );
192 #endif
195 RTMIDI_DLL_PUBLIC RtMidiOut :: RtMidiOut( RtMidi::Api api, const std::string &clientName)
197 if ( api != UNSPECIFIED ) {
198 // Attempt to open the specified API.
199 openMidiApi( api, clientName );
200 if ( rtapi_ ) return;
202 // No compiled support for specified API value. Issue a warning
203 // and continue as if no API was specified.
204 std::cerr << "\nRtMidiOut: no compiled support for specified API argument!\n\n" << std::endl;
207 // Iterate through the compiled APIs and return as soon as we find
208 // one with at least one port or we reach the end of the list.
209 std::vector< RtMidi::Api > apis;
210 getCompiledApi( apis );
211 for ( unsigned int i=0; i<apis.size(); i++ ) {
212 openMidiApi( apis[i], clientName );
213 if ( rtapi_ && rtapi_->getPortCount() ) break;
216 if ( rtapi_ ) return;
218 // It should not be possible to get here because the preprocessor
219 // definition __RTMIDI_DUMMY__ is automatically defined if no
220 // API-specific definitions are passed to the compiler. But just in
221 // case something weird happens, we'll thrown an error.
222 std::string errorText = "RtMidiOut: no compiled API support found ... critical error!!";
223 throw( RtMidiError( errorText, RtMidiError::UNSPECIFIED ) );
226 RtMidiOut :: ~RtMidiOut() throw()
230 //*********************************************************************//
231 // Common MidiApi Definitions
232 //*********************************************************************//
234 MidiApi :: MidiApi( void )
235 : apiData_( 0 ), connected_( false ), errorCallback_(0), firstErrorOccurred_(false), errorCallbackUserData_(0)
239 MidiApi :: ~MidiApi( void )
243 void MidiApi :: setErrorCallback( RtMidiErrorCallback errorCallback, void *userData = 0 )
245 errorCallback_ = errorCallback;
246 errorCallbackUserData_ = userData;
249 void MidiApi :: error( RtMidiError::Type type, std::string errorString )
251 if ( errorCallback_ ) {
253 if ( firstErrorOccurred_ )
254 return;
256 firstErrorOccurred_ = true;
257 const std::string errorMessage = errorString;
259 errorCallback_( type, errorMessage, errorCallbackUserData_);
260 firstErrorOccurred_ = false;
261 return;
264 if ( type == RtMidiError::WARNING ) {
265 std::cerr << '\n' << errorString << "\n\n";
267 else if ( type == RtMidiError::DEBUG_WARNING ) {
268 #if defined(__RTMIDI_DEBUG__)
269 std::cerr << '\n' << errorString << "\n\n";
270 #endif
272 else {
273 std::cerr << '\n' << errorString << "\n\n";
274 throw RtMidiError( errorString, type );
278 //*********************************************************************//
279 // Common MidiInApi Definitions
280 //*********************************************************************//
282 MidiInApi :: MidiInApi( unsigned int queueSizeLimit )
283 : MidiApi()
285 // Allocate the MIDI queue.
286 inputData_.queue.ringSize = queueSizeLimit;
287 if ( inputData_.queue.ringSize > 0 )
288 inputData_.queue.ring = new MidiMessage[ inputData_.queue.ringSize ];
291 MidiInApi :: ~MidiInApi( void )
293 // Delete the MIDI queue.
294 if ( inputData_.queue.ringSize > 0 ) delete [] inputData_.queue.ring;
297 void MidiInApi :: setCallback( RtMidiIn::RtMidiCallback callback, void *userData )
299 if ( inputData_.usingCallback ) {
300 errorString_ = "MidiInApi::setCallback: a callback function is already set!";
301 error( RtMidiError::WARNING, errorString_ );
302 return;
305 if ( !callback ) {
306 errorString_ = "RtMidiIn::setCallback: callback function value is invalid!";
307 error( RtMidiError::WARNING, errorString_ );
308 return;
311 inputData_.userCallback = callback;
312 inputData_.userData = userData;
313 inputData_.usingCallback = true;
316 void MidiInApi :: cancelCallback()
318 if ( !inputData_.usingCallback ) {
319 errorString_ = "RtMidiIn::cancelCallback: no callback function was set!";
320 error( RtMidiError::WARNING, errorString_ );
321 return;
324 inputData_.userCallback = 0;
325 inputData_.userData = 0;
326 inputData_.usingCallback = false;
329 void MidiInApi :: ignoreTypes( bool midiSysex, bool midiTime, bool midiSense )
331 inputData_.ignoreFlags = 0;
332 if ( midiSysex ) inputData_.ignoreFlags = 0x01;
333 if ( midiTime ) inputData_.ignoreFlags |= 0x02;
334 if ( midiSense ) inputData_.ignoreFlags |= 0x04;
337 double MidiInApi :: getMessage( std::vector<unsigned char> *message )
339 message->clear();
341 if ( inputData_.usingCallback ) {
342 errorString_ = "RtMidiIn::getNextMessage: a user callback is currently set for this port.";
343 error( RtMidiError::WARNING, errorString_ );
344 return 0.0;
347 double timeStamp;
348 if (!inputData_.queue.pop(message, &timeStamp))
349 return 0.0;
351 return timeStamp;
354 unsigned int MidiInApi::MidiQueue::size(unsigned int *__back,
355 unsigned int *__front)
357 // Access back/front members exactly once and make stack copies for
358 // size calculation
359 unsigned int _back = back, _front = front, _size;
360 if (_back >= _front)
361 _size = _back - _front;
362 else
363 _size = ringSize - _front + _back;
365 // Return copies of back/front so no new and unsynchronized accesses
366 // to member variables are needed.
367 if (__back) *__back = _back;
368 if (__front) *__front = _front;
369 return _size;
372 // As long as we haven't reached our queue size limit, push the message.
373 bool MidiInApi::MidiQueue::push(const MidiInApi::MidiMessage& msg)
375 // Local stack copies of front/back
376 unsigned int _back, _front, _size;
378 // Get back/front indexes exactly once and calculate current size
379 _size = size(&_back, &_front);
381 if ( _size < ringSize-1 )
383 ring[_back] = msg;
384 back = (back+1)%ringSize;
385 return true;
388 return false;
391 bool MidiInApi::MidiQueue::pop(std::vector<unsigned char> *msg, double* timeStamp)
393 // Local stack copies of front/back
394 unsigned int _back, _front, _size;
396 // Get back/front indexes exactly once and calculate current size
397 _size = size(&_back, &_front);
399 if (_size == 0)
400 return false;
402 // Copy queued message to the vector pointer argument and then "pop" it.
403 msg->assign( ring[_front].bytes.begin(), ring[_front].bytes.end() );
404 *timeStamp = ring[_front].timeStamp;
406 // Update front
407 front = (front+1)%ringSize;
408 return true;
411 //*********************************************************************//
412 // Common MidiOutApi Definitions
413 //*********************************************************************//
415 MidiOutApi :: MidiOutApi( void )
416 : MidiApi()
420 MidiOutApi :: ~MidiOutApi( void )
424 // *************************************************** //
426 // OS/API-specific methods.
428 // *************************************************** //
430 #if defined(__MACOSX_CORE__)
432 // The CoreMIDI API is based on the use of a callback function for
433 // MIDI input. We convert the system specific time stamps to delta
434 // time values.
436 // OS-X CoreMIDI header files.
437 #include <CoreMIDI/CoreMIDI.h>
438 #include <CoreAudio/HostTime.h>
439 #include <CoreServices/CoreServices.h>
441 // A structure to hold variables related to the CoreMIDI API
442 // implementation.
443 struct CoreMidiData {
444 MIDIClientRef client;
445 MIDIPortRef port;
446 MIDIEndpointRef endpoint;
447 MIDIEndpointRef destinationId;
448 unsigned long long lastTime;
449 MIDISysexSendRequest sysexreq;
452 //*********************************************************************//
453 // API: OS-X
454 // Class Definitions: MidiInCore
455 //*********************************************************************//
457 static void midiInputCallback( const MIDIPacketList *list, void *procRef, void */*srcRef*/ )
459 MidiInApi::RtMidiInData *data = static_cast<MidiInApi::RtMidiInData *> (procRef);
460 CoreMidiData *apiData = static_cast<CoreMidiData *> (data->apiData);
462 unsigned char status;
463 unsigned short nBytes, iByte, size;
464 unsigned long long time;
466 bool& continueSysex = data->continueSysex;
467 MidiInApi::MidiMessage& message = data->message;
469 const MIDIPacket *packet = &list->packet[0];
470 for ( unsigned int i=0; i<list->numPackets; ++i ) {
472 // My interpretation of the CoreMIDI documentation: all message
473 // types, except sysex, are complete within a packet and there may
474 // be several of them in a single packet. Sysex messages can be
475 // broken across multiple packets and PacketLists but are bundled
476 // alone within each packet (these packets do not contain other
477 // message types). If sysex messages are split across multiple
478 // MIDIPacketLists, they must be handled by multiple calls to this
479 // function.
481 nBytes = packet->length;
482 if ( nBytes == 0 ) continue;
484 // Calculate time stamp.
485 if ( data->firstMessage ) {
486 message.timeStamp = 0.0;
487 data->firstMessage = false;
489 else {
490 time = packet->timeStamp;
491 if ( time == 0 ) { // this happens when receiving asynchronous sysex messages
492 time = AudioGetCurrentHostTime();
494 time -= apiData->lastTime;
495 time = AudioConvertHostTimeToNanos( time );
496 if ( !continueSysex )
497 message.timeStamp = time * 0.000000001;
500 // Track whether any non-filtered messages were found in this
501 // packet for timestamp calculation
502 bool foundNonFiltered = false;
504 iByte = 0;
505 if ( continueSysex ) {
506 // We have a continuing, segmented sysex message.
507 if ( !( data->ignoreFlags & 0x01 ) ) {
508 // If we're not ignoring sysex messages, copy the entire packet.
509 for ( unsigned int j=0; j<nBytes; ++j )
510 message.bytes.push_back( packet->data[j] );
512 continueSysex = packet->data[nBytes-1] != 0xF7;
514 if ( !( data->ignoreFlags & 0x01 ) && !continueSysex ) {
515 // If not a continuing sysex message, invoke the user callback function or queue the message.
516 if ( data->usingCallback ) {
517 RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
518 callback( message.timeStamp, &message.bytes, data->userData );
520 else {
521 // As long as we haven't reached our queue size limit, push the message.
522 if (!data->queue.push(message))
523 std::cerr << "\nMidiInCore: message queue limit reached!!\n\n";
525 message.bytes.clear();
528 else {
529 while ( iByte < nBytes ) {
530 size = 0;
531 // We are expecting that the next byte in the packet is a status byte.
532 status = packet->data[iByte];
533 if ( !(status & 0x80) ) break;
534 // Determine the number of bytes in the MIDI message.
535 if ( status < 0xC0 ) size = 3;
536 else if ( status < 0xE0 ) size = 2;
537 else if ( status < 0xF0 ) size = 3;
538 else if ( status == 0xF0 ) {
539 // A MIDI sysex
540 if ( data->ignoreFlags & 0x01 ) {
541 size = 0;
542 iByte = nBytes;
544 else size = nBytes - iByte;
545 continueSysex = packet->data[nBytes-1] != 0xF7;
547 else if ( status == 0xF1 ) {
548 // A MIDI time code message
549 if ( data->ignoreFlags & 0x02 ) {
550 size = 0;
551 iByte += 2;
553 else size = 2;
555 else if ( status == 0xF2 ) size = 3;
556 else if ( status == 0xF3 ) size = 2;
557 else if ( status == 0xF8 && ( data->ignoreFlags & 0x02 ) ) {
558 // A MIDI timing tick message and we're ignoring it.
559 size = 0;
560 iByte += 1;
562 else if ( status == 0xFE && ( data->ignoreFlags & 0x04 ) ) {
563 // A MIDI active sensing message and we're ignoring it.
564 size = 0;
565 iByte += 1;
567 else size = 1;
569 // Copy the MIDI data to our vector.
570 if ( size ) {
571 foundNonFiltered = true;
572 message.bytes.assign( &packet->data[iByte], &packet->data[iByte+size] );
573 if ( !continueSysex ) {
574 // If not a continuing sysex message, invoke the user callback function or queue the message.
575 if ( data->usingCallback ) {
576 RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
577 callback( message.timeStamp, &message.bytes, data->userData );
579 else {
580 // As long as we haven't reached our queue size limit, push the message.
581 if (!data->queue.push(message))
582 std::cerr << "\nMidiInCore: message queue limit reached!!\n\n";
584 message.bytes.clear();
586 iByte += size;
591 // Save the time of the last non-filtered message
592 if (foundNonFiltered)
594 apiData->lastTime = packet->timeStamp;
595 if ( apiData->lastTime == 0 ) { // this happens when receiving asynchronous sysex messages
596 apiData->lastTime = AudioGetCurrentHostTime();
600 packet = MIDIPacketNext(packet);
604 MidiInCore :: MidiInCore( const std::string &clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
606 MidiInCore::initialize( clientName );
609 MidiInCore :: ~MidiInCore( void )
611 // Close a connection if it exists.
612 MidiInCore::closePort();
614 // Cleanup.
615 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
616 MIDIClientDispose( data->client );
617 if ( data->endpoint ) MIDIEndpointDispose( data->endpoint );
618 delete data;
621 void MidiInCore :: initialize( const std::string& clientName )
623 // Set up our client.
624 MIDIClientRef client;
625 CFStringRef name = CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII );
626 OSStatus result = MIDIClientCreate(name, NULL, NULL, &client );
627 if ( result != noErr ) {
628 std::ostringstream ost;
629 ost << "MidiInCore::initialize: error creating OS-X MIDI client object (" << result << ").";
630 errorString_ = ost.str();
631 error( RtMidiError::DRIVER_ERROR, errorString_ );
632 return;
635 // Save our api-specific connection information.
636 CoreMidiData *data = (CoreMidiData *) new CoreMidiData;
637 data->client = client;
638 data->endpoint = 0;
639 apiData_ = (void *) data;
640 inputData_.apiData = (void *) data;
641 CFRelease(name);
644 void MidiInCore :: openPort( unsigned int portNumber, const std::string &portName )
646 if ( connected_ ) {
647 errorString_ = "MidiInCore::openPort: a valid connection already exists!";
648 error( RtMidiError::WARNING, errorString_ );
649 return;
652 CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
653 unsigned int nSrc = MIDIGetNumberOfSources();
654 if (nSrc < 1) {
655 errorString_ = "MidiInCore::openPort: no MIDI input sources found!";
656 error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
657 return;
660 if ( portNumber >= nSrc ) {
661 std::ostringstream ost;
662 ost << "MidiInCore::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
663 errorString_ = ost.str();
664 error( RtMidiError::INVALID_PARAMETER, errorString_ );
665 return;
668 MIDIPortRef port;
669 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
670 CFStringRef portNameRef = CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII );
671 OSStatus result = MIDIInputPortCreate( data->client,
672 portNameRef,
673 midiInputCallback, (void *)&inputData_, &port );
674 CFRelease( portNameRef );
676 if ( result != noErr ) {
677 MIDIClientDispose( data->client );
678 errorString_ = "MidiInCore::openPort: error creating OS-X MIDI input port.";
679 error( RtMidiError::DRIVER_ERROR, errorString_ );
680 return;
683 // Get the desired input source identifier.
684 MIDIEndpointRef endpoint = MIDIGetSource( portNumber );
685 if ( endpoint == 0 ) {
686 MIDIPortDispose( port );
687 MIDIClientDispose( data->client );
688 errorString_ = "MidiInCore::openPort: error getting MIDI input source reference.";
689 error( RtMidiError::DRIVER_ERROR, errorString_ );
690 return;
693 // Make the connection.
694 result = MIDIPortConnectSource( port, endpoint, NULL );
695 if ( result != noErr ) {
696 MIDIPortDispose( port );
697 MIDIClientDispose( data->client );
698 errorString_ = "MidiInCore::openPort: error connecting OS-X MIDI input port.";
699 error( RtMidiError::DRIVER_ERROR, errorString_ );
700 return;
703 // Save our api-specific port information.
704 data->port = port;
706 connected_ = true;
709 void MidiInCore :: openVirtualPort( const std::string &portName )
711 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
713 // Create a virtual MIDI input destination.
714 MIDIEndpointRef endpoint;
715 CFStringRef portNameRef = CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII );
716 OSStatus result = MIDIDestinationCreate( data->client,
717 portNameRef,
718 midiInputCallback, (void *)&inputData_, &endpoint );
719 CFRelease( portNameRef );
721 if ( result != noErr ) {
722 errorString_ = "MidiInCore::openVirtualPort: error creating virtual OS-X MIDI destination.";
723 error( RtMidiError::DRIVER_ERROR, errorString_ );
724 return;
727 // Save our api-specific connection information.
728 data->endpoint = endpoint;
731 void MidiInCore :: closePort( void )
733 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
735 if ( data->endpoint ) {
736 MIDIEndpointDispose( data->endpoint );
737 data->endpoint = 0;
740 if ( data->port ) {
741 MIDIPortDispose( data->port );
742 data->port = 0;
745 connected_ = false;
748 unsigned int MidiInCore :: getPortCount()
750 CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
751 return MIDIGetNumberOfSources();
754 // This function was submitted by Douglas Casey Tucker and apparently
755 // derived largely from PortMidi.
756 CFStringRef EndpointName( MIDIEndpointRef endpoint, bool isExternal )
758 CFMutableStringRef result = CFStringCreateMutable( NULL, 0 );
759 CFStringRef str;
761 // Begin with the endpoint's name.
762 str = NULL;
763 MIDIObjectGetStringProperty( endpoint, kMIDIPropertyName, &str );
764 if ( str != NULL ) {
765 CFStringAppend( result, str );
766 CFRelease( str );
769 MIDIEntityRef entity = 0;
770 MIDIEndpointGetEntity( endpoint, &entity );
771 if ( entity == 0 )
772 // probably virtual
773 return result;
775 if ( CFStringGetLength( result ) == 0 ) {
776 // endpoint name has zero length -- try the entity
777 str = NULL;
778 MIDIObjectGetStringProperty( entity, kMIDIPropertyName, &str );
779 if ( str != NULL ) {
780 CFStringAppend( result, str );
781 CFRelease( str );
784 // now consider the device's name
785 MIDIDeviceRef device = 0;
786 MIDIEntityGetDevice( entity, &device );
787 if ( device == 0 )
788 return result;
790 str = NULL;
791 MIDIObjectGetStringProperty( device, kMIDIPropertyName, &str );
792 if ( CFStringGetLength( result ) == 0 ) {
793 CFRelease( result );
794 return str;
796 if ( str != NULL ) {
797 // if an external device has only one entity, throw away
798 // the endpoint name and just use the device name
799 if ( isExternal && MIDIDeviceGetNumberOfEntities( device ) < 2 ) {
800 CFRelease( result );
801 return str;
802 } else {
803 if ( CFStringGetLength( str ) == 0 ) {
804 CFRelease( str );
805 return result;
807 // does the entity name already start with the device name?
808 // (some drivers do this though they shouldn't)
809 // if so, do not prepend
810 if ( CFStringCompareWithOptions( result, /* endpoint name */
811 str /* device name */,
812 CFRangeMake(0, CFStringGetLength( str ) ), 0 ) != kCFCompareEqualTo ) {
813 // prepend the device name to the entity name
814 if ( CFStringGetLength( result ) > 0 )
815 CFStringInsert( result, 0, CFSTR(" ") );
816 CFStringInsert( result, 0, str );
818 CFRelease( str );
821 return result;
824 // This function was submitted by Douglas Casey Tucker and apparently
825 // derived largely from PortMidi.
826 static CFStringRef ConnectedEndpointName( MIDIEndpointRef endpoint )
828 CFMutableStringRef result = CFStringCreateMutable( NULL, 0 );
829 CFStringRef str;
830 OSStatus err;
831 int i;
833 // Does the endpoint have connections?
834 CFDataRef connections = NULL;
835 int nConnected = 0;
836 bool anyStrings = false;
837 err = MIDIObjectGetDataProperty( endpoint, kMIDIPropertyConnectionUniqueID, &connections );
838 if ( connections != NULL ) {
839 // It has connections, follow them
840 // Concatenate the names of all connected devices
841 nConnected = CFDataGetLength( connections ) / sizeof(MIDIUniqueID);
842 if ( nConnected ) {
843 const SInt32 *pid = (const SInt32 *)(CFDataGetBytePtr(connections));
844 for ( i=0; i<nConnected; ++i, ++pid ) {
845 MIDIUniqueID id = EndianS32_BtoN( *pid );
846 MIDIObjectRef connObject;
847 MIDIObjectType connObjectType;
848 err = MIDIObjectFindByUniqueID( id, &connObject, &connObjectType );
849 if ( err == noErr ) {
850 if ( connObjectType == kMIDIObjectType_ExternalSource ||
851 connObjectType == kMIDIObjectType_ExternalDestination ) {
852 // Connected to an external device's endpoint (10.3 and later).
853 str = EndpointName( (MIDIEndpointRef)(connObject), true );
854 } else {
855 // Connected to an external device (10.2) (or something else, catch-
856 str = NULL;
857 MIDIObjectGetStringProperty( connObject, kMIDIPropertyName, &str );
859 if ( str != NULL ) {
860 if ( anyStrings )
861 CFStringAppend( result, CFSTR(", ") );
862 else anyStrings = true;
863 CFStringAppend( result, str );
864 CFRelease( str );
869 CFRelease( connections );
871 if ( anyStrings )
872 return result;
874 CFRelease( result );
876 // Here, either the endpoint had no connections, or we failed to obtain names
877 return EndpointName( endpoint, false );
880 std::string MidiInCore :: getPortName( unsigned int portNumber )
882 CFStringRef nameRef;
883 MIDIEndpointRef portRef;
884 char name[128];
886 std::string stringName;
887 CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
888 if ( portNumber >= MIDIGetNumberOfSources() ) {
889 std::ostringstream ost;
890 ost << "MidiInCore::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
891 errorString_ = ost.str();
892 error( RtMidiError::WARNING, errorString_ );
893 return stringName;
896 portRef = MIDIGetSource( portNumber );
897 nameRef = ConnectedEndpointName(portRef);
898 CFStringGetCString( nameRef, name, sizeof(name), kCFStringEncodingUTF8);
899 CFRelease( nameRef );
901 return stringName = name;
904 //*********************************************************************//
905 // API: OS-X
906 // Class Definitions: MidiOutCore
907 //*********************************************************************//
909 MidiOutCore :: MidiOutCore( const std::string &clientName ) : MidiOutApi()
911 MidiOutCore::initialize( clientName );
914 MidiOutCore :: ~MidiOutCore( void )
916 // Close a connection if it exists.
917 MidiOutCore::closePort();
919 // Cleanup.
920 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
921 MIDIClientDispose( data->client );
922 if ( data->endpoint ) MIDIEndpointDispose( data->endpoint );
923 delete data;
926 void MidiOutCore :: initialize( const std::string& clientName )
928 // Set up our client.
929 MIDIClientRef client;
930 CFStringRef name = CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII );
931 OSStatus result = MIDIClientCreate(name, NULL, NULL, &client );
932 if ( result != noErr ) {
933 std::ostringstream ost;
934 ost << "MidiOutCore::initialize: error creating OS-X MIDI client object (" << result << ").";
935 errorString_ = ost.str();
936 error( RtMidiError::DRIVER_ERROR, errorString_ );
937 return;
940 // Save our api-specific connection information.
941 CoreMidiData *data = (CoreMidiData *) new CoreMidiData;
942 data->client = client;
943 data->endpoint = 0;
944 apiData_ = (void *) data;
945 CFRelease( name );
948 unsigned int MidiOutCore :: getPortCount()
950 CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
951 return MIDIGetNumberOfDestinations();
954 std::string MidiOutCore :: getPortName( unsigned int portNumber )
956 CFStringRef nameRef;
957 MIDIEndpointRef portRef;
958 char name[128];
960 std::string stringName;
961 CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
962 if ( portNumber >= MIDIGetNumberOfDestinations() ) {
963 std::ostringstream ost;
964 ost << "MidiOutCore::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
965 errorString_ = ost.str();
966 error( RtMidiError::WARNING, errorString_ );
967 return stringName;
970 portRef = MIDIGetDestination( portNumber );
971 nameRef = ConnectedEndpointName(portRef);
972 CFStringGetCString( nameRef, name, sizeof(name), kCFStringEncodingUTF8 );
973 CFRelease( nameRef );
975 return stringName = name;
978 void MidiOutCore :: openPort( unsigned int portNumber, const std::string &portName )
980 if ( connected_ ) {
981 errorString_ = "MidiOutCore::openPort: a valid connection already exists!";
982 error( RtMidiError::WARNING, errorString_ );
983 return;
986 CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
987 unsigned int nDest = MIDIGetNumberOfDestinations();
988 if (nDest < 1) {
989 errorString_ = "MidiOutCore::openPort: no MIDI output destinations found!";
990 error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
991 return;
994 if ( portNumber >= nDest ) {
995 std::ostringstream ost;
996 ost << "MidiOutCore::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
997 errorString_ = ost.str();
998 error( RtMidiError::INVALID_PARAMETER, errorString_ );
999 return;
1002 MIDIPortRef port;
1003 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
1004 CFStringRef portNameRef = CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII );
1005 OSStatus result = MIDIOutputPortCreate( data->client,
1006 portNameRef,
1007 &port );
1008 CFRelease( portNameRef );
1009 if ( result != noErr ) {
1010 MIDIClientDispose( data->client );
1011 errorString_ = "MidiOutCore::openPort: error creating OS-X MIDI output port.";
1012 error( RtMidiError::DRIVER_ERROR, errorString_ );
1013 return;
1016 // Get the desired output port identifier.
1017 MIDIEndpointRef destination = MIDIGetDestination( portNumber );
1018 if ( destination == 0 ) {
1019 MIDIPortDispose( port );
1020 MIDIClientDispose( data->client );
1021 errorString_ = "MidiOutCore::openPort: error getting MIDI output destination reference.";
1022 error( RtMidiError::DRIVER_ERROR, errorString_ );
1023 return;
1026 // Save our api-specific connection information.
1027 data->port = port;
1028 data->destinationId = destination;
1029 connected_ = true;
1032 void MidiOutCore :: closePort( void )
1034 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
1036 if ( data->endpoint ) {
1037 MIDIEndpointDispose( data->endpoint );
1038 data->endpoint = 0;
1041 if ( data->port ) {
1042 MIDIPortDispose( data->port );
1043 data->port = 0;
1046 connected_ = false;
1049 void MidiOutCore :: openVirtualPort( const std::string &portName )
1051 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
1053 if ( data->endpoint ) {
1054 errorString_ = "MidiOutCore::openVirtualPort: a virtual output port already exists!";
1055 error( RtMidiError::WARNING, errorString_ );
1056 return;
1059 // Create a virtual MIDI output source.
1060 MIDIEndpointRef endpoint;
1061 CFStringRef portNameRef = CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII );
1062 OSStatus result = MIDISourceCreate( data->client,
1063 portNameRef,
1064 &endpoint );
1065 CFRelease( portNameRef );
1067 if ( result != noErr ) {
1068 errorString_ = "MidiOutCore::initialize: error creating OS-X virtual MIDI source.";
1069 error( RtMidiError::DRIVER_ERROR, errorString_ );
1070 return;
1073 // Save our api-specific connection information.
1074 data->endpoint = endpoint;
1077 void MidiOutCore :: sendMessage( const unsigned char *message, size_t size )
1079 // We use the MIDISendSysex() function to asynchronously send sysex
1080 // messages. Otherwise, we use a single CoreMidi MIDIPacket.
1081 unsigned int nBytes = static_cast<unsigned int> (size);
1082 if ( nBytes == 0 ) {
1083 errorString_ = "MidiOutCore::sendMessage: no data in message argument!";
1084 error( RtMidiError::WARNING, errorString_ );
1085 return;
1088 MIDITimeStamp timeStamp = AudioGetCurrentHostTime();
1089 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
1090 OSStatus result;
1092 if ( message[0] != 0xF0 && nBytes > 3 ) {
1093 errorString_ = "MidiOutCore::sendMessage: message format problem ... not sysex but > 3 bytes?";
1094 error( RtMidiError::WARNING, errorString_ );
1095 return;
1098 Byte buffer[nBytes+(sizeof(MIDIPacketList))];
1099 ByteCount listSize = sizeof(buffer);
1100 MIDIPacketList *packetList = (MIDIPacketList*)buffer;
1101 MIDIPacket *packet = MIDIPacketListInit( packetList );
1103 ByteCount remainingBytes = nBytes;
1104 while (remainingBytes && packet) {
1105 ByteCount bytesForPacket = remainingBytes > 65535 ? 65535 : remainingBytes; // 65535 = maximum size of a MIDIPacket
1106 const Byte* dataStartPtr = (const Byte *) &message[nBytes - remainingBytes];
1107 packet = MIDIPacketListAdd( packetList, listSize, packet, timeStamp, bytesForPacket, dataStartPtr);
1108 remainingBytes -= bytesForPacket;
1111 if ( !packet ) {
1112 errorString_ = "MidiOutCore::sendMessage: could not allocate packet list";
1113 error( RtMidiError::DRIVER_ERROR, errorString_ );
1114 return;
1117 // Send to any destinations that may have connected to us.
1118 if ( data->endpoint ) {
1119 result = MIDIReceived( data->endpoint, packetList );
1120 if ( result != noErr ) {
1121 errorString_ = "MidiOutCore::sendMessage: error sending MIDI to virtual destinations.";
1122 error( RtMidiError::WARNING, errorString_ );
1126 // And send to an explicit destination port if we're connected.
1127 if ( connected_ ) {
1128 result = MIDISend( data->port, data->destinationId, packetList );
1129 if ( result != noErr ) {
1130 errorString_ = "MidiOutCore::sendMessage: error sending MIDI message to port.";
1131 error( RtMidiError::WARNING, errorString_ );
1136 #endif // __MACOSX_CORE__
1139 //*********************************************************************//
1140 // API: LINUX ALSA SEQUENCER
1141 //*********************************************************************//
1143 // API information found at:
1144 // - http://www.alsa-project.org/documentation.php#Library
1146 #if defined(__LINUX_ALSA__)
1148 // The ALSA Sequencer API is based on the use of a callback function for
1149 // MIDI input.
1151 // Thanks to Pedro Lopez-Cabanillas for help with the ALSA sequencer
1152 // time stamps and other assorted fixes!!!
1154 // If you don't need timestamping for incoming MIDI events, define the
1155 // preprocessor definition AVOID_TIMESTAMPING to save resources
1156 // associated with the ALSA sequencer queues.
1158 #include <pthread.h>
1159 #include <sys/time.h>
1161 // ALSA header file.
1162 #include <alsa/asoundlib.h>
1164 // A structure to hold variables related to the ALSA API
1165 // implementation.
1166 struct AlsaMidiData {
1167 snd_seq_t *seq;
1168 unsigned int portNum;
1169 int vport;
1170 snd_seq_port_subscribe_t *subscription;
1171 snd_midi_event_t *coder;
1172 unsigned int bufferSize;
1173 unsigned char *buffer;
1174 pthread_t thread;
1175 pthread_t dummy_thread_id;
1176 snd_seq_real_time_t lastTime;
1177 int queue_id; // an input queue is needed to get timestamped events
1178 int trigger_fds[2];
1181 #define PORT_TYPE( pinfo, bits ) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
1183 //*********************************************************************//
1184 // API: LINUX ALSA
1185 // Class Definitions: MidiInAlsa
1186 //*********************************************************************//
1188 static void *alsaMidiHandler( void *ptr )
1190 MidiInApi::RtMidiInData *data = static_cast<MidiInApi::RtMidiInData *> (ptr);
1191 AlsaMidiData *apiData = static_cast<AlsaMidiData *> (data->apiData);
1193 long nBytes;
1194 double time;
1195 bool continueSysex = false;
1196 bool doDecode = false;
1197 MidiInApi::MidiMessage message;
1198 int poll_fd_count;
1199 struct pollfd *poll_fds;
1201 snd_seq_event_t *ev;
1202 int result;
1203 apiData->bufferSize = 32;
1204 result = snd_midi_event_new( 0, &apiData->coder );
1205 if ( result < 0 ) {
1206 data->doInput = false;
1207 std::cerr << "\nMidiInAlsa::alsaMidiHandler: error initializing MIDI event parser!\n\n";
1208 return 0;
1210 unsigned char *buffer = (unsigned char *) malloc( apiData->bufferSize );
1211 if ( buffer == NULL ) {
1212 data->doInput = false;
1213 snd_midi_event_free( apiData->coder );
1214 apiData->coder = 0;
1215 std::cerr << "\nMidiInAlsa::alsaMidiHandler: error initializing buffer memory!\n\n";
1216 return 0;
1218 snd_midi_event_init( apiData->coder );
1219 snd_midi_event_no_status( apiData->coder, 1 ); // suppress running status messages
1221 poll_fd_count = snd_seq_poll_descriptors_count( apiData->seq, POLLIN ) + 1;
1222 poll_fds = (struct pollfd*)alloca( poll_fd_count * sizeof( struct pollfd ));
1223 snd_seq_poll_descriptors( apiData->seq, poll_fds + 1, poll_fd_count - 1, POLLIN );
1224 poll_fds[0].fd = apiData->trigger_fds[0];
1225 poll_fds[0].events = POLLIN;
1227 while ( data->doInput ) {
1229 if ( snd_seq_event_input_pending( apiData->seq, 1 ) == 0 ) {
1230 // No data pending
1231 if ( poll( poll_fds, poll_fd_count, -1) >= 0 ) {
1232 if ( poll_fds[0].revents & POLLIN ) {
1233 bool dummy;
1234 int res = read( poll_fds[0].fd, &dummy, sizeof(dummy) );
1235 (void) res;
1238 continue;
1241 // If here, there should be data.
1242 result = snd_seq_event_input( apiData->seq, &ev );
1243 if ( result == -ENOSPC ) {
1244 std::cerr << "\nMidiInAlsa::alsaMidiHandler: MIDI input buffer overrun!\n\n";
1245 continue;
1247 else if ( result <= 0 ) {
1248 std::cerr << "\nMidiInAlsa::alsaMidiHandler: unknown MIDI input error!\n";
1249 perror("System reports");
1250 continue;
1253 // This is a bit weird, but we now have to decode an ALSA MIDI
1254 // event (back) into MIDI bytes. We'll ignore non-MIDI types.
1255 if ( !continueSysex ) message.bytes.clear();
1257 doDecode = false;
1258 switch ( ev->type ) {
1260 case SND_SEQ_EVENT_PORT_SUBSCRIBED:
1261 #if defined(__RTMIDI_DEBUG__)
1262 std::cout << "MidiInAlsa::alsaMidiHandler: port connection made!\n";
1263 #endif
1264 break;
1266 case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
1267 #if defined(__RTMIDI_DEBUG__)
1268 std::cerr << "MidiInAlsa::alsaMidiHandler: port connection has closed!\n";
1269 std::cout << "sender = " << (int) ev->data.connect.sender.client << ":"
1270 << (int) ev->data.connect.sender.port
1271 << ", dest = " << (int) ev->data.connect.dest.client << ":"
1272 << (int) ev->data.connect.dest.port
1273 << std::endl;
1274 #endif
1275 break;
1277 case SND_SEQ_EVENT_QFRAME: // MIDI time code
1278 if ( !( data->ignoreFlags & 0x02 ) ) doDecode = true;
1279 break;
1281 case SND_SEQ_EVENT_TICK: // 0xF9 ... MIDI timing tick
1282 if ( !( data->ignoreFlags & 0x02 ) ) doDecode = true;
1283 break;
1285 case SND_SEQ_EVENT_CLOCK: // 0xF8 ... MIDI timing (clock) tick
1286 if ( !( data->ignoreFlags & 0x02 ) ) doDecode = true;
1287 break;
1289 case SND_SEQ_EVENT_SENSING: // Active sensing
1290 if ( !( data->ignoreFlags & 0x04 ) ) doDecode = true;
1291 break;
1293 case SND_SEQ_EVENT_SYSEX:
1294 if ( (data->ignoreFlags & 0x01) ) break;
1295 if ( ev->data.ext.len > apiData->bufferSize ) {
1296 apiData->bufferSize = ev->data.ext.len;
1297 free( buffer );
1298 buffer = (unsigned char *) malloc( apiData->bufferSize );
1299 if ( buffer == NULL ) {
1300 data->doInput = false;
1301 std::cerr << "\nMidiInAlsa::alsaMidiHandler: error resizing buffer memory!\n\n";
1302 break;
1306 default:
1307 doDecode = true;
1310 if ( doDecode ) {
1312 nBytes = snd_midi_event_decode( apiData->coder, buffer, apiData->bufferSize, ev );
1313 if ( nBytes > 0 ) {
1314 // The ALSA sequencer has a maximum buffer size for MIDI sysex
1315 // events of 256 bytes. If a device sends sysex messages larger
1316 // than this, they are segmented into 256 byte chunks. So,
1317 // we'll watch for this and concatenate sysex chunks into a
1318 // single sysex message if necessary.
1319 if ( !continueSysex )
1320 message.bytes.assign( buffer, &buffer[nBytes] );
1321 else
1322 message.bytes.insert( message.bytes.end(), buffer, &buffer[nBytes] );
1324 continueSysex = ( ( ev->type == SND_SEQ_EVENT_SYSEX ) && ( message.bytes.back() != 0xF7 ) );
1325 if ( !continueSysex ) {
1327 // Calculate the time stamp:
1328 message.timeStamp = 0.0;
1330 // Method 1: Use the system time.
1331 //(void)gettimeofday(&tv, (struct timezone *)NULL);
1332 //time = (tv.tv_sec * 1000000) + tv.tv_usec;
1334 // Method 2: Use the ALSA sequencer event time data.
1335 // (thanks to Pedro Lopez-Cabanillas!).
1337 // Using method from:
1338 // https://www.gnu.org/software/libc/manual/html_node/Elapsed-Time.html
1340 // Perform the carry for the later subtraction by updating y.
1341 snd_seq_real_time_t &x(ev->time.time);
1342 snd_seq_real_time_t &y(apiData->lastTime);
1343 if (x.tv_nsec < y.tv_nsec) {
1344 int nsec = (y.tv_nsec - x.tv_nsec) / 1000000000 + 1;
1345 y.tv_nsec -= 1000000000 * nsec;
1346 y.tv_sec += nsec;
1348 if (x.tv_nsec - y.tv_nsec > 1000000000) {
1349 int nsec = (x.tv_nsec - y.tv_nsec) / 1000000000;
1350 y.tv_nsec += 1000000000 * nsec;
1351 y.tv_sec -= nsec;
1354 // Compute the time difference.
1355 time = x.tv_sec - y.tv_sec + (x.tv_nsec - y.tv_nsec)*1e-9;
1357 apiData->lastTime = ev->time.time;
1359 if ( data->firstMessage == true )
1360 data->firstMessage = false;
1361 else
1362 message.timeStamp = time;
1364 else {
1365 #if defined(__RTMIDI_DEBUG__)
1366 std::cerr << "\nMidiInAlsa::alsaMidiHandler: event parsing error or not a MIDI event!\n\n";
1367 #endif
1372 snd_seq_free_event( ev );
1373 if ( message.bytes.size() == 0 || continueSysex ) continue;
1375 if ( data->usingCallback ) {
1376 RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
1377 callback( message.timeStamp, &message.bytes, data->userData );
1379 else {
1380 // As long as we haven't reached our queue size limit, push the message.
1381 if (!data->queue.push(message))
1382 std::cerr << "\nMidiInAlsa: message queue limit reached!!\n\n";
1386 if ( buffer ) free( buffer );
1387 snd_midi_event_free( apiData->coder );
1388 apiData->coder = 0;
1389 apiData->thread = apiData->dummy_thread_id;
1390 return 0;
1393 MidiInAlsa :: MidiInAlsa( const std::string &clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
1395 MidiInAlsa::initialize( clientName );
1398 MidiInAlsa :: ~MidiInAlsa()
1400 // Close a connection if it exists.
1401 MidiInAlsa::closePort();
1403 // Shutdown the input thread.
1404 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1405 if ( inputData_.doInput ) {
1406 inputData_.doInput = false;
1407 int res = write( data->trigger_fds[1], &inputData_.doInput, sizeof(inputData_.doInput) );
1408 (void) res;
1409 if ( !pthread_equal(data->thread, data->dummy_thread_id) )
1410 pthread_join( data->thread, NULL );
1413 // Cleanup.
1414 close ( data->trigger_fds[0] );
1415 close ( data->trigger_fds[1] );
1416 if ( data->vport >= 0 ) snd_seq_delete_port( data->seq, data->vport );
1417 #ifndef AVOID_TIMESTAMPING
1418 snd_seq_free_queue( data->seq, data->queue_id );
1419 #endif
1420 snd_seq_close( data->seq );
1421 delete data;
1424 void MidiInAlsa :: initialize( const std::string& clientName )
1426 // Set up the ALSA sequencer client.
1427 snd_seq_t *seq;
1428 int result = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK);
1429 if ( result < 0 ) {
1430 errorString_ = "MidiInAlsa::initialize: error creating ALSA sequencer client object.";
1431 error( RtMidiError::DRIVER_ERROR, errorString_ );
1432 return;
1435 // Set client name.
1436 snd_seq_set_client_name( seq, clientName.c_str() );
1438 // Save our api-specific connection information.
1439 AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
1440 data->seq = seq;
1441 data->portNum = -1;
1442 data->vport = -1;
1443 data->subscription = 0;
1444 data->dummy_thread_id = pthread_self();
1445 data->thread = data->dummy_thread_id;
1446 data->trigger_fds[0] = -1;
1447 data->trigger_fds[1] = -1;
1448 apiData_ = (void *) data;
1449 inputData_.apiData = (void *) data;
1451 if ( pipe(data->trigger_fds) == -1 ) {
1452 errorString_ = "MidiInAlsa::initialize: error creating pipe objects.";
1453 error( RtMidiError::DRIVER_ERROR, errorString_ );
1454 return;
1457 // Create the input queue
1458 #ifndef AVOID_TIMESTAMPING
1459 data->queue_id = snd_seq_alloc_named_queue(seq, "RtMidi Queue");
1460 // Set arbitrary tempo (mm=100) and resolution (240)
1461 snd_seq_queue_tempo_t *qtempo;
1462 snd_seq_queue_tempo_alloca(&qtempo);
1463 snd_seq_queue_tempo_set_tempo(qtempo, 600000);
1464 snd_seq_queue_tempo_set_ppq(qtempo, 240);
1465 snd_seq_set_queue_tempo(data->seq, data->queue_id, qtempo);
1466 snd_seq_drain_output(data->seq);
1467 #endif
1470 // This function is used to count or get the pinfo structure for a given port number.
1471 unsigned int portInfo( snd_seq_t *seq, snd_seq_port_info_t *pinfo, unsigned int type, int portNumber )
1473 snd_seq_client_info_t *cinfo;
1474 int client;
1475 int count = 0;
1476 snd_seq_client_info_alloca( &cinfo );
1478 snd_seq_client_info_set_client( cinfo, -1 );
1479 while ( snd_seq_query_next_client( seq, cinfo ) >= 0 ) {
1480 client = snd_seq_client_info_get_client( cinfo );
1481 if ( client == 0 ) continue;
1482 // Reset query info
1483 snd_seq_port_info_set_client( pinfo, client );
1484 snd_seq_port_info_set_port( pinfo, -1 );
1485 while ( snd_seq_query_next_port( seq, pinfo ) >= 0 ) {
1486 unsigned int atyp = snd_seq_port_info_get_type( pinfo );
1487 if ( ( ( atyp & SND_SEQ_PORT_TYPE_MIDI_GENERIC ) == 0 ) &&
1488 ( ( atyp & SND_SEQ_PORT_TYPE_SYNTH ) == 0 ) &&
1489 ( ( atyp & SND_SEQ_PORT_TYPE_APPLICATION ) == 0 ) ) continue;
1491 unsigned int caps = snd_seq_port_info_get_capability( pinfo );
1492 if ( ( caps & type ) != type ) continue;
1493 if ( count == portNumber ) return 1;
1494 ++count;
1498 // If a negative portNumber was used, return the port count.
1499 if ( portNumber < 0 ) return count;
1500 return 0;
1503 unsigned int MidiInAlsa :: getPortCount()
1505 snd_seq_port_info_t *pinfo;
1506 snd_seq_port_info_alloca( &pinfo );
1508 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1509 return portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, -1 );
1512 std::string MidiInAlsa :: getPortName( unsigned int portNumber )
1514 snd_seq_client_info_t *cinfo;
1515 snd_seq_port_info_t *pinfo;
1516 snd_seq_client_info_alloca( &cinfo );
1517 snd_seq_port_info_alloca( &pinfo );
1519 std::string stringName;
1520 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1521 if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) ) {
1522 int cnum = snd_seq_port_info_get_client( pinfo );
1523 snd_seq_get_any_client_info( data->seq, cnum, cinfo );
1524 std::ostringstream os;
1525 os << snd_seq_client_info_get_name( cinfo );
1526 os << ":";
1527 os << snd_seq_port_info_get_name( pinfo );
1528 os << " "; // These lines added to make sure devices are listed
1529 os << snd_seq_port_info_get_client( pinfo ); // with full portnames added to ensure individual device names
1530 os << ":";
1531 os << snd_seq_port_info_get_port( pinfo );
1532 stringName = os.str();
1533 return stringName;
1536 // If we get here, we didn't find a match.
1537 errorString_ = "MidiInAlsa::getPortName: error looking for port name!";
1538 error( RtMidiError::WARNING, errorString_ );
1539 return stringName;
1542 void MidiInAlsa :: openPort( unsigned int portNumber, const std::string &portName )
1544 if ( connected_ ) {
1545 errorString_ = "MidiInAlsa::openPort: a valid connection already exists!";
1546 error( RtMidiError::WARNING, errorString_ );
1547 return;
1550 unsigned int nSrc = this->getPortCount();
1551 if ( nSrc < 1 ) {
1552 errorString_ = "MidiInAlsa::openPort: no MIDI input sources found!";
1553 error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
1554 return;
1557 snd_seq_port_info_t *src_pinfo;
1558 snd_seq_port_info_alloca( &src_pinfo );
1559 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1560 if ( portInfo( data->seq, src_pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) == 0 ) {
1561 std::ostringstream ost;
1562 ost << "MidiInAlsa::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
1563 errorString_ = ost.str();
1564 error( RtMidiError::INVALID_PARAMETER, errorString_ );
1565 return;
1568 snd_seq_addr_t sender, receiver;
1569 sender.client = snd_seq_port_info_get_client( src_pinfo );
1570 sender.port = snd_seq_port_info_get_port( src_pinfo );
1571 receiver.client = snd_seq_client_id( data->seq );
1573 snd_seq_port_info_t *pinfo;
1574 snd_seq_port_info_alloca( &pinfo );
1575 if ( data->vport < 0 ) {
1576 snd_seq_port_info_set_client( pinfo, 0 );
1577 snd_seq_port_info_set_port( pinfo, 0 );
1578 snd_seq_port_info_set_capability( pinfo,
1579 SND_SEQ_PORT_CAP_WRITE |
1580 SND_SEQ_PORT_CAP_SUBS_WRITE );
1581 snd_seq_port_info_set_type( pinfo,
1582 SND_SEQ_PORT_TYPE_MIDI_GENERIC |
1583 SND_SEQ_PORT_TYPE_APPLICATION );
1584 snd_seq_port_info_set_midi_channels(pinfo, 16);
1585 #ifndef AVOID_TIMESTAMPING
1586 snd_seq_port_info_set_timestamping(pinfo, 1);
1587 snd_seq_port_info_set_timestamp_real(pinfo, 1);
1588 snd_seq_port_info_set_timestamp_queue(pinfo, data->queue_id);
1589 #endif
1590 snd_seq_port_info_set_name(pinfo, portName.c_str() );
1591 data->vport = snd_seq_create_port(data->seq, pinfo);
1593 if ( data->vport < 0 ) {
1594 errorString_ = "MidiInAlsa::openPort: ALSA error creating input port.";
1595 error( RtMidiError::DRIVER_ERROR, errorString_ );
1596 return;
1598 data->vport = snd_seq_port_info_get_port(pinfo);
1601 receiver.port = data->vport;
1603 if ( !data->subscription ) {
1604 // Make subscription
1605 if (snd_seq_port_subscribe_malloc( &data->subscription ) < 0) {
1606 errorString_ = "MidiInAlsa::openPort: ALSA error allocation port subscription.";
1607 error( RtMidiError::DRIVER_ERROR, errorString_ );
1608 return;
1610 snd_seq_port_subscribe_set_sender(data->subscription, &sender);
1611 snd_seq_port_subscribe_set_dest(data->subscription, &receiver);
1612 if ( snd_seq_subscribe_port(data->seq, data->subscription) ) {
1613 snd_seq_port_subscribe_free( data->subscription );
1614 data->subscription = 0;
1615 errorString_ = "MidiInAlsa::openPort: ALSA error making port connection.";
1616 error( RtMidiError::DRIVER_ERROR, errorString_ );
1617 return;
1621 if ( inputData_.doInput == false ) {
1622 // Start the input queue
1623 #ifndef AVOID_TIMESTAMPING
1624 snd_seq_start_queue( data->seq, data->queue_id, NULL );
1625 snd_seq_drain_output( data->seq );
1626 #endif
1627 // Start our MIDI input thread.
1628 pthread_attr_t attr;
1629 pthread_attr_init(&attr);
1630 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1631 pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
1633 inputData_.doInput = true;
1634 int err = pthread_create(&data->thread, &attr, alsaMidiHandler, &inputData_);
1635 pthread_attr_destroy(&attr);
1636 if ( err ) {
1637 snd_seq_unsubscribe_port( data->seq, data->subscription );
1638 snd_seq_port_subscribe_free( data->subscription );
1639 data->subscription = 0;
1640 inputData_.doInput = false;
1641 errorString_ = "MidiInAlsa::openPort: error starting MIDI input thread!";
1642 error( RtMidiError::THREAD_ERROR, errorString_ );
1643 return;
1647 connected_ = true;
1650 void MidiInAlsa :: openVirtualPort( const std::string &portName )
1652 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1653 if ( data->vport < 0 ) {
1654 snd_seq_port_info_t *pinfo;
1655 snd_seq_port_info_alloca( &pinfo );
1656 snd_seq_port_info_set_capability( pinfo,
1657 SND_SEQ_PORT_CAP_WRITE |
1658 SND_SEQ_PORT_CAP_SUBS_WRITE );
1659 snd_seq_port_info_set_type( pinfo,
1660 SND_SEQ_PORT_TYPE_MIDI_GENERIC |
1661 SND_SEQ_PORT_TYPE_APPLICATION );
1662 snd_seq_port_info_set_midi_channels(pinfo, 16);
1663 #ifndef AVOID_TIMESTAMPING
1664 snd_seq_port_info_set_timestamping(pinfo, 1);
1665 snd_seq_port_info_set_timestamp_real(pinfo, 1);
1666 snd_seq_port_info_set_timestamp_queue(pinfo, data->queue_id);
1667 #endif
1668 snd_seq_port_info_set_name(pinfo, portName.c_str());
1669 data->vport = snd_seq_create_port(data->seq, pinfo);
1671 if ( data->vport < 0 ) {
1672 errorString_ = "MidiInAlsa::openVirtualPort: ALSA error creating virtual port.";
1673 error( RtMidiError::DRIVER_ERROR, errorString_ );
1674 return;
1676 data->vport = snd_seq_port_info_get_port(pinfo);
1679 if ( inputData_.doInput == false ) {
1680 // Wait for old thread to stop, if still running
1681 if ( !pthread_equal(data->thread, data->dummy_thread_id) )
1682 pthread_join( data->thread, NULL );
1684 // Start the input queue
1685 #ifndef AVOID_TIMESTAMPING
1686 snd_seq_start_queue( data->seq, data->queue_id, NULL );
1687 snd_seq_drain_output( data->seq );
1688 #endif
1689 // Start our MIDI input thread.
1690 pthread_attr_t attr;
1691 pthread_attr_init(&attr);
1692 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1693 pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
1695 inputData_.doInput = true;
1696 int err = pthread_create(&data->thread, &attr, alsaMidiHandler, &inputData_);
1697 pthread_attr_destroy(&attr);
1698 if ( err ) {
1699 if ( data->subscription ) {
1700 snd_seq_unsubscribe_port( data->seq, data->subscription );
1701 snd_seq_port_subscribe_free( data->subscription );
1702 data->subscription = 0;
1704 inputData_.doInput = false;
1705 errorString_ = "MidiInAlsa::openPort: error starting MIDI input thread!";
1706 error( RtMidiError::THREAD_ERROR, errorString_ );
1707 return;
1712 void MidiInAlsa :: closePort( void )
1714 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1716 if ( connected_ ) {
1717 if ( data->subscription ) {
1718 snd_seq_unsubscribe_port( data->seq, data->subscription );
1719 snd_seq_port_subscribe_free( data->subscription );
1720 data->subscription = 0;
1722 // Stop the input queue
1723 #ifndef AVOID_TIMESTAMPING
1724 snd_seq_stop_queue( data->seq, data->queue_id, NULL );
1725 snd_seq_drain_output( data->seq );
1726 #endif
1727 connected_ = false;
1730 // Stop thread to avoid triggering the callback, while the port is intended to be closed
1731 if ( inputData_.doInput ) {
1732 inputData_.doInput = false;
1733 int res = write( data->trigger_fds[1], &inputData_.doInput, sizeof(inputData_.doInput) );
1734 (void) res;
1735 if ( !pthread_equal(data->thread, data->dummy_thread_id) )
1736 pthread_join( data->thread, NULL );
1740 //*********************************************************************//
1741 // API: LINUX ALSA
1742 // Class Definitions: MidiOutAlsa
1743 //*********************************************************************//
1745 MidiOutAlsa :: MidiOutAlsa( const std::string &clientName ) : MidiOutApi()
1747 MidiOutAlsa::initialize( clientName );
1750 MidiOutAlsa :: ~MidiOutAlsa()
1752 // Close a connection if it exists.
1753 MidiOutAlsa::closePort();
1755 // Cleanup.
1756 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1757 if ( data->vport >= 0 ) snd_seq_delete_port( data->seq, data->vport );
1758 if ( data->coder ) snd_midi_event_free( data->coder );
1759 if ( data->buffer ) free( data->buffer );
1760 snd_seq_close( data->seq );
1761 delete data;
1764 void MidiOutAlsa :: initialize( const std::string& clientName )
1766 // Set up the ALSA sequencer client.
1767 snd_seq_t *seq;
1768 int result1 = snd_seq_open( &seq, "default", SND_SEQ_OPEN_OUTPUT, SND_SEQ_NONBLOCK );
1769 if ( result1 < 0 ) {
1770 errorString_ = "MidiOutAlsa::initialize: error creating ALSA sequencer client object.";
1771 error( RtMidiError::DRIVER_ERROR, errorString_ );
1772 return;
1775 // Set client name.
1776 snd_seq_set_client_name( seq, clientName.c_str() );
1778 // Save our api-specific connection information.
1779 AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
1780 data->seq = seq;
1781 data->portNum = -1;
1782 data->vport = -1;
1783 data->bufferSize = 32;
1784 data->coder = 0;
1785 data->buffer = 0;
1786 int result = snd_midi_event_new( data->bufferSize, &data->coder );
1787 if ( result < 0 ) {
1788 delete data;
1789 errorString_ = "MidiOutAlsa::initialize: error initializing MIDI event parser!\n\n";
1790 error( RtMidiError::DRIVER_ERROR, errorString_ );
1791 return;
1793 data->buffer = (unsigned char *) malloc( data->bufferSize );
1794 if ( data->buffer == NULL ) {
1795 delete data;
1796 errorString_ = "MidiOutAlsa::initialize: error allocating buffer memory!\n\n";
1797 error( RtMidiError::MEMORY_ERROR, errorString_ );
1798 return;
1800 snd_midi_event_init( data->coder );
1801 apiData_ = (void *) data;
1804 unsigned int MidiOutAlsa :: getPortCount()
1806 snd_seq_port_info_t *pinfo;
1807 snd_seq_port_info_alloca( &pinfo );
1809 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1810 return portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, -1 );
1813 std::string MidiOutAlsa :: getPortName( unsigned int portNumber )
1815 snd_seq_client_info_t *cinfo;
1816 snd_seq_port_info_t *pinfo;
1817 snd_seq_client_info_alloca( &cinfo );
1818 snd_seq_port_info_alloca( &pinfo );
1820 std::string stringName;
1821 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1822 if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) ) {
1823 int cnum = snd_seq_port_info_get_client(pinfo);
1824 snd_seq_get_any_client_info( data->seq, cnum, cinfo );
1825 std::ostringstream os;
1826 os << snd_seq_client_info_get_name(cinfo);
1827 os << ":";
1828 os << snd_seq_port_info_get_name( pinfo );
1829 os << " "; // These lines added to make sure devices are listed
1830 os << snd_seq_port_info_get_client( pinfo ); // with full portnames added to ensure individual device names
1831 os << ":";
1832 os << snd_seq_port_info_get_port(pinfo);
1833 stringName = os.str();
1834 return stringName;
1837 // If we get here, we didn't find a match.
1838 errorString_ = "MidiOutAlsa::getPortName: error looking for port name!";
1839 error( RtMidiError::WARNING, errorString_ );
1840 return stringName;
1843 void MidiOutAlsa :: openPort( unsigned int portNumber, const std::string &portName )
1845 if ( connected_ ) {
1846 errorString_ = "MidiOutAlsa::openPort: a valid connection already exists!";
1847 error( RtMidiError::WARNING, errorString_ );
1848 return;
1851 unsigned int nSrc = this->getPortCount();
1852 if (nSrc < 1) {
1853 errorString_ = "MidiOutAlsa::openPort: no MIDI output sources found!";
1854 error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
1855 return;
1858 snd_seq_port_info_t *pinfo;
1859 snd_seq_port_info_alloca( &pinfo );
1860 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1861 if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) == 0 ) {
1862 std::ostringstream ost;
1863 ost << "MidiOutAlsa::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
1864 errorString_ = ost.str();
1865 error( RtMidiError::INVALID_PARAMETER, errorString_ );
1866 return;
1869 snd_seq_addr_t sender, receiver;
1870 receiver.client = snd_seq_port_info_get_client( pinfo );
1871 receiver.port = snd_seq_port_info_get_port( pinfo );
1872 sender.client = snd_seq_client_id( data->seq );
1874 if ( data->vport < 0 ) {
1875 data->vport = snd_seq_create_simple_port( data->seq, portName.c_str(),
1876 SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
1877 SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_APPLICATION );
1878 if ( data->vport < 0 ) {
1879 errorString_ = "MidiOutAlsa::openPort: ALSA error creating output port.";
1880 error( RtMidiError::DRIVER_ERROR, errorString_ );
1881 return;
1885 sender.port = data->vport;
1887 // Make subscription
1888 if (snd_seq_port_subscribe_malloc( &data->subscription ) < 0) {
1889 snd_seq_port_subscribe_free( data->subscription );
1890 errorString_ = "MidiOutAlsa::openPort: error allocating port subscription.";
1891 error( RtMidiError::DRIVER_ERROR, errorString_ );
1892 return;
1894 snd_seq_port_subscribe_set_sender(data->subscription, &sender);
1895 snd_seq_port_subscribe_set_dest(data->subscription, &receiver);
1896 snd_seq_port_subscribe_set_time_update(data->subscription, 1);
1897 snd_seq_port_subscribe_set_time_real(data->subscription, 1);
1898 if ( snd_seq_subscribe_port(data->seq, data->subscription) ) {
1899 snd_seq_port_subscribe_free( data->subscription );
1900 errorString_ = "MidiOutAlsa::openPort: ALSA error making port connection.";
1901 error( RtMidiError::DRIVER_ERROR, errorString_ );
1902 return;
1905 connected_ = true;
1908 void MidiOutAlsa :: closePort( void )
1910 if ( connected_ ) {
1911 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1912 snd_seq_unsubscribe_port( data->seq, data->subscription );
1913 snd_seq_port_subscribe_free( data->subscription );
1914 data->subscription = 0;
1915 connected_ = false;
1919 void MidiOutAlsa :: openVirtualPort( const std::string &portName )
1921 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1922 if ( data->vport < 0 ) {
1923 data->vport = snd_seq_create_simple_port( data->seq, portName.c_str(),
1924 SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
1925 SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_APPLICATION );
1927 if ( data->vport < 0 ) {
1928 errorString_ = "MidiOutAlsa::openVirtualPort: ALSA error creating virtual port.";
1929 error( RtMidiError::DRIVER_ERROR, errorString_ );
1934 void MidiOutAlsa :: sendMessage( const unsigned char *message, size_t size )
1936 int result;
1937 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1938 unsigned int nBytes = static_cast<unsigned int> (size);
1939 if ( nBytes > data->bufferSize ) {
1940 data->bufferSize = nBytes;
1941 result = snd_midi_event_resize_buffer ( data->coder, nBytes);
1942 if ( result != 0 ) {
1943 errorString_ = "MidiOutAlsa::sendMessage: ALSA error resizing MIDI event buffer.";
1944 error( RtMidiError::DRIVER_ERROR, errorString_ );
1945 return;
1947 free (data->buffer);
1948 data->buffer = (unsigned char *) malloc( data->bufferSize );
1949 if ( data->buffer == NULL ) {
1950 errorString_ = "MidiOutAlsa::initialize: error allocating buffer memory!\n\n";
1951 error( RtMidiError::MEMORY_ERROR, errorString_ );
1952 return;
1956 snd_seq_event_t ev;
1957 snd_seq_ev_clear(&ev);
1958 snd_seq_ev_set_source(&ev, data->vport);
1959 snd_seq_ev_set_subs(&ev);
1960 snd_seq_ev_set_direct(&ev);
1961 for ( unsigned int i=0; i<nBytes; ++i ) data->buffer[i] = message[i];
1962 result = snd_midi_event_encode( data->coder, data->buffer, (long)nBytes, &ev );
1963 if ( result < (int)nBytes ) {
1964 errorString_ = "MidiOutAlsa::sendMessage: event parsing error!";
1965 error( RtMidiError::WARNING, errorString_ );
1966 return;
1969 // Send the event.
1970 result = snd_seq_event_output(data->seq, &ev);
1971 if ( result < 0 ) {
1972 errorString_ = "MidiOutAlsa::sendMessage: error sending MIDI message to port.";
1973 error( RtMidiError::WARNING, errorString_ );
1974 return;
1976 snd_seq_drain_output(data->seq);
1979 #endif // __LINUX_ALSA__
1982 //*********************************************************************//
1983 // API: Windows Multimedia Library (MM)
1984 //*********************************************************************//
1986 // API information deciphered from:
1987 // - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_midi_reference.asp
1989 // Thanks to Jean-Baptiste Berruchon for the sysex code.
1991 #if defined(__WINDOWS_MM__)
1993 // The Windows MM API is based on the use of a callback function for
1994 // MIDI input. We convert the system specific time stamps to delta
1995 // time values.
1997 // Windows MM MIDI header files.
1998 #include <windows.h>
1999 #include <mmsystem.h>
2001 // Convert a null-terminated wide string or ANSI-encoded string to UTF-8.
2002 static std::string ConvertToUTF8(const TCHAR *str)
2004 std::string u8str;
2005 const WCHAR *wstr = L"";
2006 #if defined( UNICODE ) || defined( _UNICODE )
2007 wstr = str;
2008 #else
2009 // Convert from ANSI encoding to wide string
2010 int wlength = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
2011 std::wstring wstrtemp;
2012 if ( wlength )
2014 wstrtemp.assign( wlength - 1, 0 );
2015 MultiByteToWideChar( CP_ACP, 0, str, -1, &wstrtemp[0], wlength );
2016 wstr = &wstrtemp[0];
2018 #endif
2019 // Convert from wide string to UTF-8
2020 int length = WideCharToMultiByte( CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL );
2021 if ( length )
2023 u8str.assign( length - 1, 0 );
2024 length = WideCharToMultiByte( CP_UTF8, 0, wstr, -1, &u8str[0], length, NULL, NULL );
2026 return u8str;
2029 #define RT_SYSEX_BUFFER_SIZE 1024
2030 #define RT_SYSEX_BUFFER_COUNT 4
2032 // A structure to hold variables related to the CoreMIDI API
2033 // implementation.
2034 struct WinMidiData {
2035 HMIDIIN inHandle; // Handle to Midi Input Device
2036 HMIDIOUT outHandle; // Handle to Midi Output Device
2037 DWORD lastTime;
2038 MidiInApi::MidiMessage message;
2039 LPMIDIHDR sysexBuffer[RT_SYSEX_BUFFER_COUNT];
2040 CRITICAL_SECTION _mutex; // [Patrice] see https://groups.google.com/forum/#!topic/mididev/6OUjHutMpEo
2043 //*********************************************************************//
2044 // API: Windows MM
2045 // Class Definitions: MidiInWinMM
2046 //*********************************************************************//
2048 static void CALLBACK midiInputCallback( HMIDIIN /*hmin*/,
2049 UINT inputStatus,
2050 DWORD_PTR instancePtr,
2051 DWORD_PTR midiMessage,
2052 DWORD timestamp )
2054 if ( inputStatus != MIM_DATA && inputStatus != MIM_LONGDATA && inputStatus != MIM_LONGERROR ) return;
2056 //MidiInApi::RtMidiInData *data = static_cast<MidiInApi::RtMidiInData *> (instancePtr);
2057 MidiInApi::RtMidiInData *data = (MidiInApi::RtMidiInData *)instancePtr;
2058 WinMidiData *apiData = static_cast<WinMidiData *> (data->apiData);
2060 // Calculate time stamp.
2061 if ( data->firstMessage == true ) {
2062 apiData->message.timeStamp = 0.0;
2063 data->firstMessage = false;
2065 else apiData->message.timeStamp = (double) ( timestamp - apiData->lastTime ) * 0.001;
2067 if ( inputStatus == MIM_DATA ) { // Channel or system message
2069 // Make sure the first byte is a status byte.
2070 unsigned char status = (unsigned char) (midiMessage & 0x000000FF);
2071 if ( !(status & 0x80) ) return;
2073 // Determine the number of bytes in the MIDI message.
2074 unsigned short nBytes = 1;
2075 if ( status < 0xC0 ) nBytes = 3;
2076 else if ( status < 0xE0 ) nBytes = 2;
2077 else if ( status < 0xF0 ) nBytes = 3;
2078 else if ( status == 0xF1 ) {
2079 if ( data->ignoreFlags & 0x02 ) return;
2080 else nBytes = 2;
2082 else if ( status == 0xF2 ) nBytes = 3;
2083 else if ( status == 0xF3 ) nBytes = 2;
2084 else if ( status == 0xF8 && (data->ignoreFlags & 0x02) ) {
2085 // A MIDI timing tick message and we're ignoring it.
2086 return;
2088 else if ( status == 0xFE && (data->ignoreFlags & 0x04) ) {
2089 // A MIDI active sensing message and we're ignoring it.
2090 return;
2093 // Copy bytes to our MIDI message.
2094 unsigned char *ptr = (unsigned char *) &midiMessage;
2095 for ( int i=0; i<nBytes; ++i ) apiData->message.bytes.push_back( *ptr++ );
2097 else { // Sysex message ( MIM_LONGDATA or MIM_LONGERROR )
2098 MIDIHDR *sysex = ( MIDIHDR *) midiMessage;
2099 if ( !( data->ignoreFlags & 0x01 ) && inputStatus != MIM_LONGERROR ) {
2100 // Sysex message and we're not ignoring it
2101 for ( int i=0; i<(int)sysex->dwBytesRecorded; ++i )
2102 apiData->message.bytes.push_back( sysex->lpData[i] );
2105 // The WinMM API requires that the sysex buffer be requeued after
2106 // input of each sysex message. Even if we are ignoring sysex
2107 // messages, we still need to requeue the buffer in case the user
2108 // decides to not ignore sysex messages in the future. However,
2109 // it seems that WinMM calls this function with an empty sysex
2110 // buffer when an application closes and in this case, we should
2111 // avoid requeueing it, else the computer suddenly reboots after
2112 // one or two minutes.
2113 if ( apiData->sysexBuffer[sysex->dwUser]->dwBytesRecorded > 0 ) {
2114 //if ( sysex->dwBytesRecorded > 0 ) {
2115 EnterCriticalSection( &(apiData->_mutex) );
2116 MMRESULT result = midiInAddBuffer( apiData->inHandle, apiData->sysexBuffer[sysex->dwUser], sizeof(MIDIHDR) );
2117 LeaveCriticalSection( &(apiData->_mutex) );
2118 if ( result != MMSYSERR_NOERROR )
2119 std::cerr << "\nRtMidiIn::midiInputCallback: error sending sysex to Midi device!!\n\n";
2121 if ( data->ignoreFlags & 0x01 ) return;
2123 else return;
2126 // Save the time of the last non-filtered message
2127 apiData->lastTime = timestamp;
2129 if ( data->usingCallback ) {
2130 RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
2131 callback( apiData->message.timeStamp, &apiData->message.bytes, data->userData );
2133 else {
2134 // As long as we haven't reached our queue size limit, push the message.
2135 if (!data->queue.push(apiData->message))
2136 std::cerr << "\nMidiInWinMM: message queue limit reached!!\n\n";
2139 // Clear the vector for the next input message.
2140 apiData->message.bytes.clear();
2143 MidiInWinMM :: MidiInWinMM( const std::string &clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
2145 MidiInWinMM::initialize( clientName );
2148 MidiInWinMM :: ~MidiInWinMM()
2150 // Close a connection if it exists.
2151 MidiInWinMM::closePort();
2153 WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2154 DeleteCriticalSection( &(data->_mutex) );
2156 // Cleanup.
2157 delete data;
2160 void MidiInWinMM :: initialize( const std::string& /*clientName*/ )
2162 // We'll issue a warning here if no devices are available but not
2163 // throw an error since the user can plugin something later.
2164 unsigned int nDevices = midiInGetNumDevs();
2165 if ( nDevices == 0 ) {
2166 errorString_ = "MidiInWinMM::initialize: no MIDI input devices currently available.";
2167 error( RtMidiError::WARNING, errorString_ );
2170 // Save our api-specific connection information.
2171 WinMidiData *data = (WinMidiData *) new WinMidiData;
2172 apiData_ = (void *) data;
2173 inputData_.apiData = (void *) data;
2174 data->message.bytes.clear(); // needs to be empty for first input message
2176 if ( !InitializeCriticalSectionAndSpinCount(&(data->_mutex), 0x00000400) ) {
2177 errorString_ = "MidiInWinMM::initialize: InitializeCriticalSectionAndSpinCount failed.";
2178 error( RtMidiError::WARNING, errorString_ );
2182 void MidiInWinMM :: openPort( unsigned int portNumber, const std::string &/*portName*/ )
2184 if ( connected_ ) {
2185 errorString_ = "MidiInWinMM::openPort: a valid connection already exists!";
2186 error( RtMidiError::WARNING, errorString_ );
2187 return;
2190 unsigned int nDevices = midiInGetNumDevs();
2191 if (nDevices == 0) {
2192 errorString_ = "MidiInWinMM::openPort: no MIDI input sources found!";
2193 error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
2194 return;
2197 if ( portNumber >= nDevices ) {
2198 std::ostringstream ost;
2199 ost << "MidiInWinMM::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
2200 errorString_ = ost.str();
2201 error( RtMidiError::INVALID_PARAMETER, errorString_ );
2202 return;
2205 WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2206 MMRESULT result = midiInOpen( &data->inHandle,
2207 portNumber,
2208 (DWORD_PTR)&midiInputCallback,
2209 (DWORD_PTR)&inputData_,
2210 CALLBACK_FUNCTION );
2211 if ( result != MMSYSERR_NOERROR ) {
2212 errorString_ = "MidiInWinMM::openPort: error creating Windows MM MIDI input port.";
2213 error( RtMidiError::DRIVER_ERROR, errorString_ );
2214 return;
2217 // Allocate and init the sysex buffers.
2218 for ( int i=0; i<RT_SYSEX_BUFFER_COUNT; ++i ) {
2219 data->sysexBuffer[i] = (MIDIHDR*) new char[ sizeof(MIDIHDR) ];
2220 data->sysexBuffer[i]->lpData = new char[ RT_SYSEX_BUFFER_SIZE ];
2221 data->sysexBuffer[i]->dwBufferLength = RT_SYSEX_BUFFER_SIZE;
2222 data->sysexBuffer[i]->dwUser = i; // We use the dwUser parameter as buffer indicator
2223 data->sysexBuffer[i]->dwFlags = 0;
2225 result = midiInPrepareHeader( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) );
2226 if ( result != MMSYSERR_NOERROR ) {
2227 midiInClose( data->inHandle );
2228 data->inHandle = 0;
2229 errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port (PrepareHeader).";
2230 error( RtMidiError::DRIVER_ERROR, errorString_ );
2231 return;
2234 // Register the buffer.
2235 result = midiInAddBuffer( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) );
2236 if ( result != MMSYSERR_NOERROR ) {
2237 midiInClose( data->inHandle );
2238 data->inHandle = 0;
2239 errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port (AddBuffer).";
2240 error( RtMidiError::DRIVER_ERROR, errorString_ );
2241 return;
2245 result = midiInStart( data->inHandle );
2246 if ( result != MMSYSERR_NOERROR ) {
2247 midiInClose( data->inHandle );
2248 data->inHandle = 0;
2249 errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port.";
2250 error( RtMidiError::DRIVER_ERROR, errorString_ );
2251 return;
2254 connected_ = true;
2257 void MidiInWinMM :: openVirtualPort( const std::string &/*portName*/ )
2259 // This function cannot be implemented for the Windows MM MIDI API.
2260 errorString_ = "MidiInWinMM::openVirtualPort: cannot be implemented in Windows MM MIDI API!";
2261 error( RtMidiError::WARNING, errorString_ );
2264 void MidiInWinMM :: closePort( void )
2266 if ( connected_ ) {
2267 WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2268 EnterCriticalSection( &(data->_mutex) );
2269 midiInReset( data->inHandle );
2270 midiInStop( data->inHandle );
2272 for ( int i=0; i<RT_SYSEX_BUFFER_COUNT; ++i ) {
2273 int result = midiInUnprepareHeader(data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR));
2274 delete [] data->sysexBuffer[i]->lpData;
2275 delete [] data->sysexBuffer[i];
2276 if ( result != MMSYSERR_NOERROR ) {
2277 midiInClose( data->inHandle );
2278 data->inHandle = 0;
2279 errorString_ = "MidiInWinMM::openPort: error closing Windows MM MIDI input port (midiInUnprepareHeader).";
2280 error( RtMidiError::DRIVER_ERROR, errorString_ );
2281 return;
2285 midiInClose( data->inHandle );
2286 data->inHandle = 0;
2287 connected_ = false;
2288 LeaveCriticalSection( &(data->_mutex) );
2292 unsigned int MidiInWinMM :: getPortCount()
2294 return midiInGetNumDevs();
2297 std::string MidiInWinMM :: getPortName( unsigned int portNumber )
2299 std::string stringName;
2300 unsigned int nDevices = midiInGetNumDevs();
2301 if ( portNumber >= nDevices ) {
2302 std::ostringstream ost;
2303 ost << "MidiInWinMM::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
2304 errorString_ = ost.str();
2305 error( RtMidiError::WARNING, errorString_ );
2306 return stringName;
2309 MIDIINCAPS deviceCaps;
2310 midiInGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIINCAPS));
2311 stringName = ConvertToUTF8( deviceCaps.szPname );
2313 // Next lines added to add the portNumber to the name so that
2314 // the device's names are sure to be listed with individual names
2315 // even when they have the same brand name
2316 #ifndef RTMIDI_DO_NOT_ENSURE_UNIQUE_PORTNAMES
2317 std::ostringstream os;
2318 os << " ";
2319 os << portNumber;
2320 stringName += os.str();
2321 #endif
2323 return stringName;
2326 //*********************************************************************//
2327 // API: Windows MM
2328 // Class Definitions: MidiOutWinMM
2329 //*********************************************************************//
2331 MidiOutWinMM :: MidiOutWinMM( const std::string &clientName ) : MidiOutApi()
2333 MidiOutWinMM::initialize( clientName );
2336 MidiOutWinMM :: ~MidiOutWinMM()
2338 // Close a connection if it exists.
2339 MidiOutWinMM::closePort();
2341 // Cleanup.
2342 WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2343 delete data;
2346 void MidiOutWinMM :: initialize( const std::string& /*clientName*/ )
2348 // We'll issue a warning here if no devices are available but not
2349 // throw an error since the user can plug something in later.
2350 unsigned int nDevices = midiOutGetNumDevs();
2351 if ( nDevices == 0 ) {
2352 errorString_ = "MidiOutWinMM::initialize: no MIDI output devices currently available.";
2353 error( RtMidiError::WARNING, errorString_ );
2356 // Save our api-specific connection information.
2357 WinMidiData *data = (WinMidiData *) new WinMidiData;
2358 apiData_ = (void *) data;
2361 unsigned int MidiOutWinMM :: getPortCount()
2363 return midiOutGetNumDevs();
2366 std::string MidiOutWinMM :: getPortName( unsigned int portNumber )
2368 std::string stringName;
2369 unsigned int nDevices = midiOutGetNumDevs();
2370 if ( portNumber >= nDevices ) {
2371 std::ostringstream ost;
2372 ost << "MidiOutWinMM::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
2373 errorString_ = ost.str();
2374 error( RtMidiError::WARNING, errorString_ );
2375 return stringName;
2378 MIDIOUTCAPS deviceCaps;
2379 midiOutGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIOUTCAPS));
2380 stringName = ConvertToUTF8( deviceCaps.szPname );
2382 // Next lines added to add the portNumber to the name so that
2383 // the device's names are sure to be listed with individual names
2384 // even when they have the same brand name
2385 std::ostringstream os;
2386 #ifndef RTMIDI_DO_NOT_ENSURE_UNIQUE_PORTNAMES
2387 os << " ";
2388 os << portNumber;
2389 stringName += os.str();
2390 #endif
2392 return stringName;
2395 void MidiOutWinMM :: openPort( unsigned int portNumber, const std::string &/*portName*/ )
2397 if ( connected_ ) {
2398 errorString_ = "MidiOutWinMM::openPort: a valid connection already exists!";
2399 error( RtMidiError::WARNING, errorString_ );
2400 return;
2403 unsigned int nDevices = midiOutGetNumDevs();
2404 if (nDevices < 1) {
2405 errorString_ = "MidiOutWinMM::openPort: no MIDI output destinations found!";
2406 error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
2407 return;
2410 if ( portNumber >= nDevices ) {
2411 std::ostringstream ost;
2412 ost << "MidiOutWinMM::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
2413 errorString_ = ost.str();
2414 error( RtMidiError::INVALID_PARAMETER, errorString_ );
2415 return;
2418 WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2419 MMRESULT result = midiOutOpen( &data->outHandle,
2420 portNumber,
2421 (DWORD)NULL,
2422 (DWORD)NULL,
2423 CALLBACK_NULL );
2424 if ( result != MMSYSERR_NOERROR ) {
2425 errorString_ = "MidiOutWinMM::openPort: error creating Windows MM MIDI output port.";
2426 error( RtMidiError::DRIVER_ERROR, errorString_ );
2427 return;
2430 connected_ = true;
2433 void MidiOutWinMM :: closePort( void )
2435 if ( connected_ ) {
2436 WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2437 midiOutReset( data->outHandle );
2438 midiOutClose( data->outHandle );
2439 data->outHandle = 0;
2440 connected_ = false;
2444 void MidiOutWinMM :: openVirtualPort( const std::string &/*portName*/ )
2446 // This function cannot be implemented for the Windows MM MIDI API.
2447 errorString_ = "MidiOutWinMM::openVirtualPort: cannot be implemented in Windows MM MIDI API!";
2448 error( RtMidiError::WARNING, errorString_ );
2451 void MidiOutWinMM :: sendMessage( const unsigned char *message, size_t size )
2453 if ( !connected_ ) return;
2455 unsigned int nBytes = static_cast<unsigned int>(size);
2456 if ( nBytes == 0 ) {
2457 errorString_ = "MidiOutWinMM::sendMessage: message argument is empty!";
2458 error( RtMidiError::WARNING, errorString_ );
2459 return;
2462 MMRESULT result;
2463 WinMidiData *data = static_cast<WinMidiData *> (apiData_);
2464 if ( message[0] == 0xF0 ) { // Sysex message
2466 // Allocate buffer for sysex data.
2467 char *buffer = (char *) malloc( nBytes );
2468 if ( buffer == NULL ) {
2469 errorString_ = "MidiOutWinMM::sendMessage: error allocating sysex message memory!";
2470 error( RtMidiError::MEMORY_ERROR, errorString_ );
2471 return;
2474 // Copy data to buffer.
2475 for ( unsigned int i=0; i<nBytes; ++i ) buffer[i] = message[i];
2477 // Create and prepare MIDIHDR structure.
2478 MIDIHDR sysex;
2479 sysex.lpData = (LPSTR) buffer;
2480 sysex.dwBufferLength = nBytes;
2481 sysex.dwFlags = 0;
2482 result = midiOutPrepareHeader( data->outHandle, &sysex, sizeof(MIDIHDR) );
2483 if ( result != MMSYSERR_NOERROR ) {
2484 free( buffer );
2485 errorString_ = "MidiOutWinMM::sendMessage: error preparing sysex header.";
2486 error( RtMidiError::DRIVER_ERROR, errorString_ );
2487 return;
2490 // Send the message.
2491 result = midiOutLongMsg( data->outHandle, &sysex, sizeof(MIDIHDR) );
2492 if ( result != MMSYSERR_NOERROR ) {
2493 free( buffer );
2494 errorString_ = "MidiOutWinMM::sendMessage: error sending sysex message.";
2495 error( RtMidiError::DRIVER_ERROR, errorString_ );
2496 return;
2499 // Unprepare the buffer and MIDIHDR.
2500 while ( MIDIERR_STILLPLAYING == midiOutUnprepareHeader( data->outHandle, &sysex, sizeof (MIDIHDR) ) ) Sleep( 1 );
2501 free( buffer );
2503 else { // Channel or system message.
2505 // Make sure the message size isn't too big.
2506 if ( nBytes > 3 ) {
2507 errorString_ = "MidiOutWinMM::sendMessage: message size is greater than 3 bytes (and not sysex)!";
2508 error( RtMidiError::WARNING, errorString_ );
2509 return;
2512 // Pack MIDI bytes into double word.
2513 DWORD packet;
2514 unsigned char *ptr = (unsigned char *) &packet;
2515 for ( unsigned int i=0; i<nBytes; ++i ) {
2516 *ptr = message[i];
2517 ++ptr;
2520 // Send the message immediately.
2521 result = midiOutShortMsg( data->outHandle, packet );
2522 if ( result != MMSYSERR_NOERROR ) {
2523 errorString_ = "MidiOutWinMM::sendMessage: error sending MIDI message.";
2524 error( RtMidiError::DRIVER_ERROR, errorString_ );
2529 #endif // __WINDOWS_MM__
2532 //*********************************************************************//
2533 // API: UNIX JACK
2535 // Written primarily by Alexander Svetalkin, with updates for delta
2536 // time by Gary Scavone, April 2011.
2538 // *********************************************************************//
2540 #if defined(__UNIX_JACK__)
2542 // JACK header files
2543 #include <jack/jack.h>
2544 #include <jack/midiport.h>
2545 #include <jack/ringbuffer.h>
2546 #ifdef HAVE_SEMAPHORE
2547 #include <semaphore.h>
2548 #endif
2550 #define JACK_RINGBUFFER_SIZE 16384 // Default size for ringbuffer
2552 struct JackMidiData {
2553 jack_client_t *client;
2554 jack_port_t *port;
2555 jack_ringbuffer_t *buffSize;
2556 jack_ringbuffer_t *buffMessage;
2557 jack_time_t lastTime;
2558 #ifdef HAVE_SEMAPHORE
2559 sem_t sem_cleanup;
2560 sem_t sem_needpost;
2561 #endif
2562 MidiInApi :: RtMidiInData *rtMidiIn;
2565 //*********************************************************************//
2566 // API: JACK
2567 // Class Definitions: MidiInJack
2568 //*********************************************************************//
2570 static int jackProcessIn( jack_nframes_t nframes, void *arg )
2572 JackMidiData *jData = (JackMidiData *) arg;
2573 MidiInApi :: RtMidiInData *rtData = jData->rtMidiIn;
2574 jack_midi_event_t event;
2575 jack_time_t time;
2577 // Is port created?
2578 if ( jData->port == NULL ) return 0;
2579 void *buff = jack_port_get_buffer( jData->port, nframes );
2581 // We have midi events in buffer
2582 int evCount = jack_midi_get_event_count( buff );
2583 for (int j = 0; j < evCount; j++) {
2584 MidiInApi::MidiMessage message;
2585 message.bytes.clear();
2587 jack_midi_event_get( &event, buff, j );
2589 for ( unsigned int i = 0; i < event.size; i++ )
2590 message.bytes.push_back( event.buffer[i] );
2592 // Compute the delta time.
2593 time = jack_get_time();
2594 if ( rtData->firstMessage == true )
2595 rtData->firstMessage = false;
2596 else
2597 message.timeStamp = ( time - jData->lastTime ) * 0.000001;
2599 jData->lastTime = time;
2601 if ( !rtData->continueSysex ) {
2602 if ( rtData->usingCallback ) {
2603 RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) rtData->userCallback;
2604 callback( message.timeStamp, &message.bytes, rtData->userData );
2606 else {
2607 // As long as we haven't reached our queue size limit, push the message.
2608 if (!rtData->queue.push(message))
2609 std::cerr << "\nMidiInJack: message queue limit reached!!\n\n";
2614 return 0;
2617 MidiInJack :: MidiInJack( const std::string &clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
2619 MidiInJack::initialize( clientName );
2622 void MidiInJack :: initialize( const std::string& clientName )
2624 JackMidiData *data = new JackMidiData;
2625 apiData_ = (void *) data;
2627 data->rtMidiIn = &inputData_;
2628 data->port = NULL;
2629 data->client = NULL;
2630 this->clientName = clientName;
2632 connect();
2635 void MidiInJack :: connect()
2637 JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2638 if ( data->client )
2639 return;
2641 // Initialize JACK client
2642 if (( data->client = jack_client_open( clientName.c_str(), JackNoStartServer, NULL )) == 0) {
2643 errorString_ = "MidiInJack::initialize: JACK server not running?";
2644 error( RtMidiError::WARNING, errorString_ );
2645 return;
2648 jack_set_process_callback( data->client, jackProcessIn, data );
2649 jack_activate( data->client );
2652 MidiInJack :: ~MidiInJack()
2654 JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2655 MidiInJack::closePort();
2657 if ( data->client )
2658 jack_client_close( data->client );
2659 delete data;
2662 void MidiInJack :: openPort( unsigned int portNumber, const std::string &portName )
2664 JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2666 connect();
2668 // Creating new port
2669 if ( data->port == NULL)
2670 data->port = jack_port_register( data->client, portName.c_str(),
2671 JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0 );
2673 if ( data->port == NULL) {
2674 errorString_ = "MidiInJack::openPort: JACK error creating port";
2675 error( RtMidiError::DRIVER_ERROR, errorString_ );
2676 return;
2679 // Connecting to the output
2680 std::string name = getPortName( portNumber );
2681 jack_connect( data->client, name.c_str(), jack_port_name( data->port ) );
2684 void MidiInJack :: openVirtualPort( const std::string &portName )
2686 JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2688 connect();
2689 if ( data->port == NULL )
2690 data->port = jack_port_register( data->client, portName.c_str(),
2691 JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0 );
2693 if ( data->port == NULL ) {
2694 errorString_ = "MidiInJack::openVirtualPort: JACK error creating virtual port";
2695 error( RtMidiError::DRIVER_ERROR, errorString_ );
2699 unsigned int MidiInJack :: getPortCount()
2701 int count = 0;
2702 JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2703 connect();
2704 if ( !data->client )
2705 return 0;
2707 // List of available ports
2708 const char **ports = jack_get_ports( data->client, NULL, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput );
2710 if ( ports == NULL ) return 0;
2711 while ( ports[count] != NULL )
2712 count++;
2714 free( ports );
2716 return count;
2719 std::string MidiInJack :: getPortName( unsigned int portNumber )
2721 JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2722 std::string retStr("");
2724 connect();
2726 // List of available ports
2727 const char **ports = jack_get_ports( data->client, NULL,
2728 JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput );
2730 // Check port validity
2731 if ( ports == NULL ) {
2732 errorString_ = "MidiInJack::getPortName: no ports available!";
2733 error( RtMidiError::WARNING, errorString_ );
2734 return retStr;
2737 if ( ports[portNumber] == NULL ) {
2738 std::ostringstream ost;
2739 ost << "MidiInJack::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
2740 errorString_ = ost.str();
2741 error( RtMidiError::WARNING, errorString_ );
2743 else retStr.assign( ports[portNumber] );
2745 free( ports );
2746 return retStr;
2749 void MidiInJack :: closePort()
2751 JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2753 if ( data->port == NULL ) return;
2754 jack_port_unregister( data->client, data->port );
2755 data->port = NULL;
2758 //*********************************************************************//
2759 // API: JACK
2760 // Class Definitions: MidiOutJack
2761 //*********************************************************************//
2763 // Jack process callback
2764 static int jackProcessOut( jack_nframes_t nframes, void *arg )
2766 JackMidiData *data = (JackMidiData *) arg;
2767 jack_midi_data_t *midiData;
2768 int space;
2770 // Is port created?
2771 if ( data->port == NULL ) return 0;
2773 void *buff = jack_port_get_buffer( data->port, nframes );
2774 jack_midi_clear_buffer( buff );
2776 while ( jack_ringbuffer_read_space( data->buffSize ) > 0 ) {
2777 jack_ringbuffer_read( data->buffSize, (char *) &space, (size_t) sizeof(space) );
2778 midiData = jack_midi_event_reserve( buff, 0, space );
2780 jack_ringbuffer_read( data->buffMessage, (char *) midiData, (size_t) space );
2783 #ifdef HAVE_SEMAPHORE
2784 if (!sem_trywait(&data->sem_needpost))
2785 sem_post(&data->sem_cleanup);
2786 #endif
2788 return 0;
2791 MidiOutJack :: MidiOutJack( const std::string &clientName ) : MidiOutApi()
2793 MidiOutJack::initialize( clientName );
2796 void MidiOutJack :: initialize( const std::string& clientName )
2798 JackMidiData *data = new JackMidiData;
2799 apiData_ = (void *) data;
2801 data->port = NULL;
2802 data->client = NULL;
2803 #ifdef HAVE_SEMAPHORE
2804 sem_init(&data->sem_cleanup, 0, 0);
2805 sem_init(&data->sem_needpost, 0, 0);
2806 #endif
2807 this->clientName = clientName;
2809 connect();
2812 void MidiOutJack :: connect()
2814 JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2815 if ( data->client )
2816 return;
2818 // Initialize output ringbuffers
2819 data->buffSize = jack_ringbuffer_create( JACK_RINGBUFFER_SIZE );
2820 data->buffMessage = jack_ringbuffer_create( JACK_RINGBUFFER_SIZE );
2822 // Initialize JACK client
2823 if (( data->client = jack_client_open( clientName.c_str(), JackNoStartServer, NULL )) == 0) {
2824 errorString_ = "MidiOutJack::initialize: JACK server not running?";
2825 error( RtMidiError::WARNING, errorString_ );
2826 return;
2829 jack_set_process_callback( data->client, jackProcessOut, data );
2830 jack_activate( data->client );
2833 MidiOutJack :: ~MidiOutJack()
2835 JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2836 MidiOutJack::closePort();
2838 // Cleanup
2839 jack_ringbuffer_free( data->buffSize );
2840 jack_ringbuffer_free( data->buffMessage );
2841 if ( data->client ) {
2842 jack_client_close( data->client );
2845 #ifdef HAVE_SEMAPHORE
2846 sem_destroy(&data->sem_cleanup);
2847 sem_destroy(&data->sem_needpost);
2848 #endif
2850 delete data;
2853 void MidiOutJack :: openPort( unsigned int portNumber, const std::string &portName )
2855 JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2857 connect();
2859 // Creating new port
2860 if ( data->port == NULL )
2861 data->port = jack_port_register( data->client, portName.c_str(),
2862 JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0 );
2864 if ( data->port == NULL ) {
2865 errorString_ = "MidiOutJack::openPort: JACK error creating port";
2866 error( RtMidiError::DRIVER_ERROR, errorString_ );
2867 return;
2870 // Connecting to the output
2871 std::string name = getPortName( portNumber );
2872 jack_connect( data->client, jack_port_name( data->port ), name.c_str() );
2875 void MidiOutJack :: openVirtualPort( const std::string &portName )
2877 JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2879 connect();
2880 if ( data->port == NULL )
2881 data->port = jack_port_register( data->client, portName.c_str(),
2882 JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0 );
2884 if ( data->port == NULL ) {
2885 errorString_ = "MidiOutJack::openVirtualPort: JACK error creating virtual port";
2886 error( RtMidiError::DRIVER_ERROR, errorString_ );
2890 unsigned int MidiOutJack :: getPortCount()
2892 int count = 0;
2893 JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2894 connect();
2895 if ( !data->client )
2896 return 0;
2898 // List of available ports
2899 const char **ports = jack_get_ports( data->client, NULL,
2900 JACK_DEFAULT_MIDI_TYPE, JackPortIsInput );
2902 if ( ports == NULL ) return 0;
2903 while ( ports[count] != NULL )
2904 count++;
2906 free( ports );
2908 return count;
2911 std::string MidiOutJack :: getPortName( unsigned int portNumber )
2913 JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2914 std::string retStr("");
2916 connect();
2918 // List of available ports
2919 const char **ports = jack_get_ports( data->client, NULL,
2920 JACK_DEFAULT_MIDI_TYPE, JackPortIsInput );
2922 // Check port validity
2923 if ( ports == NULL) {
2924 errorString_ = "MidiOutJack::getPortName: no ports available!";
2925 error( RtMidiError::WARNING, errorString_ );
2926 return retStr;
2929 if ( ports[portNumber] == NULL) {
2930 std::ostringstream ost;
2931 ost << "MidiOutJack::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
2932 errorString_ = ost.str();
2933 error( RtMidiError::WARNING, errorString_ );
2935 else retStr.assign( ports[portNumber] );
2937 free( ports );
2938 return retStr;
2941 void MidiOutJack :: closePort()
2943 JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2945 if ( data->port == NULL ) return;
2947 #ifdef HAVE_SEMAPHORE
2948 struct timespec ts;
2949 if (clock_gettime(CLOCK_REALTIME, &ts) != -1)
2951 ts.tv_sec += 1; // wait max one second
2952 sem_post(&data->sem_needpost);
2953 sem_timedwait(&data->sem_cleanup, &ts);
2955 #endif
2957 jack_port_unregister( data->client, data->port );
2958 data->port = NULL;
2961 void MidiOutJack :: sendMessage( const unsigned char *message, size_t size )
2963 int nBytes = static_cast<int>(size);
2964 JackMidiData *data = static_cast<JackMidiData *> (apiData_);
2966 // Write full message to buffer
2967 jack_ringbuffer_write( data->buffMessage, ( const char * ) message,
2968 nBytes );
2969 jack_ringbuffer_write( data->buffSize, ( char * ) &nBytes, sizeof( nBytes ) );
2972 #endif // __UNIX_JACK__