|
@@ -8,7 +8,7 @@
|
|
|
RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/
|
|
|
|
|
|
RtMidi: realtime MIDI i/o C++ classes
|
|
|
- Copyright (c) 2003-2010 Gary P. Scavone
|
|
|
+ Copyright (c) 2003-2011 Gary P. Scavone
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person
|
|
|
obtaining a copy of this software and associated documentation files
|
|
@@ -35,7 +35,7 @@
|
|
|
*/
|
|
|
/**********************************************************************/
|
|
|
|
|
|
-// RtMidi: Version 1.0.11
|
|
|
+// RtMidi: Version 1.0.12
|
|
|
|
|
|
#include "RtMidi.h"
|
|
|
#include <sstream>
|
|
@@ -176,6 +176,7 @@ struct CoreMidiData {
|
|
|
MIDIEndpointRef endpoint;
|
|
|
MIDIEndpointRef destinationId;
|
|
|
unsigned long long lastTime;
|
|
|
+ MIDISysexSendRequest sysexreq;
|
|
|
};
|
|
|
|
|
|
//*********************************************************************//
|
|
@@ -216,11 +217,18 @@ void midiInputCallback( const MIDIPacketList *list, void *procRef, void *srcRef
|
|
|
data->firstMessage = false;
|
|
|
else {
|
|
|
time = packet->timeStamp;
|
|
|
+ if ( time == 0 ) { // this happens when receiving asynchronous sysex messages
|
|
|
+ time = AudioGetCurrentHostTime();
|
|
|
+ }
|
|
|
time -= apiData->lastTime;
|
|
|
time = AudioConvertHostTimeToNanos( time );
|
|
|
message.timeStamp = time * 0.000000001;
|
|
|
}
|
|
|
apiData->lastTime = packet->timeStamp;
|
|
|
+ if ( apiData->lastTime == 0 ) { // this happens when receiving asynchronous sysex messages
|
|
|
+ apiData->lastTime = AudioGetCurrentHostTime();
|
|
|
+ }
|
|
|
+ //std::cout << "TimeStamp = " << packet->timeStamp << std::endl;
|
|
|
|
|
|
iByte = 0;
|
|
|
if ( continueSysex ) {
|
|
@@ -265,26 +273,24 @@ void midiInputCallback( const MIDIPacketList *list, void *procRef, void *srcRef
|
|
|
iByte = nBytes;
|
|
|
}
|
|
|
else size = nBytes - iByte;
|
|
|
- continueSysex = packet->data[nBytes-1] != 0xF7;
|
|
|
+ continueSysex = packet->data[nBytes-1] != 0xF7;
|
|
|
}
|
|
|
- else if ( status < 0xF3 ) {
|
|
|
- if ( status == 0xF1 && (data->ignoreFlags & 0x02) ) {
|
|
|
- // A MIDI time code message and we're ignoring it.
|
|
|
+ else if ( status == 0xF1 ) {
|
|
|
+ // A MIDI time code message
|
|
|
+ if ( data->ignoreFlags & 0x02 ) {
|
|
|
size = 0;
|
|
|
- iByte += 3;
|
|
|
- }
|
|
|
- else size = 3;
|
|
|
+ iByte += 2;
|
|
|
+ }
|
|
|
+ else size = 2;
|
|
|
}
|
|
|
+ else if ( status == 0xF2 ) size = 3;
|
|
|
else if ( status == 0xF3 ) size = 2;
|
|
|
- else if ( status == 0xF8 ) {
|
|
|
- size = 1;
|
|
|
- if ( data->ignoreFlags & 0x02 ) {
|
|
|
- // A MIDI timing tick message and we're ignoring it.
|
|
|
- size = 0;
|
|
|
- iByte += 3;
|
|
|
- }
|
|
|
+ else if ( status == 0xF8 && ( data->ignoreFlags & 0x02 ) ) {
|
|
|
+ // A MIDI timing tick message and we're ignoring it.
|
|
|
+ size = 0;
|
|
|
+ iByte += 1;
|
|
|
}
|
|
|
- else if ( status == 0xFE && (data->ignoreFlags & 0x04) ) {
|
|
|
+ else if ( status == 0xFE && ( data->ignoreFlags & 0x04 ) ) {
|
|
|
// A MIDI active sensing message and we're ignoring it.
|
|
|
size = 0;
|
|
|
iByte += 1;
|
|
@@ -566,21 +572,21 @@ std::string RtMidiIn :: getPortName( unsigned int portNumber )
|
|
|
std::ostringstream ost;
|
|
|
char name[128];
|
|
|
|
|
|
+ std::string stringName;
|
|
|
if ( portNumber >= MIDIGetNumberOfSources() ) {
|
|
|
ost << "RtMidiIn::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
|
|
|
errorString_ = ost.str();
|
|
|
- error( RtError::INVALID_PARAMETER );
|
|
|
+ error( RtError::WARNING );
|
|
|
+ //error( RtError::INVALID_PARAMETER );
|
|
|
+ return stringName;
|
|
|
}
|
|
|
- portRef = MIDIGetSource( portNumber );
|
|
|
|
|
|
+ portRef = MIDIGetSource( portNumber );
|
|
|
nameRef = ConnectedEndpointName(portRef);
|
|
|
- //MIDIObjectGetStringProperty( portRef, kMIDIPropertyName, &nameRef );
|
|
|
- // modified by D. Casey Tucker 2009-03-10
|
|
|
-
|
|
|
CFStringGetCString( nameRef, name, sizeof(name), 0);
|
|
|
CFRelease( nameRef );
|
|
|
- std::string stringName = name;
|
|
|
- return stringName;
|
|
|
+
|
|
|
+ return stringName = name;
|
|
|
}
|
|
|
|
|
|
//*********************************************************************//
|
|
@@ -600,19 +606,21 @@ std::string RtMidiOut :: getPortName( unsigned int portNumber )
|
|
|
std::ostringstream ost;
|
|
|
char name[128];
|
|
|
|
|
|
+ std::string stringName;
|
|
|
if ( portNumber >= MIDIGetNumberOfDestinations() ) {
|
|
|
ost << "RtMidiOut::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
|
|
|
errorString_ = ost.str();
|
|
|
- error( RtError::INVALID_PARAMETER );
|
|
|
+ error( RtError::WARNING );
|
|
|
+ return stringName;
|
|
|
+ //error( RtError::INVALID_PARAMETER );
|
|
|
}
|
|
|
- portRef = MIDIGetDestination( portNumber );
|
|
|
|
|
|
+ portRef = MIDIGetDestination( portNumber );
|
|
|
nameRef = ConnectedEndpointName(portRef);
|
|
|
- //MIDIObjectGetStringProperty( portRef, kMIDIPropertyName, &nameRef );
|
|
|
CFStringGetCString( nameRef, name, sizeof(name), 0);
|
|
|
CFRelease( nameRef );
|
|
|
- std::string stringName = name;
|
|
|
- return stringName;
|
|
|
+
|
|
|
+ return stringName = name;
|
|
|
}
|
|
|
|
|
|
void RtMidiOut :: initialize( const std::string& clientName )
|
|
@@ -724,11 +732,19 @@ RtMidiOut :: ~RtMidiOut()
|
|
|
delete data;
|
|
|
}
|
|
|
|
|
|
+char *sysexBuffer = 0;
|
|
|
+
|
|
|
+void sysexCompletionProc( MIDISysexSendRequest * sreq )
|
|
|
+{
|
|
|
+ //std::cout << "Completed SysEx send\n";
|
|
|
+ delete sysexBuffer;
|
|
|
+ sysexBuffer = 0;
|
|
|
+}
|
|
|
+
|
|
|
void RtMidiOut :: sendMessage( std::vector<unsigned char> *message )
|
|
|
{
|
|
|
- // The CoreMidi documentation indicates a maximum PackList size of
|
|
|
- // 64K, so we may need to break long sysex messages into pieces and
|
|
|
- // send via separate lists.
|
|
|
+ // We use the MIDISendSysex() function to asynchronously send sysex
|
|
|
+ // messages. Otherwise, we use a single CoreMidi MIDIPacket.
|
|
|
unsigned int nBytes = message->size();
|
|
|
if ( nBytes == 0 ) {
|
|
|
errorString_ = "RtMidiOut::sendMessage: no data in message argument!";
|
|
@@ -736,51 +752,71 @@ void RtMidiOut :: sendMessage( std::vector<unsigned char> *message )
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if ( nBytes > 3 && ( message->at(0) != 0xF0 ) ) {
|
|
|
- errorString_ = "RtMidiOut::sendMessage: message format problem ... not sysex but > 3 bytes?";
|
|
|
- error( RtError::WARNING );
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- unsigned int packetBytes, bytesLeft = nBytes;
|
|
|
- unsigned int messageIndex = 0;
|
|
|
+ // unsigned int packetBytes, bytesLeft = nBytes;
|
|
|
+ // unsigned int messageIndex = 0;
|
|
|
MIDITimeStamp timeStamp = AudioGetCurrentHostTime();
|
|
|
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
|
|
|
+ OSStatus result;
|
|
|
|
|
|
- while ( bytesLeft > 0 ) {
|
|
|
+ if ( message->at(0) == 0xF0 ) {
|
|
|
|
|
|
- packetBytes = ( bytesLeft > 32736 ) ? 32736 : bytesLeft;
|
|
|
- Byte buffer[packetBytes + 32]; // extra memory for other structure variables
|
|
|
- MIDIPacketList *packetList = (MIDIPacketList *) buffer;
|
|
|
- MIDIPacket *curPacket = MIDIPacketListInit( packetList );
|
|
|
+ while ( sysexBuffer != 0 ) usleep( 1000 ); // sleep 1 ms
|
|
|
+
|
|
|
+ sysexBuffer = new char[nBytes];
|
|
|
+ if ( sysexBuffer == NULL ) {
|
|
|
+ errorString_ = "RtMidiOut::sendMessage: error allocating sysex message memory!";
|
|
|
+ error( RtError::MEMORY_ERROR );
|
|
|
+ }
|
|
|
+
|
|
|
+ // Copy data to buffer.
|
|
|
+ for ( unsigned int i=0; i<nBytes; ++i ) sysexBuffer[i] = message->at(i);
|
|
|
+
|
|
|
+ data->sysexreq.destination = data->destinationId;
|
|
|
+ data->sysexreq.data = (Byte *)sysexBuffer;
|
|
|
+ data->sysexreq.bytesToSend = nBytes;
|
|
|
+ data->sysexreq.complete = 0;
|
|
|
+ data->sysexreq.completionProc = sysexCompletionProc;
|
|
|
+ data->sysexreq.completionRefCon = &(data->sysexreq);
|
|
|
+
|
|
|
+ result = MIDISendSysex( &(data->sysexreq) );
|
|
|
+ if ( result != noErr ) {
|
|
|
+ errorString_ = "RtMidiOut::sendMessage: error sending MIDI to virtual destinations.";
|
|
|
+ error( RtError::WARNING );
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ else if ( nBytes > 3 ) {
|
|
|
+ errorString_ = "RtMidiOut::sendMessage: message format problem ... not sysex but > 3 bytes?";
|
|
|
+ error( RtError::WARNING );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ MIDIPacketList packetList;
|
|
|
+ MIDIPacket *packet = MIDIPacketListInit( &packetList );
|
|
|
+ packet = MIDIPacketListAdd( &packetList, sizeof(packetList), packet, timeStamp, nBytes, (const Byte *) &message->at( 0 ) );
|
|
|
+ if ( !packet ) {
|
|
|
+ errorString_ = "RtMidiOut::sendMessage: could not allocate packet list";
|
|
|
+ error( RtError::DRIVER_ERROR );
|
|
|
+ }
|
|
|
|
|
|
- curPacket = MIDIPacketListAdd( packetList, packetBytes+32, curPacket, timeStamp, packetBytes, (const Byte *) &message->at( messageIndex ) );
|
|
|
- if ( !curPacket ) {
|
|
|
- errorString_ = "RtMidiOut::sendMessage: could not allocate packet list";
|
|
|
- error( RtError::DRIVER_ERROR );
|
|
|
- }
|
|
|
- messageIndex += packetBytes;
|
|
|
- bytesLeft -= packetBytes;
|
|
|
-
|
|
|
- // Send to any destinations that may have connected to us.
|
|
|
- OSStatus result;
|
|
|
- if ( data->endpoint ) {
|
|
|
- result = MIDIReceived( data->endpoint, packetList );
|
|
|
- if ( result != noErr ) {
|
|
|
- errorString_ = "RtMidiOut::sendMessage: error sending MIDI to virtual destinations.";
|
|
|
- error( RtError::WARNING );
|
|
|
- }
|
|
|
+ // Send to any destinations that may have connected to us.
|
|
|
+ if ( data->endpoint ) {
|
|
|
+ result = MIDIReceived( data->endpoint, &packetList );
|
|
|
+ if ( result != noErr ) {
|
|
|
+ errorString_ = "RtMidiOut::sendMessage: error sending MIDI to virtual destinations.";
|
|
|
+ error( RtError::WARNING );
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- // And send to an explicit destination port if we're connected.
|
|
|
- if ( connected_ ) {
|
|
|
- result = MIDISend( data->port, data->destinationId, packetList );
|
|
|
- if ( result != noErr ) {
|
|
|
- errorString_ = "RtMidiOut::sendMessage: error sending MIDI message to port.";
|
|
|
- error( RtError::WARNING );
|
|
|
- }
|
|
|
+ // And send to an explicit destination port if we're connected.
|
|
|
+ if ( connected_ ) {
|
|
|
+ result = MIDISend( data->port, data->destinationId, &packetList );
|
|
|
+ if ( result != noErr ) {
|
|
|
+ errorString_ = "RtMidiOut::sendMessage: error sending MIDI message to port.";
|
|
|
+ error( RtError::WARNING );
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
}
|
|
|
|
|
|
#endif // __MACOSX_CORE__
|
|
@@ -840,6 +876,7 @@ extern "C" void *alsaMidiHandler( void *ptr )
|
|
|
long nBytes;
|
|
|
unsigned long long time, lastTime;
|
|
|
bool continueSysex = false;
|
|
|
+ bool doDecode = false;
|
|
|
RtMidiIn::MidiMessage message;
|
|
|
|
|
|
snd_seq_event_t *ev;
|
|
@@ -881,9 +918,9 @@ extern "C" void *alsaMidiHandler( void *ptr )
|
|
|
|
|
|
// This is a bit weird, but we now have to decode an ALSA MIDI
|
|
|
// event (back) into MIDI bytes. We'll ignore non-MIDI types.
|
|
|
- if ( !continueSysex )
|
|
|
- message.bytes.clear();
|
|
|
+ if ( !continueSysex ) message.bytes.clear();
|
|
|
|
|
|
+ doDecode = false;
|
|
|
switch ( ev->type ) {
|
|
|
|
|
|
case SND_SEQ_EVENT_PORT_SUBSCRIBED:
|
|
@@ -896,21 +933,24 @@ extern "C" void *alsaMidiHandler( void *ptr )
|
|
|
#if defined(__RTMIDI_DEBUG__)
|
|
|
std::cerr << "RtMidiIn::alsaMidiHandler: port connection has closed!\n";
|
|
|
std::cout << "sender = " << (int) ev->data.connect.sender.client << ":"
|
|
|
- << (int) ev->data.connect.sender.port
|
|
|
+ << (int) ev->data.connect.sender.port
|
|
|
<< ", dest = " << (int) ev->data.connect.dest.client << ":"
|
|
|
- << (int) ev->data.connect.dest.port
|
|
|
+ << (int) ev->data.connect.dest.port
|
|
|
<< std::endl;
|
|
|
#endif
|
|
|
break;
|
|
|
|
|
|
case SND_SEQ_EVENT_QFRAME: // MIDI time code
|
|
|
- if ( data->ignoreFlags & 0x02 ) break;
|
|
|
+ if ( !( data->ignoreFlags & 0x02 ) ) doDecode = true;
|
|
|
+ break;
|
|
|
|
|
|
case SND_SEQ_EVENT_TICK: // MIDI timing tick
|
|
|
- if ( data->ignoreFlags & 0x02 ) break;
|
|
|
+ if ( !( data->ignoreFlags & 0x02 ) ) doDecode = true;
|
|
|
+ break;
|
|
|
|
|
|
case SND_SEQ_EVENT_SENSING: // Active sensing
|
|
|
- if ( data->ignoreFlags & 0x04 ) break;
|
|
|
+ if ( !( data->ignoreFlags & 0x04 ) ) doDecode = true;
|
|
|
+ break;
|
|
|
|
|
|
case SND_SEQ_EVENT_SYSEX:
|
|
|
if ( (data->ignoreFlags & 0x01) ) break;
|
|
@@ -926,48 +966,53 @@ extern "C" void *alsaMidiHandler( void *ptr )
|
|
|
}
|
|
|
|
|
|
default:
|
|
|
+ doDecode = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( doDecode ) {
|
|
|
+
|
|
|
nBytes = snd_midi_event_decode( apiData->coder, buffer, apiData->bufferSize, ev );
|
|
|
- if ( nBytes <= 0 ) {
|
|
|
+ if ( nBytes > 0 ) {
|
|
|
+ // The ALSA sequencer has a maximum buffer size for MIDI sysex
|
|
|
+ // events of 256 bytes. If a device sends sysex messages larger
|
|
|
+ // than this, they are segmented into 256 byte chunks. So,
|
|
|
+ // we'll watch for this and concatenate sysex chunks into a
|
|
|
+ // single sysex message if necessary.
|
|
|
+ if ( !continueSysex )
|
|
|
+ message.bytes.assign( buffer, &buffer[nBytes] );
|
|
|
+ else
|
|
|
+ message.bytes.insert( message.bytes.end(), buffer, &buffer[nBytes] );
|
|
|
+
|
|
|
+ continueSysex = ( ( ev->type == SND_SEQ_EVENT_SYSEX ) && ( message.bytes.back() != 0xF7 ) );
|
|
|
+ if ( !continueSysex ) {
|
|
|
+
|
|
|
+ // Calculate the time stamp:
|
|
|
+ message.timeStamp = 0.0;
|
|
|
+
|
|
|
+ // Method 1: Use the system time.
|
|
|
+ //(void)gettimeofday(&tv, (struct timezone *)NULL);
|
|
|
+ //time = (tv.tv_sec * 1000000) + tv.tv_usec;
|
|
|
+
|
|
|
+ // Method 2: Use the ALSA sequencer event time data.
|
|
|
+ // (thanks to Pedro Lopez-Cabanillas!).
|
|
|
+ time = ( ev->time.time.tv_sec * 1000000 ) + ( ev->time.time.tv_nsec/1000 );
|
|
|
+ lastTime = time;
|
|
|
+ time -= apiData->lastTime;
|
|
|
+ apiData->lastTime = lastTime;
|
|
|
+ if ( data->firstMessage == true )
|
|
|
+ data->firstMessage = false;
|
|
|
+ else
|
|
|
+ message.timeStamp = time * 0.000001;
|
|
|
+ }
|
|
|
+ else {
|
|
|
#if defined(__RTMIDI_DEBUG__)
|
|
|
- std::cerr << "\nRtMidiIn::alsaMidiHandler: event parsing error or not a MIDI event!\n\n";
|
|
|
+ std::cerr << "\nRtMidiIn::alsaMidiHandler: event parsing error or not a MIDI event!\n\n";
|
|
|
#endif
|
|
|
- break;
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- // The ALSA sequencer has a maximum buffer size for MIDI sysex
|
|
|
- // events of 256 bytes. If a device sends sysex messages larger
|
|
|
- // than this, they are segmented into 256 byte chunks. So,
|
|
|
- // we'll watch for this and concatenate sysex chunks into a
|
|
|
- // single sysex message if necessary.
|
|
|
- if ( !continueSysex )
|
|
|
- message.bytes.assign( buffer, &buffer[nBytes] );
|
|
|
- else
|
|
|
- message.bytes.insert( message.bytes.end(), buffer, &buffer[nBytes] );
|
|
|
-
|
|
|
- continueSysex = ( ( ev->type == SND_SEQ_EVENT_SYSEX ) && ( message.bytes.back() != 0xF7 ) );
|
|
|
- if ( continueSysex )
|
|
|
- break;
|
|
|
-
|
|
|
- // Calculate the time stamp:
|
|
|
- message.timeStamp = 0.0;
|
|
|
-
|
|
|
- // Method 1: Use the system time.
|
|
|
- //(void)gettimeofday(&tv, (struct timezone *)NULL);
|
|
|
- //time = (tv.tv_sec * 1000000) + tv.tv_usec;
|
|
|
-
|
|
|
- // Method 2: Use the ALSA sequencer event time data.
|
|
|
- // (thanks to Pedro Lopez-Cabanillas!).
|
|
|
- time = ( ev->time.time.tv_sec * 1000000 ) + ( ev->time.time.tv_nsec/1000 );
|
|
|
- lastTime = time;
|
|
|
- time -= apiData->lastTime;
|
|
|
- apiData->lastTime = lastTime;
|
|
|
- if ( data->firstMessage == true )
|
|
|
- data->firstMessage = false;
|
|
|
- else
|
|
|
- message.timeStamp = time * 0.000001;
|
|
|
}
|
|
|
|
|
|
- snd_seq_free_event(ev);
|
|
|
+ snd_seq_free_event( ev );
|
|
|
if ( message.bytes.size() == 0 ) continue;
|
|
|
|
|
|
if ( data->usingCallback && !continueSysex ) {
|
|
@@ -1247,6 +1292,7 @@ std::string RtMidiIn :: getPortName( unsigned int portNumber )
|
|
|
snd_seq_client_info_alloca( &cinfo );
|
|
|
snd_seq_port_info_alloca( &pinfo );
|
|
|
|
|
|
+ std::string stringName;
|
|
|
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
|
|
|
if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, (int) portNumber ) ) {
|
|
|
int cnum = snd_seq_port_info_get_client( pinfo );
|
|
@@ -1255,14 +1301,15 @@ std::string RtMidiIn :: getPortName( unsigned int portNumber )
|
|
|
os << snd_seq_client_info_get_name( cinfo );
|
|
|
os << ":";
|
|
|
os << snd_seq_port_info_get_port( pinfo );
|
|
|
- std::string stringName = os.str();
|
|
|
+ stringName = os.str();
|
|
|
return stringName;
|
|
|
}
|
|
|
|
|
|
// If we get here, we didn't find a match.
|
|
|
errorString_ = "RtMidiIn::getPortName: error looking for port name!";
|
|
|
- error( RtError::INVALID_PARAMETER );
|
|
|
- return 0;
|
|
|
+ error( RtError::WARNING );
|
|
|
+ return stringName;
|
|
|
+ //error( RtError::INVALID_PARAMETER );
|
|
|
}
|
|
|
|
|
|
//*********************************************************************//
|
|
@@ -1286,6 +1333,7 @@ std::string RtMidiOut :: getPortName( unsigned int portNumber )
|
|
|
snd_seq_client_info_alloca( &cinfo );
|
|
|
snd_seq_port_info_alloca( &pinfo );
|
|
|
|
|
|
+ std::string stringName;
|
|
|
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
|
|
|
if ( portInfo( data->seq, pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, (int) portNumber ) ) {
|
|
|
int cnum = snd_seq_port_info_get_client(pinfo);
|
|
@@ -1294,14 +1342,15 @@ std::string RtMidiOut :: getPortName( unsigned int portNumber )
|
|
|
os << snd_seq_client_info_get_name(cinfo);
|
|
|
os << ":";
|
|
|
os << snd_seq_port_info_get_port(pinfo);
|
|
|
- std::string stringName = os.str();
|
|
|
+ stringName = os.str();
|
|
|
return stringName;
|
|
|
}
|
|
|
|
|
|
// If we get here, we didn't find a match.
|
|
|
errorString_ = "RtMidiOut::getPortName: error looking for port name!";
|
|
|
- error( RtError::INVALID_PARAMETER );
|
|
|
- return 0;
|
|
|
+ //error( RtError::INVALID_PARAMETER );
|
|
|
+ error( RtError::WARNING );
|
|
|
+ return stringName;
|
|
|
}
|
|
|
|
|
|
void RtMidiOut :: initialize( const std::string& clientName )
|
|
@@ -1591,12 +1640,11 @@ extern "C" void *irixMidiHandler( void *ptr )
|
|
|
else if ( status < 0xC0 ) size = 3;
|
|
|
else if ( status < 0xE0 ) size = 2;
|
|
|
else if ( status < 0xF0 ) size = 3;
|
|
|
- else if ( status < 0xF3 ) {
|
|
|
- if ( status == 0xF1 && !(data->ignoreFlags & 0x02) ) {
|
|
|
+ else if ( status == 0xF1 && !(data->ignoreFlags & 0x02) ) {
|
|
|
// A MIDI time code message and we're not ignoring it.
|
|
|
- size = 3;
|
|
|
- }
|
|
|
+ size = 2;
|
|
|
}
|
|
|
+ else if ( status == 0xF2 ) size = 3;
|
|
|
else if ( status == 0xF3 ) size = 2;
|
|
|
else if ( status == 0xF8 ) {
|
|
|
if ( !(data->ignoreFlags & 0x02) ) {
|
|
@@ -1735,14 +1783,17 @@ std::string RtMidiIn :: getPortName( unsigned int portNumber )
|
|
|
{
|
|
|
int nPorts = mdInit();
|
|
|
|
|
|
+ std::string stringName;
|
|
|
std::ostringstream ost;
|
|
|
if ( portNumber >= nPorts ) {
|
|
|
ost << "RtMidiIn::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
|
|
|
errorString_ = ost.str();
|
|
|
- error( RtError::INVALID_PARAMETER );
|
|
|
+ //error( RtError::INVALID_PARAMETER );
|
|
|
+ error( RtError::WARNING );
|
|
|
}
|
|
|
+ else
|
|
|
+ std::string stringName = std::string( mdGetName( portNumber ) );
|
|
|
|
|
|
- std::string stringName = std::string( mdGetName( portNumber ) );
|
|
|
return stringName;
|
|
|
}
|
|
|
|
|
@@ -1762,14 +1813,17 @@ std::string RtMidiOut :: getPortName( unsigned int portNumber )
|
|
|
{
|
|
|
int nPorts = mdInit();
|
|
|
|
|
|
+ std::string stringName;
|
|
|
std::ostringstream ost;
|
|
|
if ( portNumber >= nPorts ) {
|
|
|
ost << "RtMidiIn::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
|
|
|
errorString_ = ost.str();
|
|
|
- error( RtError::INVALID_PARAMETER );
|
|
|
+ //error( RtError::INVALID_PARAMETER );
|
|
|
+ error( RtError::WARNING );
|
|
|
}
|
|
|
+ else
|
|
|
+ std::string stringName = std::string( mdGetName( portNumber ) );
|
|
|
|
|
|
- std::string stringName = std::string( mdGetName( portNumber ) );
|
|
|
return stringName;
|
|
|
}
|
|
|
|
|
@@ -1918,8 +1972,8 @@ struct WinMidiData {
|
|
|
|
|
|
static void CALLBACK midiInputCallback( HMIDIOUT hmin,
|
|
|
UINT inputStatus,
|
|
|
- DWORD instancePtr,
|
|
|
- DWORD midiMessage,
|
|
|
+ DWORD_PTR instancePtr,
|
|
|
+ DWORD_PTR midiMessage,
|
|
|
DWORD timestamp )
|
|
|
{
|
|
|
if ( inputStatus != MIM_DATA && inputStatus != MIM_LONGDATA && inputStatus != MIM_LONGERROR ) return;
|
|
@@ -1945,11 +1999,11 @@ static void CALLBACK midiInputCallback( HMIDIOUT hmin,
|
|
|
if ( status < 0xC0 ) nBytes = 3;
|
|
|
else if ( status < 0xE0 ) nBytes = 2;
|
|
|
else if ( status < 0xF0 ) nBytes = 3;
|
|
|
- else if ( status < 0xF3 ) {
|
|
|
- // A MIDI time code message and we're ignoring it.
|
|
|
- if ( status == 0xF1 && (data->ignoreFlags & 0x02) ) return;
|
|
|
- nBytes = 3;
|
|
|
+ else if ( status == 0xF1 ) {
|
|
|
+ if ( data->ignoreFlags & 0x02 ) return;
|
|
|
+ else nBytes = 2;
|
|
|
}
|
|
|
+ else if ( status == 0xF2 ) nBytes = 3;
|
|
|
else if ( status == 0xF3 ) nBytes = 2;
|
|
|
else if ( status == 0xF8 && (data->ignoreFlags & 0x02) ) {
|
|
|
// A MIDI timing tick message and we're ignoring it.
|
|
@@ -2048,8 +2102,8 @@ void RtMidiIn :: openPort( unsigned int portNumber, const std::string /*portName
|
|
|
WinMidiData *data = static_cast<WinMidiData *> (apiData_);
|
|
|
MMRESULT result = midiInOpen( &data->inHandle,
|
|
|
portNumber,
|
|
|
- (DWORD)&midiInputCallback,
|
|
|
- (DWORD)&inputData_,
|
|
|
+ (DWORD_PTR)&midiInputCallback,
|
|
|
+ (DWORD_PTR)&inputData_,
|
|
|
CALLBACK_FUNCTION );
|
|
|
if ( result != MMSYSERR_NOERROR ) {
|
|
|
errorString_ = "RtMidiIn::openPort: error creating Windows MM MIDI input port.";
|
|
@@ -2137,12 +2191,15 @@ unsigned int RtMidiIn :: getPortCount()
|
|
|
|
|
|
std::string RtMidiIn :: getPortName( unsigned int portNumber )
|
|
|
{
|
|
|
+ std::string stringName;
|
|
|
unsigned int nDevices = midiInGetNumDevs();
|
|
|
if ( portNumber >= nDevices ) {
|
|
|
std::ostringstream ost;
|
|
|
ost << "RtMidiIn::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
|
|
|
errorString_ = ost.str();
|
|
|
- error( RtError::INVALID_PARAMETER );
|
|
|
+ //error( RtError::INVALID_PARAMETER );
|
|
|
+ error( RtError::WARNING );
|
|
|
+ return stringName;
|
|
|
}
|
|
|
|
|
|
MIDIINCAPS deviceCaps;
|
|
@@ -2155,7 +2212,7 @@ std::string RtMidiIn :: getPortName( unsigned int portNumber )
|
|
|
for( int i=0; i<MAXPNAMELEN; ++i )
|
|
|
nameString[i] = (char)( deviceCaps.szPname[i] );
|
|
|
|
|
|
- std::string stringName( nameString );
|
|
|
+ stringName = nameString;
|
|
|
return stringName;
|
|
|
}
|
|
|
|
|
@@ -2171,12 +2228,15 @@ unsigned int RtMidiOut :: getPortCount()
|
|
|
|
|
|
std::string RtMidiOut :: getPortName( unsigned int portNumber )
|
|
|
{
|
|
|
+ std::string stringName;
|
|
|
unsigned int nDevices = midiOutGetNumDevs();
|
|
|
if ( portNumber >= nDevices ) {
|
|
|
std::ostringstream ost;
|
|
|
ost << "RtMidiOut::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
|
|
|
errorString_ = ost.str();
|
|
|
- error( RtError::INVALID_PARAMETER );
|
|
|
+ //error( RtError::INVALID_PARAMETER );
|
|
|
+ error( RtError::WARNING );
|
|
|
+ return stringName;
|
|
|
}
|
|
|
|
|
|
MIDIOUTCAPS deviceCaps;
|
|
@@ -2189,7 +2249,7 @@ std::string RtMidiOut :: getPortName( unsigned int portNumber )
|
|
|
for( int i=0; i<MAXPNAMELEN; ++i )
|
|
|
nameString[i] = (char)( deviceCaps.szPname[i] );
|
|
|
|
|
|
- std::string stringName( nameString );
|
|
|
+ stringName = nameString;
|
|
|
return stringName;
|
|
|
}
|
|
|
|
|
@@ -2272,7 +2332,7 @@ RtMidiOut :: ~RtMidiOut()
|
|
|
|
|
|
void RtMidiOut :: sendMessage( std::vector<unsigned char> *message )
|
|
|
{
|
|
|
- unsigned int nBytes = message->size();
|
|
|
+ unsigned int nBytes = static_cast<unsigned int>(message->size());
|
|
|
if ( nBytes == 0 ) {
|
|
|
errorString_ = "RtMidiOut::sendMessage: message argument is empty!";
|
|
|
error( RtError::WARNING );
|