System Details

For simple applications, you do not have to understand much about the structure of the CMU MIDI Toolkit in order to get useful work done. The preceding chapters have described the existing application programs as well as Moxc, a system that helps you write real-time music programs of your own. Details of the available calls to send and receive MIDI are given in Appendix ``The MIDI Interface''.

However, you may wish to write more ambitious programs or modify existing programs. To do this effectively, you must understand how the CMT programs are put together. This chapter describes the various components of the CMU MIDI Toolkit from a system programmer's perspective.


In general, CMT programs are assembled from a collection of modules, where a module is a piece of software that performs a set of related functions. For example, there is a module for parsing command lines and another module for recording MIDI data. Modules usually consist of a single ``.c'' file and a related ``.h'' file. In the following sections, each module is described, and references to example uses of the modules are given.

Basic MIDI interface

All programs in CMT that send or receive MIDI use the module midifns.c, which provides an interface between C programs and the MIDI interface hardware.

Interface Design Issues

A few words about the overall design of this interface are in order. To begin with, midifns.c is neither a complete interface to the MIDI Interface hardware nor to MIDI. Instead, midifns.c is an attempt at providing the intended community of users with a rational interface that supports experimental, real-time computer music functions. One of the reasons CMT comes with source code is so that if you disagree with these design decisions, you are free to modify or extend the system to meet your requirements.

The main areas in which midifns.c deviates from the ``conventional'' are the absence of ``tracks'', the way in which time is handled, pitch specification, and the (current) lack of external synchronization. Tracks are a concept implemented in most sequencers whereby several sequences of MIDI data can be merged in real-time. In some commercial sequencers, the use of tracks allows the sequencer to avoid a lot of bookkeeping and sorting when several sequences are to be played at the same time. In CMT, the Adagio compiler sorts its data, so tracks are not needed to play multiple sequences together. For example, to play two Adagio scores simultaneously, one can normally just concatenate the files together and run Adagio on the new file. This approach has the advantages that an arbitrary number of sequences can be merged.

Timing in CMT is probably the most radical departure from MIDI. Whereas MIDI sequencers normally tend to talk about time in terms of beats, CMT measures time in units of 0.001 seconds. This is roughly a tenth of the smallest rhythmic time deviation we can perceive. The rationale behind this decision is that not all music is measured in beats, and some music has several tempi going simultaneously. If everything is converted to time in seconds, then one can freely combine scores with different tempi and meters as well as scores with timing notated directly in seconds. Another timing issue is that the MPU-401, Apple MIDI Manager, and other interfaces allow the host computer to send data in advance of its actual use. For example, MIDI commands can be sent to the MPU-401 with a ``time tag'' that tells the MPU-401 when to send the data to MIDI OUT. This is a nice feature in that it can help a slow computer achieve tighter real-time performance. On the other hand, it is not very suitable for interactive real-time programs in which one normally wants output to occur immediately after data is sent. Time tags also have the problem that it is hard to stop a performance immediately, because several seconds of buffered data will continue to play after the host computer stops sending data. CMT does not use time tags; MIDI commands are sent immediately.

CMT allows users to redefine the interpretation of pitch numbers. Within midifns.c, there is a table with two entries for each pitch number. One of these entries specifies a pitch and the other specifies pitch bend. When the midi note routine is called, it uses the table to translate the pitch parameter into a MIDI pitch number and a pitch bend. This translation is normally only enabled if the ``-tune'' option followed by a file name is specified in the command line.

Interface Implementation For PC/XT/AT Clones

The mpu.c module is responsible for low-level MIDI input and output. At present, output is performed synchronously; that is, the processor waits for the MPU-401 device to take the data.

An interrupt handler is invoked in mpu.c whenever the MPU-401 has data ready. The data is read and decoded to determine what kind of data it is. If the data is a MIDI message (e.g. MIDI Note-on), the message is inserted into a circular buffer, which can be read by either the getbuf or getkey routines in midifns.c. The buffer provides a communication path between the interrupt handler and the non-interrupt level of CMT programs; it also helps prevent lost messages when a burst of MIDI events arrives.

Time is implemented in timer.c, which is an assembly language interface to the standard PC/AT timer hardware. The MPU-401 is not used for timing.

System Exclusive Messages

In an earlier implementation of CMT, incoming system exclusive messages were put into the buffer just like other MIDI messages. I then discovered that computers often cannot empty the buffer as fast as the messages came in. This is fine if messages are short, but some system exclusive messages are much longer than the buffer. Making the buffer bigger would penalize programs that are not interested in system exclusive messages by taking up lots of space. Consequently, the current system does not put system exclusive messages in the buffer. Instead, there is a call (midi bufferbuffer
Previous Section | Next Section | Table of Contents | Index | Title Page