For a tutorial on MIDI you could see, for example, http://www.harmony-central.com/MIDI/Doc/tutorial.html
wxMidi is mainly a wrapper for portmidi, a platform independent package to deal with MIDI sound. It is part of the portaudio package, that is developed by many computer music researchers and developers who, after considering many options, decided to endorse the work of Phil Burk and Ross Bencina who created the PortAudio library (http://www-2.cs.cmu.edu/~music/portmusic/).
The main differences with portmidi are:
wxMidi is composed by several classes. wxMidiSystem is the top class of the MIDI hierachy and represents the whole MIDI system. It acts as an application's entry point to the MIDI music system, and it provides information about, and access to, the set of installed MIDI devices.
The MIDI devices are represented by wxMidiDevice objects. A wxMidiDevice can be seen as a MIDI stream on which MIDI data traffic can be read or sent. Apart of the MIDI initialization and termination routines, all MIDI communication is achieved through a wxMidiDevice by using MIDI messages. It specializes into two classes: wxMidiInDevice and wxMidiOutDevice
MIDI messages are represented by the wxMidiMessage abstract object, that contains information about the type, data length, and status byte of the raw MIDI message for which it serves as a wrapper. In addition, it provides a timestamp value that is used by devices involved in MIDI timing, such as sequencers. There are two derived clases: wxMidiShortMessage and wxMidiSysExMessage.
The wxMidi package also has a database with the General Midi standard (GM) instruments list. Instruments are grouped into sections, to facilitate the search for a specific instrument. The database includes methods to populate a combo box, a list box or, in general, any other control derived from wxControlWithItems. It is implemented by object wxMidiDatabaseGM.
wxMidi quick start
wxMidi messages
wxMidi constants and macros
Sending MIDI messages
Using wxMidi basically requires the following steps:
1. Access the wxMidiSystem instance and look for available MIDI devices:
wxMidiSystem* pMidiSystem = wxMidiSystem::GetInstance(); int nMaxDevice = pMidiSystem->CountDevices();2. Create an instance for the MIDI device you would like to use and open the device:
// In this example we will use the first device available // (device number 0) assuming it is an output device. // In your application you should use a suitable device. // See wxMidiSystem::CountDevices for an // example of how to load a combo box with the available // devices, so the user can choose the device to use. wxMidiOutDevice* pMidiOut = new wxMidiOutDevice(0); pMidiOut->Open();3. Prepare the message to send
wxMidiShortMessage msg(0x90, 60, 127);4. Send it:
pMidiOut->Write(&msg);For very common messages, such as Note On or Note Off, steps 3 and 4 can be replaced by a call to the suitable method. For example:
//Play a scale int scale[] = { 60, 62, 64, 65, 67, 69, 71, 72 }; #define SCALE_SIZE 8 int channel = 0, volume = 127; for (int i = 0; i < SCALE_SIZE; i++) { pMidiOut->NoteOn(channel, scale[i], volume); ::wxMilliSleep(200); // wait 200ms pMidiOut->NoteOff(channel, scale[i], volume); }
The procedure is, basically, the same than for sending messages. The main diference is that in reception the user program does not conthol when the message is going to be received, so a method to be informed about the arrival of a message is needed. wxMidi provides two alternatives for this:
1. By using events and an event handler method
BEGIN_EVENT_TABLE(MyFrame, wxFrame) ... EVT_COMMAND (ID_MY_PANEL, wxEVT_MIDI_INPUT, MyFrame::OnMidiReceive) ... END_EVENT_TABLE() MyFrame::MyFrame(...) { .... //Filter out active sensing messages (0xFE) and //clock messages (0xF8 only) m_pInDev->SetFilter(wxMIDI_FILT_ACTIVE | wxMIDI_FILT_CLOCK); // empty the buffer after setting filter, just in case anything // got through m_pInDev->Flush(); //now start a listening thread. An event wxEVT_MIDI_INPUT //will be produced when new input is detected m_pInDev->StartListening(this); ... } void MyFrame::OnMidiReceive(wxCommandEvent &event) { // loop to read and process all available msges. wxMidiError nErr; wxMidiMessage* pMsg; while (m_pInDev->Poll()) { pMsg = m_pInDev->Read(&nError); //error checking and do something with the read message if (!nError) { ... //delete message when no longer needed delete pMsg; } } } MyFrame::~MyFrame() { .... //Stop the lisening thread m_pInDev->StopListening(this); ... }
2. By polling