RtMidi.cpp
gehe zur Dokumentation dieser Datei
00001 /**********************************************************************/
00036 /**********************************************************************/
00037 
00038 // RtMidi: Version 1.0.3, 22 November 2004
00039 
00040 #include <iostream>
00041 #include <sstream>
00042 #include "Defs.h"
00043 #include "RtMidi.h"
00044 
00045 //*********************************************************************//
00046 //  Common RtMidi Definitions
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 //  Common RtMidiIn Definitions
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         //message->clear();
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         // Copy queued message to the vector pointer argument and then "pop" it.
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 //  Common RtMidiOut Definitions
00152 //*********************************************************************//
00153 
00154 RtMidiOut :: RtMidiOut() : RtMidi()
00155 {
00156         this->initialize();
00157 }
00158 
00159 
00160 //*********************************************************************//
00161 //  API: Macintosh OS-X
00162 //*********************************************************************//
00163 
00164 // API information found at:
00165 //   - http://developer. apple .com/audio/pdf/coreaudio.pdf
00166 
00167 #if defined(__MACOSX_CORE__)
00168 
00169 // The CoreMIDI API is based on the use of a callback function for
00170 // MIDI input.  We convert the system specific time stamps to delta
00171 // time values.
00172 
00173 // OS-X CoreMIDI header files.
00174 #include <CoreMIDI/CoreMIDI.h>
00175 #include <CoreAudio/HostTime.h>
00176 
00177 // A structure to hold variables related to the CoreMIDI API
00178 // implementation.
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 //  API: OS-X
00191 //  Class Definitions: RtMidiIn
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                 // My interpretation of the CoreMIDI documentation: all message
00210                 // types, except sysex, are complete within a packet and there may
00211                 // be several of them in a single packet.  Sysex messages can be
00212                 // broken across multiple packets but are bundled alone within a
00213                 // packet.  I'm assuming that sysex messages, if segmented, must
00214                 // be complete within the same MIDIPacketList.
00215 
00216                 nBytes = packet->length;
00217 
00218                 if ( nBytes == 0 ) continue;
00219 
00220                 // Calculate time stamp.
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                         // We have a continuing, segmented sysex message.
00238 
00239                         if ( !(data->ignoreFlags & 0x01) ) {
00240                                 // If we're not ignoring sysex messages, copy the entire packet.
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                                 // If not a continuing sysex message, invoke the user callback function or queue the message.
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                                         // As long as we haven't reached our queue size limit, push the message.
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                                 // We are expecting that the next byte in the packet is a status byte.
00269                                 status = packet->data[iByte];
00270 
00271                                 if ( !(status & 0x80) ) break;
00272 
00273                                 // Determine the number of bytes in the MIDI message.
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                                         // A MIDI sysex
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                                                 // A MIDI time code message and we're ignoring it.
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                                         // A MIDI active sensing message and we're ignoring it.
00295                                         size = 0;
00296                                         iByte += 1;
00297                                 } else size = 1;
00298 
00299                                 // Copy the MIDI data to our vector.
00300                                 if ( size ) {
00301                                         message.bytes.assign( &packet->data[iByte], &packet->data[iByte+size] );
00302 
00303                                         if ( !continueSysex ) {
00304                                                 // If not a continuing sysex message, invoke the user callback function or queue the message.
00305 
00306                                                 if ( data->usingCallback ) {
00307                                                         RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
00308                                                         callback( message.timeStamp, &message.bytes, data->userData );
00309                                                 } else {
00310                                                         // As long as we haven't reached our queue size limit, push the message.
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         // Set up our client.
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         // Save our api-specific connection information.
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         // Get the desired input source identifier.
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         // Make the connection.
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         // Save our api-specific port information.
00411         data->port = port;
00412 
00413         connected_ = true;
00414 }
00415 
00416 void RtMidiIn :: openVirtualPort()
00417 {
00418         CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
00419 
00420         // Create a virtual MIDI input destination.
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         // Save our api-specific connection information.
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         // Close a connection if it exists.
00445         closePort();
00446 
00447         // Cleanup.
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 //  API: OS-X
00486 //  Class Definitions: RtMidiOut
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         // Set up our client.
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         // Save our api-specific connection information.
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         // Get the desired output port identifier.
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         // Save our api-specific connection information.
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         // Create a virtual MIDI output source.
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         // Save our api-specific connection information.
00664         data->endpoint = endpoint;
00665 }
00666 
00667 RtMidiOut :: ~RtMidiOut()
00668 {
00669         // Close a connection if it exists.
00670         closePort();
00671 
00672         // Cleanup.
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         // Pad the buffer for extra (unknown) structure data.
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         // Send to any destinations that may have connected to us.
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         // And send to an explicit destination port if we're connected.
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 //  API: LINUX ALSA SEQUENCER
00722 //*********************************************************************//
00723 
00724 // API information found at:
00725 //   - http://www.alsa-project.org/documentation.php#Library
00726 
00727 #if defined(__LINUX_ALSASEQ__)
00728 
00729 // The ALSA Sequencer API is based on the use of a callback function for
00730 // MIDI input.  We convert the system specific time stamps to delta
00731 // time values.
00732 
00733 #include <pthread.h>
00734 #include <sys/time.h>
00735 
00736 // ALSA header file.
00737 #include <alsa/asoundlib.h>
00738 
00739 // A structure to hold variables related to the ALSA API
00740 // implementation.
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 //  API: LINUX ALSA
00758 //  Class Definitions: RtMidiIn
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                         // No data pending ... sleep a bit.
00798                         usleep( 1000 );
00799                         continue;
00800                 }
00801 
00802                 // If here, there should be data.
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                 // This is a bit weird, but we now have to decode an ALSA MIDI
00814                 // event (back) into MIDI bytes.  We'll ignore non-MIDI types.
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: // MIDI time code
00834                         if ( data->ignoreFlags & 0x02 ) break;
00835 
00836                 case SND_SEQ_EVENT_SENSING: // Active 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                         // Save last status byte in case of running status.
00867 
00868                         if ( message.bytes[0] & 0x80 ) lastStatus = message.bytes[0];
00869                         else if ( lastStatus ) message.bytes.insert( message.bytes.begin(), lastStatus );
00870 
00871                         // I found the ALSA sequencer documentation to be very inadequate,
00872                         // especially regarding timestamps.  So, I ignore the event
00873                         // timestamp and use system time to determine ours.
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                         // As long as we haven't reached our queue size limit, push the message.
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         // Set up the ALSA sequencer client.
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         // Set client name.
00929         snd_seq_set_client_name(seq, "RtMidi Input Client");
00930 
00931         // Save our api-specific connection information.
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 // This function is used to count or get the pinfo structure for a given port number.
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                 // Reset query info
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         // If a negative portNumber was used, return the port count.
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         // Make subscription
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                 // Start our MIDI input thread.
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                 // Start our MIDI input thread.
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         // Close a connection if it exists.
01109         closePort();
01110 
01111         // Shutdown the input thread.
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         // Cleanup.
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         // If we get here, we didn't find a match.
01149         errorString_ = "RtMidiIn::getPortName: error looking for port name!";
01150 
01151         error( RtError::INVALID_PARAMETER );
01152 
01153         return 0;
01154 }
01155 
01156 //*********************************************************************//
01157 //  API: LINUX ALSA
01158 //  Class Definitions: RtMidiOut
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         // If we get here, we didn't find a match.
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         // Set up the ALSA sequencer client.
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         // Set client name.
01202         snd_seq_set_client_name(seq, "RtMidi Output Client");
01203 
01204         // Save our api-specific connection information.
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         // Make subscription
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         // Close a connection if it exists.
01328         closePort();
01329 
01330         // Cleanup.
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         // Send the event.
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 //  API: IRIX MD
01402 //*********************************************************************//
01403 
01404 // API information gleamed from:
01405 //   http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?cmd=getdoc&coll=0650&db=man&fname=3%20mdIntro
01406 
01407 // If the Makefile doesn't work, try the following:
01408 // CC -o midiinfo -LANG:std -D__IRIX_MD__ -I../ ../RtMidi.cpp midiinfo.cpp -lpthread -lmd
01409 // CC -o midiout -LANG:std -D__IRIX_MD__ -I../ ../RtMidi.cpp midiout.cpp -lpthread -lmd
01410 // CC -o qmidiin -LANG:std -D__IRIX_MD__ -I../ ../RtMidi.cpp qmidiin.cpp -lpthread -lmd
01411 // CC -o cmidiin -LANG:std -D__IRIX_MD__ -I../ ../RtMidi.cpp cmidiin.cpp -lpthread -lmd
01412 
01413 #if defined(__IRIX_MD__)
01414 
01415 #include <pthread.h>
01416 #include <sys/time.h>
01417 #include <unistd.h>
01418 
01419 // Irix MIDI header file.
01420 #include <dmedia/midi.h>
01421 
01422 // A structure to hold variables related to the IRIX API
01423 // implementation.
01424 
01425 struct IrixMidiData
01426 {
01427         MDport port;
01428         pthread_t thread;
01429 };
01430 
01431 //*********************************************************************//
01432 //  API: IRIX
01433 //  Class Definitions: RtMidiIn
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                         // No data pending ... sleep a bit.
01473                         usleep( 1000 );
01474                         continue;
01475                 }
01476 
01477                 // If here, there should be data.
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                         // Sysex message ... can be segmented across multiple messages.
01494 
01495                         if ( !(data->ignoreFlags & 0x01) ) {
01496                                 if ( continueSysex ) {
01497                                         // We have a continuing, segmented sysex message.  Append
01498                                         // the new bytes to our existing message.
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                                                 // If not a continuing sysex message, invoke the user callback function or queue the message.
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                                                         // As long as we haven't reached our queue size limit, push the message.
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                                 // A MIDI time code message and we're not ignoring it.
01534                                 size = 3;
01535                         }
01536                 } else if ( status == 0xF3 ) size = 2;
01537                 else if ( status == 0xFE ) { // MIDI active sensing
01538 
01539                         if ( !(data->ignoreFlags & 0x04) )
01540                                 size = 1;
01541                 } else size = 1;
01542 
01543                 // Copy the MIDI data to our vector.
01544                 if ( size ) {
01545                         message.bytes.assign( &event.msg[0], &event.msg[size] );
01546                         // Invoke the user callback function or queue the message.
01547 
01548                         if ( data->usingCallback ) {
01549                                 RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
01550                                 callback( message.timeStamp, &message.bytes, data->userData );
01551                         } else {
01552                                 // As long as we haven't reached our queue size limit, push the message.
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         // Initialize the Irix MIDI system.  At the moment, we will not
01571         // worry about a return value of zero (ports) because there is a
01572         // chance the user could plug something in after instantiation.
01573         int nPorts = mdInit();
01574 
01575         // Create our api-specific connection information.
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         // Start our MIDI input thread.
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         // This function cannot be implemented for the Irix MIDI API.
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                 // Shutdown the input thread.
01651                 inputData_.doInput = false;
01652                 pthread_join( data->thread, NULL );
01653         }
01654 }
01655 
01656 RtMidiIn :: ~RtMidiIn()
01657 {
01658         // Close a connection if it exists.
01659         closePort();
01660 
01661         // Cleanup.
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 //  API: IRIX MD
01693 //  Class Definitions: RtMidiOut
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         // Initialize the Irix MIDI system.  At the moment, we will not
01724         // worry about a return value of zero (ports) because there is a
01725         // chance the user could plug something in after instantiation.
01726         int nPorts = mdInit();
01727 
01728         // Create our api-specific connection information.
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         // This function cannot be implemented for the Irix MIDI API.
01783         errorString_ = "RtMidiOut::openVirtualPort: cannot be implemented in Irix MIDI API!";
01784         error( RtError::WARNING );
01785 }
01786 
01787 RtMidiOut :: ~RtMidiOut()
01788 {
01789         // Close a connection if it exists.
01790         closePort();
01791 
01792         // Cleanup.
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; // check for bogus sysex
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         // Send the event.
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 //  API: Windows Multimedia Library (MM)
01843 //*********************************************************************//
01844 
01845 // API information deciphered from:
01846 //  - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_midi_reference.asp
01847 
01848 #if defined(__WINDOWS_MM__)
01849 
01850 #define CLEAR(que) \
01851   while ( !que.empty() ) que.erase(que.begin())
01852 
01853 // The Windows MM API is based on the use of a callback function for
01854 // MIDI input.  We convert the system specific time stamps to delta
01855 // time values.
01856 
01857 // Windows MM MIDI header files.
01858 #include <windows.h>
01859 #include <mmsystem.h>
01860 #include <strstream>
01861 
01862 // A structure to hold variables related to the CoreMIDI API
01863 // implementation.
01864 
01865 struct WinMidiData
01866 {
01867         HMIDIIN inHandle;    // Handle to Midi Input Device
01868         HMIDIOUT outHandle;  // Handle to Midi Output Device
01869         DWORD lastTime;
01870         RtMidiIn::MidiMessage message;
01871 };
01872 
01873 //*********************************************************************//
01874 //  API: Windows MM
01875 //  Class Definitions: RtMidiIn
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         //RtMidiIn::RtMidiInData *data = static_cast<RtMidiIn::RtMidiInData *> (instancePtr);
01887         RtMidiIn::RtMidiInData *data = (RtMidiIn::RtMidiInData *)instancePtr;
01888 
01889         WinMidiData *apiData = static_cast<WinMidiData *> (data->apiData);
01890 
01891         // Calculate time stamp.
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 ) { // Channel or system message
01900 
01901                 // Make sure the first byte is a status byte.
01902                 unsigned char status = (unsigned char) (midiMessage & 0x000000FF);
01903 
01904                 if ( !(status & 0x80) ) return;
01905 
01906                 // Determine the number of bytes in the MIDI message.
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                         // A MIDI time code message and we're ignoring it.
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                         // A MIDI active sensing message and we're ignoring it.
01921                         return;
01922                 }
01923 
01924                 // Copy bytes to our MIDI message.
01925                 unsigned char *ptr = (unsigned char *) &midiMessage;
01926 
01927                 for ( int i=0; i<nBytes; i++ ) apiData->message.bytes.push_back( *ptr++ );
01928         } else { // Sysex message
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                 // As long as we haven't reached our queue size limit, push the message.
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         // Clear the vector for the next input message.  Note that doing
01950         // this here allows our code to work for sysex messages which are
01951         // segmented across multiple buffers.
01952         //BC apiData->message.bytes.clear();
01953         CLEAR(apiData->message.bytes);
01954 }
01955 
01956 void RtMidiIn :: initialize( void )
01957 
01958 {
01959         // We'll issue a warning here if no devices are available but not
01960         // throw an error since the user can plugin something later.
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         // Save our api-specific connection information.
01969         WinMidiData *data = (WinMidiData *) new WinMidiData;
01970 
01971         apiData_ = (void *) data;
01972 
01973         inputData_.apiData = (void *) data;
01974 
01975         //BC data->message.bytes.clear();  // needs to be empty for first input message
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         // This function cannot be implemented for the Windows MM MIDI API.
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         // Close a connection if it exists.
02047         closePort();
02048 
02049         // Cleanup.
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 //  API: Windows MM
02113 //  Class Definitions: RtMidiOut
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         // We'll issue a warning here if no devices are available but not
02167         // throw an error since the user can plug something in later.
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         // Save our api-specific connection information.
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         // This function cannot be implemented for the Windows MM MIDI API.
02233         errorString_ = "RtMidiOut::openVirtualPort: cannot be implemented in Windows MM MIDI API!";
02234         error( RtError::WARNING );
02235 }
02236 
02237 RtMidiOut :: ~RtMidiOut()
02238 {
02239         // Close a connection if it exists.
02240         closePort();
02241 
02242         // Cleanup.
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 ) { // Sysex message
02262 
02263                 // Allocate buffer for sysex data.
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                 // Copy data to buffer.
02272                 for ( unsigned int i=0; i<nBytes; i++ ) buffer[i] = message->at(i);
02273 
02274                 // Create and prepare MIDIHDR structure.
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                 // Send the message.
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                 // Unprepare the buffer and MIDIHDR.
02301                 while ( MIDIERR_STILLPLAYING == midiOutUnprepareHeader( data->outHandle, &sysex, sizeof (MIDIHDR) ) ) Sleep( 1 );
02302 
02303                 free( buffer );
02304 
02305         } else { // Channel or system message.
02306 
02307                 // Make sure the message size isn't too big.
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                 // Pack MIDI bytes into double word.
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                 // Send the message immediately.
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__

Erzeugt am Sun Aug 21 2011 10:51:57 für Mutabor von doxygen 1.7.4