comparison data/midi/rtmidi/RtMidi.cpp @ 565:3086876472dc

* rtmidi & activity updates
author Chris Cannam
date Tue, 24 Feb 2009 17:25:55 +0000
parents a5e0d1068cae
children 1a30913e26bc
comparison
equal deleted inserted replaced
564:ecef2f1bec18 565:3086876472dc
6 MIDI input/output subclasses RtMidiIn and RtMidiOut. 6 MIDI input/output subclasses RtMidiIn and RtMidiOut.
7 7
8 RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/ 8 RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/
9 9
10 RtMidi: realtime MIDI i/o C++ classes 10 RtMidi: realtime MIDI i/o C++ classes
11 Copyright (c) 2003-2007 Gary P. Scavone 11 Copyright (c) 2003-2009 Gary P. Scavone
12 12
13 Permission is hereby granted, free of charge, to any person 13 Permission is hereby granted, free of charge, to any person
14 obtaining a copy of this software and associated documentation files 14 obtaining a copy of this software and associated documentation files
15 (the "Software"), to deal in the Software without restriction, 15 (the "Software"), to deal in the Software without restriction,
16 including without limitation the rights to use, copy, modify, merge, 16 including without limitation the rights to use, copy, modify, merge,
33 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 33 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 34 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 */ 35 */
36 /**********************************************************************/ 36 /**********************************************************************/
37 37
38 // RtMidi: Version 1.0.7 38 // RtMidi: Version 1.0.8
39 39
40 #include "RtMidi.h" 40 #include "RtMidi.h"
41 #include <sstream> 41 #include <sstream>
42 42
43 //*********************************************************************// 43 //*********************************************************************//
67 67
68 //*********************************************************************// 68 //*********************************************************************//
69 // Common RtMidiIn Definitions 69 // Common RtMidiIn Definitions
70 //*********************************************************************// 70 //*********************************************************************//
71 71
72 RtMidiIn :: RtMidiIn(std::string name) : RtMidi() 72 RtMidiIn :: RtMidiIn( const std::string clientName ) : RtMidi()
73 { 73 {
74 this->initialize(name); 74 this->initialize( clientName );
75 } 75 }
76 76
77 void RtMidiIn :: setCallback( RtMidiCallback callback, void *userData ) 77 void RtMidiIn :: setCallback( RtMidiCallback callback, void *userData )
78 { 78 {
79 if ( inputData_.usingCallback ) { 79 if ( inputData_.usingCallback ) {
142 142
143 //*********************************************************************// 143 //*********************************************************************//
144 // Common RtMidiOut Definitions 144 // Common RtMidiOut Definitions
145 //*********************************************************************// 145 //*********************************************************************//
146 146
147 RtMidiOut :: RtMidiOut(std::string name) : RtMidi() 147 RtMidiOut :: RtMidiOut( const std::string clientName ) : RtMidi()
148 { 148 {
149 this->initialize(name); 149 this->initialize( clientName );
150 } 150 }
151 151
152 152
153 //*********************************************************************// 153 //*********************************************************************//
154 // API: Macintosh OS-X 154 // API: Macintosh OS-X
185 void midiInputCallback( const MIDIPacketList *list, void *procRef, void *srcRef ) 185 void midiInputCallback( const MIDIPacketList *list, void *procRef, void *srcRef )
186 { 186 {
187 RtMidiIn::RtMidiInData *data = static_cast<RtMidiIn::RtMidiInData *> (procRef); 187 RtMidiIn::RtMidiInData *data = static_cast<RtMidiIn::RtMidiInData *> (procRef);
188 CoreMidiData *apiData = static_cast<CoreMidiData *> (data->apiData); 188 CoreMidiData *apiData = static_cast<CoreMidiData *> (data->apiData);
189 189
190 bool continueSysex = false;
191 unsigned char status; 190 unsigned char status;
192 unsigned short nBytes, iByte, size; 191 unsigned short nBytes, iByte, size;
193 unsigned long long time; 192 unsigned long long time;
194 RtMidiIn::MidiMessage message; 193
194 bool& continueSysex = data->continueSysex;
195 RtMidiIn::MidiMessage& message = data->message;
196
195 const MIDIPacket *packet = &list->packet[0]; 197 const MIDIPacket *packet = &list->packet[0];
196 for ( unsigned int i=0; i<list->numPackets; ++i ) { 198 for ( unsigned int i=0; i<list->numPackets; ++i ) {
197 199
198 // My interpretation of the CoreMIDI documentation: all message 200 // My interpretation of the CoreMIDI documentation: all message
199 // types, except sysex, are complete within a packet and there may 201 // types, except sysex, are complete within a packet and there may
200 // be several of them in a single packet. Sysex messages can be 202 // be several of them in a single packet. Sysex messages can be
201 // broken across multiple packets but are bundled alone within a 203 // broken across multiple packets and PacketLists but are bundled
202 // packet. I'm assuming that sysex messages, if segmented, must 204 // alone within each packet (these packets do not contain other
203 // be complete within the same MIDIPacketList. 205 // message types). If sysex messages are split across multiple
206 // MIDIPacketLists, they must be handled by multiple calls to this
207 // function.
204 208
205 nBytes = packet->length; 209 nBytes = packet->length;
206 if ( nBytes == 0 ) continue; 210 if ( nBytes == 0 ) continue;
207 211
208 // Calculate time stamp. 212 // Calculate time stamp.
218 apiData->lastTime = packet->timeStamp; 222 apiData->lastTime = packet->timeStamp;
219 223
220 iByte = 0; 224 iByte = 0;
221 if ( continueSysex ) { 225 if ( continueSysex ) {
222 // We have a continuing, segmented sysex message. 226 // We have a continuing, segmented sysex message.
223 if ( !(data->ignoreFlags & 0x01) ) { 227 if ( !( data->ignoreFlags & 0x01 ) ) {
224 // If we're not ignoring sysex messages, copy the entire packet. 228 // If we're not ignoring sysex messages, copy the entire packet.
225 for ( unsigned int j=0; j<nBytes; j++ ) 229 for ( unsigned int j=0; j<nBytes; j++ )
226 message.bytes.push_back( packet->data[j] ); 230 message.bytes.push_back( packet->data[j] );
227 } 231 }
228 if ( packet->data[nBytes] == 0xF7 ) continueSysex = false; 232 continueSysex = packet->data[nBytes-1] != 0xF7;
233
229 if ( !continueSysex ) { 234 if ( !continueSysex ) {
230 // If not a continuing sysex message, invoke the user callback function or queue the message. 235 // If not a continuing sysex message, invoke the user callback function or queue the message.
231 if ( data->usingCallback && message.bytes.size() > 0 ) { 236 if ( data->usingCallback && message.bytes.size() > 0 ) {
232 RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback; 237 RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
233 callback( message.timeStamp, &message.bytes, data->userData ); 238 callback( message.timeStamp, &message.bytes, data->userData );
257 if ( data->ignoreFlags & 0x01 ) { 262 if ( data->ignoreFlags & 0x01 ) {
258 size = 0; 263 size = 0;
259 iByte = nBytes; 264 iByte = nBytes;
260 } 265 }
261 else size = nBytes - iByte; 266 else size = nBytes - iByte;
262 if ( packet->data[nBytes] == 0xF7 ) continueSysex = false; 267 continueSysex = packet->data[nBytes-1] != 0xF7;
263 } 268 }
264 else if ( status < 0xF3 ) { 269 else if ( status < 0xF3 ) {
265 if ( status == 0xF1 && (data->ignoreFlags & 0x02) ) { 270 if ( status == 0xF1 && (data->ignoreFlags & 0x02) ) {
266 // A MIDI time code message and we're ignoring it. 271 // A MIDI time code message and we're ignoring it.
267 size = 0; 272 size = 0;
309 } 314 }
310 packet = MIDIPacketNext(packet); 315 packet = MIDIPacketNext(packet);
311 } 316 }
312 } 317 }
313 318
314 void RtMidiIn :: initialize(std::string name) 319 void RtMidiIn :: initialize( const std::string& clientName )
315 { 320 {
316 // Set up our client. 321 // Set up our client.
317 MIDIClientRef client; 322 MIDIClientRef client;
318 OSStatus result = MIDIClientCreate 323 OSStatus result = MIDIClientCreate( CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII ), NULL, NULL, &client );
319 ( CFStringCreateWithBytes(0, (unsigned char *)name.data(),
320 name.size(), kCFStringEncodingUTF8, 0), NULL, NULL, &client );
321 if ( result != noErr ) { 324 if ( result != noErr ) {
322 errorString_ = "RtMidiIn::initialize: error creating OS-X MIDI client object."; 325 errorString_ = "RtMidiIn::initialize: error creating OS-X MIDI client object.";
323 error( RtError::DRIVER_ERROR ); 326 error( RtError::DRIVER_ERROR );
324 } 327 }
325 328
329 data->endpoint = 0; 332 data->endpoint = 0;
330 apiData_ = (void *) data; 333 apiData_ = (void *) data;
331 inputData_.apiData = (void *) data; 334 inputData_.apiData = (void *) data;
332 } 335 }
333 336
334 void RtMidiIn :: openPort( unsigned int portNumber ) 337 void RtMidiIn :: openPort( unsigned int portNumber, const std::string portName )
335 { 338 {
336 if ( connected_ ) { 339 if ( connected_ ) {
337 errorString_ = "RtMidiIn::openPort: a valid connection already exists!"; 340 errorString_ = "RtMidiIn::openPort: a valid connection already exists!";
338 error( RtError::WARNING ); 341 error( RtError::WARNING );
339 return; 342 return;
352 error( RtError::INVALID_PARAMETER ); 355 error( RtError::INVALID_PARAMETER );
353 } 356 }
354 357
355 MIDIPortRef port; 358 MIDIPortRef port;
356 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_); 359 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
357 OSStatus result = MIDIInputPortCreate( data->client, CFSTR("MIDI Input Port"), midiInputCallback, (void *)&inputData_, &port ); 360 OSStatus result = MIDIInputPortCreate( data->client,
361 CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
362 midiInputCallback, (void *)&inputData_, &port );
358 if ( result != noErr ) { 363 if ( result != noErr ) {
359 MIDIClientDispose( data->client ); 364 MIDIClientDispose( data->client );
360 errorString_ = "RtMidiIn::openPort: error creating OS-X MIDI input port."; 365 errorString_ = "RtMidiIn::openPort: error creating OS-X MIDI input port.";
361 error( RtError::DRIVER_ERROR ); 366 error( RtError::DRIVER_ERROR );
362 } 367 }
479 CFRelease( nameRef ); 484 CFRelease( nameRef );
480 std::string stringName = name; 485 std::string stringName = name;
481 return stringName; 486 return stringName;
482 } 487 }
483 488
484 void RtMidiOut :: initialize(std::string name) 489 void RtMidiOut :: initialize( const std::string& clientName )
485 { 490 {
486 // Set up our client. 491 // Set up our client.
487 MIDIClientRef client; 492 MIDIClientRef client;
488 OSStatus result = MIDIClientCreate 493 OSStatus result = MIDIClientCreate( CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII ), NULL, NULL, &client );
489 ( CFStringCreateWithBytes(0, (unsigned char *)name.data(),
490 name.size(), kCFStringEncodingUTF8, 0), NULL, NULL, &client );
491 if ( result != noErr ) { 494 if ( result != noErr ) {
492 errorString_ = "RtMidiOut::initialize: error creating OS-X MIDI client object."; 495 errorString_ = "RtMidiOut::initialize: error creating OS-X MIDI client object.";
493 error( RtError::DRIVER_ERROR ); 496 error( RtError::DRIVER_ERROR );
494 } 497 }
495 498
498 data->client = client; 501 data->client = client;
499 data->endpoint = 0; 502 data->endpoint = 0;
500 apiData_ = (void *) data; 503 apiData_ = (void *) data;
501 } 504 }
502 505
503 void RtMidiOut :: openPort( unsigned int portNumber ) 506 void RtMidiOut :: openPort( unsigned int portNumber, const std::string portName )
504 { 507 {
505 if ( connected_ ) { 508 if ( connected_ ) {
506 errorString_ = "RtMidiOut::openPort: a valid connection already exists!"; 509 errorString_ = "RtMidiOut::openPort: a valid connection already exists!";
507 error( RtError::WARNING ); 510 error( RtError::WARNING );
508 return; 511 return;
521 error( RtError::INVALID_PARAMETER ); 524 error( RtError::INVALID_PARAMETER );
522 } 525 }
523 526
524 MIDIPortRef port; 527 MIDIPortRef port;
525 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_); 528 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
526 OSStatus result = MIDIOutputPortCreate( data->client, CFSTR("Virtual MIDI Output Port"), &port ); 529 OSStatus result = MIDIOutputPortCreate( data->client,
530 CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
531 &port );
527 if ( result != noErr ) { 532 if ( result != noErr ) {
528 MIDIClientDispose( data->client ); 533 MIDIClientDispose( data->client );
529 errorString_ = "RtMidiOut::openPort: error creating OS-X MIDI output port."; 534 errorString_ = "RtMidiOut::openPort: error creating OS-X MIDI output port.";
530 error( RtError::DRIVER_ERROR ); 535 error( RtError::DRIVER_ERROR );
531 } 536 }
590 delete data; 595 delete data;
591 } 596 }
592 597
593 void RtMidiOut :: sendMessage( std::vector<unsigned char> *message ) 598 void RtMidiOut :: sendMessage( std::vector<unsigned char> *message )
594 { 599 {
600 // The CoreMidi documentation indicates a maximum PackList size of
601 // 64K, so we may need to break long sysex messages into pieces and
602 // send via separate lists.
595 unsigned int nBytes = message->size(); 603 unsigned int nBytes = message->size();
596 // Pad the buffer for extra (unknown) structure data. 604 if ( nBytes == 0 ) {
597 Byte buffer[nBytes+32]; 605 errorString_ = "RtMidiOut::sendMessage: no data in message argument!";
598 MIDIPacketList *pktlist = (MIDIPacketList *) buffer; 606 error( RtError::WARNING );
599 MIDIPacket *curPacket = MIDIPacketListInit( pktlist ); 607 return;
600 608 }
609
610 if ( nBytes > 3 && ( message->at(0) != 0xF0 ) ) {
611 errorString_ = "RtMidiOut::sendMessage: message format problem ... not sysex but > 3 bytes?";
612 error( RtError::WARNING );
613 return;
614 }
615
616 unsigned int packetBytes, bytesLeft = nBytes;
617 unsigned int messageIndex = 0;
601 MIDITimeStamp timeStamp = 0; 618 MIDITimeStamp timeStamp = 0;
602 curPacket = MIDIPacketListAdd( pktlist, sizeof(buffer), curPacket, timeStamp, nBytes, &message->at(0) );
603
604 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_); 619 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
605 620
606 // Send to any destinations that may have connected to us. 621 while ( bytesLeft > 0 ) {
607 OSStatus result; 622
608 if ( data->endpoint ) { 623 packetBytes = ( bytesLeft > 32736 ) ? 32736 : bytesLeft;
609 result = MIDIReceived( data->endpoint, pktlist ); 624 Byte buffer[packetBytes + 32]; // extra memory for other structure variables
610 if ( result != noErr ) { 625 MIDIPacketList *packetList = (MIDIPacketList *) buffer;
611 errorString_ = "RtMidiOut::sendMessage: error sending MIDI to virtual destinations."; 626 MIDIPacket *curPacket = MIDIPacketListInit( packetList );
612 error( RtError::WARNING ); 627
613 } 628 curPacket = MIDIPacketListAdd( packetList, packetBytes+32, curPacket, timeStamp, packetBytes, (const Byte *) &message->at( messageIndex ) );
614 } 629 if ( !curPacket ) {
615 630 errorString_ = "RtMidiOut::sendMessage: could not allocate packet list";
616 // And send to an explicit destination port if we're connected. 631 error( RtError::DRIVER_ERROR );
617 if ( connected_ ) { 632 }
618 result = MIDISend( data->port, data->destinationId, pktlist ); 633 messageIndex += packetBytes;
619 if ( result != noErr ) { 634 bytesLeft -= packetBytes;
620 errorString_ = "RtMidiOut::sendMessage: error sending MIDI message to port."; 635
621 error( RtError::WARNING ); 636 // Send to any destinations that may have connected to us.
637 OSStatus result;
638 if ( data->endpoint ) {
639 result = MIDIReceived( data->endpoint, packetList );
640 if ( result != noErr ) {
641 errorString_ = "RtMidiOut::sendMessage: error sending MIDI to virtual destinations.";
642 error( RtError::WARNING );
643 }
644 }
645
646 // And send to an explicit destination port if we're connected.
647 if ( connected_ ) {
648 result = MIDISend( data->port, data->destinationId, packetList );
649 if ( result != noErr ) {
650 errorString_ = "RtMidiOut::sendMessage: error sending MIDI message to port.";
651 error( RtError::WARNING );
652 }
622 } 653 }
623 } 654 }
624 } 655 }
625 656
626 #endif // __MACOSX_CORE__ 657 #endif // __MACOSX_CORE__
715 continue; 746 continue;
716 } 747 }
717 748
718 // This is a bit weird, but we now have to decode an ALSA MIDI 749 // This is a bit weird, but we now have to decode an ALSA MIDI
719 // event (back) into MIDI bytes. We'll ignore non-MIDI types. 750 // event (back) into MIDI bytes. We'll ignore non-MIDI types.
720 message.bytes.clear(); 751 if ( !continueSysex )
752 message.bytes.clear();
753
721 switch ( ev->type ) { 754 switch ( ev->type ) {
722 755
723 case SND_SEQ_EVENT_PORT_SUBSCRIBED: 756 case SND_SEQ_EVENT_PORT_SUBSCRIBED:
724 #if defined(__RTMIDI_DEBUG__) 757 #if defined(__RTMIDI_DEBUG__)
725 std::cout << "RtMidiIn::alsaMidiHandler: port connection made!\n"; 758 std::cout << "RtMidiIn::alsaMidiHandler: port connection made!\n";
726 #endif 759 #endif
727 break; 760 break;
728 761
729 case SND_SEQ_EVENT_PORT_UNSUBSCRIBED: 762 case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
763 #if defined(__RTMIDI_DEBUG__)
730 std::cerr << "RtMidiIn::alsaMidiHandler: port connection has closed!\n"; 764 std::cerr << "RtMidiIn::alsaMidiHandler: port connection has closed!\n";
731 data->doInput = false; 765 // FIXME: this is called for all unsubscribe events, even ones
766 //not related to this particular connection. As it stands, I
767 //see no data provided in the "source" and "dest" fields so
768 //there is nothing we can do about this at this time.
769 // std::cout << "sender = " << ev->source.client << ", dest = " << ev->dest.port << std::endl;
770 #endif
771 //data->doInput = false;
732 break; 772 break;
733 773
734 case SND_SEQ_EVENT_QFRAME: // MIDI time code 774 case SND_SEQ_EVENT_QFRAME: // MIDI time code
735 if ( data->ignoreFlags & 0x02 ) break; 775 if ( data->ignoreFlags & 0x02 ) break;
736 776
770 if ( !continueSysex ) 810 if ( !continueSysex )
771 message.bytes.assign( buffer, &buffer[nBytes] ); 811 message.bytes.assign( buffer, &buffer[nBytes] );
772 else 812 else
773 message.bytes.insert( message.bytes.end(), buffer, &buffer[nBytes] ); 813 message.bytes.insert( message.bytes.end(), buffer, &buffer[nBytes] );
774 814
775 continueSysex = ( ev->type == SND_SEQ_EVENT_SYSEX && message.bytes.back() != 0xF7 ); 815 continueSysex = ( ( ev->type == SND_SEQ_EVENT_SYSEX ) && ( message.bytes.back() != 0xF7 ) );
776 if ( continueSysex ) 816 if ( continueSysex )
777 break; 817 break;
778 818
779 // Calculate the time stamp: 819 // Calculate the time stamp:
780 message.timeStamp = 0.0; 820 message.timeStamp = 0.0;
796 } 836 }
797 837
798 snd_seq_free_event(ev); 838 snd_seq_free_event(ev);
799 if ( message.bytes.size() == 0 ) continue; 839 if ( message.bytes.size() == 0 ) continue;
800 840
801 if ( data->usingCallback ) { 841 if ( data->usingCallback && !continueSysex ) {
802 RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback; 842 RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
803 callback( message.timeStamp, &message.bytes, data->userData ); 843 callback( message.timeStamp, &message.bytes, data->userData );
804 } 844 }
805 else { 845 else {
806 // As long as we haven't reached our queue size limit, push the message. 846 // As long as we haven't reached our queue size limit, push the message.
815 snd_midi_event_free( apiData->coder ); 855 snd_midi_event_free( apiData->coder );
816 apiData->coder = 0; 856 apiData->coder = 0;
817 return 0; 857 return 0;
818 } 858 }
819 859
820 void RtMidiIn :: initialize(std::string name) 860 void RtMidiIn :: initialize( const std::string& clientName )
821 { 861 {
822 // Set up the ALSA sequencer client. 862 // Set up the ALSA sequencer client.
823 snd_seq_t *seq; 863 snd_seq_t *seq;
824 int result = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK); 864 int result = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK);
825 if ( result < 0 ) { 865 if ( result < 0 ) {
826 errorString_ = "RtMidiIn::initialize: error creating ALSA sequencer input client object."; 866 errorString_ = "RtMidiIn::initialize: error creating ALSA sequencer input client object.";
827 error( RtError::DRIVER_ERROR ); 867 error( RtError::DRIVER_ERROR );
828 } 868 }
829 869
830 // Set client name. 870 // Set client name.
831 snd_seq_set_client_name(seq, name.c_str()); 871 snd_seq_set_client_name( seq, clientName.c_str() );
832 872
833 // Save our api-specific connection information. 873 // Save our api-specific connection information.
834 AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData; 874 AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
835 data->seq = seq; 875 data->seq = seq;
836 data->vport = -1; 876 data->vport = -1;
862 if ( client == 0 ) continue; 902 if ( client == 0 ) continue;
863 // Reset query info 903 // Reset query info
864 snd_seq_port_info_set_client( pinfo, client ); 904 snd_seq_port_info_set_client( pinfo, client );
865 snd_seq_port_info_set_port( pinfo, -1 ); 905 snd_seq_port_info_set_port( pinfo, -1 );
866 while ( snd_seq_query_next_port( seq, pinfo ) >= 0 ) { 906 while ( snd_seq_query_next_port( seq, pinfo ) >= 0 ) {
867 if ( !PORT_TYPE( pinfo, type ) ) continue; 907 unsigned int atyp = snd_seq_port_info_get_type( pinfo );
908 if ( ( atyp & SND_SEQ_PORT_TYPE_MIDI_GENERIC ) == 0 ) continue;
909 unsigned int caps = snd_seq_port_info_get_capability( pinfo );
910 if ( ( caps & type ) != type ) continue;
868 if ( count == portNumber ) return 1; 911 if ( count == portNumber ) return 1;
869 count++; 912 count++;
870 } 913 }
871 } 914 }
872 915
873 // If a negative portNumber was used, return the port count. 916 // If a negative portNumber was used, return the port count.
874 if ( portNumber < 0 ) return count; 917 if ( portNumber < 0 ) return count;
875 return 0; 918 return 0;
876 } 919 }
877 920
878 void RtMidiIn :: openPort( unsigned int portNumber ) 921 void RtMidiIn :: openPort( unsigned int portNumber, const std::string portName )
879 { 922 {
880 if ( connected_ ) { 923 if ( connected_ ) {
881 errorString_ = "RtMidiIn::openPort: a valid connection already exists!"; 924 errorString_ = "RtMidiIn::openPort: a valid connection already exists!";
882 error( RtError::WARNING ); 925 error( RtError::WARNING );
883 return; 926 return;
887 if (nSrc < 1) { 930 if (nSrc < 1) {
888 errorString_ = "RtMidiIn::openPort: no MIDI input sources found!"; 931 errorString_ = "RtMidiIn::openPort: no MIDI input sources found!";
889 error( RtError::NO_DEVICES_FOUND ); 932 error( RtError::NO_DEVICES_FOUND );
890 } 933 }
891 934
892 snd_seq_port_info_t *pinfo; 935 snd_seq_port_info_t *pinfo;
893 snd_seq_port_info_alloca( &pinfo ); 936 snd_seq_port_info_alloca( &pinfo );
894 std::ostringstream ost; 937 std::ostringstream ost;
895 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_); 938 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
896 if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) == 0 ) { 939 if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) == 0 ) {
897 ost << "RtMidiIn::openPort: the 'portNumber' argument (" << portNumber << ") is invalid."; 940 ost << "RtMidiIn::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
898 errorString_ = ost.str(); 941 errorString_ = ost.str();
899 error( RtError::INVALID_PARAMETER ); 942 error( RtError::INVALID_PARAMETER );
900 } 943 }
901 944
902 char name[20];
903 sprintf(name, "Input %d", portNumber + 1);
904 945
905 snd_seq_addr_t sender, receiver; 946 snd_seq_addr_t sender, receiver;
906 sender.client = snd_seq_port_info_get_client( pinfo ); 947 sender.client = snd_seq_port_info_get_client( pinfo );
907 sender.port = snd_seq_port_info_get_port( pinfo ); 948 sender.port = snd_seq_port_info_get_port( pinfo );
908 receiver.client = snd_seq_client_id( data->seq ); 949 receiver.client = snd_seq_client_id( data->seq );
917 SND_SEQ_PORT_TYPE_APPLICATION ); 958 SND_SEQ_PORT_TYPE_APPLICATION );
918 snd_seq_port_info_set_midi_channels(pinfo, 16); 959 snd_seq_port_info_set_midi_channels(pinfo, 16);
919 snd_seq_port_info_set_timestamping(pinfo, 1); 960 snd_seq_port_info_set_timestamping(pinfo, 1);
920 snd_seq_port_info_set_timestamp_real(pinfo, 1); 961 snd_seq_port_info_set_timestamp_real(pinfo, 1);
921 snd_seq_port_info_set_timestamp_queue(pinfo, data->queue_id); 962 snd_seq_port_info_set_timestamp_queue(pinfo, data->queue_id);
922 snd_seq_port_info_set_name(pinfo, name); 963 snd_seq_port_info_set_name(pinfo, portName.c_str() );
923 data->vport = snd_seq_create_port(data->seq, pinfo); 964 data->vport = snd_seq_create_port(data->seq, pinfo);
924 965
925 if ( data->vport < 0 ) { 966 if ( data->vport < 0 ) {
926 errorString_ = "RtMidiIn::openPort: ALSA error creating input port."; 967 errorString_ = "RtMidiIn::openPort: ALSA error creating input port.";
927 error( RtError::DRIVER_ERROR ); 968 error( RtError::DRIVER_ERROR );
1053 return portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, -1 ); 1094 return portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, -1 );
1054 } 1095 }
1055 1096
1056 std::string RtMidiIn :: getPortName( unsigned int portNumber ) 1097 std::string RtMidiIn :: getPortName( unsigned int portNumber )
1057 { 1098 {
1058 snd_seq_port_info_t *pinfo; 1099 snd_seq_client_info_t *cinfo;
1059 snd_seq_port_info_alloca( &pinfo ); 1100 snd_seq_port_info_t *pinfo;
1101 snd_seq_client_info_alloca( &cinfo );
1102 snd_seq_port_info_alloca( &pinfo );
1060 1103
1061 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_); 1104 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1062 if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) ) { 1105 if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) ) {
1063 std::string stringName = std::string( snd_seq_port_info_get_name( pinfo ) ); 1106 int cnum = snd_seq_port_info_get_client( pinfo );
1107 snd_seq_get_any_client_info( data->seq, cnum, cinfo );
1108 std::ostringstream os;
1109 os << snd_seq_client_info_get_name( cinfo );
1110 os << ":";
1111 os << snd_seq_port_info_get_port( pinfo );
1112 std::string stringName = os.str();
1064 return stringName; 1113 return stringName;
1065 } 1114 }
1066 1115
1067 // If we get here, we didn't find a match. 1116 // If we get here, we didn't find a match.
1068 errorString_ = "RtMidiIn::getPortName: error looking for port name!"; 1117 errorString_ = "RtMidiIn::getPortName: error looking for port name!";
1084 return portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, -1 ); 1133 return portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, -1 );
1085 } 1134 }
1086 1135
1087 std::string RtMidiOut :: getPortName( unsigned int portNumber ) 1136 std::string RtMidiOut :: getPortName( unsigned int portNumber )
1088 { 1137 {
1089 snd_seq_port_info_t *pinfo; 1138 snd_seq_client_info_t *cinfo;
1090 snd_seq_port_info_alloca( &pinfo ); 1139 snd_seq_port_info_t *pinfo;
1140 snd_seq_client_info_alloca( &cinfo );
1141 snd_seq_port_info_alloca( &pinfo );
1091 1142
1092 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_); 1143 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1093 if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) ) { 1144 if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) ) {
1094 std::string stringName = std::string( snd_seq_port_info_get_name( pinfo ) ); 1145 int cnum = snd_seq_port_info_get_client(pinfo);
1146 snd_seq_get_any_client_info( data->seq, cnum, cinfo );
1147 std::ostringstream os;
1148 os << snd_seq_client_info_get_name(cinfo);
1149 os << ":";
1150 os << snd_seq_port_info_get_port(pinfo);
1151 std::string stringName = os.str();
1095 return stringName; 1152 return stringName;
1096 } 1153 }
1097 1154
1098 // If we get here, we didn't find a match. 1155 // If we get here, we didn't find a match.
1099 errorString_ = "RtMidiOut::getPortName: error looking for port name!"; 1156 errorString_ = "RtMidiOut::getPortName: error looking for port name!";
1100 error( RtError::INVALID_PARAMETER ); 1157 error( RtError::INVALID_PARAMETER );
1101 return 0; 1158 return 0;
1102 } 1159 }
1103 1160
1104 void RtMidiOut :: initialize(std::string name) 1161 void RtMidiOut :: initialize( const std::string& clientName )
1105 { 1162 {
1106 // Set up the ALSA sequencer client. 1163 // Set up the ALSA sequencer client.
1107 snd_seq_t *seq; 1164 snd_seq_t *seq;
1108 int result = snd_seq_open(&seq, "default", SND_SEQ_OPEN_OUTPUT, 0); 1165 int result = snd_seq_open( &seq, "default", SND_SEQ_OPEN_OUTPUT, SND_SEQ_NONBLOCK );
1109 if ( result < 0 ) { 1166 if ( result < 0 ) {
1110 errorString_ = "RtMidiOut::initialize: error creating ALSA sequencer client object."; 1167 errorString_ = "RtMidiOut::initialize: error creating ALSA sequencer client object.";
1111 error( RtError::DRIVER_ERROR ); 1168 error( RtError::DRIVER_ERROR );
1112 } 1169 }
1113 1170
1114 // Set client name. 1171 // Set client name.
1115 snd_seq_set_client_name(seq, name.c_str()); 1172 snd_seq_set_client_name( seq, clientName.c_str() );
1116 1173
1117 // Save our api-specific connection information. 1174 // Save our api-specific connection information.
1118 AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData; 1175 AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
1119 data->seq = seq; 1176 data->seq = seq;
1120 data->vport = -1; 1177 data->vport = -1;
1135 } 1192 }
1136 snd_midi_event_init( data->coder ); 1193 snd_midi_event_init( data->coder );
1137 apiData_ = (void *) data; 1194 apiData_ = (void *) data;
1138 } 1195 }
1139 1196
1140 void RtMidiOut :: openPort( unsigned int portNumber ) 1197 void RtMidiOut :: openPort( unsigned int portNumber, const std::string portName )
1141 { 1198 {
1142 if ( connected_ ) { 1199 if ( connected_ ) {
1143 errorString_ = "RtMidiOut::openPort: a valid connection already exists!"; 1200 errorString_ = "RtMidiOut::openPort: a valid connection already exists!";
1144 error( RtError::WARNING ); 1201 error( RtError::WARNING );
1145 return; 1202 return;
1149 if (nSrc < 1) { 1206 if (nSrc < 1) {
1150 errorString_ = "RtMidiOut::openPort: no MIDI output sources found!"; 1207 errorString_ = "RtMidiOut::openPort: no MIDI output sources found!";
1151 error( RtError::NO_DEVICES_FOUND ); 1208 error( RtError::NO_DEVICES_FOUND );
1152 } 1209 }
1153 1210
1154 snd_seq_port_info_t *pinfo; 1211 snd_seq_port_info_t *pinfo;
1155 snd_seq_port_info_alloca( &pinfo ); 1212 snd_seq_port_info_alloca( &pinfo );
1156 std::ostringstream ost; 1213 std::ostringstream ost;
1157 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_); 1214 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
1158 if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) == 0 ) { 1215 if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) == 0 ) {
1159 ost << "RtMidiOut::openPort: the 'portNumber' argument (" << portNumber << ") is invalid."; 1216 ost << "RtMidiOut::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
1160 errorString_ = ost.str(); 1217 errorString_ = ost.str();
1164 snd_seq_addr_t sender, receiver; 1221 snd_seq_addr_t sender, receiver;
1165 receiver.client = snd_seq_port_info_get_client( pinfo ); 1222 receiver.client = snd_seq_port_info_get_client( pinfo );
1166 receiver.port = snd_seq_port_info_get_port( pinfo ); 1223 receiver.port = snd_seq_port_info_get_port( pinfo );
1167 sender.client = snd_seq_client_id( data->seq ); 1224 sender.client = snd_seq_client_id( data->seq );
1168 1225
1169 char name[20];
1170 sprintf(name, "Output %d", portNumber + 1);
1171
1172 if ( data->vport < 0 ) { 1226 if ( data->vport < 0 ) {
1173 data->vport = snd_seq_create_simple_port( data->seq, name, 1227 data->vport = snd_seq_create_simple_port( data->seq, portName.c_str(),
1174 SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, 1228 SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
1175 SND_SEQ_PORT_TYPE_MIDI_GENERIC ); 1229 SND_SEQ_PORT_TYPE_MIDI_GENERIC );
1176 if ( data->vport < 0 ) { 1230 if ( data->vport < 0 ) {
1177 errorString_ = "RtMidiOut::openPort: ALSA error creating output port."; 1231 errorString_ = "RtMidiOut::openPort: ALSA error creating output port.";
1178 error( RtError::DRIVER_ERROR ); 1232 error( RtError::DRIVER_ERROR );
1430 } 1484 }
1431 1485
1432 return 0; 1486 return 0;
1433 } 1487 }
1434 1488
1435 void RtMidiIn :: initialize(std::string name) 1489 void RtMidiIn :: initialize( const std::string& /*clientName*/ )
1436 { 1490 {
1437 // Initialize the Irix MIDI system. At the moment, we will not 1491 // Initialize the Irix MIDI system. At the moment, we will not
1438 // worry about a return value of zero (ports) because there is a 1492 // worry about a return value of zero (ports) because there is a
1439 // chance the user could plug something in after instantiation. 1493 // chance the user could plug something in after instantiation.
1440 int nPorts = mdInit(); 1494 int nPorts = mdInit();
1443 IrixMidiData *data = (IrixMidiData *) new IrixMidiData; 1497 IrixMidiData *data = (IrixMidiData *) new IrixMidiData;
1444 apiData_ = (void *) data; 1498 apiData_ = (void *) data;
1445 inputData_.apiData = (void *) data; 1499 inputData_.apiData = (void *) data;
1446 } 1500 }
1447 1501
1448 void RtMidiIn :: openPort( unsigned int portNumber ) 1502 void RtMidiIn :: openPort( unsigned int portNumber, const std::string /*portName*/ )
1449 { 1503 {
1450 if ( connected_ ) { 1504 if ( connected_ ) {
1451 errorString_ = "RtMidiIn::openPort: a valid connection already exists!"; 1505 errorString_ = "RtMidiIn::openPort: a valid connection already exists!";
1452 error( RtError::WARNING ); 1506 error( RtError::WARNING );
1453 return; 1507 return;
1571 1625
1572 std::string stringName = std::string( mdGetName( portNumber ) ); 1626 std::string stringName = std::string( mdGetName( portNumber ) );
1573 return stringName; 1627 return stringName;
1574 } 1628 }
1575 1629
1576 void RtMidiOut :: initialize(std::string name) 1630 void RtMidiOut :: initialize( const std::string& /*clientName*/ )
1577 { 1631 {
1578 // Initialize the Irix MIDI system. At the moment, we will not 1632 // Initialize the Irix MIDI system. At the moment, we will not
1579 // worry about a return value of zero (ports) because there is a 1633 // worry about a return value of zero (ports) because there is a
1580 // chance the user could plug something in after instantiation. 1634 // chance the user could plug something in after instantiation.
1581 int nPorts = mdInit(); 1635 int nPorts = mdInit();
1583 // Create our api-specific connection information. 1637 // Create our api-specific connection information.
1584 IrixMidiData *data = (IrixMidiData *) new IrixMidiData; 1638 IrixMidiData *data = (IrixMidiData *) new IrixMidiData;
1585 apiData_ = (void *) data; 1639 apiData_ = (void *) data;
1586 } 1640 }
1587 1641
1588 void RtMidiOut :: openPort( unsigned int portNumber ) 1642 void RtMidiOut :: openPort( unsigned int portNumber, const std::string /*portName*/ )
1589 { 1643 {
1590 if ( connected_ ) { 1644 if ( connected_ ) {
1591 errorString_ = "RtMidiOut::openPort: a valid connection already exists!"; 1645 errorString_ = "RtMidiOut::openPort: a valid connection already exists!";
1592 error( RtError::WARNING ); 1646 error( RtError::WARNING );
1593 return; 1647 return;
1761 1815
1762 // Copy bytes to our MIDI message. 1816 // Copy bytes to our MIDI message.
1763 unsigned char *ptr = (unsigned char *) &midiMessage; 1817 unsigned char *ptr = (unsigned char *) &midiMessage;
1764 for ( int i=0; i<nBytes; i++ ) apiData->message.bytes.push_back( *ptr++ ); 1818 for ( int i=0; i<nBytes; i++ ) apiData->message.bytes.push_back( *ptr++ );
1765 } 1819 }
1766 else if ( !(data->ignoreFlags & 0x01) ) { 1820 else { // Sysex message ( MIM_LONGDATA )
1767 // Sysex message and we're not ignoring it 1821 MIDIHDR *sysex = ( MIDIHDR *) midiMessage;
1768 MIDIHDR *sysex = ( MIDIHDR *) midiMessage; 1822 if ( !( data->ignoreFlags & 0x01 ) ) {
1769 for ( int i=0; i<(int)sysex->dwBytesRecorded; i++ ) 1823 // Sysex message and we're not ignoring it
1770 apiData->message.bytes.push_back( sysex->lpData[i] ); 1824 for ( int i=0; i<(int)sysex->dwBytesRecorded; i++ )
1771 1825 apiData->message.bytes.push_back( sysex->lpData[i] );
1772 // When the callback has to be unaffected (application closes), 1826 }
1773 // it seems WinMM calls it with an empty sysex to de-queue the buffer 1827
1774 // If the buffer is requeued afer that message, the PC suddenly reboots 1828 // The WinMM API requires that the sysex buffer be requeued after
1775 // after one or two minutes (JB). 1829 // input of each sysex message. Even if we are ignoring sysex
1830 // messages, we still need to requeue the buffer in case the user
1831 // decides to not ignore sysex messages in the future. However,
1832 // it seems that WinMM calls this function with an empty sysex
1833 // buffer when an application closes and in this case, we should
1834 // avoid requeueing it, else the computer suddenly reboots after
1835 // one or two minutes.
1776 if ( apiData->sysexBuffer->dwBytesRecorded > 0 ) { 1836 if ( apiData->sysexBuffer->dwBytesRecorded > 0 ) {
1837 //if ( sysex->dwBytesRecorded > 0 ) {
1777 MMRESULT result = midiInAddBuffer( apiData->inHandle, apiData->sysexBuffer, sizeof(MIDIHDR) ); 1838 MMRESULT result = midiInAddBuffer( apiData->inHandle, apiData->sysexBuffer, sizeof(MIDIHDR) );
1778 if ( result != MMSYSERR_NOERROR ) 1839 if ( result != MMSYSERR_NOERROR )
1779 std::cerr << "\nRtMidiIn::midiInputCallback: error sending sysex to Midi device!!\n\n"; 1840 std::cerr << "\nRtMidiIn::midiInputCallback: error sending sysex to Midi device!!\n\n";
1780 } 1841
1842 if ( data->ignoreFlags & 0x01 ) return;
1843 }
1844 else return;
1781 } 1845 }
1782 1846
1783 if ( data->usingCallback ) { 1847 if ( data->usingCallback ) {
1784 RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback; 1848 RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
1785 callback( apiData->message.timeStamp, &apiData->message.bytes, data->userData ); 1849 callback( apiData->message.timeStamp, &apiData->message.bytes, data->userData );
1790 data->queue.push( apiData->message ); 1854 data->queue.push( apiData->message );
1791 else 1855 else
1792 std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n"; 1856 std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
1793 } 1857 }
1794 1858
1795 // Clear the vector for the next input message. Note that doing 1859 // Clear the vector for the next input message.
1796 // this here allows our code to work for sysex messages which are
1797 // segmented across multiple buffers.
1798 apiData->message.bytes.clear(); 1860 apiData->message.bytes.clear();
1799 } 1861 }
1800 1862
1801 void RtMidiIn :: initialize(std::string name) 1863 void RtMidiIn :: initialize( const std::string& /*clientName*/ )
1802 { 1864 {
1803 // We'll issue a warning here if no devices are available but not 1865 // We'll issue a warning here if no devices are available but not
1804 // throw an error since the user can plugin something later. 1866 // throw an error since the user can plugin something later.
1805 unsigned int nDevices = midiInGetNumDevs(); 1867 unsigned int nDevices = midiInGetNumDevs();
1806 if ( nDevices == 0 ) { 1868 if ( nDevices == 0 ) {
1813 apiData_ = (void *) data; 1875 apiData_ = (void *) data;
1814 inputData_.apiData = (void *) data; 1876 inputData_.apiData = (void *) data;
1815 data->message.bytes.clear(); // needs to be empty for first input message 1877 data->message.bytes.clear(); // needs to be empty for first input message
1816 } 1878 }
1817 1879
1818 void RtMidiIn :: openPort( unsigned int portNumber ) 1880 void RtMidiIn :: openPort( unsigned int portNumber, const std::string /*portName*/ )
1819 { 1881 {
1820 if ( connected_ ) { 1882 if ( connected_ ) {
1821 errorString_ = "RtMidiIn::openPort: a valid connection already exists!"; 1883 errorString_ = "RtMidiIn::openPort: a valid connection already exists!";
1822 error( RtError::WARNING ); 1884 error( RtError::WARNING );
1823 return; 1885 return;
1847 error( RtError::DRIVER_ERROR ); 1909 error( RtError::DRIVER_ERROR );
1848 } 1910 }
1849 1911
1850 // Allocate and init the sysex buffer. 1912 // Allocate and init the sysex buffer.
1851 data->sysexBuffer = (MIDIHDR*) new char[ sizeof(MIDIHDR) ]; 1913 data->sysexBuffer = (MIDIHDR*) new char[ sizeof(MIDIHDR) ];
1852 data->sysexBuffer->lpData = new char[1024]; 1914 data->sysexBuffer->lpData = new char[ RT_SYSEX_BUFFER_SIZE ];
1853 data->sysexBuffer->dwBufferLength = 1024; 1915 data->sysexBuffer->dwBufferLength = RT_SYSEX_BUFFER_SIZE;
1854 data->sysexBuffer->dwFlags = 0; 1916 data->sysexBuffer->dwFlags = 0;
1855 1917
1856 result = midiInPrepareHeader( data->inHandle, data->sysexBuffer, sizeof(MIDIHDR) ); 1918 result = midiInPrepareHeader( data->inHandle, data->sysexBuffer, sizeof(MIDIHDR) );
1857 if ( result != MMSYSERR_NOERROR ) { 1919 if ( result != MMSYSERR_NOERROR ) {
1858 midiInClose( data->inHandle ); 1920 midiInClose( data->inHandle );
1977 2039
1978 std::string stringName( nameString ); 2040 std::string stringName( nameString );
1979 return stringName; 2041 return stringName;
1980 } 2042 }
1981 2043
1982 void RtMidiOut :: initialize(std::string name) 2044 void RtMidiOut :: initialize( const std::string& /*clientName*/ )
1983 { 2045 {
1984 // We'll issue a warning here if no devices are available but not 2046 // We'll issue a warning here if no devices are available but not
1985 // throw an error since the user can plug something in later. 2047 // throw an error since the user can plug something in later.
1986 unsigned int nDevices = midiOutGetNumDevs(); 2048 unsigned int nDevices = midiOutGetNumDevs();
1987 if ( nDevices == 0 ) { 2049 if ( nDevices == 0 ) {
1992 // Save our api-specific connection information. 2054 // Save our api-specific connection information.
1993 WinMidiData *data = (WinMidiData *) new WinMidiData; 2055 WinMidiData *data = (WinMidiData *) new WinMidiData;
1994 apiData_ = (void *) data; 2056 apiData_ = (void *) data;
1995 } 2057 }
1996 2058
1997 void RtMidiOut :: openPort( unsigned int portNumber ) 2059 void RtMidiOut :: openPort( unsigned int portNumber, const std::string /*portName*/ )
1998 { 2060 {
1999 if ( connected_ ) { 2061 if ( connected_ ) {
2000 errorString_ = "RtMidiOut::openPort: a valid connection already exists!"; 2062 errorString_ = "RtMidiOut::openPort: a valid connection already exists!";
2001 error( RtError::WARNING ); 2063 error( RtError::WARNING );
2002 return; 2064 return;