diff options
Diffstat (limited to 'RtMidi.cpp')
| -rw-r--r-- | RtMidi.cpp | 98 |
1 files changed, 81 insertions, 17 deletions
@@ -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!"; |
