MIDI input and output functionality are separated into two classes, RtMidiIn and RtMidiOut. Each class instance supports only a single MIDI connection. RtMidi does not provide timing functionality (i.e., output messages are sent immediately). Input messages are timestamped with delta times in seconds (via a double
floating point type). MIDI data is passed to the user as raw bytes using an std::vector<unsigned char>.
#include "RtMidi.h" int main() { RtMidiIn *midiin = 0; // RtMidiIn constructor try { midiin = new RtMidiIn(); } catch (RtError &error) { // Handle the exception here error.printMessage(); } // Clean up delete midiin; }
Obviously, this example doesn't demonstrate any of the real functionality of RtMidi. However, all uses of RtMidi must begin with construction and must end with class destruction. Further, it is necessary that all class methods that can throw a C++ exception be called within a try/catch block.
// midiinfo.cpp #include <iostream> #include "RtMidi.h" int main() { RtMidiIn *midiin = 0; RtMidiOut *midiout = 0; // RtMidiIn constructor try { midiin = new RtMidiIn(); } catch (RtError &error) { error.printMessage(); exit(EXIT_FAILURE); } // Check inputs. unsigned int nPorts = midiin->getPortCount(); std::cout << "\nThere are " << nPorts << " MIDI input sources available.\n"; std::string portName; for ( unsigned int i=0; i<nPorts; i++ ) { try { portName = midiin->getPortName(i); } catch (RtError &error) { error.printMessage(); goto cleanup; } std::cout << " Input Port #" << i+1 << ": " << portName << '\n'; } // RtMidiOut constructor try { midiout = new RtMidiOut(); } catch (RtError &error) { error.printMessage(); exit(EXIT_FAILURE); } // Check outputs. nPorts = midiout->getPortCount(); std::cout << "\nThere are " << nPorts << " MIDI output ports available.\n"; for ( unsigned int i=0; i<nPorts; i++ ) { try { portName = midiout->getPortName(i); } catch (RtError &error) { error.printMessage(); goto cleanup; } std::cout << " Output Port #" << i+1 << ": " << portName << '\n'; } std::cout << '\n'; // Clean up cleanup: delete midiin; delete midiout; return 0; }
In the following example, we omit necessary error checking and details regarding OS-dependent sleep functions. For a complete example, see the midiout.cpp
program in the tests
directory.
// midiout.cpp #include <iostream> #include "RtMidi.h" int main() { RtMidiOut *midiout = new RtMidiOut(); std::vector<unsigned char> message; // Check available ports. unsigned int nPorts = midiout->getPortCount(); if ( nPorts == 0 ) { std::cout << "No ports available!\n"; goto cleanup; } // Open first available port. midiout->openPort( 0 ); // Send out a series of MIDI messages. // Program change: 192, 5 message.push_back( 192 ); message.push_back( 5 ); midiout->sendMessage( &message ); // Control Change: 176, 7, 100 (volume) message[0] = 176; message[1] = 7; message.push_back( 100 ); midiout->sendMessage( &message ); // Note On: 144, 64, 90 message[0] = 144; message[1] = 64; message[2] = 90; midiout->sendMessage( &message ); SLEEP( 500 ); // Platform-dependent ... see example in tests directory. // Note Off: 128, 64, 40 message[0] = 128; message[1] = 64; message[2] = 40; midiout->sendMessage( &message ); // Clean up cleanup: delete midiout; return 0; }
The RtMidiIn class provides the RtMidiIn::ignoreTypes() function to specify that certain MIDI message types be ignored. By default, sysem exclusive, timing, and active sensing messages are ignored.
std::vector<unsigned char>
container. When no MIDI message is available, the function returns an empty container. The default maximum MIDI queue size is 1024 messages. This value may be modified with the RtMidiIn::setQueueSizeLimit() function. If the maximum queue size limit is reached, subsequent incoming MIDI messages are discarded until the queue size is reduced.
In the following example, we omit some necessary error checking and details regarding OS-dependent sleep functions. For a more complete example, see the qmidiin.cpp
program in the tests
directory.
// qmidiin.cpp #include <iostream> #include <signal.h> #include "RtMidi.h" bool done; static void finish(int ignore){ done = true; } int main() { RtMidiIn *midiin = new RtMidiIn(); std::vector<unsigned char> message; int nBytes, i; double stamp; // Check available ports. unsigned int nPorts = midiin->getPortCount(); if ( nPorts == 0 ) { std::cout << "No ports available!\n"; goto cleanup; } midiin->openPort( 0 ); // Don't ignore sysex, timing, or active sensing messages. midiin->ignoreTypes( false, false, false ); // Install an interrupt handler function. done = false; (void) signal(SIGINT, finish); // Periodically check input queue. std::cout << "Reading MIDI from port ... quit with Ctrl-C.\n"; while ( !done ) { stamp = midiin->getMessage( &message ); nBytes = message.size(); for ( i=0; i<nBytes; i++ ) std::cout << "Byte " << i << " = " << (int)message[i] << ", "; if ( nBytes > 0 ) std::cout << "stamp = " << stamp << '\n'; // Sleep for 10 milliseconds ... platform-dependent. SLEEP( 10 ); } // Clean up cleanup: delete midiin; return 0; }
In the following example, we omit some necessary error checking. For a more complete example, see the cmidiin.cpp
program in the tests
directory.
// cmidiin.cpp #include <iostream> #include "RtMidi.h" void mycallback( double deltatime, std::vector< unsigned char > *message, void *userData ) { unsigned int nBytes = message->size(); for ( unsigned int i=0; i<nBytes; i++ ) std::cout << "Byte " << i << " = " << (int)message->at(i) << ", "; if ( nBytes > 0 ) std::cout << "stamp = " << deltatime << '\n'; } int main() { RtMidiIn *midiin = new RtMidiIn(); // Check available ports. unsigned int nPorts = midiin->getPortCount(); if ( nPorts == 0 ) { std::cout << "No ports available!\n"; goto cleanup; } midiin->openPort( 0 ); // Set our callback function. This should be done immediately after // opening the port to avoid having incoming messages written to the // queue. midiin->setCallback( &mycallback ); // Don't ignore sysex, timing, or active sensing messages. midiin->ignoreTypes( false, false, false ); std::cout << "\nReading MIDI input ... press <enter> to quit.\n"; char input; std::cin.get(input); // Clean up cleanup: delete midiin; return 0; }
OS: | MIDI API: | Preprocessor Definition: | Library or Framework: | Example Compiler Statement: |
Linux | ALSA Sequencer | __LINUX_ALSASEQ__ | asound, pthread | g++ -Wall -D__LINUX_ALSASEQ__ -o midiinfo midiinfo.cpp RtMidi.cpp -lasound -lpthread |
Macintosh OS X | CoreMidi | __MACOSX_CORE__ | CoreMidi, CoreAudio, CoreFoundation | g++ -Wall -D__MACOSX_CORE__ -o midiinfo midiinfo.cpp RtMidi.cpp -framework CoreMidi -framework CoreAudio -framework CoreFoundation |
Irix | MD | __IRIX_MD__ | md, pthread | CC -Wall -D__IRIX_MD__ -o midiinfo midiinfo.cpp RtMidi.cpp -laudio -lpthread |
Windows | Multimedia Library | __WINDOWS_MM__ | winmm.lib, multithreaded | compiler specific |
The example compiler statements above could be used to compile the probe.cpp
example file, assuming that midiinfo.cpp
, RtMidi.h
, RtError.h
, and RtMidi.cpp
all exist in the same directory.
__RTMIDI_DEBUG__
to the compiler (or uncomment the definition at the bottom of RtMidi.h). A variety of warning messages will be displayed which may help in determining the problem. Also try using the programs included in the test
directory. The program midiinfo
displays the queried capabilities of all MIDI ports found.Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
![]() |
©2003-2005 Gary P. Scavone, McGill University. All Rights Reserved. Maintained by Gary P. Scavone, gary at music.mcgill.ca |