There are two separate categories of MIDI output in /dev/sequencer: midi output and synth output. Midi output ports send MIDI messages to synthesizers external to the computer, and synth output ports send MIDI messages to synthesizers internal to the computer (i.e., on a soundcard).
You can ask /dev/sequencer how many ports are available for each type of MIDI output with the following code examples. seqfd is the /dev/sequencer file descriptor returned when it is opened for writing.
|
If the returned status of the ioctl() call is not zero, then there was an error reading to the midiCount variable from /dev/sequencer. Likewise, shown below is the method for determining the number of synths (internal MIDI devices) accessible from /dev/sequencer:
|
Now that you know the number of midis and synths, you can get the name of each port by sending a midi_info or synth_info struct to /dev/sequencer to be filled with information about a particular MIDI device. As shown in the example code below, you must first fill in the device number for the midi or synth device in the info struct before sending it to /dev/sequencer to get the information on the correct device number.
|
Likewise for internal midi devices:
|
Writing packets to internal MIDI devices is much more complicated than sending to external MIDI devices. To review, sending a MIDI byte out to an external synthesizer involves writing an array of bytes to /dev/sequencer. The first byte is a flag to /dev/sequencer which informs it that the incoming packet is for sending one MIDI byte out to an external synthesizer. The second byte of the packet is the actual MIDI byte to send, and the third byte specifies which MIDI port to send the byte out on. The last byte in the packet is not used, and is set to zero. Here is the packet description for sending MIDI bytes out to external synthesizers:
unsigned packet[4]; | |
packet[0] | the packet type, which is set to SEQ_MIDIPUTC (the value 5) which tells /dev/sequencer that the packet is for sending out one MIDI byte. |
packet[1] | the MIDI byte to send |
packet[2] | the /dev/sequencer MIDI out port number |
packet[3] | unused, set to zero. |
To send MIDI to synthesizers, you must write complete MIDI messages to /dev/sequencer unlike external MIDI ports where you write individual message bytes to /dev/sequencer.
The packet size for internal synth messages is eight bytes. There are two general categories of message types: (1) voice messages and (2) common messages. Voice messages deal with note-on, note-off, and aftertouch MIDI messages, while common messages handle control change, patch change, channel pressure, and pitch wheel MIDI messages.
For the three voice message types, the packet forms are similar for each MIDI message command:
packet[0] EV_CHN_VOICE |
packet[1] synth device |
packet[2] first nibble of MIDI command |
packet[3] second nibble of MIDI command (channel) |
packet[4] first parameter of MIDI message |
packet[5] second parameter of MIDI message |
packet[6] set to zero |
packet[7] set to zero |
Common messages are less straightforward. Here are the approximate packet specification for the common messages. The first four bytes of the packet are the same for all common messages:
packet[0] EV_CHN_COMMON |
packet[1] synth device |
packet[2] first nibble of MIDI command |
packet[3] second nibble of MIDI command (channel) |
The final packet bytes for Control changes (0xB0):
packet[4] first parameter of control change |
packet[5] set to zero |
packet[6] second parameter of control change |
packet[7] set to zero |
The final packet bytes for Patch changes (0xC0) and Channel pressure (0xD0):
packet[4] the parameter byte |
packet[5] set to zero |
packet[6] set to zero |
packet[7] set to zero |
The final packet bytes for Pitch Bend (0xE0)
packet[4] set to zero |
packet[5] set to zero |
packet[6] least significant byte (parameter 1) |
packet[7] most significant byte (parameter 2) |
Note that the Common message packet description is probabably not completely correct yet.