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. |