00001
00036
00037
00038
00039
00040 #include <iostream>
00041 #include <sstream>
00042 #include "Defs.h"
00043 #include "RtMidi.h"
00044
00045
00046
00047
00048
00049 RtMidi :: RtMidi()
00050 : apiData_( 0 ), connected_( false )
00051 {}
00052
00053 void RtMidi :: error( RtError::Type type )
00054 {
00055 if (type == RtError::WARNING) {
00056 STD_PRE::cerr << '\n' << errorString_.c_str() << "\n\n";
00057 } else if (type == RtError::DEBUG_WARNING) {
00058 #if defined(__RTMIDI_DEBUG__)
00059 STD_PRE::cerr << '\n' << errorString_.c_str() << "\n\n";
00060 #endif
00061 } else {
00062 STD_PRE::cerr << '\n' << errorString_.c_str() << "\n\n";
00063 throw RtError( errorString_, type );
00064 }
00065 }
00066
00067
00068
00069
00070
00071 RtMidiIn :: RtMidiIn() : RtMidi()
00072 {
00073 this->initialize();
00074 }
00075
00076 void RtMidiIn :: setCallback( RtMidiCallback callback, void *userData )
00077 {
00078 if ( inputData_.usingCallback ) {
00079 errorString_ = "RtMidiIn::setCallback: a callback function is already set!";
00080 error( RtError::WARNING );
00081 return;
00082 }
00083
00084 if ( !callback ) {
00085 errorString_ = "RtMidiIn::setCallback: callback function value is invalid!";
00086 error( RtError::WARNING );
00087 return;
00088 }
00089
00090 inputData_.userCallback = (void *) callback;
00091
00092 inputData_.userData = userData;
00093 inputData_.usingCallback = true;
00094 }
00095
00096 void RtMidiIn :: cancelCallback()
00097 {
00098 if ( !inputData_.usingCallback ) {
00099 errorString_ = "RtMidiIn::cancelCallback: no callback function was set!";
00100 error( RtError::WARNING );
00101 return;
00102 }
00103
00104 inputData_.userCallback = 0;
00105
00106 inputData_.userData = 0;
00107 inputData_.usingCallback = false;
00108 }
00109
00110 void RtMidiIn :: setQueueSizeLimit( unsigned int queueSize )
00111 {
00112 inputData_.queueLimit = queueSize;
00113 }
00114
00115 void RtMidiIn :: ignoreTypes( bool midiSysex, bool midiTime, bool midiSense )
00116 {
00117 inputData_.ignoreFlags = 0;
00118
00119 if ( midiSysex ) inputData_.ignoreFlags = 0x01;
00120
00121 if ( midiTime ) inputData_.ignoreFlags |= 0x02;
00122
00123 if ( midiSense ) inputData_.ignoreFlags |= 0x04;
00124 }
00125
00126 double RtMidiIn :: getMessage( std::vector<unsigned char> *message )
00127 {
00128
00129
00130 if ( inputData_.usingCallback ) {
00131 errorString_ = "RtMidiIn::getNextMessage: a user callback is currently set for this port.";
00132 error( RtError::WARNING );
00133 return 0.0;
00134 }
00135
00136 if ( inputData_.queue.size() == 0 ) return 0.0;
00137
00138
00139 std::vector<unsigned char> *bytes = &(inputData_.queue.front().bytes);
00140
00141 message->assign( bytes->begin(), bytes->end() );
00142
00143 double deltaTime = inputData_.queue.front().timeStamp;
00144
00145 inputData_.queue.pop();
00146
00147 return deltaTime;
00148 }
00149
00150
00151
00152
00153
00154 RtMidiOut :: RtMidiOut() : RtMidi()
00155 {
00156 this->initialize();
00157 }
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167 #if defined(__MACOSX_CORE__)
00168
00169
00170
00171
00172
00173
00174 #include <CoreMIDI/CoreMIDI.h>
00175 #include <CoreAudio/HostTime.h>
00176
00177
00178
00179
00180 struct CoreMidiData
00181 {
00182 MIDIClientRef client;
00183 MIDIPortRef port;
00184 MIDIEndpointRef endpoint;
00185 MIDIEndpointRef destinationId;
00186 unsigned long long lastTime;
00187 };
00188
00189
00190
00191
00192
00193
00194 void midiInputCallback( const MIDIPacketList *list, void *procRef, void *srcRef )
00195 {
00196 RtMidiIn::RtMidiInData *data = static_cast<RtMidiIn::RtMidiInData *> (procRef);
00197 CoreMidiData *apiData = static_cast<CoreMidiData *> (data->apiData);
00198
00199 bool continueSysex = false;
00200 unsigned char status;
00201 unsigned short nBytes, iByte, size;
00202 unsigned long long time;
00203 RtMidiIn::MidiMessage message;
00204
00205 const MIDIPacket *packet = &list->packet[0];
00206
00207 for ( unsigned int i=0; i<list->numPackets; ++i ) {
00208
00209
00210
00211
00212
00213
00214
00215
00216 nBytes = packet->length;
00217
00218 if ( nBytes == 0 ) continue;
00219
00220
00221 message.timeStamp = 0.0;
00222
00223 if ( data->firstMessage )
00224 data->firstMessage = false;
00225 else {
00226 time = packet->timeStamp;
00227 time -= apiData->lastTime;
00228 time = AudioConvertHostTimeToNanos( time );
00229 message.timeStamp = time * 0.000000001;
00230 }
00231
00232 apiData->lastTime = packet->timeStamp;
00233
00234 iByte = 0;
00235
00236 if ( continueSysex ) {
00237
00238
00239 if ( !(data->ignoreFlags & 0x01) ) {
00240
00241
00242 for ( unsigned int j=0; j<nBytes; j++ )
00243 message.bytes.push_back( packet->data[j] );
00244 }
00245
00246 if ( packet->data[nBytes] == 0xF7 ) continueSysex = false;
00247
00248 if ( !continueSysex ) {
00249
00250
00251 if ( data->usingCallback && message.bytes.size() > 0 ) {
00252 RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
00253 callback( message.timeStamp, &message.bytes, data->userData );
00254 } else {
00255
00256
00257 if ( data->queueLimit > data->queue.size() )
00258 data->queue.push( message );
00259 else
00260 STD_PRE::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
00261 }
00262
00263 message.bytes.clear();
00264 }
00265 } else {
00266 while ( iByte < nBytes ) {
00267 size = 0;
00268
00269 status = packet->data[iByte];
00270
00271 if ( !(status & 0x80) ) break;
00272
00273
00274 if ( status < 0xC0 ) size = 3;
00275 else if ( status < 0xE0 ) size = 2;
00276 else if ( status < 0xF0 ) size = 3;
00277 else if ( status == 0xF0 ) {
00278
00279
00280 if ( data->ignoreFlags & 0x01 ) {
00281 size = 0;
00282 iByte = nBytes;
00283 } else size = nBytes - iByte;
00284
00285 if ( packet->data[nBytes] == 0xF7 ) continueSysex = false;
00286 } else if ( status < 0xF3 ) {
00287 if ( status == 0xF1 && (data->ignoreFlags & 0x02) ) {
00288
00289 size = 0;
00290 iByte += 3;
00291 } else size = 3;
00292 } else if ( status == 0xF3 ) size = 2;
00293 else if ( status == 0xFE && (data->ignoreFlags & 0x04) ) {
00294
00295 size = 0;
00296 iByte += 1;
00297 } else size = 1;
00298
00299
00300 if ( size ) {
00301 message.bytes.assign( &packet->data[iByte], &packet->data[iByte+size] );
00302
00303 if ( !continueSysex ) {
00304
00305
00306 if ( data->usingCallback ) {
00307 RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
00308 callback( message.timeStamp, &message.bytes, data->userData );
00309 } else {
00310
00311
00312 if ( data->queueLimit > data->queue.size() )
00313 data->queue.push( message );
00314 else
00315 STD_PRE::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
00316 }
00317
00318 message.bytes.clear();
00319 }
00320
00321 iByte += size;
00322 }
00323 }
00324 }
00325
00326 packet = MIDIPacketNext(packet);
00327 }
00328 }
00329
00330 void RtMidiIn :: initialize( void )
00331
00332 {
00333
00334 MIDIClientRef client;
00335 OSStatus result = MIDIClientCreate( CFSTR("RtMidi Input Client"), NULL, NULL, &client );
00336
00337 if ( result != noErr ) {
00338 errorString_ = "RtMidiIn::initialize: error creating OS-X MIDI client object.";
00339 error( RtError::DRIVER_ERROR );
00340 }
00341
00342
00343 CoreMidiData *data = (CoreMidiData *) new CoreMidiData;
00344
00345 data->client = client;
00346
00347 data->endpoint = 0;
00348
00349 apiData_ = (void *) data;
00350
00351 inputData_.apiData = (void *) data;
00352 }
00353
00354 #include <sstream>
00355
00356 void RtMidiIn :: openPort( unsigned int portNumber )
00357 {
00358 if ( connected_ ) {
00359 errorString_ = "RtMidiIn::openPort: a valid connection already exists!";
00360 error( RtError::WARNING );
00361 return;
00362 }
00363
00364 unsigned int nSrc = MIDIGetNumberOfSources();
00365
00366 if (nSrc < 1) {
00367 errorString_ = "RtMidiIn::openPort: no MIDI input sources found!";
00368 error( RtError::NO_DEVICES_FOUND );
00369 }
00370
00371 STD_PRE::ostringstream ost;
00372
00373 if ( portNumber >= nSrc ) {
00374 ost << "RtMidiIn::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
00375 errorString_ = ost.str();
00376 error( RtError::INVALID_PARAMETER );
00377 }
00378
00379 MIDIPortRef port;
00380
00381 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
00382 OSStatus result = MIDIInputPortCreate( data->client, CFSTR("RtMidi MIDI Input Port"), midiInputCallback, (void *)&inputData_, &port );
00383
00384 if ( result != noErr ) {
00385 MIDIClientDispose( data->client );
00386 errorString_ = "RtMidiIn::openPort: error creating OS-X MIDI input port.";
00387 error( RtError::DRIVER_ERROR );
00388 }
00389
00390
00391 MIDIEndpointRef endpoint = MIDIGetSource( portNumber );
00392
00393 if ( endpoint == NULL ) {
00394 MIDIPortDispose( port );
00395 MIDIClientDispose( data->client );
00396 errorString_ = "RtMidiIn::openPort: error getting MIDI input source reference.";
00397 error( RtError::DRIVER_ERROR );
00398 }
00399
00400
00401 result = MIDIPortConnectSource( port, endpoint, NULL );
00402
00403 if ( result != noErr ) {
00404 MIDIPortDispose( port );
00405 MIDIClientDispose( data->client );
00406 errorString_ = "RtMidiIn::openPort: error connecting OS-X MIDI input port.";
00407 error( RtError::DRIVER_ERROR );
00408 }
00409
00410
00411 data->port = port;
00412
00413 connected_ = true;
00414 }
00415
00416 void RtMidiIn :: openVirtualPort()
00417 {
00418 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
00419
00420
00421 MIDIEndpointRef endpoint;
00422 OSStatus result = MIDIDestinationCreate( data->client, CFSTR("RtMidi Input"), midiInputCallback, (void *)&inputData_, &endpoint );
00423
00424 if ( result != noErr ) {
00425 errorString_ = "RtMidiIn::openVirtualPort: error creating virtual OS-X MIDI destination.";
00426 error( RtError::DRIVER_ERROR );
00427 }
00428
00429
00430 data->endpoint = endpoint;
00431 }
00432
00433 void RtMidiIn :: closePort( void )
00434 {
00435 if ( connected_ ) {
00436 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
00437 MIDIPortDispose( data->port );
00438 connected_ = false;
00439 }
00440 }
00441
00442 RtMidiIn :: ~RtMidiIn()
00443 {
00444
00445 closePort();
00446
00447
00448 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
00449 MIDIClientDispose( data->client );
00450
00451 if ( data->endpoint ) MIDIEndpointDispose( data->endpoint );
00452
00453 delete data;
00454 }
00455
00456 unsigned int RtMidiIn :: getPortCount()
00457 {
00458 return MIDIGetNumberOfSources();
00459 }
00460
00461
00462 STD_PRE::string RtMidiIn :: getPortName( unsigned int portNumber )
00463 {
00464 CFStringRef nameRef;
00465 MIDIEndpointRef portRef;
00466 STD_PRE::ostringstream ost;
00467 char name[128];
00468
00469 if ( portNumber >= MIDIGetNumberOfSources() ) {
00470 ost << "RtMidiIn::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
00471 errorString_ = ost.str();
00472 error( RtError::INVALID_PARAMETER );
00473 }
00474
00475 portRef = MIDIGetSource( portNumber );
00476
00477 MIDIObjectGetStringProperty( portRef, kMIDIPropertyName, &nameRef );
00478 CFStringGetCString( nameRef, name, sizeof(name), 0);
00479 CFRelease( nameRef );
00480 STD_PRE::string stringName = name;
00481 return stringName;
00482 }
00483
00484
00485
00486
00487
00488
00489 unsigned int RtMidiOut :: getPortCount()
00490 {
00491 return MIDIGetNumberOfDestinations();
00492 }
00493
00494 STD_PRE::string RtMidiOut :: getPortName( unsigned int portNumber )
00495 {
00496 CFStringRef nameRef;
00497 MIDIEndpointRef portRef;
00498 STD_PRE::ostringstream ost;
00499 char name[128];
00500
00501 if ( portNumber >= MIDIGetNumberOfDestinations() ) {
00502 ost << "RtMidiOut::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
00503 errorString_ = ost.str();
00504 error( RtError::INVALID_PARAMETER );
00505 }
00506
00507 portRef = MIDIGetDestination( portNumber );
00508
00509 MIDIObjectGetStringProperty( portRef, kMIDIPropertyName, &nameRef );
00510 CFStringGetCString( nameRef, name, sizeof(name), 0);
00511 CFRelease( nameRef );
00512 STD_PRE::string stringName = name;
00513 return stringName;
00514 }
00515
00516 void RtMidiOut :: initialize( void )
00517 {
00518
00519 MIDIClientRef client;
00520 DEBUGLOG(midiio,_T("client: %d"),client);
00521 OSStatus result = MIDIClientCreate( CFSTR("RtMidi Output Client"), NULL, NULL, &client );
00522 DEBUGLOG(midiio,_T("client: %d"),client);
00523
00524 if ( result != noErr ) {
00525 errorString_ = "RtMidiOut::initialize: error creating OS-X MIDI client object.\n\t";
00526 switch (result) {
00527 case kMIDIInvalidClient:
00528 errorString_ += "An invalid MIDIClientRef was passed.";
00529 break;
00530 case kMIDIInvalidPort:
00531 errorString_ += "An invalid MIDIPortRef was passed.";
00532 break;
00533 case kMIDIWrongEndpointType:
00534 errorString_ += "A source endpoint was passed to a function expecting a destination, or vice versa.";
00535 break;
00536 case kMIDINoConnection:
00537 errorString_ += "Attempt to close a non-existant connection.";
00538 break;
00539 case kMIDIUnknownEndpoint:
00540 errorString_ += "An invalid MIDIEndpointRef was passed.";
00541 break;
00542 case kMIDIUnknownProperty:
00543 errorString_ += "Attempt to query a property not set on the object.";
00544 break;
00545 case kMIDIWrongPropertyType:
00546 errorString_ += "Attempt to set a property with a value not of the correct type.";
00547 break;
00548 case kMIDINoCurrentSetup:
00549 errorString_ += "Internal error; there is no current MIDI setup object.";
00550 break;
00551 case kMIDIMessageSendErr:
00552 errorString_ += "Communication with MIDIServer failed.";
00553 break;
00554 case kMIDIServerStartErr:
00555 errorString_ += "Unable to start MIDIServer.";
00556 break;
00557 case kMIDISetupFormatErr:
00558 errorString_ += "Unable to read the saved state.";
00559 break;
00560 case kMIDIWrongThread:
00561 errorString_ += "A driver is calling a non-I/O function in the server from a thread other than the server's main thread.";
00562 break;
00563 case kMIDIObjectNotFound:
00564 errorString_ += "The requested object does not exist.";
00565 break;
00566 case kMIDIIDNotUnique:
00567 errorString_ += "Attempt to set a non-unique kMIDIPropertyUniqueID on an object.";
00568 }
00569 error( RtError::DRIVER_ERROR );
00570 }
00571
00572
00573 CoreMidiData *data = (CoreMidiData *) new CoreMidiData;
00574
00575 data->client = client;
00576
00577 data->endpoint = 0;
00578
00579 apiData_ = (void *) data;
00580 }
00581
00582 void RtMidiOut :: openPort( unsigned int portNumber )
00583 {
00584 if ( connected_ ) {
00585 errorString_ = "RtMidiOut::openPort: a valid connection already exists!";
00586 error( RtError::WARNING );
00587 return;
00588 }
00589
00590 unsigned int nDest = MIDIGetNumberOfDestinations();
00591
00592 if (nDest < 1) {
00593 errorString_ = "RtMidiOut::openPort: no MIDI output destinations found!";
00594 error( RtError::NO_DEVICES_FOUND );
00595 }
00596
00597 STD_PRE::ostringstream ost;
00598
00599 if ( portNumber >= nDest ) {
00600 ost << "RtMidiOut::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
00601 errorString_ = ost.str();
00602 error( RtError::INVALID_PARAMETER );
00603 }
00604
00605 MIDIPortRef port;
00606
00607 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
00608 OSStatus result = MIDIOutputPortCreate( data->client, CFSTR("RtMidi Virtual MIDI Output Port"), &port );
00609
00610 if ( result != noErr ) {
00611 MIDIClientDispose( data->client );
00612 errorString_ = "RtMidiOut::openPort: error creating OS-X MIDI output port.";
00613 error( RtError::DRIVER_ERROR );
00614 }
00615
00616
00617 MIDIEndpointRef destination = MIDIGetDestination( portNumber );
00618
00619 if ( destination == NULL ) {
00620 MIDIPortDispose( port );
00621 MIDIClientDispose( data->client );
00622 errorString_ = "RtMidiOut::openPort: error getting MIDI output destination reference.";
00623 error( RtError::DRIVER_ERROR );
00624 }
00625
00626
00627 data->port = port;
00628
00629 data->destinationId = destination;
00630
00631 connected_ = true;
00632 }
00633
00634 void RtMidiOut :: closePort( void )
00635 {
00636 if ( connected_ ) {
00637 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
00638 MIDIPortDispose( data->port );
00639 connected_ = false;
00640 }
00641 }
00642
00643 void RtMidiOut :: openVirtualPort()
00644 {
00645 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
00646
00647 if ( data->endpoint ) {
00648 errorString_ = "RtMidiOut::openVirtualPort: a virtual output port already exists!";
00649 error( RtError::WARNING );
00650 return;
00651 }
00652
00653
00654 MIDIEndpointRef endpoint;
00655
00656 OSStatus result = MIDISourceCreate( data->client, CFSTR("RtMidi Output"), &endpoint );
00657
00658 if ( result != noErr ) {
00659 errorString_ = "RtMidiOut::initialize: error creating OS-X virtual MIDI source.";
00660 error( RtError::DRIVER_ERROR );
00661 }
00662
00663
00664 data->endpoint = endpoint;
00665 }
00666
00667 RtMidiOut :: ~RtMidiOut()
00668 {
00669
00670 closePort();
00671
00672
00673 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
00674 MIDIClientDispose( data->client );
00675
00676 if ( data->endpoint ) MIDIEndpointDispose( data->endpoint );
00677
00678 delete data;
00679 }
00680
00681 void RtMidiOut :: sendMessage( STD_PRE::vector<unsigned char> *message )
00682 {
00683 unsigned int nBytes = message->size();
00684
00685 Byte buffer[nBytes+32];
00686 MIDIPacketList *pktlist = (MIDIPacketList *) buffer;
00687 MIDIPacket *curPacket = MIDIPacketListInit( pktlist );
00688
00689 MIDITimeStamp timeStamp = 0;
00690 curPacket = MIDIPacketListAdd( pktlist, sizeof(buffer), curPacket, timeStamp, nBytes, &message->at(0) );
00691
00692 CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
00693
00694
00695 OSStatus result;
00696
00697 if ( data->endpoint ) {
00698 result = MIDIReceived( data->endpoint, pktlist );
00699
00700 if ( result != noErr ) {
00701 errorString_ = "RtMidiOut::sendMessage: error sending MIDI to virtual destinations.";
00702 error( RtError::WARNING );
00703 }
00704 }
00705
00706
00707 if ( connected_ ) {
00708 result = MIDISend( data->port, data->destinationId, pktlist );
00709
00710 if ( result != noErr ) {
00711 errorString_ = "RtMidiOut::sendMessage: error sending MIDI message to port.";
00712 error( RtError::WARNING );
00713 }
00714 }
00715 }
00716
00717 #endif // __MACOSX_CORE__
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727 #if defined(__LINUX_ALSASEQ__)
00728
00729
00730
00731
00732
00733 #include <pthread.h>
00734 #include <sys/time.h>
00735
00736
00737 #include <alsa/asoundlib.h>
00738
00739
00740
00741
00742 struct AlsaMidiData
00743 {
00744 snd_seq_t *seq;
00745 int vport;
00746 snd_seq_port_subscribe_t *subscription;
00747 snd_midi_event_t *coder;
00748 unsigned int bufferSize;
00749 unsigned char *buffer;
00750 pthread_t thread;
00751 unsigned long long lastTime;
00752 };
00753
00754 #define PORT_TYPE( pinfo, bits ) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
00755
00756
00757
00758
00759
00760
00761 extern "C" void *alsaMidiHandler( void *ptr )
00762 {
00763 RtMidiIn::RtMidiInData *data = static_cast<RtMidiIn::RtMidiInData *> (ptr);
00764 AlsaMidiData *apiData = static_cast<AlsaMidiData *> (data->apiData);
00765
00766 long nBytes;
00767 unsigned long long time, lastTime;
00768 unsigned char lastStatus = 0;
00769 RtMidiIn::MidiMessage message;
00770
00771 snd_seq_event_t *ev;
00772
00773 struct timeval tv;
00774 int result;
00775 apiData->bufferSize = 32;
00776 result = snd_midi_event_new( 0, &apiData->coder );
00777
00778 if ( result < 0 ) {
00779 data->doInput = false;
00780 STD_PRE::cerr << "\nRtMidiIn::alsaMidiHandler: error initializing MIDI event parser!\n\n";
00781 return 0;
00782 }
00783
00784 unsigned char *buffer = (unsigned char *) malloc(apiData->bufferSize);
00785
00786 if ( buffer == NULL ) {
00787 data->doInput = false;
00788 STD_PRE::cerr << "\nRtMidiIn::alsaMidiHandler: error initializing buffer memory!\n\n";
00789 return 0;
00790 }
00791
00792 snd_midi_event_init( apiData->coder );
00793
00794 while ( data->doInput ) {
00795
00796 if ( snd_seq_event_input_pending( apiData->seq, 1 ) == 0 ) {
00797
00798 usleep( 1000 );
00799 continue;
00800 }
00801
00802
00803 result = snd_seq_event_input( apiData->seq, &ev );
00804
00805 if ( result == -ENOSPC ) {
00806 STD_PRE::cerr << "\nRtMidiIn::alsaMidiHandler: MIDI input buffer overrun!\n\n";
00807 continue;
00808 } else if ( result <= 0 ) {
00809 STD_PRE::cerr << "RtMidiIn::alsaMidiHandler: unknown MIDI input error!\n";
00810 continue;
00811 }
00812
00813
00814
00815 message.bytes.clear();
00816
00817 switch (ev->type) {
00818
00819 case SND_SEQ_EVENT_PORT_SUBSCRIBED:
00820 #if defined(__RTMIDI_DEBUG__)
00821 STD_PRE::cout << "RtMidiIn::alsaMidiHandler: port connection made!\n";
00822
00823 #endif
00824 break;
00825
00826 case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
00827 STD_PRE::cerr << "RtMidiIn::alsaMidiHandler: port connection has closed!\n";
00828
00829 data->doInput = false;
00830
00831 break;
00832
00833 case SND_SEQ_EVENT_QFRAME:
00834 if ( data->ignoreFlags & 0x02 ) break;
00835
00836 case SND_SEQ_EVENT_SENSING:
00837 if ( data->ignoreFlags & 0x04 ) break;
00838
00839 case SND_SEQ_EVENT_SYSEX:
00840 if ( (data->ignoreFlags & 0x01) ) break;
00841
00842 if ( ev->data.ext.len > apiData->bufferSize ) {
00843 apiData->bufferSize = ev->data.ext.len;
00844 free(buffer);
00845 buffer = (unsigned char *) malloc(apiData->bufferSize);
00846
00847 if ( buffer == NULL ) {
00848 data->doInput = false;
00849 STD_PRE::cerr << "\nRtMidiIn::alsaMidiHandler: error resizing buffer memory!\n\n";
00850 break;
00851 }
00852 }
00853
00854 default:
00855 nBytes = snd_midi_event_decode( apiData->coder, buffer, apiData->bufferSize, ev );
00856
00857 if ( nBytes <= 0 ) {
00858 #if defined(__RTMIDI_DEBUG__)
00859 STD_PRE::cerr << "\nRtMidiIn::alsaMidiHandler: event parsing error or not a MIDI event!\n\n";
00860 #endif
00861 break;
00862 }
00863
00864 message.bytes.assign( buffer, &buffer[nBytes] );
00865
00866
00867
00868 if ( message.bytes[0] & 0x80 ) lastStatus = message.bytes[0];
00869 else if ( lastStatus ) message.bytes.insert( message.bytes.begin(), lastStatus );
00870
00871
00872
00873
00874 message.timeStamp = 0.0;
00875
00876 (void)gettimeofday(&tv, (struct timezone *)NULL);
00877
00878 time = (tv.tv_sec * 1000000) + tv.tv_usec;
00879
00880 lastTime = time;
00881
00882 time -= apiData->lastTime;
00883
00884 apiData->lastTime = lastTime;
00885
00886 if ( data->firstMessage == true )
00887 data->firstMessage = false;
00888 else {
00889 message.timeStamp = time * 0.000001;
00890 }
00891 }
00892
00893 snd_seq_free_event(ev);
00894
00895 if ( message.bytes.size() == 0 ) continue;
00896
00897 if ( data->usingCallback ) {
00898 RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
00899 callback( message.timeStamp, &message.bytes, data->userData );
00900 } else {
00901
00902
00903 if ( data->queueLimit > data->queue.size() )
00904 data->queue.push( message );
00905 else
00906 STD_PRE::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
00907 }
00908 }
00909
00910 snd_midi_event_free( apiData->coder );
00911
00912 apiData->coder = 0;
00913 return 0;
00914 }
00915
00916 void RtMidiIn :: initialize( void )
00917
00918 {
00919
00920 snd_seq_t *seq;
00921 int result = snd_seq_open(&seq, "default", SND_SEQ_OPEN_INPUT, 0);
00922
00923 if ( result < 0 ) {
00924 errorString_ = "RtMidiIn::initialize: error creating ALSA sequencer input client object.";
00925 error( RtError::DRIVER_ERROR );
00926 }
00927
00928
00929 snd_seq_set_client_name(seq, "RtMidi Input Client");
00930
00931
00932 AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
00933
00934 data->seq = seq;
00935
00936 data->vport = -1;
00937
00938 apiData_ = (void *) data;
00939
00940 inputData_.apiData = (void *) data;
00941 }
00942
00943
00944 unsigned int portInfo( snd_seq_t *seq, snd_seq_port_info_t *pinfo, unsigned int type, int portNumber )
00945 {
00946 snd_seq_client_info_t *cinfo;
00947 int client;
00948 int count = 0;
00949 snd_seq_client_info_alloca( &cinfo );
00950
00951 snd_seq_client_info_set_client( cinfo, -1 );
00952
00953 while ( snd_seq_query_next_client( seq, cinfo ) >= 0 ) {
00954 client = snd_seq_client_info_get_client( cinfo );
00955
00956 if ( client == 0 ) continue;
00957
00958
00959 snd_seq_port_info_set_client( pinfo, client );
00960
00961 snd_seq_port_info_set_port( pinfo, -1 );
00962
00963 while ( snd_seq_query_next_port( seq, pinfo ) >= 0 ) {
00964 if ( !PORT_TYPE( pinfo, type ) ) continue;
00965
00966 if ( count == portNumber ) return 1;
00967
00968 count++;
00969 }
00970 }
00971
00972
00973 if ( portNumber < 0 ) return count;
00974
00975 return 0;
00976 }
00977
00978 void RtMidiIn :: openPort( unsigned int portNumber )
00979 {
00980 if ( connected_ ) {
00981 errorString_ = "RtMidiIn::openPort: a valid connection already exists!";
00982 error( RtError::WARNING );
00983 return;
00984 }
00985
00986 unsigned int nSrc = this->getPortCount();
00987
00988 if (nSrc < 1) {
00989 errorString_ = "RtMidiIn::openPort: no MIDI input sources found!";
00990 error( RtError::NO_DEVICES_FOUND );
00991 }
00992
00993 snd_seq_port_info_t *pinfo;
00994
00995 snd_seq_port_info_alloca( &pinfo );
00996 STD_PRE::ostringstream ost;
00997 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
00998
00999 if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) == 0 ) {
01000 ost << "RtMidiIn::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
01001 errorString_ = ost.str();
01002 error( RtError::INVALID_PARAMETER );
01003 }
01004
01005
01006 snd_seq_addr_t sender, receiver;
01007
01008 sender.client = snd_seq_port_info_get_client( pinfo );
01009 sender.port = snd_seq_port_info_get_port( pinfo );
01010 receiver.client = snd_seq_client_id( data->seq );
01011
01012 if ( data->vport < 0 ) {
01013 data->vport = snd_seq_create_simple_port( data->seq, "RtMidi Input",
01014 SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
01015 SND_SEQ_PORT_TYPE_MIDI_GENERIC );
01016
01017 if ( data->vport < 0 ) {
01018 errorString_ = "RtMidiIn::openPort: ALSA error creating input port.";
01019 error( RtError::DRIVER_ERROR );
01020 }
01021 }
01022
01023 receiver.port = data->vport;
01024
01025
01026 snd_seq_port_subscribe_malloc( &data->subscription );
01027 snd_seq_port_subscribe_set_sender(data->subscription, &sender);
01028 snd_seq_port_subscribe_set_dest(data->subscription, &receiver);
01029 snd_seq_port_subscribe_set_time_update(data->subscription, 1);
01030 snd_seq_port_subscribe_set_time_real(data->subscription, 1);
01031
01032 if ( snd_seq_subscribe_port(data->seq, data->subscription) ) {
01033 errorString_ = "RtMidiIn::openPort: ALSA error making port connection.";
01034 error( RtError::DRIVER_ERROR );
01035 }
01036
01037 if ( inputData_.doInput == false ) {
01038
01039 pthread_attr_t attr;
01040 pthread_attr_init(&attr);
01041 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
01042 pthread_attr_setschedpolicy(&attr, SCHED_RR);
01043
01044 inputData_.doInput = true;
01045 int err = pthread_create(&data->thread, &attr, alsaMidiHandler, &inputData_);
01046 pthread_attr_destroy(&attr);
01047
01048 if (err) {
01049 snd_seq_unsubscribe_port( data->seq, data->subscription );
01050 snd_seq_port_subscribe_free( data->subscription );
01051 inputData_.doInput = false;
01052 errorString_ = "RtMidiIn::openPort: error starting MIDI input thread!";
01053 error( RtError::THREAD_ERROR );
01054 }
01055 }
01056
01057 connected_ = true;
01058 }
01059
01060 void RtMidiIn :: openVirtualPort()
01061 {
01062 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
01063
01064 if ( data->vport < 0 ) {
01065 data->vport = snd_seq_create_simple_port( data->seq, "RtMidi Input",
01066 SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
01067 SND_SEQ_PORT_TYPE_MIDI_GENERIC );
01068
01069 if ( data->vport < 0 ) {
01070 errorString_ = "RtMidiIn::openVirtualPort: ALSA error creating virtual port.";
01071 error( RtError::DRIVER_ERROR );
01072 }
01073 }
01074
01075 if ( inputData_.doInput == false ) {
01076
01077 pthread_attr_t attr;
01078 pthread_attr_init(&attr);
01079 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
01080 pthread_attr_setschedpolicy(&attr, SCHED_RR);
01081
01082 inputData_.doInput = true;
01083 int err = pthread_create(&data->thread, &attr, alsaMidiHandler, &inputData_);
01084 pthread_attr_destroy(&attr);
01085
01086 if (err) {
01087 snd_seq_unsubscribe_port( data->seq, data->subscription );
01088 snd_seq_port_subscribe_free( data->subscription );
01089 inputData_.doInput = false;
01090 errorString_ = "RtMidiIn::openPort: error starting MIDI input thread!";
01091 error( RtError::THREAD_ERROR );
01092 }
01093 }
01094 }
01095
01096 void RtMidiIn :: closePort( void )
01097 {
01098 if ( connected_ ) {
01099 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
01100 snd_seq_unsubscribe_port( data->seq, data->subscription );
01101 snd_seq_port_subscribe_free( data->subscription );
01102 connected_ = false;
01103 }
01104 }
01105
01106 RtMidiIn :: ~RtMidiIn()
01107 {
01108
01109 closePort();
01110
01111
01112 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
01113
01114 if ( inputData_.doInput ) {
01115 inputData_.doInput = false;
01116 pthread_join( data->thread, NULL );
01117 }
01118
01119
01120 if ( data->vport >= 0 ) snd_seq_delete_port( data->seq, data->vport );
01121
01122 snd_seq_close( data->seq );
01123
01124 delete data;
01125 }
01126
01127 unsigned int RtMidiIn :: getPortCount()
01128 {
01129 snd_seq_port_info_t *pinfo;
01130 snd_seq_port_info_alloca( &pinfo );
01131
01132 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
01133 return portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, -1 );
01134 }
01135
01136 STD_PRE::string RtMidiIn :: getPortName( unsigned int portNumber )
01137 {
01138 snd_seq_port_info_t *pinfo;
01139 snd_seq_port_info_alloca( &pinfo );
01140
01141 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
01142
01143 if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) ) {
01144 STD_PRE::string stringName = STD_PRE::string( snd_seq_port_info_get_name( pinfo ) );
01145 return stringName;
01146 }
01147
01148
01149 errorString_ = "RtMidiIn::getPortName: error looking for port name!";
01150
01151 error( RtError::INVALID_PARAMETER );
01152
01153 return 0;
01154 }
01155
01156
01157
01158
01159
01160
01161 unsigned int RtMidiOut :: getPortCount()
01162 {
01163 snd_seq_port_info_t *pinfo;
01164 snd_seq_port_info_alloca( &pinfo );
01165
01166 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
01167 return portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, -1 );
01168 }
01169
01170 STD_PRE::string RtMidiOut :: getPortName( unsigned int portNumber )
01171 {
01172 snd_seq_port_info_t *pinfo;
01173 snd_seq_port_info_alloca( &pinfo );
01174
01175 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
01176
01177 if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) ) {
01178 STD_PRE::string stringName = STD_PRE::string( snd_seq_port_info_get_name( pinfo ) );
01179 return stringName;
01180 }
01181
01182
01183 errorString_ = "RtMidiOut::getPortName: error looking for port name!";
01184
01185 error( RtError::INVALID_PARAMETER );
01186
01187 return 0;
01188 }
01189
01190 void RtMidiOut :: initialize( void )
01191 {
01192
01193 snd_seq_t *seq;
01194 int result = snd_seq_open(&seq, "default", SND_SEQ_OPEN_OUTPUT, 0);
01195
01196 if ( result < 0 ) {
01197 errorString_ = "RtMidiOut::initialize: error creating ALSA sequencer client object.";
01198 error( RtError::DRIVER_ERROR );
01199 }
01200
01201
01202 snd_seq_set_client_name(seq, "RtMidi Output Client");
01203
01204
01205 AlsaMidiData *data = (AlsaMidiData *) new AlsaMidiData;
01206
01207 data->seq = seq;
01208
01209 data->vport = -1;
01210
01211 data->bufferSize = 32;
01212
01213 data->coder = 0;
01214
01215 data->buffer = 0;
01216
01217 result = snd_midi_event_new( data->bufferSize, &data->coder );
01218
01219 if ( result < 0 ) {
01220 delete data;
01221 errorString_ = "RtMidiOut::initialize: error initializing MIDI event parser!\n\n";
01222 error( RtError::DRIVER_ERROR );
01223 }
01224
01225 data->buffer = (unsigned char *) malloc( data->bufferSize );
01226
01227 if ( data->buffer == NULL ) {
01228 delete data;
01229 errorString_ = "RtMidiOut::initialize: error allocating buffer memory!\n\n";
01230 error( RtError::MEMORY_ERROR );
01231 }
01232
01233 snd_midi_event_init( data->coder );
01234
01235 apiData_ = (void *) data;
01236 }
01237
01238 void RtMidiOut :: openPort( unsigned int portNumber )
01239 {
01240 if ( connected_ ) {
01241 errorString_ = "RtMidiOut::openPort: a valid connection already exists!";
01242 error( RtError::WARNING );
01243 return;
01244 }
01245
01246 unsigned int nSrc = this->getPortCount();
01247
01248 if (nSrc < 1) {
01249 errorString_ = "RtMidiOut::openPort: no MIDI output sources found!";
01250 error( RtError::NO_DEVICES_FOUND );
01251 }
01252
01253 snd_seq_port_info_t *pinfo;
01254
01255 snd_seq_port_info_alloca( &pinfo );
01256 STD_PRE::ostringstream ost;
01257 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
01258
01259 if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) == 0 ) {
01260 ost << "RtMidiOut::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
01261 errorString_ = ost.str();
01262 error( RtError::INVALID_PARAMETER );
01263 }
01264
01265 snd_seq_addr_t sender, receiver;
01266
01267 receiver.client = snd_seq_port_info_get_client( pinfo );
01268 receiver.port = snd_seq_port_info_get_port( pinfo );
01269 sender.client = snd_seq_client_id( data->seq );
01270
01271 if ( data->vport < 0 ) {
01272 data->vport = snd_seq_create_simple_port( data->seq, "RtMidi Output",
01273 SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
01274 SND_SEQ_PORT_TYPE_MIDI_GENERIC );
01275
01276 if ( data->vport < 0 ) {
01277 errorString_ = "RtMidiOut::openPort: ALSA error creating output port.";
01278 error( RtError::DRIVER_ERROR );
01279 }
01280 }
01281
01282 sender.port = data->vport;
01283
01284
01285 snd_seq_port_subscribe_malloc( &data->subscription );
01286 snd_seq_port_subscribe_set_sender(data->subscription, &sender);
01287 snd_seq_port_subscribe_set_dest(data->subscription, &receiver);
01288 snd_seq_port_subscribe_set_time_update(data->subscription, 1);
01289 snd_seq_port_subscribe_set_time_real(data->subscription, 1);
01290
01291 if ( snd_seq_subscribe_port(data->seq, data->subscription) ) {
01292 errorString_ = "RtMidiOut::openPort: ALSA error making port connection.";
01293 error( RtError::DRIVER_ERROR );
01294 }
01295
01296 connected_ = true;
01297 }
01298
01299 void RtMidiOut :: closePort( void )
01300 {
01301 if ( connected_ ) {
01302 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
01303 snd_seq_unsubscribe_port( data->seq, data->subscription );
01304 snd_seq_port_subscribe_free( data->subscription );
01305 connected_ = false;
01306 }
01307 }
01308
01309 void RtMidiOut :: openVirtualPort()
01310 {
01311 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
01312
01313 if ( data->vport < 0 ) {
01314 data->vport = snd_seq_create_simple_port( data->seq, "RtMidi Output",
01315 SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
01316 SND_SEQ_PORT_TYPE_MIDI_GENERIC );
01317
01318 if ( data->vport < 0 ) {
01319 errorString_ = "RtMidiOut::openVirtualPort: ALSA error creating virtual port.";
01320 error( RtError::DRIVER_ERROR );
01321 }
01322 }
01323 }
01324
01325 RtMidiOut :: ~RtMidiOut()
01326 {
01327
01328 closePort();
01329
01330
01331 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
01332
01333 if ( data->vport >= 0 ) snd_seq_delete_port( data->seq, data->vport );
01334
01335 if ( data->coder ) snd_midi_event_free( data->coder );
01336
01337 if ( data->buffer ) free( data->buffer );
01338
01339 snd_seq_close( data->seq );
01340
01341 delete data;
01342 }
01343
01344 void RtMidiOut :: sendMessage( STD_PRE::vector<unsigned char> *message )
01345 {
01346 int result;
01347 AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
01348 unsigned int nBytes = message->size();
01349
01350 if ( nBytes > data->bufferSize ) {
01351 data->bufferSize = nBytes;
01352 result = snd_midi_event_resize_buffer ( data->coder, nBytes);
01353
01354 if ( result != 0 ) {
01355 errorString_ = "RtMidiOut::sendMessage: ALSA error resizing MIDI event buffer.";
01356 error( RtError::DRIVER_ERROR );
01357 }
01358
01359 free (data->buffer);
01360
01361 data->buffer = (unsigned char *) malloc( data->bufferSize );
01362
01363 if ( data->buffer == NULL ) {
01364 errorString_ = "RtMidiOut::initialize: error allocating buffer memory!\n\n";
01365 error( RtError::MEMORY_ERROR );
01366 }
01367 }
01368
01369 snd_seq_event_t ev;
01370
01371 snd_seq_ev_clear(&ev);
01372 snd_seq_ev_set_source(&ev, data->vport);
01373 snd_seq_ev_set_subs(&ev);
01374 snd_seq_ev_set_direct(&ev);
01375
01376 for ( unsigned int i=0; i<nBytes; i++ ) data->buffer[i] = message->at(i);
01377
01378 result = snd_midi_event_encode( data->coder, data->buffer, (long)nBytes, &ev );
01379
01380 if ( result < (int)nBytes ) {
01381 errorString_ = "RtMidiOut::sendMessage: event parsing error!";
01382 error( RtError::WARNING );
01383 return;
01384 }
01385
01386
01387 result = snd_seq_event_output(data->seq, &ev);
01388
01389 if ( result < 0 ) {
01390 errorString_ = "RtMidiOut::sendMessage: error sending MIDI message to port.";
01391 error( RtError::WARNING );
01392 }
01393
01394 snd_seq_drain_output(data->seq);
01395 }
01396
01397 #endif // __LINUX_ALSA__
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413 #if defined(__IRIX_MD__)
01414
01415 #include <pthread.h>
01416 #include <sys/time.h>
01417 #include <unistd.h>
01418
01419
01420 #include <dmedia/midi.h>
01421
01422
01423
01424
01425 struct IrixMidiData
01426 {
01427 MDport port;
01428 pthread_t thread;
01429 };
01430
01431
01432
01433
01434
01435
01436 extern "C" void *irixMidiHandler( void *ptr )
01437 {
01438 RtMidiIn::RtMidiInData *data = static_cast<RtMidiIn::RtMidiInData *> (ptr);
01439 IrixMidiData *apiData = static_cast<IrixMidiData *> (data->apiData);
01440
01441 bool continueSysex = false;
01442 unsigned char status;
01443 unsigned short size;
01444 MDevent event;
01445 int fd = mdGetFd( apiData->port );
01446
01447 if ( fd < 0 ) {
01448 data->doInput = false;
01449 STD_PRE::cerr << "\nRtMidiIn::irixMidiHandler: error getting port descriptor!\n\n";
01450 return 0;
01451 }
01452
01453 fd_set mask, rmask;
01454
01455 FD_ZERO( &mask );
01456 FD_SET( fd, &mask );
01457
01458 struct timeval timeout = {
01459 0, 0
01460 };
01461
01462 RtMidiIn::MidiMessage message;
01463 int result;
01464
01465 while ( data->doInput ) {
01466
01467 rmask = mask;
01468 timeout.tv_sec = 0;
01469 timeout.tv_usec = 0;
01470
01471 if ( select( fd+1, &rmask, NULL, NULL, &timeout ) <= 0 ) {
01472
01473 usleep( 1000 );
01474 continue;
01475 }
01476
01477
01478 result = mdReceive( apiData->port, &event, 1);
01479
01480 if ( result <= 0 ) {
01481 STD_PRE::cerr << "\nRtMidiIn::irixMidiHandler: MIDI input read error!\n\n";
01482 continue;
01483 }
01484
01485 message.timeStamp = event.stamp * 0.000000001;
01486
01487 size = 0;
01488 status = event.msg[0];
01489
01490 if ( !(status & 0x80) ) continue;
01491
01492 if ( status == 0xF0 ) {
01493
01494
01495 if ( !(data->ignoreFlags & 0x01) ) {
01496 if ( continueSysex ) {
01497
01498
01499
01500 for ( int i=0; i<event.msglen; i++ )
01501 message.bytes.push_back( event.sysexmsg[i] );
01502
01503 if ( event.sysexmsg[event.msglen-1] == 0xF7 ) continueSysex = false;
01504
01505 if ( !continueSysex ) {
01506
01507
01508 if ( data->usingCallback && message.bytes.size() > 0 ) {
01509 RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
01510 callback( message.timeStamp, &message.bytes, data->userData );
01511 } else {
01512
01513
01514 if ( data->queueLimit > data->queue.size() )
01515 data->queue.push( message );
01516 else
01517 STD_PRE::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
01518 }
01519
01520 message.bytes.clear();
01521 }
01522 }
01523 }
01524
01525 mdFree( NULL );
01526
01527 continue;
01528 } else if ( status < 0xC0 ) size = 3;
01529 else if ( status < 0xE0 ) size = 2;
01530 else if ( status < 0xF0 ) size = 3;
01531 else if ( status < 0xF3 ) {
01532 if ( status == 0xF1 && !(data->ignoreFlags & 0x02) ) {
01533
01534 size = 3;
01535 }
01536 } else if ( status == 0xF3 ) size = 2;
01537 else if ( status == 0xFE ) {
01538
01539 if ( !(data->ignoreFlags & 0x04) )
01540 size = 1;
01541 } else size = 1;
01542
01543
01544 if ( size ) {
01545 message.bytes.assign( &event.msg[0], &event.msg[size] );
01546
01547
01548 if ( data->usingCallback ) {
01549 RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
01550 callback( message.timeStamp, &message.bytes, data->userData );
01551 } else {
01552
01553
01554 if ( data->queueLimit > data->queue.size() )
01555 data->queue.push( message );
01556 else
01557 STD_PRE::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
01558 }
01559
01560 message.bytes.clear();
01561 }
01562 }
01563
01564 return 0;
01565 }
01566
01567 void RtMidiIn :: initialize( void )
01568
01569 {
01570
01571
01572
01573 int nPorts = mdInit();
01574
01575
01576 IrixMidiData *data = (IrixMidiData *) new IrixMidiData;
01577 apiData_ = (void *) data;
01578 inputData_.apiData = (void *) data;
01579 }
01580
01581 void RtMidiIn :: openPort( unsigned int portNumber )
01582 {
01583 if ( connected_ ) {
01584 errorString_ = "RtMidiIn::openPort: a valid connection already exists!";
01585 error( RtError::WARNING );
01586 return;
01587 }
01588
01589 int nPorts = mdInit();
01590
01591 if (nPorts < 1) {
01592 errorString_ = "RtMidiIn::openPort: no Irix MIDI input sources found!";
01593 error( RtError::NO_DEVICES_FOUND );
01594 }
01595
01596 STD_PRE::ostringstream ost;
01597
01598 if ( portNumber >= nPorts ) {
01599 ost << "RtMidiIn::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
01600 errorString_ = ost.str();
01601 error( RtError::INVALID_PARAMETER );
01602 }
01603
01604 IrixMidiData *data = static_cast<IrixMidiData *> (apiData_);
01605
01606 data->port = mdOpenInPort( mdGetName(portNumber) );
01607
01608 if ( data->port == NULL ) {
01609 ost << "RtMidiIn::openPort: Irix error opening the port (" << portNumber << ").";
01610 errorString_ = ost.str();
01611 error( RtError::DRIVER_ERROR );
01612 }
01613
01614 mdSetStampMode(data->port, MD_DELTASTAMP);
01615
01616
01617 pthread_attr_t attr;
01618 pthread_attr_init(&attr);
01619 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
01620 pthread_attr_setschedpolicy(&attr, SCHED_RR);
01621
01622 inputData_.doInput = true;
01623 int err = pthread_create(&data->thread, &attr, irixMidiHandler, &inputData_);
01624 pthread_attr_destroy(&attr);
01625
01626 if (err) {
01627 mdClosePort( data->port );
01628 inputData_.doInput = false;
01629 errorString_ = "RtMidiIn::openPort: error starting MIDI input thread!";
01630 error( RtError::THREAD_ERROR );
01631 }
01632
01633 connected_ = true;
01634 }
01635
01636 void RtMidiIn :: openVirtualPort()
01637 {
01638
01639 errorString_ = "RtMidiIn::openVirtualPort: cannot be implemented in Irix MIDI API!";
01640 error( RtError::WARNING );
01641 }
01642
01643 void RtMidiIn :: closePort( void )
01644 {
01645 if ( connected_ ) {
01646 IrixMidiData *data = static_cast<IrixMidiData *> (apiData_);
01647 mdClosePort( data->port );
01648 connected_ = false;
01649
01650
01651 inputData_.doInput = false;
01652 pthread_join( data->thread, NULL );
01653 }
01654 }
01655
01656 RtMidiIn :: ~RtMidiIn()
01657 {
01658
01659 closePort();
01660
01661
01662 IrixMidiData *data = static_cast<IrixMidiData *> (apiData_);
01663 delete data;
01664 }
01665
01666 unsigned int RtMidiIn :: getPortCount()
01667 {
01668 int nPorts = mdInit();
01669
01670 if ( nPorts >= 0 ) return nPorts;
01671 else return 0;
01672 }
01673
01674 STD_PRE::string RtMidiIn :: getPortName( unsigned int portNumber )
01675 {
01676 int nPorts = mdInit();
01677
01678 STD_PRE::ostringstream ost;
01679
01680 if ( portNumber >= nPorts ) {
01681 ost << "RtMidiIn::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
01682 errorString_ = ost.str();
01683 error( RtError::INVALID_PARAMETER );
01684 }
01685
01686 STD_PRE::string stringName = STD_PRE::string( mdGetName( portNumber ) );
01687
01688 return stringName;
01689 }
01690
01691
01692
01693
01694
01695
01696 unsigned int RtMidiOut :: getPortCount()
01697 {
01698 int nPorts = mdInit();
01699
01700 if ( nPorts >= 0 ) return nPorts;
01701 else return 0;
01702 }
01703
01704 STD_PRE::string RtMidiOut :: getPortName( unsigned int portNumber )
01705 {
01706 int nPorts = mdInit();
01707
01708 STD_PRE::ostringstream ost;
01709
01710 if ( portNumber >= nPorts ) {
01711 ost << "RtMidiIn::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
01712 errorString_ = ost.str();
01713 error( RtError::INVALID_PARAMETER );
01714 }
01715
01716 STD_PRE::string stringName = STD_PRE::string( mdGetName( portNumber ) );
01717
01718 return stringName;
01719 }
01720
01721 void RtMidiOut :: initialize( void )
01722 {
01723
01724
01725
01726 int nPorts = mdInit();
01727
01728
01729 IrixMidiData *data = (IrixMidiData *) new IrixMidiData;
01730 apiData_ = (void *) data;
01731 }
01732
01733 void RtMidiOut :: openPort( unsigned int portNumber )
01734 {
01735 if ( connected_ ) {
01736 errorString_ = "RtMidiOut::openPort: a valid connection already exists!";
01737 error( RtError::WARNING );
01738 return;
01739 }
01740
01741 int nPorts = mdInit();
01742
01743 if (nPorts < 1) {
01744 errorString_ = "RtMidiOut::openPort: no Irix MIDI output sources found!";
01745 error( RtError::NO_DEVICES_FOUND );
01746 }
01747
01748 STD_PRE::ostringstream ost;
01749
01750 if ( portNumber >= nPorts ) {
01751 ost << "RtMidiOut::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
01752 errorString_ = ost.str();
01753 error( RtError::INVALID_PARAMETER );
01754 }
01755
01756 IrixMidiData *data = static_cast<IrixMidiData *> (apiData_);
01757
01758 data->port = mdOpenOutPort( mdGetName(portNumber) );
01759
01760 if ( data->port == NULL ) {
01761 ost << "RtMidiOut::openPort: Irix error opening the port (" << portNumber << ").";
01762 errorString_ = ost.str();
01763 error( RtError::DRIVER_ERROR );
01764 }
01765
01766 mdSetStampMode(data->port, MD_NOSTAMP);
01767
01768 connected_ = true;
01769 }
01770
01771 void RtMidiOut :: closePort( void )
01772 {
01773 if ( connected_ ) {
01774 IrixMidiData *data = static_cast<IrixMidiData *> (apiData_);
01775 mdClosePort( data->port );
01776 connected_ = false;
01777 }
01778 }
01779
01780 void RtMidiOut :: openVirtualPort()
01781 {
01782
01783 errorString_ = "RtMidiOut::openVirtualPort: cannot be implemented in Irix MIDI API!";
01784 error( RtError::WARNING );
01785 }
01786
01787 RtMidiOut :: ~RtMidiOut()
01788 {
01789
01790 closePort();
01791
01792
01793 IrixMidiData *data = static_cast<IrixMidiData *> (apiData_);
01794 delete data;
01795 }
01796
01797 void RtMidiOut :: sendMessage( STD_PRE::vector<unsigned char> *message )
01798 {
01799 int result;
01800 MDevent event;
01801 IrixMidiData *data = static_cast<IrixMidiData *> (apiData_);
01802 char *buffer = 0;
01803
01804 unsigned int nBytes = message->size();
01805
01806 if ( nBytes == 0 ) return;
01807
01808 event.stamp = 0;
01809
01810 if ( message->at(0) == 0xF0 ) {
01811 if ( nBytes < 3 ) return;
01812
01813 event.msg[0] = 0xF0;
01814
01815 event.msglen = nBytes;
01816
01817 buffer = (char *) malloc( nBytes );
01818
01819 for ( int i=0; i<nBytes; i++ ) buffer[i] = message->at(i);
01820
01821 event.sysexmsg = buffer;
01822 } else {
01823 for ( int i=0; i<nBytes; i++ )
01824 event.msg[i] = message->at(i);
01825 }
01826
01827
01828 result = mdSend( data->port, &event, 1 );
01829
01830 if ( buffer ) free( buffer );
01831
01832 if ( result < 1 ) {
01833 errorString_ = "RtMidiOut::sendMessage: IRIX error sending MIDI message!";
01834 error( RtError::WARNING );
01835 return;
01836 }
01837 }
01838
01839 #endif // __IRIX_MD__
01840
01841
01842
01843
01844
01845
01846
01847
01848 #if defined(__WINDOWS_MM__)
01849
01850 #define CLEAR(que) \
01851 while ( !que.empty() ) que.erase(que.begin())
01852
01853
01854
01855
01856
01857
01858 #include <windows.h>
01859 #include <mmsystem.h>
01860 #include <strstream>
01861
01862
01863
01864
01865 struct WinMidiData
01866 {
01867 HMIDIIN inHandle;
01868 HMIDIOUT outHandle;
01869 DWORD lastTime;
01870 RtMidiIn::MidiMessage message;
01871 };
01872
01873
01874
01875
01876
01877
01878 static void CALLBACK midiInputCallback( HMIDIOUT hmin,
01879 UINT inputStatus,
01880 DWORD instancePtr,
01881 DWORD midiMessage,
01882 DWORD timestamp )
01883 {
01884 if ( inputStatus != MIM_DATA && inputStatus != MIM_LONGDATA ) return;
01885
01886
01887 RtMidiIn::RtMidiInData *data = (RtMidiIn::RtMidiInData *)instancePtr;
01888
01889 WinMidiData *apiData = static_cast<WinMidiData *> (data->apiData);
01890
01891
01892 apiData->message.timeStamp = 0.0;
01893
01894 if ( data->firstMessage == true ) data->firstMessage = false;
01895 else apiData->message.timeStamp = (double) ( timestamp - apiData->lastTime ) * 0.001;
01896
01897 apiData->lastTime = timestamp;
01898
01899 if ( inputStatus == MIM_DATA ) {
01900
01901
01902 unsigned char status = (unsigned char) (midiMessage & 0x000000FF);
01903
01904 if ( !(status & 0x80) ) return;
01905
01906
01907 unsigned short nBytes = 1;
01908
01909 if ( status < 0xC0 ) nBytes = 3;
01910 else if ( status < 0xE0 ) nBytes = 2;
01911 else if ( status < 0xF0 ) nBytes = 3;
01912 else if ( status < 0xF3 ) {
01913
01914
01915 if ( status == 0xF1 && (data->ignoreFlags & 0x02) ) return;
01916
01917 nBytes = 3;
01918 } else if ( status == 0xF3 ) nBytes = 2;
01919 else if ( status == 0xFE && (data->ignoreFlags & 0x04) ) {
01920
01921 return;
01922 }
01923
01924
01925 unsigned char *ptr = (unsigned char *) &midiMessage;
01926
01927 for ( int i=0; i<nBytes; i++ ) apiData->message.bytes.push_back( *ptr++ );
01928 } else {
01929 MIDIHDR *sysex = ( MIDIHDR *) midiMessage;
01930
01931 for ( int i=0; i<(int)sysex->dwBytesRecorded; i++ )
01932 apiData->message.bytes.push_back( sysex->lpData[i] );
01933
01934 if ( apiData->message.bytes.back() != 0xF7 ) return;
01935 }
01936
01937 if ( data->usingCallback ) {
01938 RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
01939 callback( apiData->message.timeStamp, &apiData->message.bytes, data->userData );
01940 } else {
01941
01942
01943 if ( data->queueLimit > data->queue.size() )
01944 data->queue.push( apiData->message );
01945 else
01946 STD_PRE::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
01947 }
01948
01949
01950
01951
01952
01953 CLEAR(apiData->message.bytes);
01954 }
01955
01956 void RtMidiIn :: initialize( void )
01957
01958 {
01959
01960
01961 unsigned int nDevices = midiInGetNumDevs();
01962
01963 if ( nDevices == 0 ) {
01964 errorString_ = "RtMidiIn::initialize: no MIDI input devices currently available.";
01965 error( RtError::WARNING );
01966 }
01967
01968
01969 WinMidiData *data = (WinMidiData *) new WinMidiData;
01970
01971 apiData_ = (void *) data;
01972
01973 inputData_.apiData = (void *) data;
01974
01975
01976 CLEAR(data->message.bytes);
01977 }
01978
01979 void RtMidiIn :: openPort( unsigned int portNumber )
01980 {
01981 if ( connected_ ) {
01982 errorString_ = "RtMidiIn::openPort: a valid connection already exists!";
01983 error( RtError::WARNING );
01984 return;
01985 }
01986
01987 unsigned int nDevices = midiInGetNumDevs();
01988
01989 if (nDevices == 0) {
01990 errorString_ = "RtMidiIn::openPort: no MIDI input sources found!";
01991 error( RtError::NO_DEVICES_FOUND );
01992 }
01993
01994 STD_PRE::ostrstream ost;
01995
01996 if ( portNumber >= nDevices ) {
01997 ost << "RtMidiIn::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
01998 errorString_ = ost.str();
01999 error( RtError::INVALID_PARAMETER );
02000 }
02001
02002 WinMidiData *data = static_cast<WinMidiData *> (apiData_);
02003
02004 MMRESULT result = midiInOpen( &data->inHandle,
02005 portNumber,
02006 (DWORD)&midiInputCallback,
02007 (DWORD)&inputData_,
02008 CALLBACK_FUNCTION );
02009
02010 if ( result != MMSYSERR_NOERROR ) {
02011 errorString_ = "RtMidiIn::openPort: error creating Windows MM MIDI input port.";
02012 error( RtError::DRIVER_ERROR );
02013 }
02014
02015 result = midiInStart( data->inHandle );
02016
02017 if ( result != MMSYSERR_NOERROR ) {
02018 midiInClose( data->inHandle );
02019 errorString_ = "RtMidiIn::openPort: error starting Windows MM MIDI input port.";
02020 error( RtError::DRIVER_ERROR );
02021 }
02022
02023 connected_ = true;
02024 }
02025
02026 void RtMidiIn :: openVirtualPort()
02027 {
02028
02029 errorString_ = "RtMidiIn::openVirtualPort: cannot be implemented in Windows MM MIDI API!";
02030 error( RtError::WARNING );
02031 }
02032
02033 void RtMidiIn :: closePort( void )
02034 {
02035 if ( connected_ ) {
02036 WinMidiData *data = static_cast<WinMidiData *> (apiData_);
02037 midiInReset( data->inHandle );
02038 midiInStop( data->inHandle );
02039 midiInClose( data->inHandle );
02040 connected_ = false;
02041 }
02042 }
02043
02044 RtMidiIn :: ~RtMidiIn()
02045 {
02046
02047 closePort();
02048
02049
02050 WinMidiData *data = static_cast<WinMidiData *> (apiData_);
02051 delete data;
02052 }
02053
02054 unsigned int RtMidiIn :: getPortCount()
02055 {
02056 return midiInGetNumDevs();
02057 }
02058
02059 #ifdef __WXMSW__
02060
02061 wxString RtMidiIn :: getPortName( unsigned int portNumber )
02062 {
02063 unsigned int nDevices = midiInGetNumDevs();
02064
02065 if ( portNumber >= nDevices ) {
02066 STD_PRE::ostrstream ost;
02067 ost << "RtMidiIn::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
02068 errorString_ = ost.str();
02069 error( RtError::INVALID_PARAMETER );
02070 }
02071
02072 MIDIINCAPS deviceCaps;
02073
02074 MMRESULT result = midiInGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIINCAPS));
02075
02076 wxString stringName ( deviceCaps.szPname );
02077 return stringName;
02078 }
02079
02080 #else
02081 STD_PRE::string RtMidiIn :: getPortName( unsigned int portNumber )
02082 {
02083 unsigned int nDevices = midiInGetNumDevs();
02084
02085 if ( portNumber >= nDevices ) {
02086 STD_PRE::ostrstream ost;
02087 ost << "RtMidiIn::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
02088 errorString_ = ost.str();
02089 error( RtError::INVALID_PARAMETER );
02090 }
02091
02092 MIDIINCAPS deviceCaps;
02093
02094 MMRESULT result = midiInGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIINCAPS));
02095
02096 STD_PRE::string stringName = STD_PRE::string( (char*)deviceCaps.szPname );
02097 std::cout << "RtMidiIn::getPortName" << std::endl;
02098 std::cout << ((deviceCaps.szPname)) << " " << sizeof(*deviceCaps.szPname) << std::endl;
02099
02100 for (size_t i=0; deviceCaps.szPname[i] !=0; i++)
02101 std::cout << ((char)(deviceCaps.szPname[i]));
02102
02103 std::cout << std::endl;
02104
02105
02106 return stringName;
02107 }
02108
02109 #endif
02110
02111
02112
02113
02114
02115
02116 unsigned int RtMidiOut :: getPortCount()
02117 {
02118 return midiOutGetNumDevs();
02119 }
02120
02121
02122 #ifdef __WXMSW__
02123 wxString RtMidiOut :: getPortName( unsigned int portNumber )
02124 {
02125 unsigned int nDevices = midiOutGetNumDevs();
02126
02127 if ( portNumber >= nDevices ) {
02128 STD_PRE::ostrstream ost;
02129 ost << "RtMidiOut::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
02130 errorString_ = ost.str();
02131 error( RtError::INVALID_PARAMETER );
02132 }
02133
02134 MIDIOUTCAPS deviceCaps;
02135
02136 MMRESULT result = midiOutGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIOUTCAPS));
02137
02138 wxString stringName ( deviceCaps.szPname );
02139 return stringName;
02140 }
02141
02142 #else
02143 STD_PRE::string RtMidiOut :: getPortName( unsigned int portNumber )
02144 {
02145 unsigned int nDevices = midiOutGetNumDevs();
02146
02147 if ( portNumber >= nDevices ) {
02148 STD_PRE::ostrstream ost;
02149 ost << "RtMidiOut::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
02150 errorString_ = ost.str();
02151 error( RtError::INVALID_PARAMETER );
02152 }
02153
02154 MIDIOUTCAPS deviceCaps;
02155
02156 MMRESULT result = midiOutGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIOUTCAPS));
02157
02158 STD_PRE::string stringName = std::string( (char*)deviceCaps.szPname );
02159 return stringName;
02160 }
02161
02162 #endif
02163
02164 void RtMidiOut :: initialize( void )
02165 {
02166
02167
02168 unsigned int nDevices = midiOutGetNumDevs();
02169
02170 if ( nDevices == 0 ) {
02171 errorString_ = "RtMidiOut::initialize: no MIDI output devices currently available.";
02172 error( RtError::WARNING );
02173 }
02174
02175
02176 WinMidiData *data = (WinMidiData *) new WinMidiData;
02177
02178 apiData_ = (void *) data;
02179 }
02180
02181 void RtMidiOut :: openPort( unsigned int portNumber )
02182 {
02183 if ( connected_ ) {
02184 errorString_ = "RtMidiOut::openPort: a valid connection already exists!";
02185 error( RtError::WARNING );
02186 return;
02187 }
02188
02189 unsigned int nDevices = midiOutGetNumDevs();
02190
02191 if (nDevices < 1) {
02192 errorString_ = "RtMidiOut::openPort: no MIDI output destinations found!";
02193 error( RtError::NO_DEVICES_FOUND );
02194 }
02195
02196 STD_PRE::ostrstream ost;
02197
02198 if ( portNumber >= nDevices ) {
02199 ost << "RtMidiOut::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
02200 errorString_ = ost.str();
02201 error( RtError::INVALID_PARAMETER );
02202 }
02203
02204 WinMidiData *data = static_cast<WinMidiData *> (apiData_);
02205
02206 MMRESULT result = midiOutOpen( &data->outHandle,
02207 portNumber,
02208 (DWORD)NULL,
02209 (DWORD)NULL,
02210 CALLBACK_NULL );
02211
02212 if ( result != MMSYSERR_NOERROR ) {
02213 errorString_ = "RtMidiOut::openPort: error creating Windows MM MIDI output port.";
02214 error( RtError::DRIVER_ERROR );
02215 }
02216
02217 connected_ = true;
02218 }
02219
02220 void RtMidiOut :: closePort( void )
02221 {
02222 if ( connected_ ) {
02223 WinMidiData *data = static_cast<WinMidiData *> (apiData_);
02224 midiOutReset( data->outHandle );
02225 midiOutClose( data->outHandle );
02226 connected_ = false;
02227 }
02228 }
02229
02230 void RtMidiOut :: openVirtualPort()
02231 {
02232
02233 errorString_ = "RtMidiOut::openVirtualPort: cannot be implemented in Windows MM MIDI API!";
02234 error( RtError::WARNING );
02235 }
02236
02237 RtMidiOut :: ~RtMidiOut()
02238 {
02239
02240 closePort();
02241
02242
02243 WinMidiData *data = static_cast<WinMidiData *> (apiData_);
02244 delete data;
02245 }
02246
02247 void RtMidiOut :: sendMessage( std::vector<unsigned char> *message )
02248 {
02249 unsigned int nBytes = message->size();
02250
02251 if ( nBytes == 0 ) {
02252 errorString_ = "RtMidiOut::sendMessage: message argument is empty!";
02253 error( RtError::WARNING );
02254 return;
02255 }
02256
02257 MMRESULT result;
02258
02259 WinMidiData *data = static_cast<WinMidiData *> (apiData_);
02260
02261 if ( message->at(0) == 0xF0 ) {
02262
02263
02264 char *buffer = (char *) malloc( nBytes );
02265
02266 if ( buffer == NULL ) {
02267 errorString_ = "RtMidiOut::sendMessage: error allocating sysex message memory!";
02268 error( RtError::MEMORY_ERROR );
02269 }
02270
02271
02272 for ( unsigned int i=0; i<nBytes; i++ ) buffer[i] = message->at(i);
02273
02274
02275 MIDIHDR sysex;
02276
02277 sysex.lpData = (LPSTR) buffer;
02278
02279 sysex.dwBufferLength = nBytes;
02280
02281 sysex.dwFlags = 0;
02282
02283 result = midiOutPrepareHeader( data->outHandle, &sysex, sizeof(MIDIHDR) );
02284
02285 if ( result != MMSYSERR_NOERROR ) {
02286 free( buffer );
02287 errorString_ = "RtMidiOut::sendMessage: error preparing sysex header.";
02288 error( RtError::DRIVER_ERROR );
02289 }
02290
02291
02292 result = midiOutLongMsg( data->outHandle, &sysex, sizeof(MIDIHDR) );
02293
02294 if ( result != MMSYSERR_NOERROR ) {
02295 free( buffer );
02296 errorString_ = "RtMidiOut::sendMessage: error sending sysex message.";
02297 error( RtError::DRIVER_ERROR );
02298 }
02299
02300
02301 while ( MIDIERR_STILLPLAYING == midiOutUnprepareHeader( data->outHandle, &sysex, sizeof (MIDIHDR) ) ) Sleep( 1 );
02302
02303 free( buffer );
02304
02305 } else {
02306
02307
02308
02309 if ( nBytes > 3 ) {
02310 errorString_ = "RtMidiOut::sendMessage: message size is greater than 3 bytes (and not sysex)!";
02311 error( RtError::WARNING );
02312 return;
02313 }
02314
02315
02316 DWORD packet;
02317
02318 unsigned char *ptr = (unsigned char *) &packet;
02319
02320 for ( unsigned int i=0; i<nBytes; i++ ) {
02321 *ptr = message->at(i);
02322 ptr++;
02323 }
02324
02325
02326 result = midiOutShortMsg( data->outHandle, packet );
02327
02328 if ( result != MMSYSERR_NOERROR ) {
02329 errorString_ = "RtMidiOut::sendMessage: error sending MIDI message.";
02330 error( RtError::DRIVER_ERROR );
02331 }
02332 }
02333 }
02334
02335 #endif // __WINDOWS_MM__