How to choose a MIDI output device

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.


   int status;
   int midiCount;

   status = ioctl(seqfd, SNDCTL_SEQ_NRMIDIS, &midiCount);

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:


   int synthCount;
   
   status = ioctl(seqfd, SNDCTL_SEQ_NRSYNTHS, &synthCount);

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.


   midi_info midiinfo;
   for (i=0; i<midiCount; i++) {
      midiinfo.device = i;
      status = ioctl(seqfd, SNDCTL_MIDI_INFO, &midiinfo);
      printf("MIDI Port %d: %s\n", i, midiinfo.name);
   }

Likewise for internal midi devices:


   synth_info synthinfo;
   
   for (i=0; i<synthCount; i++) {
      synthinfo.device = i;
      status = ioctl(seqfd, SNDCTL_SYNTH_INFO, &synthinfo);
      printf("Synth Port %d: %s\n", i, synthinfo.name);
   }

A note on sending MIDI output to synth ports

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:

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:

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:

The final packet bytes for Control changes (0xB0):

The final packet bytes for Patch changes (0xC0) and Channel pressure (0xD0):

The final packet bytes for Pitch Bend (0xE0)

Note that the Common message packet description is probabably not completely correct yet.











craig@ccrma.stanford.edu