Newer
Older
// The WinMM API requires that the sysex buffer be requeued after
// input of each sysex message. Even if we are ignoring sysex
// messages, we still need to requeue the buffer in case the user
// decides to not ignore sysex messages in the future. However,
// it seems that WinMM calls this function with an empty sysex
// buffer when an application closes and in this case, we should
// avoid requeueing it, else the computer suddenly reboots after
// one or two minutes.
if ( apiData->sysexBuffer[sysex->dwUser]->dwBytesRecorded > 0 ) {
//if ( sysex->dwBytesRecorded > 0 ) {
EnterCriticalSection( &(apiData->_mutex) );
MMRESULT result = midiInAddBuffer( apiData->inHandle, apiData->sysexBuffer[sysex->dwUser], sizeof(MIDIHDR) );
LeaveCriticalSection( &(apiData->_mutex) );
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
if ( result != MMSYSERR_NOERROR )
std::cerr << "\nRtMidiIn::midiInputCallback: error sending sysex to Midi device!!\n\n";
if ( data->ignoreFlags & 0x01 ) return;
}
else return;
}
if ( data->usingCallback ) {
RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
callback( apiData->message.timeStamp, &apiData->message.bytes, data->userData );
}
else {
// As long as we haven't reached our queue size limit, push the message.
if ( data->queue.size < data->queue.ringSize ) {
data->queue.ring[data->queue.back++] = apiData->message;
if ( data->queue.back == data->queue.ringSize )
data->queue.back = 0;
data->queue.size++;
}
else
std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
}
// Clear the vector for the next input message.
apiData->message.bytes.clear();
}
MidiInWinMM :: MidiInWinMM( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
{
initialize( clientName );
}
MidiInWinMM :: ~MidiInWinMM()
{
// Close a connection if it exists.
closePort();
WinMidiData *data = static_cast<WinMidiData *> (apiData_);
DeleteCriticalSection( &(data->_mutex) );
// Cleanup.
delete data;
}
void MidiInWinMM :: initialize( const std::string& /*clientName*/ )
{
// We'll issue a warning here if no devices are available but not
// throw an error since the user can plugin something later.
unsigned int nDevices = midiInGetNumDevs();
if ( nDevices == 0 ) {
errorString_ = "MidiInWinMM::initialize: no MIDI input devices currently available.";
error( RtMidiError::WARNING, errorString_ );
}
// Save our api-specific connection information.
WinMidiData *data = (WinMidiData *) new WinMidiData;
apiData_ = (void *) data;
inputData_.apiData = (void *) data;
data->message.bytes.clear(); // needs to be empty for first input message
if ( !InitializeCriticalSectionAndSpinCount(&(data->_mutex), 0x00000400) ) {
errorString_ = "MidiInWinMM::initialize: InitializeCriticalSectionAndSpinCount failed.";
error( RtMidiError::WARNING, errorString_ );
}
}
void MidiInWinMM :: openPort( unsigned int portNumber, const std::string /*portName*/ )
{
if ( connected_ ) {
errorString_ = "MidiInWinMM::openPort: a valid connection already exists!";
error( RtMidiError::WARNING, errorString_ );
return;
}
unsigned int nDevices = midiInGetNumDevs();
if (nDevices == 0) {
errorString_ = "MidiInWinMM::openPort: no MIDI input sources found!";
error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
return;
std::ostringstream ost;
ost << "MidiInWinMM::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
errorString_ = ost.str();
error( RtMidiError::INVALID_PARAMETER, errorString_ );
return;
}
WinMidiData *data = static_cast<WinMidiData *> (apiData_);
MMRESULT result = midiInOpen( &data->inHandle,
portNumber,
(DWORD_PTR)&midiInputCallback,
(DWORD_PTR)&inputData_,
CALLBACK_FUNCTION );
if ( result != MMSYSERR_NOERROR ) {
errorString_ = "MidiInWinMM::openPort: error creating Windows MM MIDI input port.";
error( RtMidiError::DRIVER_ERROR, errorString_ );
return;
}
// Allocate and init the sysex buffers.
for ( int i=0; i<RT_SYSEX_BUFFER_COUNT; ++i ) {
data->sysexBuffer[i] = (MIDIHDR*) new char[ sizeof(MIDIHDR) ];
data->sysexBuffer[i]->lpData = new char[ RT_SYSEX_BUFFER_SIZE ];
data->sysexBuffer[i]->dwBufferLength = RT_SYSEX_BUFFER_SIZE;
data->sysexBuffer[i]->dwUser = i; // We use the dwUser parameter as buffer indicator
data->sysexBuffer[i]->dwFlags = 0;
result = midiInPrepareHeader( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) );
if ( result != MMSYSERR_NOERROR ) {
midiInClose( data->inHandle );
errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port (PrepareHeader).";
error( RtMidiError::DRIVER_ERROR, errorString_ );
return;
}
// Register the buffer.
result = midiInAddBuffer( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) );
if ( result != MMSYSERR_NOERROR ) {
midiInClose( data->inHandle );
errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port (AddBuffer).";
error( RtMidiError::DRIVER_ERROR, errorString_ );
return;
}
}
result = midiInStart( data->inHandle );
if ( result != MMSYSERR_NOERROR ) {
midiInClose( data->inHandle );
errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port.";
error( RtMidiError::DRIVER_ERROR, errorString_ );
return;
void MidiInWinMM :: openVirtualPort( std::string /*portName*/ )
{
// This function cannot be implemented for the Windows MM MIDI API.
errorString_ = "MidiInWinMM::openVirtualPort: cannot be implemented in Windows MM MIDI API!";
error( RtMidiError::WARNING, errorString_ );
}
void MidiInWinMM :: closePort( void )
{
if ( connected_ ) {
WinMidiData *data = static_cast<WinMidiData *> (apiData_);
EnterCriticalSection( &(data->_mutex) );
midiInReset( data->inHandle );
midiInStop( data->inHandle );
for ( int i=0; i<RT_SYSEX_BUFFER_COUNT; ++i ) {
int result = midiInUnprepareHeader(data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR));
delete [] data->sysexBuffer[i]->lpData;
delete [] data->sysexBuffer[i];
if ( result != MMSYSERR_NOERROR ) {
midiInClose( data->inHandle );
errorString_ = "MidiInWinMM::openPort: error closing Windows MM MIDI input port (midiInUnprepareHeader).";
error( RtMidiError::DRIVER_ERROR, errorString_ );
return;
}
}
midiInClose( data->inHandle );
connected_ = false;
LeaveCriticalSection( &(data->_mutex) );
}
}
unsigned int MidiInWinMM :: getPortCount()
{
return midiInGetNumDevs();
}
std::string MidiInWinMM :: getPortName( unsigned int portNumber )
{
std::string stringName;
unsigned int nDevices = midiInGetNumDevs();
if ( portNumber >= nDevices ) {
std::ostringstream ost;
ost << "MidiInWinMM::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
errorString_ = ost.str();
error( RtMidiError::WARNING, errorString_ );
return stringName;
}
MIDIINCAPS deviceCaps;
midiInGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIINCAPS));
#if defined( UNICODE ) || defined( _UNICODE )
int length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, -1, NULL, 0, NULL, NULL) - 1;
length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, static_cast<int>(wcslen(deviceCaps.szPname)), &stringName[0], length, NULL, NULL);
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
#else
stringName = std::string( deviceCaps.szPname );
#endif
// Next lines added to add the portNumber to the name so that
// the device's names are sure to be listed with individual names
// even when they have the same brand name
std::ostringstream os;
os << " ";
os << portNumber;
stringName += os.str();
return stringName;
}
//*********************************************************************//
// API: Windows MM
// Class Definitions: MidiOutWinMM
//*********************************************************************//
MidiOutWinMM :: MidiOutWinMM( const std::string clientName ) : MidiOutApi()
{
initialize( clientName );
}
MidiOutWinMM :: ~MidiOutWinMM()
{
// Close a connection if it exists.
closePort();
// Cleanup.
WinMidiData *data = static_cast<WinMidiData *> (apiData_);
delete data;
}
void MidiOutWinMM :: initialize( const std::string& /*clientName*/ )
{
// We'll issue a warning here if no devices are available but not
// throw an error since the user can plug something in later.
unsigned int nDevices = midiOutGetNumDevs();
if ( nDevices == 0 ) {
errorString_ = "MidiOutWinMM::initialize: no MIDI output devices currently available.";
error( RtMidiError::WARNING, errorString_ );
}
// Save our api-specific connection information.
WinMidiData *data = (WinMidiData *) new WinMidiData;
apiData_ = (void *) data;
}
unsigned int MidiOutWinMM :: getPortCount()
{
return midiOutGetNumDevs();
}
std::string MidiOutWinMM :: getPortName( unsigned int portNumber )
{
std::string stringName;
unsigned int nDevices = midiOutGetNumDevs();
if ( portNumber >= nDevices ) {
std::ostringstream ost;
ost << "MidiOutWinMM::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
errorString_ = ost.str();
error( RtMidiError::WARNING, errorString_ );
return stringName;
}
MIDIOUTCAPS deviceCaps;
midiOutGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIOUTCAPS));
#if defined( UNICODE ) || defined( _UNICODE )
int length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, -1, NULL, 0, NULL, NULL) - 1;
length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, static_cast<int>(wcslen(deviceCaps.szPname)), &stringName[0], length, NULL, NULL);
#else
stringName = std::string( deviceCaps.szPname );
#endif
return stringName;
}
void MidiOutWinMM :: openPort( unsigned int portNumber, const std::string /*portName*/ )
{
if ( connected_ ) {
errorString_ = "MidiOutWinMM::openPort: a valid connection already exists!";
error( RtMidiError::WARNING, errorString_ );
return;
}
unsigned int nDevices = midiOutGetNumDevs();
if (nDevices < 1) {
errorString_ = "MidiOutWinMM::openPort: no MIDI output destinations found!";
error( RtMidiError::NO_DEVICES_FOUND, errorString_ );
return;
std::ostringstream ost;
ost << "MidiOutWinMM::openPort: the 'portNumber' argument (" << portNumber << ") is invalid.";
errorString_ = ost.str();
error( RtMidiError::INVALID_PARAMETER, errorString_ );
return;
}
WinMidiData *data = static_cast<WinMidiData *> (apiData_);
MMRESULT result = midiOutOpen( &data->outHandle,
portNumber,
(DWORD)NULL,
(DWORD)NULL,
CALLBACK_NULL );
if ( result != MMSYSERR_NOERROR ) {
errorString_ = "MidiOutWinMM::openPort: error creating Windows MM MIDI output port.";
error( RtMidiError::DRIVER_ERROR, errorString_ );
return;
}
connected_ = true;
}
void MidiOutWinMM :: closePort( void )
{
if ( connected_ ) {
WinMidiData *data = static_cast<WinMidiData *> (apiData_);
midiOutReset( data->outHandle );
midiOutClose( data->outHandle );
connected_ = false;
}
}
void MidiOutWinMM :: openVirtualPort( std::string /*portName*/ )
{
// This function cannot be implemented for the Windows MM MIDI API.
errorString_ = "MidiOutWinMM::openVirtualPort: cannot be implemented in Windows MM MIDI API!";
error( RtMidiError::WARNING, errorString_ );
}
void MidiOutWinMM :: sendMessage( std::vector<unsigned char> *message )
{
if ( !connected_ ) return;
unsigned int nBytes = static_cast<unsigned int>(message->size());
if ( nBytes == 0 ) {
errorString_ = "MidiOutWinMM::sendMessage: message argument is empty!";
error( RtMidiError::WARNING, errorString_ );
return;
}
MMRESULT result;
WinMidiData *data = static_cast<WinMidiData *> (apiData_);
if ( message->at(0) == 0xF0 ) { // Sysex message
// Allocate buffer for sysex data.
char *buffer = (char *) malloc( nBytes );
if ( buffer == NULL ) {
errorString_ = "MidiOutWinMM::sendMessage: error allocating sysex message memory!";
error( RtMidiError::MEMORY_ERROR, errorString_ );
return;
}
// Copy data to buffer.
for ( unsigned int i=0; i<nBytes; ++i ) buffer[i] = message->at(i);
// Create and prepare MIDIHDR structure.
MIDIHDR sysex;
sysex.lpData = (LPSTR) buffer;
sysex.dwBufferLength = nBytes;
sysex.dwFlags = 0;
result = midiOutPrepareHeader( data->outHandle, &sysex, sizeof(MIDIHDR) );
if ( result != MMSYSERR_NOERROR ) {
free( buffer );
errorString_ = "MidiOutWinMM::sendMessage: error preparing sysex header.";
error( RtMidiError::DRIVER_ERROR, errorString_ );
return;
}
// Send the message.
result = midiOutLongMsg( data->outHandle, &sysex, sizeof(MIDIHDR) );
if ( result != MMSYSERR_NOERROR ) {
free( buffer );
errorString_ = "MidiOutWinMM::sendMessage: error sending sysex message.";
error( RtMidiError::DRIVER_ERROR, errorString_ );
return;
}
// Unprepare the buffer and MIDIHDR.
while ( MIDIERR_STILLPLAYING == midiOutUnprepareHeader( data->outHandle, &sysex, sizeof (MIDIHDR) ) ) Sleep( 1 );
free( buffer );
}
else { // Channel or system message.
// Make sure the message size isn't too big.
if ( nBytes > 3 ) {
errorString_ = "MidiOutWinMM::sendMessage: message size is greater than 3 bytes (and not sysex)!";
error( RtMidiError::WARNING, errorString_ );
return;
}
// Pack MIDI bytes into double word.
DWORD packet;
unsigned char *ptr = (unsigned char *) &packet;
for ( unsigned int i=0; i<nBytes; ++i ) {
*ptr = message->at(i);
++ptr;
}
// Send the message immediately.
result = midiOutShortMsg( data->outHandle, packet );
if ( result != MMSYSERR_NOERROR ) {
errorString_ = "MidiOutWinMM::sendMessage: error sending MIDI message.";
error( RtMidiError::DRIVER_ERROR, errorString_ );
//*********************************************************************//
// API: UNIX JACK
// Written primarily by Alexander Svetalkin, with updates for delta
// time by Gary Scavone, April 2011.
// *********************************************************************//
#if defined(__UNIX_JACK__)
// JACK header files
#include <jack/jack.h>
#include <jack/midiport.h>
#include <jack/ringbuffer.h>
#define JACK_RINGBUFFER_SIZE 16384 // Default size for ringbuffer
struct JackMidiData {
jack_client_t *client;
jack_port_t *port;
jack_ringbuffer_t *buffSize;
jack_ringbuffer_t *buffMessage;
jack_time_t lastTime;
MidiInApi :: RtMidiInData *rtMidiIn;
};
//*********************************************************************//
// API: JACK
// Class Definitions: MidiInJack
//*********************************************************************//
static int jackProcessIn( jack_nframes_t nframes, void *arg )
JackMidiData *jData = (JackMidiData *) arg;
MidiInApi :: RtMidiInData *rtData = jData->rtMidiIn;
jack_midi_event_t event;
jack_time_t time;
// Is port created?
if ( jData->port == NULL ) return 0;
void *buff = jack_port_get_buffer( jData->port, nframes );
// We have midi events in buffer
int evCount = jack_midi_get_event_count( buff );
for (int j = 0; j < evCount; j++) {
MidiInApi::MidiMessage message;
message.bytes.clear();
jack_midi_event_get( &event, buff, j );
for ( unsigned int i = 0; i < event.size; i++ )
message.bytes.push_back( event.buffer[i] );
// Compute the delta time.
time = jack_get_time();
if ( rtData->firstMessage == true )
rtData->firstMessage = false;
else
message.timeStamp = ( time - jData->lastTime ) * 0.000001;
jData->lastTime = time;
if ( !rtData->continueSysex ) {
if ( rtData->usingCallback ) {
RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) rtData->userCallback;
callback( message.timeStamp, &message.bytes, rtData->userData );
else {
// As long as we haven't reached our queue size limit, push the message.
if ( rtData->queue.size < rtData->queue.ringSize ) {
rtData->queue.ring[rtData->queue.back++] = message;
if ( rtData->queue.back == rtData->queue.ringSize )
rtData->queue.back = 0;
rtData->queue.size++;
}
else
std::cerr << "\nMidiInJack: message queue limit reached!!\n\n";
return 0;
}
MidiInJack :: MidiInJack( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
void MidiInJack :: initialize( const std::string& clientName )
JackMidiData *data = new JackMidiData;
apiData_ = (void *) data;
data->rtMidiIn = &inputData_;
data->port = NULL;
data->client = NULL;
this->clientName = clientName;
connect();
void MidiInJack :: connect()
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
if ( data->client )
return;
if (( data->client = jack_client_open( clientName.c_str(), JackNoStartServer, NULL )) == 0) {
error( RtMidiError::WARNING, errorString_ );
return;
}
jack_set_process_callback( data->client, jackProcessIn, data );
jack_activate( data->client );
}
MidiInJack :: ~MidiInJack()
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
closePort();
if ( data->client )
jack_client_close( data->client );
delete data;
}
void MidiInJack :: openPort( unsigned int portNumber, const std::string portName )
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
connect();
// Creating new port
if ( data->port == NULL)
data->port = jack_port_register( data->client, portName.c_str(),
JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0 );
if ( data->port == NULL) {
errorString_ = "MidiInJack::openPort: JACK error creating port";
error( RtMidiError::DRIVER_ERROR, errorString_ );
return;
}
// Connecting to the output
std::string name = getPortName( portNumber );
jack_connect( data->client, name.c_str(), jack_port_name( data->port ) );
}
void MidiInJack :: openVirtualPort( const std::string portName )
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
connect();
if ( data->port == NULL )
data->port = jack_port_register( data->client, portName.c_str(),
JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0 );
if ( data->port == NULL ) {
errorString_ = "MidiInJack::openVirtualPort: JACK error creating virtual port";
error( RtMidiError::DRIVER_ERROR, errorString_ );
}
}
unsigned int MidiInJack :: getPortCount()
{
int count = 0;
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
connect();
if ( !data->client )
return 0;
// List of available ports
const char **ports = jack_get_ports( data->client, NULL, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput );
if ( ports == NULL ) return 0;
while ( ports[count] != NULL )
count++;
free( ports );
return count;
}
std::string MidiInJack :: getPortName( unsigned int portNumber )
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
std::string retStr("");
connect();
// List of available ports
const char **ports = jack_get_ports( data->client, NULL,
JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput );
// Check port validity
if ( ports == NULL ) {
errorString_ = "MidiInJack::getPortName: no ports available!";
error( RtMidiError::WARNING, errorString_ );
std::ostringstream ost;
ost << "MidiInJack::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
errorString_ = ost.str();
error( RtMidiError::WARNING, errorString_ );
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
}
else retStr.assign( ports[portNumber] );
free( ports );
return retStr;
}
void MidiInJack :: closePort()
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
if ( data->port == NULL ) return;
jack_port_unregister( data->client, data->port );
data->port = NULL;
}
//*********************************************************************//
// API: JACK
// Class Definitions: MidiOutJack
//*********************************************************************//
// Jack process callback
static int jackProcessOut( jack_nframes_t nframes, void *arg )
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
{
JackMidiData *data = (JackMidiData *) arg;
jack_midi_data_t *midiData;
int space;
// Is port created?
if ( data->port == NULL ) return 0;
void *buff = jack_port_get_buffer( data->port, nframes );
jack_midi_clear_buffer( buff );
while ( jack_ringbuffer_read_space( data->buffSize ) > 0 ) {
jack_ringbuffer_read( data->buffSize, (char *) &space, (size_t) sizeof(space) );
midiData = jack_midi_event_reserve( buff, 0, space );
jack_ringbuffer_read( data->buffMessage, (char *) midiData, (size_t) space );
}
return 0;
}
MidiOutJack :: MidiOutJack( const std::string clientName ) : MidiOutApi()
{
initialize( clientName );
}
void MidiOutJack :: initialize( const std::string& clientName )
{
JackMidiData *data = new JackMidiData;
apiData_ = (void *) data;
data->client = NULL;
this->clientName = clientName;
connect();
}
void MidiOutJack :: connect()
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
if ( data->client )
return;
if (( data->client = jack_client_open( clientName.c_str(), JackNoStartServer, NULL )) == 0) {
error( RtMidiError::WARNING, errorString_ );
return;
}
jack_set_process_callback( data->client, jackProcessOut, data );
data->buffSize = jack_ringbuffer_create( JACK_RINGBUFFER_SIZE );
data->buffMessage = jack_ringbuffer_create( JACK_RINGBUFFER_SIZE );
jack_activate( data->client );
}
MidiOutJack :: ~MidiOutJack()
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
closePort();
if ( data->client ) {
// Cleanup
jack_client_close( data->client );
jack_ringbuffer_free( data->buffSize );
jack_ringbuffer_free( data->buffMessage );
}
delete data;
}
void MidiOutJack :: openPort( unsigned int portNumber, const std::string portName )
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
connect();
// Creating new port
if ( data->port == NULL )
data->port = jack_port_register( data->client, portName.c_str(),
JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0 );
if ( data->port == NULL ) {
errorString_ = "MidiOutJack::openPort: JACK error creating port";
error( RtMidiError::DRIVER_ERROR, errorString_ );
return;
}
// Connecting to the output
std::string name = getPortName( portNumber );
jack_connect( data->client, jack_port_name( data->port ), name.c_str() );
}
void MidiOutJack :: openVirtualPort( const std::string portName )
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
connect();
if ( data->port == NULL )
data->port = jack_port_register( data->client, portName.c_str(),
JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0 );
if ( data->port == NULL ) {
errorString_ = "MidiOutJack::openVirtualPort: JACK error creating virtual port";
error( RtMidiError::DRIVER_ERROR, errorString_ );
}
}
unsigned int MidiOutJack :: getPortCount()
{
int count = 0;
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
connect();
if ( !data->client )
return 0;
// List of available ports
const char **ports = jack_get_ports( data->client, NULL,
JACK_DEFAULT_MIDI_TYPE, JackPortIsInput );
if ( ports == NULL ) return 0;
while ( ports[count] != NULL )
count++;
free( ports );
return count;
}
std::string MidiOutJack :: getPortName( unsigned int portNumber )
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
std::string retStr("");
connect();
// List of available ports
const char **ports = jack_get_ports( data->client, NULL,
JACK_DEFAULT_MIDI_TYPE, JackPortIsInput );
// Check port validity
if ( ports == NULL) {
errorString_ = "MidiOutJack::getPortName: no ports available!";
error( RtMidiError::WARNING, errorString_ );
std::ostringstream ost;
ost << "MidiOutJack::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
errorString_ = ost.str();
error( RtMidiError::WARNING, errorString_ );
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
}
else retStr.assign( ports[portNumber] );
free( ports );
return retStr;
}
void MidiOutJack :: closePort()
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
if ( data->port == NULL ) return;
jack_port_unregister( data->client, data->port );
data->port = NULL;
}
void MidiOutJack :: sendMessage( std::vector<unsigned char> *message )
{
int nBytes = message->size();
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
// Write full message to buffer
jack_ringbuffer_write( data->buffMessage, ( const char * ) &( *message )[0],
message->size() );
jack_ringbuffer_write( data->buffSize, ( char * ) &nBytes, sizeof( nBytes ) );
}
#endif // __UNIX_JACK__