1 /**********************************************************************/
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 /**********************************************************************/
42 #if defined(__MACOSX_CORE__)
44 #define AudioGetCurrentHostTime CAHostTimeBase::GetCurrentTime
45 #define AudioConvertHostTimeToNanos CAHostTimeBase::ConvertToNanos
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 //*********************************************************************//
55 //*********************************************************************//
68 std::string
RtMidi :: getVersion( void ) throw()
70 return std::string( RTMIDI_VERSION
);
73 void RtMidi :: getCompiledApi( std::vector
<RtMidi::Api
> &apis
) throw()
77 // The order here will control the order of RtMidi's API search in
79 #if defined(__MACOSX_CORE__)
80 apis
.push_back( MACOSX_CORE
);
82 #if defined(__LINUX_ALSA__)
83 apis
.push_back( LINUX_ALSA
);
85 #if defined(__UNIX_JACK__)
86 apis
.push_back( UNIX_JACK
);
88 #if defined(__WINDOWS_MM__)
89 apis
.push_back( WINDOWS_MM
);
91 #if defined(__RTMIDI_DUMMY__)
92 apis
.push_back( RTMIDI_DUMMY
);
96 //*********************************************************************//
97 // RtMidiIn Definitions
98 //*********************************************************************//
100 void RtMidiIn :: openMidiApi( RtMidi::Api api
, const std::string
&clientName
, unsigned int queueSizeLimit
)
105 #if defined(__UNIX_JACK__)
106 if ( api
== UNIX_JACK
)
107 rtapi_
= new MidiInJack( clientName
, queueSizeLimit
);
109 #if defined(__LINUX_ALSA__)
110 if ( api
== LINUX_ALSA
)
111 rtapi_
= new MidiInAlsa( clientName
, queueSizeLimit
);
113 #if defined(__WINDOWS_MM__)
114 if ( api
== WINDOWS_MM
)
115 rtapi_
= new MidiInWinMM( clientName
, queueSizeLimit
);
117 #if defined(__MACOSX_CORE__)
118 if ( api
== MACOSX_CORE
)
119 rtapi_
= new MidiInCore( clientName
, queueSizeLimit
);
121 #if defined(__RTMIDI_DUMMY__)
122 if ( api
== RTMIDI_DUMMY
)
123 rtapi_
= new MidiInDummy( clientName
, queueSizeLimit
);
127 RTMIDI_DLL_PUBLIC
RtMidiIn :: RtMidiIn( RtMidi::Api api
, const std::string
&clientName
, unsigned int queueSizeLimit
)
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
)
173 #if defined(__UNIX_JACK__)
174 if ( api
== UNIX_JACK
)
175 rtapi_
= new MidiOutJack( clientName
);
177 #if defined(__LINUX_ALSA__)
178 if ( api
== LINUX_ALSA
)
179 rtapi_
= new MidiOutAlsa( clientName
);
181 #if defined(__WINDOWS_MM__)
182 if ( api
== WINDOWS_MM
)
183 rtapi_
= new MidiOutWinMM( clientName
);
185 #if defined(__MACOSX_CORE__)
186 if ( api
== MACOSX_CORE
)
187 rtapi_
= new MidiOutCore( clientName
);
189 #if defined(__RTMIDI_DUMMY__)
190 if ( api
== RTMIDI_DUMMY
)
191 rtapi_
= new MidiOutDummy( clientName
);
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_
)
256 firstErrorOccurred_
= true;
257 const std::string errorMessage
= errorString
;
259 errorCallback_( type
, errorMessage
, errorCallbackUserData_
);
260 firstErrorOccurred_
= false;
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";
273 std::cerr
<< '\n' << errorString
<< "\n\n";
274 throw RtMidiError( errorString
, type
);
278 //*********************************************************************//
279 // Common MidiInApi Definitions
280 //*********************************************************************//
282 MidiInApi :: MidiInApi( unsigned int queueSizeLimit
)
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_
);
306 errorString_
= "RtMidiIn::setCallback: callback function value is invalid!";
307 error( RtMidiError::WARNING
, errorString_
);
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_
);
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
)
341 if ( inputData_
.usingCallback
) {
342 errorString_
= "RtMidiIn::getNextMessage: a user callback is currently set for this port.";
343 error( RtMidiError::WARNING
, errorString_
);
348 if (!inputData_
.queue
.pop(message
, &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
359 unsigned int _back
= back
, _front
= front
, _size
;
361 _size
= _back
- _front
;
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
;
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 )
384 back
= (back
+1)%ringSize
;
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
);
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
;
407 front
= (front
+1)%ringSize
;
411 //*********************************************************************//
412 // Common MidiOutApi Definitions
413 //*********************************************************************//
415 MidiOutApi :: MidiOutApi( void )
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
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
443 struct CoreMidiData
{
444 MIDIClientRef client
;
446 MIDIEndpointRef endpoint
;
447 MIDIEndpointRef destinationId
;
448 unsigned long long lastTime
;
449 MIDISysexSendRequest sysexreq
;
452 //*********************************************************************//
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
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;
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;
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
);
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();
529 while ( iByte
< nBytes
) {
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 ) {
540 if ( data
->ignoreFlags
& 0x01 ) {
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 ) {
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.
562 else if ( status
== 0xFE && ( data
->ignoreFlags
& 0x04 ) ) {
563 // A MIDI active sensing message and we're ignoring it.
569 // Copy the MIDI data to our vector.
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
);
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();
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();
615 CoreMidiData
*data
= static_cast<CoreMidiData
*> (apiData_
);
616 MIDIClientDispose( data
->client
);
617 if ( data
->endpoint
) MIDIEndpointDispose( data
->endpoint
);
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_
);
635 // Save our api-specific connection information.
636 CoreMidiData
*data
= (CoreMidiData
*) new CoreMidiData
;
637 data
->client
= client
;
639 apiData_
= (void *) data
;
640 inputData_
.apiData
= (void *) data
;
644 void MidiInCore :: openPort( unsigned int portNumber
, const std::string
&portName
)
647 errorString_
= "MidiInCore::openPort: a valid connection already exists!";
648 error( RtMidiError::WARNING
, errorString_
);
652 CFRunLoopRunInMode( kCFRunLoopDefaultMode
, 0, false );
653 unsigned int nSrc
= MIDIGetNumberOfSources();
655 errorString_
= "MidiInCore::openPort: no MIDI input sources found!";
656 error( RtMidiError::NO_DEVICES_FOUND
, errorString_
);
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_
);
669 CoreMidiData
*data
= static_cast<CoreMidiData
*> (apiData_
);
670 CFStringRef portNameRef
= CFStringCreateWithCString( NULL
, portName
.c_str(), kCFStringEncodingASCII
);
671 OSStatus result
= MIDIInputPortCreate( data
->client
,
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_
);
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_
);
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_
);
703 // Save our api-specific port information.
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
,
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_
);
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
);
741 MIDIPortDispose( data
->port
);
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 );
761 // Begin with the endpoint's name.
763 MIDIObjectGetStringProperty( endpoint
, kMIDIPropertyName
, &str
);
765 CFStringAppend( result
, str
);
769 MIDIEntityRef entity
= 0;
770 MIDIEndpointGetEntity( endpoint
, &entity
);
775 if ( CFStringGetLength( result
) == 0 ) {
776 // endpoint name has zero length -- try the entity
778 MIDIObjectGetStringProperty( entity
, kMIDIPropertyName
, &str
);
780 CFStringAppend( result
, str
);
784 // now consider the device's name
785 MIDIDeviceRef device
= 0;
786 MIDIEntityGetDevice( entity
, &device
);
791 MIDIObjectGetStringProperty( device
, kMIDIPropertyName
, &str
);
792 if ( CFStringGetLength( result
) == 0 ) {
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 ) {
803 if ( CFStringGetLength( str
) == 0 ) {
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
);
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 );
833 // Does the endpoint have connections?
834 CFDataRef connections
= NULL
;
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
);
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 );
855 // Connected to an external device (10.2) (or something else, catch-
857 MIDIObjectGetStringProperty( connObject
, kMIDIPropertyName
, &str
);
861 CFStringAppend( result
, CFSTR(", ") );
862 else anyStrings
= true;
863 CFStringAppend( result
, str
);
869 CFRelease( connections
);
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
)
883 MIDIEndpointRef portRef
;
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_
);
896 portRef
= MIDIGetSource( portNumber
);
897 nameRef
= ConnectedEndpointName(portRef
);
898 CFStringGetCString( nameRef
, name
, sizeof(name
), kCFStringEncodingUTF8
);
899 CFRelease( nameRef
);
901 return stringName
= name
;
904 //*********************************************************************//
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();
920 CoreMidiData
*data
= static_cast<CoreMidiData
*> (apiData_
);
921 MIDIClientDispose( data
->client
);
922 if ( data
->endpoint
) MIDIEndpointDispose( data
->endpoint
);
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_
);
940 // Save our api-specific connection information.
941 CoreMidiData
*data
= (CoreMidiData
*) new CoreMidiData
;
942 data
->client
= client
;
944 apiData_
= (void *) data
;
948 unsigned int MidiOutCore :: getPortCount()
950 CFRunLoopRunInMode( kCFRunLoopDefaultMode
, 0, false );
951 return MIDIGetNumberOfDestinations();
954 std::string
MidiOutCore :: getPortName( unsigned int portNumber
)
957 MIDIEndpointRef portRef
;
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_
);
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
)
981 errorString_
= "MidiOutCore::openPort: a valid connection already exists!";
982 error( RtMidiError::WARNING
, errorString_
);
986 CFRunLoopRunInMode( kCFRunLoopDefaultMode
, 0, false );
987 unsigned int nDest
= MIDIGetNumberOfDestinations();
989 errorString_
= "MidiOutCore::openPort: no MIDI output destinations found!";
990 error( RtMidiError::NO_DEVICES_FOUND
, errorString_
);
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_
);
1003 CoreMidiData
*data
= static_cast<CoreMidiData
*> (apiData_
);
1004 CFStringRef portNameRef
= CFStringCreateWithCString( NULL
, portName
.c_str(), kCFStringEncodingASCII
);
1005 OSStatus result
= MIDIOutputPortCreate( data
->client
,
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_
);
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_
);
1026 // Save our api-specific connection information.
1028 data
->destinationId
= destination
;
1032 void MidiOutCore :: closePort( void )
1034 CoreMidiData
*data
= static_cast<CoreMidiData
*> (apiData_
);
1036 if ( data
->endpoint
) {
1037 MIDIEndpointDispose( data
->endpoint
);
1042 MIDIPortDispose( data
->port
);
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_
);
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
,
1065 CFRelease( portNameRef
);
1067 if ( result
!= noErr
) {
1068 errorString_
= "MidiOutCore::initialize: error creating OS-X virtual MIDI source.";
1069 error( RtMidiError::DRIVER_ERROR
, errorString_
);
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_
);
1088 MIDITimeStamp timeStamp
= AudioGetCurrentHostTime();
1089 CoreMidiData
*data
= static_cast<CoreMidiData
*> (apiData_
);
1092 if ( message
[0] != 0xF0 && nBytes
> 3 ) {
1093 errorString_
= "MidiOutCore::sendMessage: message format problem ... not sysex but > 3 bytes?";
1094 error( RtMidiError::WARNING
, errorString_
);
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
;
1112 errorString_
= "MidiOutCore::sendMessage: could not allocate packet list";
1113 error( RtMidiError::DRIVER_ERROR
, errorString_
);
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.
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
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
1166 struct AlsaMidiData
{
1168 unsigned int portNum
;
1170 snd_seq_port_subscribe_t
*subscription
;
1171 snd_midi_event_t
*coder
;
1172 unsigned int bufferSize
;
1173 unsigned char *buffer
;
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
1181 #define PORT_TYPE( pinfo, bits ) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
1183 //*********************************************************************//
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
);
1195 bool continueSysex
= false;
1196 bool doDecode
= false;
1197 MidiInApi::MidiMessage message
;
1199 struct pollfd
*poll_fds
;
1201 snd_seq_event_t
*ev
;
1203 apiData
->bufferSize
= 32;
1204 result
= snd_midi_event_new( 0, &apiData
->coder
);
1206 data
->doInput
= false;
1207 std::cerr
<< "\nMidiInAlsa::alsaMidiHandler: error initializing MIDI event parser!\n\n";
1210 unsigned char *buffer
= (unsigned char *) malloc( apiData
->bufferSize
);
1211 if ( buffer
== NULL
) {
1212 data
->doInput
= false;
1213 snd_midi_event_free( apiData
->coder
);
1215 std::cerr
<< "\nMidiInAlsa::alsaMidiHandler: error initializing buffer memory!\n\n";
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 ) {
1231 if ( poll( poll_fds
, poll_fd_count
, -1) >= 0 ) {
1232 if ( poll_fds
[0].revents
& POLLIN
) {
1234 int res
= read( poll_fds
[0].fd
, &dummy
, sizeof(dummy
) );
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";
1247 else if ( result
<= 0 ) {
1248 std::cerr
<< "\nMidiInAlsa::alsaMidiHandler: unknown MIDI input error!\n";
1249 perror("System reports");
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();
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";
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
1277 case SND_SEQ_EVENT_QFRAME
: // MIDI time code
1278 if ( !( data
->ignoreFlags
& 0x02 ) ) doDecode
= true;
1281 case SND_SEQ_EVENT_TICK
: // 0xF9 ... MIDI timing tick
1282 if ( !( data
->ignoreFlags
& 0x02 ) ) doDecode
= true;
1285 case SND_SEQ_EVENT_CLOCK
: // 0xF8 ... MIDI timing (clock) tick
1286 if ( !( data
->ignoreFlags
& 0x02 ) ) doDecode
= true;
1289 case SND_SEQ_EVENT_SENSING
: // Active sensing
1290 if ( !( data
->ignoreFlags
& 0x04 ) ) doDecode
= true;
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
;
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";
1312 nBytes
= snd_midi_event_decode( apiData
->coder
, buffer
, apiData
->bufferSize
, ev
);
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
] );
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
;
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
;
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;
1362 message
.timeStamp
= time
;
1365 #if defined(__RTMIDI_DEBUG__)
1366 std::cerr
<< "\nMidiInAlsa::alsaMidiHandler: event parsing error or not a MIDI event!\n\n";
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
);
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
);
1389 apiData
->thread
= apiData
->dummy_thread_id
;
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
) );
1409 if ( !pthread_equal(data
->thread
, data
->dummy_thread_id
) )
1410 pthread_join( data
->thread
, NULL
);
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
);
1420 snd_seq_close( data
->seq
);
1424 void MidiInAlsa :: initialize( const std::string
& clientName
)
1426 // Set up the ALSA sequencer client.
1428 int result
= snd_seq_open(&seq
, "default", SND_SEQ_OPEN_DUPLEX
, SND_SEQ_NONBLOCK
);
1430 errorString_
= "MidiInAlsa::initialize: error creating ALSA sequencer client object.";
1431 error( RtMidiError::DRIVER_ERROR
, errorString_
);
1436 snd_seq_set_client_name( seq
, clientName
.c_str() );
1438 // Save our api-specific connection information.
1439 AlsaMidiData
*data
= (AlsaMidiData
*) new AlsaMidiData
;
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_
);
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
);
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
;
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;
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;
1498 // If a negative portNumber was used, return the port count.
1499 if ( portNumber
< 0 ) return count
;
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
);
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
1531 os
<< snd_seq_port_info_get_port( pinfo
);
1532 stringName
= os
.str();
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_
);
1542 void MidiInAlsa :: openPort( unsigned int portNumber
, const std::string
&portName
)
1545 errorString_
= "MidiInAlsa::openPort: a valid connection already exists!";
1546 error( RtMidiError::WARNING
, errorString_
);
1550 unsigned int nSrc
= this->getPortCount();
1552 errorString_
= "MidiInAlsa::openPort: no MIDI input sources found!";
1553 error( RtMidiError::NO_DEVICES_FOUND
, errorString_
);
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_
);
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
);
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_
);
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_
);
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_
);
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
);
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
);
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_
);
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
);
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_
);
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
);
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
);
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_
);
1712 void MidiInAlsa :: closePort( void )
1714 AlsaMidiData
*data
= static_cast<AlsaMidiData
*> (apiData_
);
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
);
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
) );
1735 if ( !pthread_equal(data
->thread
, data
->dummy_thread_id
) )
1736 pthread_join( data
->thread
, NULL
);
1740 //*********************************************************************//
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();
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
);
1764 void MidiOutAlsa :: initialize( const std::string
& clientName
)
1766 // Set up the ALSA sequencer client.
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_
);
1776 snd_seq_set_client_name( seq
, clientName
.c_str() );
1778 // Save our api-specific connection information.
1779 AlsaMidiData
*data
= (AlsaMidiData
*) new AlsaMidiData
;
1783 data
->bufferSize
= 32;
1786 int result
= snd_midi_event_new( data
->bufferSize
, &data
->coder
);
1789 errorString_
= "MidiOutAlsa::initialize: error initializing MIDI event parser!\n\n";
1790 error( RtMidiError::DRIVER_ERROR
, errorString_
);
1793 data
->buffer
= (unsigned char *) malloc( data
->bufferSize
);
1794 if ( data
->buffer
== NULL
) {
1796 errorString_
= "MidiOutAlsa::initialize: error allocating buffer memory!\n\n";
1797 error( RtMidiError::MEMORY_ERROR
, errorString_
);
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
);
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
1832 os
<< snd_seq_port_info_get_port(pinfo
);
1833 stringName
= os
.str();
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_
);
1843 void MidiOutAlsa :: openPort( unsigned int portNumber
, const std::string
&portName
)
1846 errorString_
= "MidiOutAlsa::openPort: a valid connection already exists!";
1847 error( RtMidiError::WARNING
, errorString_
);
1851 unsigned int nSrc
= this->getPortCount();
1853 errorString_
= "MidiOutAlsa::openPort: no MIDI output sources found!";
1854 error( RtMidiError::NO_DEVICES_FOUND
, errorString_
);
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_
);
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_
);
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_
);
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_
);
1908 void MidiOutAlsa :: closePort( void )
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;
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
)
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_
);
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_
);
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_
);
1970 result
= snd_seq_event_output(data
->seq
, &ev
);
1972 errorString_
= "MidiOutAlsa::sendMessage: error sending MIDI message to port.";
1973 error( RtMidiError::WARNING
, errorString_
);
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
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
)
2005 const WCHAR
*wstr
= L
"";
2006 #if defined( UNICODE ) || defined( _UNICODE )
2009 // Convert from ANSI encoding to wide string
2010 int wlength
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
2011 std::wstring wstrtemp
;
2014 wstrtemp
.assign( wlength
- 1, 0 );
2015 MultiByteToWideChar( CP_ACP
, 0, str
, -1, &wstrtemp
[0], wlength
);
2016 wstr
= &wstrtemp
[0];
2019 // Convert from wide string to UTF-8
2020 int length
= WideCharToMultiByte( CP_UTF8
, 0, wstr
, -1, NULL
, 0, NULL
, NULL
);
2023 u8str
.assign( length
- 1, 0 );
2024 length
= WideCharToMultiByte( CP_UTF8
, 0, wstr
, -1, &u8str
[0], length
, NULL
, NULL
);
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
2034 struct WinMidiData
{
2035 HMIDIIN inHandle
; // Handle to Midi Input Device
2036 HMIDIOUT outHandle
; // Handle to Midi Output Device
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 //*********************************************************************//
2045 // Class Definitions: MidiInWinMM
2046 //*********************************************************************//
2048 static void CALLBACK
midiInputCallback( HMIDIIN
/*hmin*/,
2050 DWORD_PTR instancePtr
,
2051 DWORD_PTR midiMessage
,
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;
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.
2088 else if ( status
== 0xFE && (data
->ignoreFlags
& 0x04) ) {
2089 // A MIDI active sensing message and we're ignoring it.
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;
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
);
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
) );
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*/ )
2185 errorString_
= "MidiInWinMM::openPort: a valid connection already exists!";
2186 error( RtMidiError::WARNING
, errorString_
);
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_
);
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_
);
2205 WinMidiData
*data
= static_cast<WinMidiData
*> (apiData_
);
2206 MMRESULT result
= midiInOpen( &data
->inHandle
,
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_
);
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
);
2229 errorString_
= "MidiInWinMM::openPort: error starting Windows MM MIDI input port (PrepareHeader).";
2230 error( RtMidiError::DRIVER_ERROR
, errorString_
);
2234 // Register the buffer.
2235 result
= midiInAddBuffer( data
->inHandle
, data
->sysexBuffer
[i
], sizeof(MIDIHDR
) );
2236 if ( result
!= MMSYSERR_NOERROR
) {
2237 midiInClose( data
->inHandle
);
2239 errorString_
= "MidiInWinMM::openPort: error starting Windows MM MIDI input port (AddBuffer).";
2240 error( RtMidiError::DRIVER_ERROR
, errorString_
);
2245 result
= midiInStart( data
->inHandle
);
2246 if ( result
!= MMSYSERR_NOERROR
) {
2247 midiInClose( data
->inHandle
);
2249 errorString_
= "MidiInWinMM::openPort: error starting Windows MM MIDI input port.";
2250 error( RtMidiError::DRIVER_ERROR
, errorString_
);
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 )
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
);
2279 errorString_
= "MidiInWinMM::openPort: error closing Windows MM MIDI input port (midiInUnprepareHeader).";
2280 error( RtMidiError::DRIVER_ERROR
, errorString_
);
2285 midiInClose( data
->inHandle
);
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_
);
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
;
2320 stringName
+= os
.str();
2326 //*********************************************************************//
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();
2342 WinMidiData
*data
= static_cast<WinMidiData
*> (apiData_
);
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_
);
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
2389 stringName
+= os
.str();
2395 void MidiOutWinMM :: openPort( unsigned int portNumber
, const std::string
&/*portName*/ )
2398 errorString_
= "MidiOutWinMM::openPort: a valid connection already exists!";
2399 error( RtMidiError::WARNING
, errorString_
);
2403 unsigned int nDevices
= midiOutGetNumDevs();
2405 errorString_
= "MidiOutWinMM::openPort: no MIDI output destinations found!";
2406 error( RtMidiError::NO_DEVICES_FOUND
, errorString_
);
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_
);
2418 WinMidiData
*data
= static_cast<WinMidiData
*> (apiData_
);
2419 MMRESULT result
= midiOutOpen( &data
->outHandle
,
2424 if ( result
!= MMSYSERR_NOERROR
) {
2425 errorString_
= "MidiOutWinMM::openPort: error creating Windows MM MIDI output port.";
2426 error( RtMidiError::DRIVER_ERROR
, errorString_
);
2433 void MidiOutWinMM :: closePort( void )
2436 WinMidiData
*data
= static_cast<WinMidiData
*> (apiData_
);
2437 midiOutReset( data
->outHandle
);
2438 midiOutClose( data
->outHandle
);
2439 data
->outHandle
= 0;
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_
);
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_
);
2474 // Copy data to buffer.
2475 for ( unsigned int i
=0; i
<nBytes
; ++i
) buffer
[i
] = message
[i
];
2477 // Create and prepare MIDIHDR structure.
2479 sysex
.lpData
= (LPSTR
) buffer
;
2480 sysex
.dwBufferLength
= nBytes
;
2482 result
= midiOutPrepareHeader( data
->outHandle
, &sysex
, sizeof(MIDIHDR
) );
2483 if ( result
!= MMSYSERR_NOERROR
) {
2485 errorString_
= "MidiOutWinMM::sendMessage: error preparing sysex header.";
2486 error( RtMidiError::DRIVER_ERROR
, errorString_
);
2490 // Send the message.
2491 result
= midiOutLongMsg( data
->outHandle
, &sysex
, sizeof(MIDIHDR
) );
2492 if ( result
!= MMSYSERR_NOERROR
) {
2494 errorString_
= "MidiOutWinMM::sendMessage: error sending sysex message.";
2495 error( RtMidiError::DRIVER_ERROR
, errorString_
);
2499 // Unprepare the buffer and MIDIHDR.
2500 while ( MIDIERR_STILLPLAYING
== midiOutUnprepareHeader( data
->outHandle
, &sysex
, sizeof (MIDIHDR
) ) ) Sleep( 1 );
2503 else { // Channel or system message.
2505 // Make sure the message size isn't too big.
2507 errorString_
= "MidiOutWinMM::sendMessage: message size is greater than 3 bytes (and not sysex)!";
2508 error( RtMidiError::WARNING
, errorString_
);
2512 // Pack MIDI bytes into double word.
2514 unsigned char *ptr
= (unsigned char *) &packet
;
2515 for ( unsigned int i
=0; i
<nBytes
; ++i
) {
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 //*********************************************************************//
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>
2550 #define JACK_RINGBUFFER_SIZE 16384 // Default size for ringbuffer
2552 struct JackMidiData
{
2553 jack_client_t
*client
;
2555 jack_ringbuffer_t
*buffSize
;
2556 jack_ringbuffer_t
*buffMessage
;
2557 jack_time_t lastTime
;
2558 #ifdef HAVE_SEMAPHORE
2562 MidiInApi :: RtMidiInData
*rtMidiIn
;
2565 //*********************************************************************//
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
;
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;
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
);
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";
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_
;
2629 data
->client
= NULL
;
2630 this->clientName
= clientName
;
2635 void MidiInJack :: connect()
2637 JackMidiData
*data
= static_cast<JackMidiData
*> (apiData_
);
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_
);
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();
2658 jack_client_close( data
->client
);
2662 void MidiInJack :: openPort( unsigned int portNumber
, const std::string
&portName
)
2664 JackMidiData
*data
= static_cast<JackMidiData
*> (apiData_
);
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_
);
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_
);
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()
2702 JackMidiData
*data
= static_cast<JackMidiData
*> (apiData_
);
2704 if ( !data
->client
)
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
)
2719 std::string
MidiInJack :: getPortName( unsigned int portNumber
)
2721 JackMidiData
*data
= static_cast<JackMidiData
*> (apiData_
);
2722 std::string
retStr("");
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_
);
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
] );
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
);
2758 //*********************************************************************//
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
;
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
);
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
;
2802 data
->client
= NULL
;
2803 #ifdef HAVE_SEMAPHORE
2804 sem_init(&data
->sem_cleanup
, 0, 0);
2805 sem_init(&data
->sem_needpost
, 0, 0);
2807 this->clientName
= clientName
;
2812 void MidiOutJack :: connect()
2814 JackMidiData
*data
= static_cast<JackMidiData
*> (apiData_
);
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_
);
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();
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
);
2853 void MidiOutJack :: openPort( unsigned int portNumber
, const std::string
&portName
)
2855 JackMidiData
*data
= static_cast<JackMidiData
*> (apiData_
);
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_
);
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_
);
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()
2893 JackMidiData
*data
= static_cast<JackMidiData
*> (apiData_
);
2895 if ( !data
->client
)
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
)
2911 std::string
MidiOutJack :: getPortName( unsigned int portNumber
)
2913 JackMidiData
*data
= static_cast<JackMidiData
*> (apiData_
);
2914 std::string
retStr("");
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_
);
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
] );
2941 void MidiOutJack :: closePort()
2943 JackMidiData
*data
= static_cast<JackMidiData
*> (apiData_
);
2945 if ( data
->port
== NULL
) return;
2947 #ifdef HAVE_SEMAPHORE
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
);
2957 jack_port_unregister( data
->client
, data
->port
);
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
,
2969 jack_ringbuffer_write( data
->buffSize
, ( char * ) &nBytes
, sizeof( nBytes
) );
2972 #endif // __UNIX_JACK__