Appendix C - MIDI and the QuickTime Music Architecture


What is MIDI ?

The Musical Instrument Digital Interface (MIDI) protocol has been widely accepted and utilized by musicians and composers since its conception in the 1982/1983 time frame. MIDI data is a very efficient method of representing musical performance information, and this makes MIDI an attractive protocol not only for composers or performers, but also for computer applications which produce sound, such as multimedia presentations or computer games.

Originally developed to allow musicians to connect synthesizers together, the MIDI protocol is now finding widespread use as a delivery medium to replace or supplement digitized audio in games and multimedia applications. There are several advantages to generating sound with a MIDI synthesizer rather than using sampled audio from disk or CD-ROM. The first advantage is storage space. Data files used to store digitally sampled audio in PCM format (such as .WAV files) tend to be quite large. This is especially true for lengthy musical pieces captured in stereo using high sampling rates.

MIDI data files, on the other hand, are extremely small when compared with sampled audio files. For instance, files containing high quality stereo sampled audio require about 10 Mbytes of data per minute of sound, while a typical MIDI sequence might consume less than 10 Kbytes of data per minute of sound. This is because the MIDI file does not contain the sampled audio data, it contains only the instructions needed by a synthesizer to play the sounds. These instructions are in the form of MIDI messages, which instruct the synthesizer which sounds to use, which notes to play, and how loud to play each note. The actual sounds are then generated by the synthesizer.

For computers, the smaller file size also means that less of the PCs bandwidth is utilized in spooling this data out to the peripheral which is generating sound. Other advantages of utilizing MIDI to generate sounds include the ability to easily edit the music, and the ability to change the playback speed and the pitch or key of the sounds independently. This last point is particularly important in synthesis applications such as karaoke equipment, where the musical key and tempo of a song may be selected by the user.

MIDI uses a serial protocol and a standard 5-pin connector that you'll find on professional electronic music gear made after 1985 or so. The connector's relatively large size, about half an inch in diameter, was chosen so that it could withstand the rigors of the road -- in other words, so that even drummers could plug it in. Because MIDI cables can carry signals in only one direction, synthesizers have separate connectors for MIDI input and MIDI output. (This differs from modem cables, which carry signals in both directions.)

MIDI is a serial protocol running at 31250 baud, 8 data bits, 1 stop bit, no parity. The command structure for a MIDI stream is simple: each byte is either a status byte or a data byte.
A status byte establishes a mode for interpreting the data bytes that follow it. The high bit is set, and the next three bits indicate the type of status byte. The low four bits are typically used to specify a MIDI channel. Thus MIDI can address up to 16 unique channels, each of which may play a different musical instrument sound. Later extensions to MIDI let you address more channels through the use of escape codes and bank switching.

The most common status message is the Play Note message, which has a value of 0x90 plus the MIDI channel number. Each note is defined by a pitch and velocity. The pitch is an integer from 0 to 127, where 60 is musical middle C (61 is C sharp, 59 is B, 72 is the C above middle C, and so on). The velocity is an integer from 0 to 127 that describes how loud to play the note; 64 is average loudness, 127 is very loud, 1 is nearly inaudible, and 0 means to stop playing the note.
So, to play a C-major chord on MIDI channel 0, you send the seven bytes 0x90 0x3C 0x40 0x40 0x40 0x43 0x40 to begin the sound. After a suitable interval, you send 0x90 0x3C 0x00 0x40 0x00 0x43 0x00 to silence it.

The above was reprinted from the following web sites:

          http://www.harmony-central.com/MIDI/Doc/tutorial.html
          http://developer.apple.com/dev/techsupport/develop/issue23/vanbrink.html

QuickTime

The QuickTime Music Architecture has a set of well-supported high-level calls for playing musical notes and sequences, it deals with MIDI protocols so that your application doesn't have to, and it handles timing for entire tunes. With QTMA, you can specify musical instruments independent of device, and play music either directly out of built-in speakers or through a MIDI synthesizer.
QuickTime provides its own virtual synthesizer that eliminates the need for any cables, and connections to external synthesizers. Everything can be played through the computer's speakers.

Here is a brief overview of the functions that are used in this project:

First of all, to output any sound, we need to initialize a channel with a particular instrument on it to which we can subsequently send note requests.

   NoteRequest                myNoteRequest;
   NoteAllocator              theNoteAllocator = NULL;
   NoteChannel                theNoteChannel   = NULL;
   ComponentResult            myErr = noErr;
 
   /* Open the note allocator component. */
   theNoteAllocator = OpenDefaultComponent(kNoteAllocatorType, 0);
 

   /* Fill out a note request, using NAStuffToneDescription.
      Request a piano with two simultaneous tones */

   myNoteRequest.polyphony = 2;                         // simultaneous tones
   myNoteRequest.typicalPolyphony = 0x00010000;

   myErr = NAStuffToneDescription(theNoteAllocator, i, &myNoteRequest.tone);
 
   /* Allocate the note channel. */
   myErr = NANewNoteChannel(theNoteAllocator, &myNoteRequest, &theNoteChannel);
 
 

Now that we have a channel at our disposal we can request notes.

   unsigned long               myDelay;
   ComponentResult             myErr1, myErr2;
   int                         note, velocity, duration;

   // Output a midi note of 60 (middle C) at maximum volume.
   note = 60;
   velocity = 127;
   myErr1 = NAPlayNote(theNoteAllocator, theNoteChannel, note, velocity);

   // Keep playing the note for 1 second.
   duration = 60;         // in 60ths of a second
 
   Delay(duration, (long *)&myDelay);

   // Stop the Midi note once it has been output for the specified duration.
   velocity = 0;          // indicates note is released
   myErr2 = NAPlayNote(theNoteAllocator, theNoteChannel, note, velocity);
 

NOTE: