|
First, you must create an object derived from the MidiInPort class, such as the classes: MidiInput, MidiIO, Synthesizer, or RadioBaton. For example, the following line of code creates an object of type MidiInput:
MidiInput incoming;
The above line of code (probably placed with the global variables)
creates an object named incoming of the type
MidiInput.
The variable name incoming is completely arbitrary. You can
use any valid variable name in its place.
Secondly, if you are not using the MIDI interfaces in one of the Improv environments, then you should set the MIDI input port as necessary. The default port is 0, but you can find out how many MIDI input ports are available by the calling the following function which returns the total number of MIDI inputs available:
incoming.getNumPorts();
You can then select any one of the ports in the range from 0 to one
minus the value returned above. For example if there were two
MIDI input ports available, then you can access port 0, or port 1.
Here is how you would set the port to port 1 for the "incoming" object:
incoming.setPort(1);
There is one more step and you will be ready to read MIDI input: By
default, the port is not opened automatically, so you will have to
specifically tell the "incoming" object to start reading the MIDI
input on port 1:
incoming.open();
Now you are ready to read incoming MIDI messages from the "incoming"
object. There is one more useful low-level function which you should
know about, however. There is a pause() and unpause() set of
functions for MidiInPort objects which is sometime useful. The
pause() function will keep the particular port open, but it will
no add any incoming messages into the input buffer. This is handy
if you want to ignore messages for a short period of time to prevent
old MIDI messages in the buffer to be overwritten, as in the following
case of a user input:
incoming.pause();
cout << "Enter a number for some reason: ";
cin >> aUserEnteredNumber;
incoming.unpause();
So while the user of the program is typing in a number, all MIDI
messages coming in are ignored.
Finally, now that you have a working MIDI input object which is actively waiting for MIDI input messages, you can ask the object for a count of how many MIDI messages are waiting in the input buffer with the following command:
incoming.getCount();
This function call will return the number of messages currently
waiting for you in the input buffer. The default size of the
buffer is 1024 messages (which should be MORE than enought),
but you can change that size with the following command:
incoming.setBufferSize(47);
which would set the maximum number of input stored messages to 47.
Now suppose that incoming.getCount() returns a non-zero number. That means that there is at least 1 messages waiting in the buffer. To get the message out of the buffer, you use the incoming.extract() command, but first I should explain what form the incoming message is stored in. MIDI messages are stored in MidiInPort-related classes with the type "MidiMessage" which is a class containing two primary data fields:
Suppose that I create a MidiMessage object called "aMessage":
MidiMessage aMessage;
The initial contents of "aMessage" are undefined. but the data can be
accessed with the following commands:
Anyway, back to the incoming.extract() command. If there is a MIDI message in the buffer, then you can get it out of the MIDI input buffer, with the following code:
aMessage = incoming.extract();
aMessage now contain the extrated Message. Which Message is
extracted if there are more than one message in the buffer? The
oldest message is extracted.
Suppose that you overflow the input buffer? That is OK in most cases, since the buffer is circular. The most oldest message will be forgotten by the buffer, and the total number of messages will remain constant at the size of the buffer (1024 by default). Suppose that there are a lot of messages in the input bufferr that you want to skip over. Then you can use the command:
incoming.clear();
but I haven't added that command yet. For now you can change the
size of the buffer and it will remove all of the current messages
as a side effect.
Input spoofingYou can fool a MidiInput related class into thinking that a MIDI message has come into the computer by placing a fake input message into the buffer. First you would create a legitimate MidiMessage object, and then call the following function:
incoming.insert(aMessage);
If the incoming.getCount(); function call returned 0 before
the example code above was called, then it will return a 1 after the
example code above is called since there is one more MIDI message
in the input buffer.
Multiple MIDI input objected connected to a single portYou should be careful if you have more than one MidiInPort object connnected to the same port. There is only one buffer for each input port, so any other object listening to the same input port might be stealing input MIDI messages from the other object. The objects will not share the buffer with each other -- it is first come first served for the extraction of MIDI messages from the input buffer. There is a way to get around this by creating what I call "orphan buffers". Perhaps I will explain this more later but here is an example for now: Suppose that you have two MidiInput objects and only one port. one of the objects you want to look only at MIDI messages coming from on MIDI channel 1, and the other object listening to MIDI channel 2. The way that this could be accomplished is that there would be another MidiInput object which would have full control of the input buffer by itself. Then the other two objects would have their own private input buffers not connected to the hardware MIDI input. The third MidiInput object would then sort messages and deliver them to the appropriate object according to a programming users instructions. The example below shows the general method:
// objects to use:
MidiInput processor;
MidiInput buffer1;
MidiInput buffer2;
// somewhere (in an initialization function):
buffer1.makeOrphanBuffer();
buffer2.makeOrphanBuffer();
processor.setPort(0);
processor.open();
// somewhere in a program interpreter loop:
if (processor.getCount() !=0) {
aMessage = processor.extract();
if (aMessage.command() & 0x0f == 0x00) {
buffer1.insert(aMessage);
} else if (aMessage.command() & 0x0f == 0x01) {
buffer2.insert(aMessage);
}
}
// now can interpret incoming messages in buffer1
// and buffer2 as if they were actually hooked up
// to the real hardware MIDI input ports.
Note that you cannot use the lowest-level MIDI input class (MidiInPort) with the orphan buffer feature. You must use classes which are derived from MidiInput instead. Once you extract a message from the buffer, it is not erased. There is another way to access MIDI messages. This other method is not particularly appropriate in most cases however. You can look at the last written midi message with the index operator:
incoming[0].time;
The above code for example, would return the time of the most recent
midi Message in the buffer.
incoming[-1].command();
incoming[1].command();
would return the MIDI command of the second most recent MIDI message
in the buffer. This operator[] is not fully implemented yet however.
Higher-level MIDI input interpretationHigh-level MIDI input classes (such as the Synthesizer and RadioDrum classes) do their own interpretation of the Midi input buffer. The classes MidiInPort, MidiPort, MidiInput, and MidiIO do not do any processing on the input messages other than to place them in the input buffer. The Synthszier class, for example, extracts the note messages out of the MIDI input buffer and puts them in a separate buffer which can be accesed like this:
Synthesizer synth;
synth.getNoteCount();
if (synth.getNoteCount() != 0) {
aMessage = synth.extractNote();
}
The RadioBaton is very sophisticated MIDI interpreter. It interprets MIDI aftertouch message primarily to extract xyz position data sent from the radio drum instrument. It ignores most any other type of MIDI message. Essentially, the RadioDrum class uses MIDI for a non-musical transfer of data over a MIDI cable. |