Mercurial > hg > svcore
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; |