summaryrefslogtreecommitdiff
path: root/RtMidi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'RtMidi.cpp')
-rw-r--r--RtMidi.cpp98
1 files changed, 81 insertions, 17 deletions
diff --git a/RtMidi.cpp b/RtMidi.cpp
index d82c9f1..cbf7eb6 100644
--- a/RtMidi.cpp
+++ b/RtMidi.cpp
@@ -35,7 +35,7 @@
*/
/**********************************************************************/
-// RtMidi: Version 1.0.4, 14 October 2005
+// RtMidi: Version 1.0.5, in development
#include "RtMidi.h"
#include <sstream>
@@ -383,13 +383,15 @@ void RtMidiIn :: openPort( unsigned int portNumber )
connected_ = true;
}
-void RtMidiIn :: openVirtualPort()
+void RtMidiIn :: openVirtualPort( const std::string portName )
{
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
// Create a virtual MIDI input destination.
MIDIEndpointRef endpoint;
- OSStatus result = MIDIDestinationCreate( data->client, CFSTR("RtMidi Input"), midiInputCallback, (void *)&inputData_, &endpoint );
+ OSStatus result = MIDIDestinationCreate( data->client,
+ CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
+ midiInputCallback, (void *)&inputData_, &endpoint );
if ( result != noErr ) {
errorString_ = "RtMidiIn::openVirtualPort: error creating virtual OS-X MIDI destination.";
error( RtError::DRIVER_ERROR );
@@ -548,7 +550,7 @@ void RtMidiOut :: closePort( void )
}
}
-void RtMidiOut :: openVirtualPort()
+void RtMidiOut :: openVirtualPort( std::string portName )
{
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
@@ -560,7 +562,9 @@ void RtMidiOut :: openVirtualPort()
// Create a virtual MIDI output source.
MIDIEndpointRef endpoint;
- OSStatus result = MIDISourceCreate( data->client, CFSTR("RtMidi Output"), &endpoint );
+ OSStatus result = MIDISourceCreate( data->client,
+ CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
+ &endpoint );
if ( result != noErr ) {
errorString_ = "RtMidiOut::initialize: error creating OS-X virtual MIDI source.";
error( RtError::DRIVER_ERROR );
@@ -957,7 +961,7 @@ void RtMidiIn :: openPort( unsigned int portNumber )
connected_ = true;
}
-void RtMidiIn :: openVirtualPort()
+void RtMidiIn :: openVirtualPort( std::string portName )
{
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
if ( data->vport < 0 ) {
@@ -973,7 +977,7 @@ void RtMidiIn :: openVirtualPort()
snd_seq_port_info_set_timestamping(pinfo, 1);
snd_seq_port_info_set_timestamp_real(pinfo, 1);
snd_seq_port_info_set_timestamp_queue(pinfo, data->queue_id);
- snd_seq_port_info_set_name(pinfo, "RtMidi Input");
+ snd_seq_port_info_set_name(pinfo, portName.c_str());
data->vport = snd_seq_create_port(data->seq, pinfo);
if ( data->vport < 0 ) {
@@ -1195,11 +1199,11 @@ void RtMidiOut :: closePort( void )
}
}
-void RtMidiOut :: openVirtualPort()
+void RtMidiOut :: openVirtualPort( std::string portName )
{
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
if ( data->vport < 0 ) {
- data->vport = snd_seq_create_simple_port( data->seq, "RtMidi Output",
+ data->vport = snd_seq_create_simple_port( data->seq, portName.c_str(),
SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
SND_SEQ_PORT_TYPE_MIDI_GENERIC );
@@ -1484,7 +1488,7 @@ void RtMidiIn :: openPort( unsigned int portNumber )
connected_ = true;
}
-void RtMidiIn :: openVirtualPort()
+void RtMidiIn :: openVirtualPort( std::string portName )
{
// This function cannot be implemented for the Irix MIDI API.
errorString_ = "RtMidiIn::openVirtualPort: cannot be implemented in Irix MIDI API!";
@@ -1617,7 +1621,7 @@ void RtMidiOut :: closePort( void )
}
}
-void RtMidiOut :: openVirtualPort()
+void RtMidiOut :: openVirtualPort( std::string portName )
{
// This function cannot be implemented for the Irix MIDI API.
errorString_ = "RtMidiOut::openVirtualPort: cannot be implemented in Irix MIDI API!";
@@ -1676,6 +1680,8 @@ void RtMidiOut :: sendMessage( std::vector<unsigned char> *message )
// API information deciphered from:
// - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_midi_reference.asp
+// Thanks to Jean-Baptiste Berruchon for the sysex code.
+
#if defined(__WINDOWS_MM__)
// The Windows MM API is based on the use of a callback function for
@@ -1693,8 +1699,11 @@ struct WinMidiData {
HMIDIOUT outHandle; // Handle to Midi Output Device
DWORD lastTime;
RtMidiIn::MidiMessage message;
+ LPMIDIHDR sysexBuffer;
};
+#define RT_SYSEX_BUFFER_SIZE 1024
+
//*********************************************************************//
// API: Windows MM
// Class Definitions: RtMidiIn
@@ -1748,11 +1757,21 @@ static void CALLBACK midiInputCallback( HMIDIOUT hmin,
unsigned char *ptr = (unsigned char *) &midiMessage;
for ( int i=0; i<nBytes; i++ ) apiData->message.bytes.push_back( *ptr++ );
}
- else { // Sysex message
+ else if ( !(data->ignoreFlags & 0x01) ) {
+ // Sysex message and we're not ignoring it
MIDIHDR *sysex = ( MIDIHDR *) midiMessage;
for ( int i=0; i<(int)sysex->dwBytesRecorded; i++ )
apiData->message.bytes.push_back( sysex->lpData[i] );
- if ( apiData->message.bytes.back() != 0xF7 ) return;
+
+ // When the callback has to be unaffected (application closes),
+ // it seems WinMM calls it with an empty sysex to de-queue the buffer
+ // If the buffer is requeued afer that message, the PC suddenly reboots
+ // after one or two minutes (JB).
+ if ( apiData->sysexBuffer->dwBytesRecorded > 0 ) {
+ MMRESULT result = midiInAddBuffer( apiData->inHandle, apiData->sysexBuffer, sizeof(MIDIHDR) );
+ if ( result != MMSYSERR_NOERROR )
+ std::cerr << "\nRtMidiIn::midiInputCallback: error sending sysex to Midi device!!\n\n";
+ }
}
if ( data->usingCallback ) {
@@ -1822,6 +1841,27 @@ void RtMidiIn :: openPort( unsigned int portNumber )
error( RtError::DRIVER_ERROR );
}
+ // Allocate and init the sysex buffer.
+ data->sysexBuffer = (MIDIHDR*) new char[ sizeof(MIDIHDR) ];
+ data->sysexBuffer->lpData = new char[1024];
+ data->sysexBuffer->dwBufferLength = 1024;
+ data->sysexBuffer->dwFlags = 0;
+
+ result = midiInPrepareHeader( data->inHandle, data->sysexBuffer, sizeof(MIDIHDR) );
+ if ( result != MMSYSERR_NOERROR ) {
+ midiInClose( data->inHandle );
+ errorString_ = "RtMidiIn::openPort: error starting Windows MM MIDI input port (PrepareHeader).";
+ error( RtError::DRIVER_ERROR );
+ }
+
+ // Register the buffer.
+ result = midiInAddBuffer( data->inHandle, data->sysexBuffer, sizeof(MIDIHDR) );
+ if ( result != MMSYSERR_NOERROR ) {
+ midiInClose( data->inHandle );
+ errorString_ = "RtMidiIn::openPort: error starting Windows MM MIDI input port (AddBuffer).";
+ error( RtError::DRIVER_ERROR );
+ }
+
result = midiInStart( data->inHandle );
if ( result != MMSYSERR_NOERROR ) {
midiInClose( data->inHandle );
@@ -1832,7 +1872,7 @@ void RtMidiIn :: openPort( unsigned int portNumber )
connected_ = true;
}
-void RtMidiIn :: openVirtualPort()
+void RtMidiIn :: openVirtualPort( std::string portName )
{
// This function cannot be implemented for the Windows MM MIDI API.
errorString_ = "RtMidiIn::openVirtualPort: cannot be implemented in Windows MM MIDI API!";
@@ -1845,6 +1885,16 @@ void RtMidiIn :: closePort( void )
WinMidiData *data = static_cast<WinMidiData *> (apiData_);
midiInReset( data->inHandle );
midiInStop( data->inHandle );
+
+ int result = midiInUnprepareHeader(data->inHandle, data->sysexBuffer, sizeof(MIDIHDR));
+ delete [] data->sysexBuffer->lpData;
+ delete [] data->sysexBuffer;
+ if ( result != MMSYSERR_NOERROR ) {
+ midiInClose( data->inHandle );
+ errorString_ = "RtMidiIn::openPort: error closing Windows MM MIDI input port (midiInUnprepareHeader).";
+ error( RtError::DRIVER_ERROR );
+ }
+
midiInClose( data->inHandle );
connected_ = false;
}
@@ -1878,7 +1928,14 @@ std::string RtMidiIn :: getPortName( unsigned int portNumber )
MIDIINCAPS deviceCaps;
MMRESULT result = midiInGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIINCAPS));
- std::string stringName = std::string( deviceCaps.szPname );
+ // For some reason, we need to copy character by character with
+ // UNICODE (thanks to Eduardo Coutinho!).
+ //std::string stringName = std::string( deviceCaps.szPname );
+ char nameString[MAXPNAMELEN];
+ for( int i=0; i<MAXPNAMELEN; i++ )
+ nameString[i] = (char)( deviceCaps.szPname[i] );
+
+ std::string stringName( nameString );
return stringName;
}
@@ -1905,7 +1962,14 @@ std::string RtMidiOut :: getPortName( unsigned int portNumber )
MIDIOUTCAPS deviceCaps;
MMRESULT result = midiOutGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIOUTCAPS));
- std::string stringName = std::string( deviceCaps.szPname );
+ // For some reason, we need to copy character by character with
+ // UNICODE (thanks to Eduardo Coutinho!).
+ //std::string stringName = std::string( deviceCaps.szPname );
+ char nameString[MAXPNAMELEN];
+ for( int i=0; i<MAXPNAMELEN; i++ )
+ nameString[i] = (char)( deviceCaps.szPname[i] );
+
+ std::string stringName( nameString );
return stringName;
}
@@ -1969,7 +2033,7 @@ void RtMidiOut :: closePort( void )
}
}
-void RtMidiOut :: openVirtualPort()
+void RtMidiOut :: openVirtualPort( std::string portName )
{
// This function cannot be implemented for the Windows MM MIDI API.
errorString_ = "RtMidiOut::openVirtualPort: cannot be implemented in Windows MM MIDI API!";