📄 rtmidi.cpp
字号:
void RtMidiOut :: sendMessage( std::vector<unsigned char> *message ){ int result; AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_); unsigned int nBytes = message->size(); if ( nBytes > data->bufferSize ) { data->bufferSize = nBytes; result = snd_midi_event_resize_buffer ( data->coder, nBytes); if ( result != 0 ) { errorString_ = "RtMidiOut::sendMessage: ALSA error resizing MIDI event buffer."; error( RtError::DRIVER_ERROR ); } free (data->buffer); data->buffer = (unsigned char *) malloc( data->bufferSize ); if ( data->buffer == NULL ) { errorString_ = "RtMidiOut::initialize: error allocating buffer memory!\n\n"; error( RtError::MEMORY_ERROR ); } } snd_seq_event_t ev; snd_seq_ev_clear(&ev); snd_seq_ev_set_source(&ev, data->vport); snd_seq_ev_set_subs(&ev); snd_seq_ev_set_direct(&ev); for ( unsigned int i=0; i<nBytes; i++ ) data->buffer[i] = message->at(i); result = snd_midi_event_encode( data->coder, data->buffer, (long)nBytes, &ev ); if ( result < (int)nBytes ) { errorString_ = "RtMidiOut::sendMessage: event parsing error!"; error( RtError::WARNING ); return; } // Send the event. result = snd_seq_event_output(data->seq, &ev); if ( result < 0 ) { errorString_ = "RtMidiOut::sendMessage: error sending MIDI message to port."; error( RtError::WARNING ); } snd_seq_drain_output(data->seq);}#endif // __LINUX_ALSA__//*********************************************************************//// API: IRIX MD//*********************************************************************//// API information gleamed from:// http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?cmd=getdoc&coll=0650&db=man&fname=3%20mdIntro// If the Makefile doesn't work, try the following:// CC -o midiinfo -LANG:std -D__IRIX_MD__ -I../ ../RtMidi.cpp midiinfo.cpp -lpthread -lmd// CC -o midiout -LANG:std -D__IRIX_MD__ -I../ ../RtMidi.cpp midiout.cpp -lpthread -lmd// CC -o qmidiin -LANG:std -D__IRIX_MD__ -I../ ../RtMidi.cpp qmidiin.cpp -lpthread -lmd// CC -o cmidiin -LANG:std -D__IRIX_MD__ -I../ ../RtMidi.cpp cmidiin.cpp -lpthread -lmd#if defined(__IRIX_MD__)#include <pthread.h>#include <sys/time.h>#include <unistd.h>// Irix MIDI header file.#include <dmedia/midi.h>// A structure to hold variables related to the IRIX API// implementation.struct IrixMidiData { MDport port; pthread_t thread;};//*********************************************************************//// API: IRIX// Class Definitions: RtMidiIn//*********************************************************************//extern "C" void *irixMidiHandler( void *ptr ){ RtMidiIn::RtMidiInData *data = static_cast<RtMidiIn::RtMidiInData *> (ptr); IrixMidiData *apiData = static_cast<IrixMidiData *> (data->apiData); bool continueSysex = false; unsigned char status; unsigned short size; MDevent event; int fd = mdGetFd( apiData->port ); if ( fd < 0 ) { data->doInput = false; std::cerr << "\nRtMidiIn::irixMidiHandler: error getting port descriptor!\n\n"; return 0; } fd_set mask, rmask; FD_ZERO( &mask ); FD_SET( fd, &mask ); struct timeval timeout = {0, 0}; RtMidiIn::MidiMessage message; int result; while ( data->doInput ) { rmask = mask; timeout.tv_sec = 0; timeout.tv_usec = 0; if ( select( fd+1, &rmask, NULL, NULL, &timeout ) <= 0 ) { // No data pending ... sleep a bit. usleep( 1000 ); continue; } // If here, there should be data. result = mdReceive( apiData->port, &event, 1); if ( result <= 0 ) { std::cerr << "\nRtMidiIn::irixMidiHandler: MIDI input read error!\n\n"; continue; } message.timeStamp = event.stamp * 0.000000001; size = 0; status = event.msg[0]; if ( !(status & 0x80) ) continue; if ( status == 0xF0 ) { // Sysex message ... can be segmented across multiple messages. if ( !(data->ignoreFlags & 0x01) ) { if ( continueSysex ) { // We have a continuing, segmented sysex message. Append // the new bytes to our existing message. for ( int i=0; i<event.msglen; i++ ) message.bytes.push_back( event.sysexmsg[i] ); if ( event.sysexmsg[event.msglen-1] == 0xF7 ) continueSysex = false; if ( !continueSysex ) { // If not a continuing sysex message, invoke the user callback function or queue the message. if ( data->usingCallback && message.bytes.size() > 0 ) { RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback; callback( message.timeStamp, &message.bytes, data->userData ); } else { // As long as we haven't reached our queue size limit, push the message. if ( data->queueLimit > data->queue.size() ) data->queue.push( message ); else std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n"; } message.bytes.clear(); } } } mdFree( NULL ); continue; } 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) ) { // A MIDI time code message and we're not ignoring it. size = 3; } } else if ( status == 0xF3 ) size = 2; else if ( status == 0xF8 ) { if ( !(data->ignoreFlags & 0x02) ) { // A MIDI timing tick message and we're not ignoring it. size = 1; } } else if ( status == 0xFE ) { // MIDI active sensing if ( !(data->ignoreFlags & 0x04) ) size = 1; } else size = 1; // Copy the MIDI data to our vector. if ( size ) { message.bytes.assign( &event.msg[0], &event.msg[size] ); // Invoke the user callback function or queue the message. if ( data->usingCallback ) { RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback; callback( message.timeStamp, &message.bytes, data->userData ); } else { // As long as we haven't reached our queue size limit, push the message. if ( data->queueLimit > data->queue.size() ) data->queue.push( message ); else std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n"; } message.bytes.clear(); } } return 0;}void RtMidiIn :: initialize( void ){ // Initialize the Irix MIDI system. At the moment, we will not // worry about a return value of zero (ports) because there is a // chance the user could plug something in after instantiation. int nPorts = mdInit(); // Create our api-specific connection information. IrixMidiData *data = (IrixMidiData *) new IrixMidiData; apiData_ = (void *) data; inputData_.apiData = (void *) data;}void RtMidiIn :: openPort( unsigned int portNumber ){ if ( connected_ ) { errorString_ = "RtMidiIn::openPort: a valid connection already exists!"; error( RtError::WARNING ); return; } int nPorts = mdInit(); if (nPorts < 1) { errorString_ = "RtMidiIn::openPort: no Irix MIDI input sources found!"; error( RtError::NO_DEVICES_FOUND ); } std::ostringstream ost; if ( portNumber >= nPorts ) { ost << "RtMidiIn::openPort: the 'portNumber' argument (" << portNumber << ") is invalid."; errorString_ = ost.str(); error( RtError::INVALID_PARAMETER ); } IrixMidiData *data = static_cast<IrixMidiData *> (apiData_); data->port = mdOpenInPort( mdGetName(portNumber) ); if ( data->port == NULL ) { ost << "RtMidiIn::openPort: Irix error opening the port (" << portNumber << ")."; errorString_ = ost.str(); error( RtError::DRIVER_ERROR ); } mdSetStampMode(data->port, MD_DELTASTAMP); // Start our MIDI input thread. pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); pthread_attr_setschedpolicy(&attr, SCHED_RR); inputData_.doInput = true; int err = pthread_create(&data->thread, &attr, irixMidiHandler, &inputData_); pthread_attr_destroy(&attr); if (err) { mdClosePort( data->port ); inputData_.doInput = false; errorString_ = "RtMidiIn::openPort: error starting MIDI input thread!"; error( RtError::THREAD_ERROR ); } connected_ = true;}void RtMidiIn :: openVirtualPort(){ // This function cannot be implemented for the Irix MIDI API. errorString_ = "RtMidiIn::openVirtualPort: cannot be implemented in Irix MIDI API!"; error( RtError::WARNING );}void RtMidiIn :: closePort( void ){ if ( connected_ ) { IrixMidiData *data = static_cast<IrixMidiData *> (apiData_); mdClosePort( data->port ); connected_ = false; // Shutdown the input thread. inputData_.doInput = false; pthread_join( data->thread, NULL ); }}RtMidiIn :: ~RtMidiIn(){ // Close a connection if it exists. closePort(); // Cleanup. IrixMidiData *data = static_cast<IrixMidiData *> (apiData_); delete data;}unsigned int RtMidiIn :: getPortCount(){ int nPorts = mdInit(); if ( nPorts >= 0 ) return nPorts; else return 0;}std::string RtMidiIn :: getPortName( unsigned int portNumber ){ int nPorts = mdInit(); std::ostringstream ost; if ( portNumber >= nPorts ) { ost << "RtMidiIn::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid."; errorString_ = ost.str(); error( RtError::INVALID_PARAMETER ); } std::string stringName = std::string( mdGetName( portNumber ) ); return stringName;}//*********************************************************************//// API: IRIX MD// Class Definitions: RtMidiOut//*********************************************************************//unsigned int RtMidiOut :: getPortCount(){ int nPorts = mdInit(); if ( nPorts >= 0 ) return nPorts; else return 0;}std::string RtMidiOut :: getPortName( unsigned int portNumber ){ int nPorts = mdInit(); std::ostringstream ost; if ( portNumber >= nPorts ) { ost << "RtMidiIn::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid."; errorString_ = ost.str(); error( RtError::INVALID_PARAMETER ); } std::string stringName = std::string( mdGetName( portNumber ) ); return stringName;}void RtMidiOut :: initialize( void ){ // Initialize the Irix MIDI system. At the moment, we will not // worry about a return value of zero (ports) because there is a // chance the user could plug something in after instantiation. int nPorts = mdInit(); // Create our api-specific connection information. IrixMidiData *data = (IrixMidiData *) new IrixMidiData; apiData_ = (void *) data;}void RtMidiOut :: openPort( unsigned int portNumber ){ if ( connected_ ) { errorString_ = "RtMidiOut::openPort: a valid connection already exists!"; error( RtError::WARNING ); return; } int nPorts = mdInit(); if (nPorts < 1) { errorString_ = "RtMidiOut::openPort: no Irix MIDI output sources found!"; error( RtError::NO_DEVICES_FOUND ); } std::ostringstream ost; if ( portNumber >= nPorts ) { ost << "RtMidiOut::openPort: the 'portNumber' argument (" << portNumber << ") is invalid."; errorString_ = ost.str(); error( RtError::INVALID_PARAMETER ); } IrixMidiData *data = static_cast<IrixMidiData *> (apiData_); data->port = mdOpenOutPort( mdGetName(portNumber) ); if ( data->port == NULL ) { ost << "RtMidiOut::openPort: Irix error opening the port (" << portNumber << ")."; errorString_ = ost.str(); error( RtError::DRIVER_ERROR ); } mdSetStampMode(data->port, MD_NOSTAMP); connected_ = true;}void RtMidiOut :: closePort( void ){ if ( connected_ ) { IrixMidiData *data = static_cast<IrixMidiData *> (apiData_); mdClosePort( data->port ); connected_ = false; }}void RtMidiOut :: openVirtualPort(){ // This function cannot be implemented for the Irix MIDI API. errorString_ = "RtMidiOut::openVirtualPort: cannot be implemented in Irix MIDI API!"; error( RtError::WARNING );}RtMidiOut :: ~RtMidiOut(){ // Close a connection if it exists. closePort(); // Cleanup. IrixMidiData *data = static_cast<IrixMidiData *> (apiData_); delete data;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -