Many people have contributed to CMT which grew out of earlier computer music systems used in the CMU Computer and Electronic Music Studio. Dean Rubine wrote the first MPU-401 interface routines with help from Dale Amon. Joe Newcomer ported this first version to his IBM-AT and helped clear up many of our interrupt problems. Aaron Wohl wrote routines to use the PC timer and made many good suggestions for improvements. Most of the development work was done on the IBM-XT in the CMU Computer and Electronic Music Studio. This machine was part of a grant from IBM. I also wish to acknowledge support from CMU through the Music Department, the Computer Science Department, the Center for the Design of Educational Computing, and especially the Center for Art and Technology. @chapter(Introduction and Overview) The @i(CMU MIDI Toolkit) (CMT) is a software package designed for experimental computer music education, composition, performance, and research. CMT includes a compiler for a simple, text-based music language, and software for recording, playing, and computing MIDI data in real time. CMT has three major attractions: the flexibility of an open-ended design, the availability of source code, and low system cost. What does CMT do? The major components and their functions are: @begin(itemize) @b(Adagio) is a language and an associated compiler. In Adagio, a note is represented by a line of text that specifies attributes such as pitch, duration, and loudness. Adagio is quite flexible and is compatible with several different ways of thinking about scores. For example, ``Q'' stands for a quarter note, but duration can also be indicated by ``U87'', which means 0.87 seconds. Adagio also supports arbitrary tuning systems. @b(Transcribe) reads input from a MIDI keyboard or other MIDI controller and produces an Adagio score. The score can be played back using Adagio, or it can be edited with a text editor to make alterations. Since Transcribe output is at least somewhat readable by people, it can also be used for performance analysis. @b(Record) is a combination of Adagio and Transcribe. It plays an existing Adagio score while transcribing a performance. Thus, complex compositions can be created one part at a time as if using a multi-track tape recorder. @b(DXGet) and @b(DXPut) are programs for recording and replaying MIDI system exclusive messages. These programs are typically used to save and restore synthesis parameters for a digital synthesizer. @b(Moxc) is a real-time programming environment that is ideal for writing interactive music programs. Moxc is an extension of the C programming language and is based on Douglas Collinge's @i(Moxie) language. Also provided are routines (in C) that allow direct production of MIDI output. Other routines are available to read MIDI data from a circular input buffer and to get the current time with 0.01 second resolution. @end(itemize) @b(Required hardware and software.) CMT runs on an IBM-XT or IBM-AT with a Roland MPU-401 MIDI interface and IBM-PC interface adapter. You should also have a screen-based text editor. To use Moxc, you will need a Lattice C compiler. @b(Other details.) CMT is distributed by the CMU Center for Art and Technology, Carnegie-Mellon University, Pittsburgh, PA, 15213. We hope that users will contribute new software to the system and enhance the existing software in various ways. We will encourage this by helping to integrate and document new software and by distributing software updates to CMT users. **************************************************************** @section(Adagio) Adagio is a small compiler for note-oriented scores. It has its roots in the score languages of Music V and related computer music synthesis programs, but Adagio is easier to use and more portable. Adagio also has the capability of expressing (sampled) continuous functions although more work is needed to make this a useful feature. A note is described in Adagio by a set of attributes@Index(attributes), and any attribute not specified is ``inherited'' from the previous line. Attributes may appear in any order and must be separated by one or more blanks. An attribute may not contain any blanks. The attributes are: time@Index(time), pitch@Index(pitch), loudness@Index(loudness), voice@Index(voice) number, duration@Index(duration), and timbre@Index(timbre). Adagio has been used to program a variety of hardware and software synthesizers, and the Adagio compiler can be easily adapted to new environments. Although not originally intended for MIDI, Adagio works quite well as a representation for MIDI scores. The MIDI version of Adagio currently uses the timbre attribute to select a MIDI ``program'' (synthesizer preset). Adagio has been extended to allow MIDI controller data such as modulation wheels, pitch bend, and volume. A note command in Adagio must be separated from other notes. Usually, notes are distinguished by writing each one on a separate line. Notes can also be separated by using a comma or semicolon as will be described below. Besides notes, there are several other types of commands: @begin(enumerate) An asterisk@Index(asterisk) (*) in column one (or immediately after a comma or semicolon) indicates that the rest of the line is a comment@Index(comment). The line is ignored by Adagio, and is therefore a good way to insert text to be read by people. An empty command (a blank@Index(blank) line, for example) is ignored as if it were a comment@Index(comment)@foot(To be consistent, a blank line ought to generate a note that inherits all of its attributes from the previous one. Adagio is intentionally inconsistent in this respect. ). An exclamation point@Index(exclamation point) (!) in column one (or immediately after a comma or semicolon) indicates a special command@Index(special command). A special command does not generate a note, and currently, the only special commands are the Rate and Tempo commands, described below. Special commands extend to the end of the line. Control change commands are used to control parameters like pitch bend that can change as a note is playing. Control change commands can be specified along with notes or by themselves. A command that specifies only control changes will not produce a note. @end(enumerate) Adagio is insensitive to case@Index(case), thus ``A'' is equivalent to ``a'', and you can mix upper and lower case letters freely. @section(Nonstandard Tunings) Tuning@Index(Tuning) in MIDI is normally twelve-tone equal temperment@Index(equal temperment). MIDI has no provisions to change this except by using the pitch bend@Index(pitch bend) control. In general, a different setting of pitch bend is needed for each pitch in a scale. Needless to say, this can be very tedious to program explicitly; however CMT has a way to automate the use of pitch bend to obtain the desired scale. Notice that pitch bend affects every note on a given channel; therefore, it is generally not possible to play several notes on one channel whenever alternate tunings are desired. (Ignoring this limitation can lead to some very interesting effects, however.) The tuning mechanism in CMT is quite simple: whenever a program (Adagio, Record, Transcribe, Moxc, etc.) goes to play a note, the note's pitch is used as an index into a table of (pitch, pitch bend) pairs. The pitch bend is sent, followed immediately by the pitch from the table. Using the table, it is possible to translate every specified pitch into an arbitrary pitch and pitch bend. @i(Important:) CMT assumes that you have set up your synthesizer so that the pitch bend range is one semitone (100 cents) and that the synthesizer changes frequency exponentially with respect to the pitch bend value. If your synthesizer is different, it will be necessary to modify CMT to make its tuning mechanism more general. The current system seems to work fine with a DX7. The formula used to calculate the MIDI pitch bend data is @center[PitchBend = (8192 * @i(c)) + 8192,] where @i(c) is the pitch bend in cents (not the velocity of light). A scale is defined by a ``tuning'' file (``.tun'' is the default suffix), which can be created with the help of a program called @i(tuning), described below. The format of the file is simple. Each line of text in the file consists of three numbers. The first is a note number (48 is middle C) between -12 and 115. The second is a pitch, also between -12 and 115, and the third is the pitch bend, between -100, and 100. Any pitches that are not mentioned in the file are given their normal equal-temperment interpretation. If no tuning is specified, then notes are not translated and no pitch bend commands are sent. **************************************************************** @section(Moxc) The best way to describe Moxc is to present a program that illustrates its features. The following program plays a sequence of notes with diminishing velocities to simulate an echo. The sequence is triggered by a pressing a synthesizer key and arbitrarily many sequences can be started by pressing multiple keys. @begin(programexample) @end(programexample) @subsection(Event Handlers) Event@Index(event handler) handling procedures were described in the example above, including @i(keydown) and @i(asciievent). A complete list of these is given below. If your program does not provide an event handler, the @i(cmtl) (link) step of preparing your program will provide a default handler which does nothing except for @i(asciievent), which is given in the example above. @begin(description) asciievent@Index(asciievent)(k)@\action for terminal input, @i(k) is the ascii key code. bendchange@Index(bendchange)(ch, val)@\pitch bend handler; @i(ch) is the channel, and @i(val) is the new value. ctrlchange@Index(ctrlchange)(ch, c, val)@\control change handler; @i(ch) is the channel, @i(c) is the control number, and @i(val) is the new value. keydown@Index(keydown)(ch, p, v)@\MIDI note on handler; @i(ch) is the channel, @i(p) is the pitch code (48 = middle C), and @i(v) is the velocity. keyup@Index(keyup)(ch, p)@\MIDI note off handler; @i(ch) is the channel, and @i(p) is the pitch code.. mainscore@Index(mainscore)()@\first action(s). This ``event'' is called once at the beginning of execution. peddown@Index(peddown)(ch)@\sustain pedal down handler; @i(ch) is the channel. pedup@Index(pedup)(ch)@\sustain pedal up handler; @i(ch) is the channel. touchchange@Index(touchchange)(ch, val)@\aftertouch handler; @i(ch) is the channel, and @i(val) is the value. @end(description) **************************************************************** @subsection(Interface design issues) A few words about the overall design of this interface are in order. To begin with, @i(mpu.c) is neither a complete interface to the MPU-401 nor to MIDI. Instead, @i(mpu.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 @i(mpu.c) deviates from the ``conventional'' are the absence of ``tracks'', the way in which time is handled, pitch specification, and the lack of external synchronization. Tracks@Index(tracks) are a concept implemented in the MPU-401 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, and the resulting system is more portable (not all MIDI interfaces implement the notion of tracks). 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.01 seconds. This is roughly 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 was designed to allow the host computer to send data in advance of its actual use. 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 to the MPU-401. Time tags also have the problem that it is hard to stop a performance immediately, because several seconds of data buffered in the MPU-401 will continue to play after the host computer stops sending data. CMT does not use time tags; MIDI commands are send immediately. Pitch in CMT is based on earlier computer music systems in which middle C is represented by the number 48. Therefore, CMT pitch numbers are 12 less than the corresponding MIDI pitch numbers. CMT also allows users to redefine the interpretation of pitch numbers. Within @i(mpu.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 @i(midi@ux( )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. Finally, CMT at present has no means for external synchronization and cannot now be used with other sequencers or drum machines to achieve a synchronized performance. This is partly a consequence of the fact that CMT does not measure time in beats, while sequencers synchronize by sending MIDI messages to mark beats and their subdivisions.