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: