home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-06-28 | 146.4 KB | 3,453 lines |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- THE CMU MIDI TOOLKIT
-
- ``Charles Ives'' Edition
-
-
- Roger B. Dannenberg
- 14 January 1988
-
-
-
-
-
-
-
-
-
-
- Carnegie Mellon University
-
- Pittsburgh, PA 15213, U.S.A.
-
-
-
-
-
-
-
- The CMU MIDI Toolkit (CMT), consisting of software and documentation, is
- provided ``as is'' without warranty of any kind, either expressed or implied.
- Should CMT prove defective, you (and not Carnegie-Mellon University) assume the
- entire cost of all necessary servicing, repair or correction. Further,
- Carnegie-Mellon University does not warrant, guarantee or make any
- representation regarding your requirements or that CMT is free of errors.
-
- Neither Carnegie-Mellon University nor anyone else who has been involved in
- the creation, production, or delivery of CMT program shall be liable for any
- direct, indirect, consequential or incidental damages arising out of use or
- inability to use CMT.
-
-
-
- Preface
- This manual is a guide for users of the Carnegie Mellon University MIDI
- Toolkit, also known as CMT, a collection of software for experimental computer
- music using standard Musical Instrument Digital Interface (MIDI) equipment.
- This manual corresponds to CMT Version 2.00.
-
- This is the Charles Ives edition, the first CMT manual. This manual is
- updated periodically as new programs are contributed to CMT and as bugs are
- discovered and fixed. I solicit your help in making this manual more accurate
- and complete. PLEASE help us by noting any errors, omissions, or suggestions
- you may have. You can send your suggestions to Dannenberg@A.CS.CMU.EDU
- (ARPAnet) via computer mail, or by campus mail to Roger B. Dannenberg, Center
- for Art and Technology, CFA, or by ordinary mail to Roger B. Dannenberg, Center
- for Art and Technology, Carnegie Mellon University, Pittsburgh, PA 15213-3890,
- USA. A bug report form can be found at the end of this manual.
-
- 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. The Tuning program and the initial
- tuning software were written by Michael Cressman. 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.
-
-
-
- 1. Introduction and Overview
- The 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:
-
- - 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.
-
- - 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.
-
- - 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.
-
- - DXGet and 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.
-
- - 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 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.
-
- 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.
-
- 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.
-
- 1.1. Installing CMT
- CMT comes on a set of two floppy disks. Disk #1 contains executable programs
- and some example files. Disk #2 contains source code and files you need in
- order to recompile CMT programs. If you have a hard disk, you should copy the
- contents of the floppy disks that come with CMT onto the hard disk. Put Disk
- #1 in the floppy disk drive and type:
-
- c:
- cd \
- mkdir cmt
- cd cmt
- copy a:*.*
-
- There are some test files in the directory test on Disk #1. You can copy them
- as well by typing:
-
- mkdir test
- cd test
- copy a:\test\*.*
-
- Some useful non-music programs are included with CMT. They are make, grep, and
- ls. To install these programs, type:
-
- cd \bin
- copy a:\bin\*.*
-
- If you want to use CMT to write programs, you should copy the contents of Disk
- #2 into your cmt directory. Put Disk #2 into the floppy disk drive and type:
-
- cd \cmt
- copy a:*.*
-
- Finally, you add c:\cmt to the path in your autoexec.bat file so that DOS can
- find CMT programs.
-
- Assuming you have installed an MPU-401 MIDI interface, you should now connect
- your synthesizer(s). At Carnegie Mellon, we generally use a Yamaha DX7 as
- input and a TX816 as output. Thus, we connect the DX7 MIDI OUT to the MPU-401
- MIDI IN and the MPU-401 MIDI OUT to the TX816 MIDI IN. You should not connect
- the MPU-401 OUT to the DX7 IN. Doing so will cause outputs from the DX7 to be
- returned as inputs. This can cause problems in the DX7.
-
- If you want to use the same synthesizer for both input and output, a slightly
- different approach is necessary. Here, you should go ahead and connect both
- MPU-401 IN and OUT to your synthesizer OUT and IN, respectively. To avoid the
- problem of having outputs returned as inputs, you should use the ``-block''
- option on all CMT software. When the software is not running, it may be
- necessary to disconnect either of the two MIDI cables because the MPU-401
- default is to resend all inputs as outputs. In some cases, the DX7 cannot
- handle having its output data returned to its input.
-
-
-
- 2. DOS Utilities
- Before describing music software that comes with the CMU MIDI Toolkit, some
- DOS commands and utility programs are described. Three programs are provided
- with CMT to help make your life easier. These are make, ls, and grep. A
- section on backing up files, intended for novice users, is also included in
- this chapter.
-
- 2.1. make
- The make program is based on the Unix(Unix is a trademark of A.T.& T. Bell
- Laboratories) program of the same name, and is documented in the file make.man.
- The purpose of make is to figure out what has to be recompiled when you edit a
- file. A file called makefile contains a list of file dependencies and a
- command that specifies how to recompile a dependent file. The make program
- figures out what files have changed by examining their ``last modified'' times
- and dates. Therefore, if you use make, you must always tell DOS the time and
- date when you turn on your machine. An example of an entry in makefile
- describing a dependency is
-
- ADOBJ = adagio.obj phase1.obj phase2.obj adaspace.obj noteoff.obj
- MUSICLIB = cmt.lib
-
- adagio.exe : #(ADOBJ) #(MUSICLIB)
- link #(COBJ) #(ADOBJ),adagio,,#(LIBS)
-
- In this example, ADOBJ is a symbol that is defined in the first line to be a
- list of files. The line with the colon (:) says that adagio.exe depends upon
- everything on the right of the colon, that is, all of the object files
- represented by ADOBJ and also the file cmt.lib, represented by MUSICLIB. If
- adagio.exe does not exist or is older than one of the files it depends upon, it
- should be remade by executing the lines after the line stating the dependency.
- In this case, there is only one command (starting with the word link) needed.
-
- The file makefile, from which this example was taken, is provided with CMT
- and contains a complete list of CMT file dependencies. It is a good reference
- if you have questions about how to write a makefile.
-
- To use make, simply give it the file you want to make up-to-date. For
- example,
-
- make adagio.exe
-
- will make adagio.exe up to date. To make sure the entire CMT is up-to-date,
- you can type
-
- make everything
-
- Note: the makefile provided with CMT assumes you are in the directory with all
- the CMT source files when you run make. To clean up leftover files, type:
-
- make clean
-
- This will not remove .OBJ files. You can get rid of unneeded .OBJ files by
- typing:
-
- make cleanobjs
-
- 2.2. ls
- The ls program is like the DOS dir command, except it lists file names only
- (no size and date information), and the names are formatted into columns in
- alphabetical order. The current version of ls does not work with large
- directories, although this may be fixed by the time you read this.
-
- 2.3. grep
- The grep program searches one or more files for a text string. If the string
- is found, the line containing the string is printed. grep is indispensable for
- reading someone else's code. For example, to find out where fileopen is
- declared (as well as where it is used), type
-
- grep fileopen *.c
-
- in the CMT source code directory.
-
- 2.4. Backing up files
- Note: This section is intended for new users of the CMU Computer Music
- Studio, but it is worth reading if you are inexperienced with personal
- computers.
-
- The IBM XT system has a built-in disk that can store about 10 million
- characters of information. Unfortunately, that may not be enough to meet the
- demands of all of the studio users. Fortunately, there is an alternative way
- to store information called the floppy disk. Floppy disks are also a good way
- to make copies of your work for safe keeping. There is always a small chance
- that all of your data will be lost from the Studio computer. To protect
- yourself, you should keep a backup copy of any critical files on a floppy disk.
- Floppy disks are thin magnetic disks that come in a protective sleeve and
- insert into the slot in front of the IBM XT.
-
- To make a backup copy of your directory,
-
- 1. put a floppy disk into the disk drive slot and push down the door
-
- 2. if you have not used the disk before, type
-
- format a:
-
- This will completely erase your disk, so only do this if the disk is
- new or there is nothing on the disk you want to keep.
-
- 3. type
-
- copy *.* a:
-
- This will copy all files from your directory to the floppy disk. If there is a
- file on the floppy disk whose name is the same as a file in your directory,
- then it will be erased and replaced. For example, if you copied a file called
- tune.gio to your floppy disk last week, then edited tune.gio, and now you back
- up you directory, then you will lose last week's version of tune.gio from your
- floppy disk. It will be replaced by the current version.
-
- To copy individual files, type
-
- copy filename a:
-
- where filename is the file you want to save on floppy. To recover an
- individual file from floppy disk to your directory, type
-
- copy a:filename
-
-
-
- 3. The Adagio Language
- Adagio is an easy-to-use, non-procedural notation for scores. In Adagio,
- text commands are used to specify each note. If you are new to Adagio, you may
- want to glance at the examples in Section 3.3 starting on page 5 before reading
- any further.
-
- A note is described in Adagio by a set of 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, pitch, loudness, voice number,
- duration, and 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:
-
- 1. An asterisk (*) in column one (or immediately after a comma or
- semicolon) indicates that the rest of the line is a comment. The
- line is ignored by Adagio, and is therefore a good way to insert
- text to be read by people.
-
- 2. An empty command (a blank line, for example) is ignored as if it
- were a comment(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. ).
-
- 3. An exclamation point (!) in column one (or immediately after a comma
- or semicolon) indicates a 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.
-
- 4. 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.
-
- Adagio is insensitive to case, thus ``A'' is equivalent to ``a'', and you can
- mix upper and lower case letters freely.
-
- 3.1. Specifying Attributes
-
-
-
- 3.1.1. Time
- The time attribute specifies when to start the note. A time is specified by
- th
- a ``T'' followed by a number representing 100 's of a second or by a duration
- (durations are described below). Examples:
-
- T150 --1.5 sec
- TQ3 --3 quarter note's duration
-
- If no time is specified, the default time is the sum of the time and duration
- attributes of the previous note. (But see Section 3.1.4.) Time is measured
- relative to the time of the most recent Tempo or Rate command. (See the
- examples in Section 3.3 for some clarification of this point.)
-
-
-
- 3.1.2. Pitch
- The pitch attribute specifies what frequency to produce. Standard scale
- pitches are named by name, using "S" for sharp, "F" for flat, and (optionally)
- "N" for natural. For example, "C" and "CN" represent the same pitch, as do
- "FS" and "GF" (F sharp and G flat).
-
- Octaves are specified by number. C4 is middle C, and B3 is a half step lower.
- F5 is the top line of the treble clef, etc. Accidentals can go before or after
- the octave number, so FS3 and F3S have the same meaning. An alternate notation
- for pitch is Pn, where n is an integer representing the pitch. Middle C (C4)
- is equivalent to P48, CS4 is P49, etc. [If you know MIDI codes, you will
- notice that P48 in Adagio results in a MIDI pitch code of 60. The ``middle C =
- 48'' convention was borrowed from Gary Nelson's MPL and it is consistent with
- MUSIC V, cmusic, and many other computer music languages. I decided to stick
- with the convention on the assumption that if you know enough about MIDI to
- know that middle C is 60, then you know enough not to be confused by Adagio and
- other CMT software.] If you do not specify an octave, Adagio will choose one
- for you. This is done by picking the octave that will make the current pitch
- as close to the previous pitch as possible. In the case of augmented fourths
- or diminished fifths, there are two equally good choices. Adagio chooses the
- lower octave.
-
-
-
- 3.1.3. Duration
- Duration is specified by a letter indicating a number of beats, followed by
- one or several modifiers. The basic duration codes are: W (whole, 4 beats), H
- (half, 2 beats), Q (quarter, 1 beat), I (eighth, 1/2 beat), and S (sixteenth,
- 1/4 beat). The default tempo is 100 beats per minute (see Section 3.1.9).
- These codes may be followed by a "T" (triplet), indicting a duration of 2/3 the
- normal. A dot (".") after a duration code extends it by half to 3/2 the
- normal. Finally, an integer after a note multiplies its duration by the
- indicated value (the result is still just one note). Examples:
-
- Q -- 1 beat (quarter note)
- QT -- 2/3 beat (quarter triplet)
- W. -- 6 beats(dotted whole note)
- ST6 -- 1 beat (6 sixteenth triplets)
- H5 -- 10 beats(5 half notes)
-
- Finally, a duration may be noted by Un, where n is an integer indicating
- th
- 100 's of a second. For example, U25 is one quarter of one second.
-
-
-
- 3.1.4. Next Time
- The time of the next command (the next command in the Adagio program text) is
- normally the time of the current note command plus the duration of the current
- note. This can be overridden by a field consisting of the letter ``N''
- followed by a number indicating hundredths of seconds, or followed by a
- duration as described above. The next note will then start at the time of the
- current note plus the duration specified after ``N''. If the next note has an
- explicit time attribute (``T''), then the specified time will override the one
- based on the previous note. Examples:
-
- N0 -- start the next note at the same time as the current one
- N50 -- start the next note 0.5 seconds after the current one
- NQT -- start the next note 2/3 beat after the current one
-
-
-
- 3.1.5. Rest
- Rests are obtained by including the field ``R'' in a note command. The
- effect of an ``R'' field is to omit the note that would otherwise occur as the
- result of the current note command. In all other respects, the command is
- processed just like any other line. This means that attributes such as
- duration, loudness, and pitch can be specified, and anything specified will be
- inherited by the note in the next command. Normally, a rest will include just
- ``R'' and a duration. The fact that a note command specifies a rest is not
- inherited. For example:
-
- R H -- a half (two beat) rest
- RH -- illegal, R must be separated from other fields by space(s)
-
- Because some synthesizers (e.g. a DX7) cannot change programs (presets)
- rapidly, it may be desirable to change programs at the beginning of a rest so
- that the synthesizer will be ready to play by the end of the rest. See Section
- 3.1.8 for an example.
-
-
-
- 3.1.6. Loudness
- Loudness is indicated by an ``L'' followed by a dynamic marking from the
- following: PPP, PP, P, MP, MF, F, FF, FFF. Alternatively, a number from 0 to
- 127 may be used. The loudness attribute is the MIDI note velocity. The
- dynamic markings are translated into numbers as follows:
-
- Lppp 20 Lmf 58
- Lpp 26 Lf 75
- Lp 34 Lff 98
- Lmp 44 Lfff 127
-
-
-
- 3.1.7. Voice
- The voice attribute tells which of the 16 MIDI channels to use for the note.
- The voice attribute consists of a ``V'' followed by an integer from 1 (the
- default) to 16. There is a limit to how many notes can be played at the same
- time on a given voice (MIDI channel). Since the limit depends upon the
- synthesizer, Adagio cannot tell you when you exceed the limit. Similarly,
- Adagio cannot tell whether your synthesizer is set up to respond to a given
- channel, so there is no guarantee that what you write will actually be heard.
-
-
-
- 3.1.8. Timbre (MIDI program)
- A MIDI program (synthesizer preset) can be selected using the attribute
- ``Zn'', where n is the program number. Notice that in MIDI, changing the
- program on a given channel will effect all notes on that channel. Also, for
- many synthesizers, you will not be able to change programs at the start of a
- note or during a note. Change the program during a rest instead. For example:
-
- R I Z23 V4 -- change MIDI channel 4 to program 23 during rest
- A4 -- play a note on channel 4
-
- The cartridge programs on a DX7 can be accessed by adding 32 to the cartridge
- program number. For example, cartridge program number 10 is specified by Z42.
-
-
-
- 3.1.9. Tempo
- The length of a beat may be changed using a Tempo command:
-
- !TEMPO n
-
- where n indicates beats per minute. The exclamation mark tells Adagio that
- this is a special command line rather than a note definition. A special
- command takes the place of a note specification. No other attributes should be
- written on a line with a special command. The new tempo affects all succeeding
- notes. The time attribute of all succeeding notes is now measured relative to
- the time of the Tempo command. Durations specified in hundredths of seconds
- (for example U58, N15, or T821) are not affected by the Tempo command.
-
- The Tempo command is fairly clever about default durations. If the last
- duration specified before the Tempo command is symbolic (using one of S, I, Q,
- H, or W), then the default duration for the node after the Tempo command will
- be modified according to the tempo change. Consider the following tempo
- change:
-
- !TEMPO 60
- A4 H
- !TEMPO 120
- G
-
- In this example, the first note will last 2 seconds (2 beats at 60 beats per
- minute). The second note inherits the duration (H) from the first note, but at
- 120 beats per minute, the second note will last only 1 second. If the duration
- had been specified U200 (also a duration of 2 seconds), the second note would
- also last 2 seconds because the Tempo command does not affect times or
- durations specified in hundredths of seconds.
-
-
-
- 3.1.10. Rate
- The rate command scales all times including those specified in hundredths of
- seconds. A rate of 100 means no change, 200 means twice as fast, and 50 means
- half as fast. For example, to make a piece play 10% faster, you can add the
- following command at the beginning of the score:
-
- !RATE 110
-
- Rate and Tempo commands combine, so
-
- !RATE 200
- !TEMPO 70
-
- will play 70 beats per minute at double the normal speed, or 140 beats per
- minute. Like Tempo, the time of the Rate command is added to the time
- attribute of all following notes up to the next Time or Rate command.
-
- 3.2. Default Attributes
- If an attribute is omitted, the previous one is used by default (with the
- exception of the time attribute). The default values for the first note, which
- are inherited by succeeding notes until something else is specified, are given
- below in Adagio notation:
-
- Time T0
- Pitch C4
- Duration Q
- Loudness LFFF
- Voice V1
- Timbre Z1
- Tempo !TEMPO 100
- Rate !RATE 100
-
- Pitch Bend Y128
- After Touch O0
- Porta Rate J99
- Porta Switch K0
- Mod Wheel M0
- Foot Pedal X0
-
- 3.3. Examples
- The following plays the first two bars of ``Happy Birthday''. Note that
- Adagio knows nothing of bar lines, so the fact that the first note occurs on
- beat 3 or that the meter is three-four is of no consequence:
-
- *Example 1 -- Happy Birthday tune (C major)
- !TEMPO 120
- G4 I. LF
- G4 S
- A4 Q
- G4
- C5
- B4 H
-
- The time attribute for the first note is zero (0). The second note will occur
- a dotted eighth later, etc. Notice that no timbre or rate was specified.
- Adagio will provide reasonable default values of 1 and 100, respectively.
-
- The following example plays the first four bars of an exercise from Bartok's
- Mikrokosmos (Vol. 1, No. 12). An extra quarter note is inserted at the
- beginning of each voice in order to allow time to change MIDI programs. The
- right hand part is played on voice (MIDI channel) 1 and the left hand part on
- voice 2. Notice the specification of the time attribute to indicate that voice
- 2 starts at time 0. Also, I have taken advantage of default octaves to reduce
- typing.
-
- *Example 2 -- Bartok
- *voice 1, right hand
- R Q Z10 V1
- A4 H
- B Q
- C
- D H
- C
- D Q
- C
- B
- A
- B
- C
- D
- R
-
- *voice 2, left hand
- T0 R Q Z15 V2
- G3 H
- F Q
- E
- D H
- E
- D Q
- E
- F
- G
- F
- E
- D
- R
-
- The next example is the same piece expressed in a different manner,
- illustrating the interaction between the Tempo command and the time attribute.
- Recall that the time attribute is measured relative to the time of the last
- Tempo command:
-
- *Example 3 -- 4 measures in 2 sections
- !Tempo 100
- *Voice 1, Measures 1 & 2
- R Q Z10 V1
- A4 H
- B Q
- C
- D H
- C
-
- *Voice 2, Measures 1 & 2
- T0 R Q Z15 V2
- G3 H
- F Q
- E
- D H
- E H
-
- !TEMPO 100
- *Voice 1, Measures 3 & 4
- T0 V1 D4 Q
- C
- B
- A
- B
- C
- D
- R
-
- *Voice 2, Measures 3 & 4
- T0 V2 D3 Q
- E
- F
- G
- F
- E
- D
- R
-
- Notice that the piece is written in 4 sections. The first plays a rest
- followed by two measures, starting at time 0. The next section changes the
- time back to zero and plays two measures of the left hand part (voice 2). The
- next command (!TEMPO 100) sets the tempo to 100 (it already is) and sets the
- reference time to be two measures into the piece. Therefore, the next note
- (D4) will begin measure 3. The D3 that begins the last group of notes has a T0
- attribute, so it will also start at measure 3. Notice how the !TEMPO command
- can serve to divide a piece into sections.
-
- The last example will show yet another way to express the same piece of music
- using the ``Next'' attribute. Only the first bar of music is given.
-
- *Example 4 -- use of the Next attribute
- !Tempo 100
- R Q Z10 V1 N0
- R Q Z15 V2
-
- A4 H V1 N0
- G3 V2
-
- B4 Q V1 N0
- F3 V2
-
- C4 Q V1 N0
- E3 V2
-
- Here, each pair of lines represents two simultaneous notes. The ``N0''
- attribute forces the second line to start at the same time as the first line of
- each pair.
-
- 3.4. Advanced features
- Adagio allows you to write multiple commands on one line and to program MIDI
- control functions. It is also possible to write music with multiple tempi.
-
-
-
- 3.4.1. Multiple notes per line
- Notes can be separated by commas or semicolons as well as by starting a new
- line. A comma is equivalent to typing N0 and starting a new line. A semicolon
- is equivalent to starting a new line. Here is yet another rendition of the
- Bartok:
-
- *Example 5 -- use of semicolons
- !Tempo 100
- R Q Z10 V1
- A4 H; B Q; C; D H; C; D Q; C; B; A; B; C; D; R
-
- T0 R Q Z15 V2
- G3 H; F Q; E; D H; E; D Q; E; F; G; F; E; D; R
-
- This example is similar to Example 2, except semicolons are used. The next
- example is similar to Example 4, except commas are used and four bars are
- notated:
-
- *Example 6 -- use of commas
- !Tempo 100
- R Q Z10 V1, R Q Z15 V2
- A4 H V1, G3 V2
- B4 Q V1, F3 V2
- C4 V1, E3 V2
- D4 H V1, D3 V2
- C4 V1, E3 V2
- D4 Q V1, D3 V2
- C4 V1, E3 V2
- B4 V1, F3 V2
- A4 V1, G3 V2
- B4 V1, F3 V2
- C4 V1, E3 V2
- D4 V1, D3 V2
- R
-
-
-
- 3.4.2. Control change commands
- The current version of Adagio can control the following functions:
-
- Portamento rate (J)
- Portamento switch (K)
- Modulation wheel (M)
- Aftertouch (O)
- Foot pedal (X)
- Pitch bend (Y)
-
- The letter listed beside each control function is the Adagio command letter.
- For example, M23 is the command for setting the modulation wheel to 23. Except
- for pitch bend and the portamento switch, all values range from 0 to 127.
- Pitch bend is ``off'' or centered at 128, and has a range from 0 to 255. Turn
- on portamento with K127 and off with K0.
-
- There is no convenient way to get smoothly varying functions. You can either
- type in many control changes to achieve the effect you want or generate a file
- with the transcribe program containing the data you want.
-
- Control changes can be part of a note specification or independent. In the
- following example, a middle C is played with a modulation wheel setting of 50
- and a pitch bend of 120. Then, at 0.1 second intervals, the pitch bend is
- decreased by 10:
-
- *Example 7 --
- C4 LMF M50 Y120 U100 N10
- Y110 N10; Y100 N10; Y90 N10; Y80 N10; Y70 N10; Y60 N10; Y50 N10
-
-
-
- 3.4.3. Multiple Tempi
- Writing a piece with multiple tempi requires no new commands; you just have
- to be clever in the use of Tempo and Time. The following plays a 7 note
- diatonic scale on voice 1, and a 12 note chromatic scale on voice 2:
-
- *Example 8 -- multiple tempi
- !TEMPO 70
- V1 C4; D; E; F; G; A; B
- T0 R N0
-
- !TEMPO 120
- V2 C4; CS; D; DS; E; F; FS; G; GS; A; AS; B
-
- !TEMPO 100
- V1 C5, V2 C5
-
- The third line plays the 7-note diatonic scale on voice 1. The next line
- contains the tricky part: notice that the time is set back to zero, there is a
- rest, and a next (N) attribute is used to specify that the next default time
- will be at the same time as the current one. Thus, the time of the !TEMPO 120
- command is zero. After the 12 note scale, the tempo is changed to 100 and a
- final note is played on each voice. A little arithmetic will show that 7 notes
- at tempo 70 and 12 notes at tempo 120 each take 6 seconds, so the final notes
- (C5) of each scale will happen at the same time.
-
- 3.5. Running Adagio
- To use Adagio, create an Adagio score using a text editor. By convention,
- Adagio scores are named something.gio, where something is any name you like,
- and ``.gio'' is a hint that this is an Adagio score.
-
- To listen to the score, type
-
- adagio something
-
- Notice that typing the ``.gio'' is optional with Adagio (but you must type the
- full file name when you use the editor). If all goes well, you will get the
- following prompt:
-
- Type <RETURN> to play notes, q<RETURN> to quit, ?<RETURN> for help:
-
- If you type ``?RETURN'', you get a complete list of commands:
-
- <return> Play music
- q<return> Quit Adagio (Exit)
-
- r<return> Read tuning file
- m<return> Turn on MIDI byte trace
- -m<return> Turn off MIDI byte trace
- s<return> Report state
- t<return> Turn on music operation trace
- -t<return> Turn off music operation trace
- ?<return> This message
-
- If you type RETURN to start your piece, Adagio first sends a MIDI program
- change to program 1 on each of the 16 MIDI channels. Exactly 1 second after
- typing RETURN, Adagio starts playing your score.
-
- If you type ``qRETURN'', Adagio will exit.
-
- If you type ``rRETURN'', you will get a prompt for a tuning file (see Chapter
- 4). This command is useful for playing a single score with different tunings
- without exiting Adagio.
-
- The ``m'' command causes Adagio to print a trace of all MIDI data. This is
- not useful for anything other than debugging changes to Adagio. The ``-m''
- command turns tracing off.
-
- The ``s'' command reports what data will be traced.
-
- The ``t'' command causes Adagio to print a trace of all music operations.
- The information printed in a fairly readable form as opposed to the numbers
- printed using the ``m'' switch. The ``-t'' switch turns off the music
- operation trace.
-
-
-
- 3.5.1. Debugging Adagio Scores
- While the score is playing, you can type the space bar to stop the
- performance. The computer screen will then tell you where it was at the moment
- you hit the space bar. This is very handy for finding the source of bad notes.
- For example, if you hear a bad note, play the score again and type a space when
- you hear the mistake. Suppose the screen says that you were playing a note
- from line 123 and another from line 259. Remember these numbers, quit Adagio
- (type ``Q''), and type
-
- edit something.gio
-
- Now type (to the editor(I assume you have an emacs-like editor.)) CTRL-U 1 2 2
- CTRL-N. This moves the cursor down 122 lines to line number 123. If the
- mistake is not found, put the cursor back at the top of the file (ESC <) and go
- down 258 lines (CTRL-U 2 5 8 CTRL-N) to get to line 259.
-
-
-
- 3.5.2. Command Line Options
- The following options can be specified in the command line:
-
- - -debug (or -d): turn on debugging code.
-
- - -help: print a list of command line options.
-
- - -miditrace (or -m): turn on MIDI byte trace.
-
- - -trace (or -t): turn on music operation trace.
-
- - -at: tell Adagio that you are running on an AT. (This option is
- redundant information for debugging. There is no advantage to using
- it because Adagio and other CMT software can determine the machine
- type automatically.)
-
- - -metronome (or -met): turn on the MPU-401 metronome. This is only
- useful for debugging because there is no way to set the metronome
- speed.
-
- - -simulated (or -s): simulate the MPU-401 but do not use it. This is
- only useful for debugging and may not be implemented.
-
- - -xt: tell Adagio that you are running on an XT. (This option is for
- debugging _ see -at.)
-
- - -print: tells Adagio to print details of each note on the console.
-
- - -block: turns off the MPU-401 MIDI THRU function so that the input is
- not passed to the output.
-
- - -tune filename: tells Adagio to use filename to specify tuning.
-
-
-
- 3.5.3. Examples
- Run Adagio with score.gio as the score:
-
- adagio score
-
- Run Adagio with score.gio as the score and using meantone.tun to specify
- tuning:
-
- adagio score -tune meantone
-
-
-
- 4. Defining Nonstandard Tunings
- Tuning in MIDI is normally twelve-tone equal temperment. MIDI has no
- provisions to change this except by using the 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.
-
- 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
-
- PitchBend = (8192 * c) + 8192,
-
- where 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 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.
-
- To use a tuning file, say meantone.tun, you type the following option
- anywhere in the command line:
-
- -tune meantone
-
- If no tuning is specified, then notes are not translated and no pitch bend
- commands are sent.
-
- 4.1. The Tuning Program
- The tuning program lets you define scales in terms of ratios or cents.
-
- You run Tuning by typing
-
- tuning myscale
-
- where myscale.tun is the name of the tuning file you want to create. (An
- extension of ``.tun'' will automatically be appended.) The program then
- prints:
-
- You will now create a pitch file.
-
- r - enter a range of values
- o - enter one octave (that will be generalized)
- p - enter one pitch (you choose)
- q - quit
- Command >>
-
- To which you should respond with one of r, o, p, or q. The actions associated
- with each command are described below:
-
-
-
- 4.1.1. Entering a range of pitches.
- The r command prompts you for a range of pitches and then prompts you for a
- pitch and pitch bend for each pitch in the range. For example, The following
- is a transcript of what you would do to make C4 through D4 sound 1 step and 10
- cents (110 cents) higher (user typein is in italics):
-
- Command >>r
- Adagio note range is -12..115
- What range of notes would you like to enter ?
- From >> 48
- To >> 50
- For the given Adagio note number, enter the desired pitch
- and the amount of pitchbend in cents
- Bend range = -100 .. 100, '0' for no pitch bend
- (100 cents = 1 semitone)
- Pitch range = 1 .. 128, 48 is middle C
-
-
- Adagio Note 48
- pitch >>49
- bend >>10
- Adagio Note 49
- pitch >>50
- bend >>10
- Adagio Note 50
- pitch >>51
- bend >>10
-
-
-
- 4.1.2. Entering an octave
- The o command lets you enter information for one octave and then
- automatically transpose that information (by octaves) to provide information
- for all possible pitches. Here is an abbreviated sample transcript for a
- tuning in which every other note is 50 cents sharp:
-
- Command >>o
-
- You will input the information for one octave and that
- will be generalized for all octaves.
-
- Would you like to enter the information as
- (1) frequency ratios of notes to a tonic
- or (2) semitones (integer) + pitchbend (in cents)
-
-
- >>2
-
- For the given note number, enter the desired pitch
- and the amount of pitchbend in cents based on given tonic
-
- 1 unit of pitch = 1 semitone -- the tonic (note 0) has pitch 0 and
- bend 0.
- Bend range = -100 .. 100 cents, 0 for no pitch bend
- (100 cents = 1 semitone)
-
- Octave note 1
- pitch >>1
- bend >>50
-
- Octave note 2
- pitch >>2
- bend >>0
-
- Octave note 3
- pitch >>3
- bend >>50
-
- -- six entries are omitted here --
-
- Octave note 10
- pitch >>10
- bend >>0
-
- Octave note 11
- pitch >>11
- bend >>50
-
- What note would you like your octave to start on?
- C C# D D# E F F# G G# A A# B
- 0 1 2 3 4 5 6 7 8 9 10 11
- >>0
-
-
-
- 4.1.3. Entering one pitch
- You can use the p command to modify just one pitch. This is useful to go
- back and change information you have entered with the r or o commands. Here is
- an example that makes A4 (pitch number 57) play an octave higher:
-
- Command >>p
- Adagio note range is -12..115. Which note would you like to enter ?
- (type return to quit)
- Note >>57
-
- For the given pitch number, enter pitch parameters
- Bend range = -100 .. 100 cents, 0 for no pitch bend
- (100 cents = 1 semitone)
- Pitch range = 1 .. 128, 48 is middle C
-
- Adagio note 57
- pitch >>69
- bend >>0
-
- Adagio note range is -12..115. Which note would you like to enter ?
- (type return to quit)
- Note >>
-
-
-
- 4.1.4. Saving a tuning file.
- When you are done, use the q command to save the tuning file:
-
- Command >>q
-
- As discussed above, you can use the resulting file with Adagio, Record, and
- Moxc to control tuning.
-
- 4.2. The Retune Program
- A simple demonstration program is included with CMT to allow you to
- ``retune'' a MIDI controller. To use it, you should connect a MIDI controller
- (e.g. a DX7) to MIDI IN or your computer interface, and connect MIDI OUT of the
- interface to a synthesizer (e.g. a TX816). Run Retune by typing:
-
- retune -tune myscale
-
- where myscale.tun is a tuning file previously created. Now, as you play on the
- controller, the Retune program will use pitch bend in real time to adjust the
- pitch of each note.
-
- Note: The Retune program is \test\retune.exe on CMT DISK 1. You may have to
- copy it to your \cmt directory to use it from another directory. Also notice
- that since pitch bends apply to the whole keyboard, polyphonic notes interfere
- with one another.
-
-
-
- 5. The Transcribe Program
-
- 5.1. Overview
- The Transcribe program is used to record performances via MIDI and to
- translate them into Adagio. Rather than attempt to guess musical durations
- (like a dotted-quarter), Transcribe records all times and durations in
- hundredths of seconds. This program, together with Record makes it fairly
- simple to build up complex Adagio scores one part at a time. Transcribed music
- can be copied, edited, or repeated using an ordinary text editor. The output
- from Transcribe might also be useful in the study or evaluation of
- performances.
-
- 5.2. Tutorial
- To use Transcribe, type
-
- transcri filename
-
- where filename is the name of the file you want to create. If you just type
- transcri, you will be prompted for a file name. In either case, a default
- extension of ``.gio'' will be assumed. Transcribe will then ask you if you
- want to record control information:
-
- Pitch bend, etc. on? [n]
-
- Type ``y'', ``n'', or just RETURN for the default (n). Generally, you should
- type RETURN. At present, recording control information tends to use up the
- available recording memory very quickly, so it is of limited use. When you
- have finished what you want to play, type the space bar on the IBM. This
- signals the program to stop and write out the notes. This file can now be
- played by Adagio and what comes out will be very similar to what you just heard
- yourself play.
-
- 5.3. Timbre
- When you start Transcribe, it sends MIDI program change commands to program 1
- on all MIDI channels. When you make a program change on the synthesizer,
- Transcribe records the change and translates it into an Adagio Z attribute.
- This corresponds to the default Z1 attribute in Adagio and to the fact that
- Adagio also initializes all MIDI channels to program 1.
-
- Note: Transcribe (and Record) record Z attributes whenever they receive a
- MIDI Program Change command. Synthesizers normally send this when you change a
- preset sound using the controls on the synthesizer. One noteable exception is
- that if a Yamaha synthesizer is in the ``Sys Info Avail'' mode, then pressing
- a button to change the program causes the synthesizer to dump all of the
- internal data comprising the program. No MIDI Program Change command is sent,
- so Transcribe records nothing. You can find out what is happening by running
- the MM (Midi Monitor) program and pushing a program change button on your
- synthesizer. For Yamaha synthesizers, the mode should be ``Sys Info Unavail'',
- which is a fairly cryptic way to say ``send program numbers instead of program
- data''.
-
- 5.4. Command Line Options
- The following options can be specified in the command line:
-
- - -debug (or -d): turn on debugging code.
-
- - -help: print a list of command line options.
-
- - -miditrace (or -m): turn on MIDI byte trace.
-
- - -trace (or -t): turn on music operation trace.
-
- - -block: turns off the MPU-401 MIDI THRU function so that the input is
- not passed to the output.
-
- - -control (or -c) on: record control information, do not present the
- ``Pitch bend, etc. on?'' query.
-
- - -control (or -c) off: do not record control information, do not
- present the ``Pitch bend, etc. on?'' query.
-
-
-
- 5.4.1. Examples
- Print information about command line options:
-
- transcri -help
-
- Record data into file foo.gio, do not record control information, and turn
- off the MIDI THRU function of the MPU-401:
-
- transcri foo -c off -block
-
-
-
- 6. The Record Program
-
- 6.1. Overview
- The Record program is a combination of Adagio and Transcribe. It is used to
- record performances via MIDI and to translate them into Adagio while
- simultaneously playing an Adagio score. This allows you to enter scores one
- part at a time. Section 6.3 discusses how you can combine several Adagio
- scores into one.
-
- 6.2. Instructions
- Before using Record, you should first create an Adagio score, either with an
- editor or with Transcribe. This will be the score that Record plays while
- recording a new score. Let us assume that the existing score is called old.gio
- and you want to record another part called new.gio. Run Record by typing:
-
- record old
-
- Record uses the Adagio compiler to get old.gio ready to play. It then prompts
- you with:
-
- Type <RETURN> to record, q<RETURN> to quit, ?<RETURN> for help:
-
- The possible responses are described in detail in Section 3.5. Normally, you
- should just type RETURN to start playing and recording. Next, you will get a
- prompt for the file you want to create:
-
- Name of output file:
-
- Type new. The extension .gio will be added automatically if you do not provide
- any extension.
-
- After a delay of one second, Record begins to play the score in old. The
- delay is not precise, so you would normally put something into old to ``count
- off'' the start of the piece. Record also records anything you play.
- Recording does not stop until you type the space bar, even if old finishes
- playing.
-
- After you type the space bar, you will again get the prompt:
-
- Type <RETURN> to record, q<RETURN> to quit, ?<RETURN> for help:
-
- You can erase and re-record new by repeating the instructions given above.
- (This time, you will have to confirm that you want to erase new.gio.)
- Otherwise, just type q to quit.
-
- You now have two files, old.gio and new.gio. The next section describes how
- to merge files to create a single file for Adagio.
-
- 6.3. Merging Adagio Scores
- A few tricks are helpful in merging two scores into one. In this section, I
- will describe the basics of making two scores play at the same time as well as
- getting two scores to play in sequence. It should be remembered that the goal
- is simply to create an Adagio score. If you try something that does not work,
- you should be able to look at your scores and figure out where the problem is.
-
-
-
- 6.3.1. Playing two scores in sequence
- To play two scores in sequence, you should edit the first score file so that
- the last line contains the last event of that score. Since Adagio scores are
- not necessarily written in time order, this may or may not be the case.
- Transcribe and Record always write scores in the order of note start times.
- The last note will specify a next (N) attribute that corresponds to the time
- you typed the space bar.
-
- Once you get the timing of the last note right, it should be apparent that if
- you insert some notes at the end of the score, they will be played after the
- score (unless they specify a time (T) attribute). You might want to conduct an
- experiment to find out where your score ends. If you insert the line
-
- C6 LFFF U20
-
- at the end of your file, you should here a distinctively loud and high note at
- the end of your score. If the ``end'' comes too early or too late, you should
- edit your file accordingly.
-
- You can insert an entire file at the end of another file using the DOS copy
- command:
-
- copy score1.gio+score2.gio
-
- DOS knows nothing about Adagio, so the .gio extensions must be specified. This
- command will modify score1.gio by appending the contents of score2.gio, which
- is not modified. An alternative form is
-
- copy score1.gio+score2.gio score3.gio
-
- which puts the result into score3.gio, leaving score1.gio and score2.gio
- intact.
-
- If score2.gio does not specify (T) attributes, then appending the scores
- should be adequate. On the other hand, if score2.gio specifies times relative
- to the beginning of the score, you can insert a !TEMPO command at the
- beginning. Then, when score2.gio is appended to score1.gio, the !TEMPO command
- will occur at the end of score1.gio, and everything in score2.gio will be
- measured relative to the !TEMPO command.
-
-
-
- 6.3.2. Playing two scores at the same time
- To get two scores to play at the same time, you should make sure that the
- second score includes a time (T) attribute on or before its first note.
- Otherwise, the second score will be played after the first one. (Record
- automatically inserts a time attribute on the first note of each file it
- creates. The time is the correct one assuming you want to merge the recorded
- file (e.g. new.gio with the played file (e.g. old.gio). The DOS copy command
- is used to merge the two files as described above.
-
- A typical problem is trying to play two scores on the same voice (MIDI
- channel). This is only a problem if both scores try to play the same note at
- the same time. MIDI assumes that notes are turned on by pressing keys, and it
- is impossible to press the same key twice without first releasing it. This
- problem usually manifests itself as notes that get cut off early. If you are
- trying to merge two files with the same voice, you might want to change the
- voice specified for the second file to make sure the two scores do not
- interfere. (This of course assumes you have several synthesizers so that you
- can play several channels at once.)
-
- 6.4. Command Line Options
- The following options can be specified in the command line:
-
- - -debug (or -d): turn on debugging code.
-
- - -help: print a list of command line options.
-
- - -miditrace (or -m): turn on MIDI byte trace.
-
- - -trace (or -t): turn on music operation trace.
-
- - -at: tell Record that you are running on an AT. (This option is
- redundant information for debugging. There is no advantage to using
- it because Record and other CMT software can determine the machine
- type automatically.)
-
- - -metronome (or -met): turn on the MPU-401 metronome. This is only
- useful for debugging because there is no way to set the metronome
- speed.
-
- - -simulated (or -s): simulate the MPU-401 but do not use it. This is
- only useful for debugging and may not be implemented.
-
- - -xt: tell Record that you are running on an XT. (This option is for
- debugging -- see -at.)
-
- - -print: tells Record to print details of each compiled note on the
- console.
-
- - -block: turns off the MPU-401 MIDI THRU function so that the input is
- not passed to the output.
-
- - -control (or -c) on: record control information, do not present the
- ``Pitch bend, etc. on?'' query.
-
- - -control (or -c) off: do not record control information, do not
- present the ``Pitch bend, etc. on?'' query.
-
-
-
- 6.4.1. Examples
- Print information about command line options:
-
- record -help
-
- Play score in file foo.gio, do not record control information, and turn off
- the MIDI THRU function of the MPU-401:
-
- record foo -c off -block
-
-
-
- 7. DXGet and DXPut
- DXGet and DXPut are used to store and recall programs for synthesizers.
- These are generally voice programs, but in general they can be any sequence of
- MIDI system exclusive messages.
-
- 7.1. DXGet
- The DXGet program is used to record MIDI system exclusive messages and store
- them in files. The program is designed to work with DX7 and TX816
- synthesizers, although it should work with any others. To run DXGet, type
-
- dxget filename
-
- where filename is the name of a file you want to create. If you leave off the
- extension, DXGet will use the extension ``.dx7''. If you do not specify a
- file, you will be prompted for one. After DXGet starts, you will get the
- following prompt:
-
- Do you want instructions? [y]
-
- to which you can respond with "y," "n," or just RETURN to indicate yes. If
- your response is yes, the following instructions are printed:
-
- This program will let you save DX7 and TX816 voice programs. To save
- DX7 programs, you must connect DX7 MIDI OUT to MPU 401 MIDI IN. For
- TX816 programs, connect TX816 MIDI OUT to MPU 401 MIDI IN, and set the
- OUT SLOT (leftmost display) to the module from which you want data.
- For DX7: push the orange FUNCTION key, then the green 8. Push 8
- repeatedly until the display says SYS INFO AVAIL or SYS INFO UNAVAIL.
- If the display says SYS INFO UNAVAIL, push YES to change the display to
- SYS INFO AVAIL. Now, select a voice with the INTERNAL or CARTRIDGE
- button followed by a (green) number. For ALL DX7 voices: after getting
- the SYS INFO AVAIL display, push 8 again to get MIDI TRANSMIT ?. Push
- YES. For TX816: Hold down SELECT until you see UT in the display. Let
- up on SELECT and then push it once more to get the flashing dU. Push
- YES to dump all data from this module. Hold down SELECT until you see
- digits in the display. After data is dumped, dxget will tell you what
- it got and write data to a file. Use dxput to copy a file to a dx
- module.
-
- Next, you are prompted as follows:
-
- Ready for your data. Type space when you are done...
-
- and you should cause your synthesizer to send whatever system exclusive
- messages you want to save. One or more messages can be saved. Notice that
- DXGet will not request information automatically. This would require DXGet to
- know about types of synthesizers. To be more general, DXGet is very simple.
- Consequently, you must manually cause your synthesizer to send the desired
- information to DXGet.
-
- After one or more messages have been sent, type the space bar and the
- messages will be saved in the file you specified. The file format is simply
- bytes in hexadecimal separated by spaces. As the data is output, DXGet will
- check to make sure the data has not been garbled. A warning will be printed if
- any errors are detected. DXGet will also try to print a description of the
- exclusive messages it received. You can send the data back to your synthesizer
- using the DXPut program described below.
-
- NOTE: If you find that you are sending two messages instead of one when you
- use DXGet, here is what is probably happening: When you push the ``yes''
- button to send data, the DX7 sends a MIDI message that means ``push the `yes'
- button'', analogous to sending a MIDI note-on message whey you press a key.
- Next, the DX7 sends voice data as requested. Meanwhile, the first MIDI message
- has gone into the MPU-401 MIDI IN port and has been forwarded to the MIDI OUT
- port. If the MPU-401 MIDI OUT is connected to the DX7 MIDI IN, then the DX7
- gets a second request (via MIDI) to send data! You can avoid this by
- disconnecting the DX7 MIDI IN cable or by using the ``-block'' switch when you
- run DXGet.
-
- 7.2. DXPut
- The DXPut program takes files created by DXGet and sends them as MIDI output.
- To run DXPut, type
-
- dxput filename
-
- where filename is the file created by DXGet. A default extension of ``dx7'' is
- assumed if you do not specify one. After starting, DXPut will ask:
-
- Do you want instructions? [y]
-
- The instructions are as follows:
-
- This program will let you send voice programs to a DX7 or TX816. You
- must send a file previously created by the dxget program. To send DX7
- programs, you must connect MPU 401 MIDI OUT to DX7 MIDI IN. For TX816
- programs, connect MPU 401 MIDI OUT to TX816 MIDI IN. For a DX7 voice:
- push the orange FUNCTION key, then the green 8. Push 8 repeatedly
- until the display says SYS INFO AVAIL or SYS INFO UNAVAIL. If the
- display says SYS INFO UNAVAIL, push YES to change to SYS INFO AVAIL.
- Next, push MEMORY PROTECT/INTERNAL, then NO, and then then MEMORY
- SELECT/INTERNAL. Now, type the name of a file created by dxget and then
- the space bar to send data. To store the voice program on the DX7,
- hold down STORE while you push a (green) number. The current voice at
- this number will be erased and replaced by the new voice. For ALL DX7
- voices: Same as for a single DX7 voice, but all 32 voice programs on
- the DX7 will be replaced when you type Y in response to `Are you sure?'
- on the computer. For all TX816 voices: To store into one module, push
- NO until the MEMORY PROTECT light goes out. Make sure other MEMORY
- PROTECT lights are ON. Type Y in response to 'Are you sure?' on the
- computer.
-
- Assuming the file you specified contains valid data, you will next see the
- prompt:
-
- Ready with your data. Type space when you are ready...
-
- Type space to send the data. If a message is one which DXPut knows will cause
- a major change, you will be asked for confirmation before the data is sent. At
- present DXPut only asks you to confirm Yamaha 32 voice and 64 performance data
- messages.
-
- After the data in the file is sent, you are prompted by:
-
- Type Q to quit, RETURN to send another file:
-
- As the computer says, you can quit or continue to send more data. Typing a
- file name gets you back to the prompt: ``Do you want instructions? [y]'', which
- even if you asked for them earlier have by now have scrolled off the screen.
-
-
-
- 8. Programming in C
-
- 8.1. Introduction
- This chapter is not about how to write in C Major, nor is it about how to
- reallize a piece by Terry Riley with a computer. Rather, it is about a
- programming language called ``C''. Specifically, this chapter is about how to
- use a somewhat twisted subset of the C language to make music with CMT. I hope
- to expand this chapter in the future, but for now, it's going to look more like
- lecture notes than a complete guide to programming.
-
- 8.2. Writing a Program
- Let's say you want to write a program called ``foo'' that plays a couple of
- notes. First use the editor to make a file called ``foo.c'':
-
- edit foo.c
-
- When you get into the editor, type the following program:
-
- /* a simple program */
- #include "cmtprog.h"
-
- mainscore()
- begin
- note(48, 100);
- note(50, 50);
- note(52, 50);
- note(53, 100)
- end
-
- This program will play 4 notes in sequence by ``calling'' note 4 times. You
- indicate what kind of note you want by giving two parameters in parentheses
- after the word ``note''. The parameters for note specify pitch and duration.
- The pitch parameter is 48 for middle C (C4), and goes up by one for each
- semitone. Thus, the pitches in this program are C4, D4, E4, and F4. The
- second parameter is the duration parameter, expressed in hundredths of a
- second. Thus, the first note will be 1 second long, the next two will be 0.5
- seconds, and the last will be 1 second.
-
- A few more observations: notice that the ``score'' consists of calls to note
- preceded by a name, ``mainscore()'', and is bracketed by the words ``begin''
- and ``end''. Also notice that calls to note are separated by semicolons (;).
- All of these details are essential, and C is not very forgiving of even trivial
- mistakes. The first line of the program is called a comment. Any text between
- /* and */ is ignored by C. You will find it useful to use comments to remind
- yourself what your program does, when it was written, and so on. The next
- line, beginning with ``#include'' tells the C compiler to read the file
- ``musiprog.h'' from the system library. This file contains important
- definitions for music, so every program you write should contain this line.
-
- Unlike Adagio, C is a case sensitive language. This means that mainscore,
- MainScore, MAINSCORE, and MaInScOrE are all distinct identifiers. Because of
- this, I suggest that you never use upper case letters in C programs, except in
- strings and comments.
-
- To hear the results of this program, you have to compile your program, then
- link it, and then execute it. The Lattice C compiler (invoked by the command
- cmtc) translates your program into a machine language form which is stored in a
- file. This file is then linked, or combined with other programs to produce an
- executable program file. This file can then be executed, meaning that the
- machine instructions in the file are loaded into working memory, and the
- computer then carries them out. To compile your program (called foo.c), type
- the following:
-
- cmtc foo.c
-
- If your program has errors, the line number where the error was discovered will
- be printed along with a brief description of the error. You must fix these
- errors by editing your program and then compiling again. When the compile
- phase and then the link phase completes without errors, you can link your
- program by typing:
-
- cmtl foo
-
- The command cmtl is short for cmt link. Be sure the last character is the
- letter l, not the numeral 1. If no errors are reported by the linker, your
- program is ready to run. Otherwise, you will have to fix your program with the
- editor, recompile, and relink. To run your program, type
-
- foo
-
- To run your program again, you need not recompile unless you change your
- program with the editor.
-
- 8.3. Stopping a Program
- Sometimes you need to stop programs in progress before they finish on their
- own. You can type CTRL-C (hold down the CTRL key and type ``C'' or CTRL-BREAK
- to stop your program in most cases. It is possible to write programs that
- cannot be stopped except by turning off the computer, but these are
- unusual[Typing CTRL-C or CTRL-BREAK sets a flag but does not terminate your
- program immediately, because doing so might leave the MPU-401 interface in a
- state that would cause problems later on. Instead, the gettime function checks
- the flag and carefully exits your program if the flag is set. Since gettime is
- called by almost every procedure that takes any significant time to execute
- (e.g. note, rest, and rest until), it is a pretty safe bet that typing CTRL-C
- will terminate any program.]
-
- 8.4. Writing a Procedure
- Procedures allow you to give a name to a musical phrase. The phrase can then
- be called from several places. This saves your having to retype all of the
- calls to note every time you want to hear the phrase. In the following
- example, there are two phrases, or procedures, up and down, which are called
- from mainscore:
-
- #include "cmtprog.h"
-
- mainscore()
- begin
- up();
- down();
- up();
- note(48, 100)
- end
-
- up()
- begin
- note(48, 20);
- note(50, 20);
- note(52, 20);
- note(53, 20)
- end
-
- down()
- begin
- note(55, 20);
- note(53, 20);
- note(52, 20);
- note(50, 20)
- end
-
- Notice that up and down obey the same rules as mainscore: procedure names are
- followed by a pair of parentheses and the word begin. Then there is a list of
- calls to note or other procedures separated by semicolons. While note has two
- parameters, up and down each have zero parameters. You indicate the absence of
- parameters when you call up or down by not putting anything between the open
- and close parentheses. However, you must always type the parentheses after the
- name of any procedure you call. Finally, the sequence of calls is ended by the
- word end.
-
- When this program is run, the computer will do what mainscore says to do.
- The first call is to up, so the computer finds the definition of up and does
- what up says to do. In this case, up plays four notes (C, D, E, F). Now that
- up is finished, mainscore continues by calling down, which in turn plays (G, F,
- E, D). When down returns, mainscore continues with another call to up, and
- again up will play C, D, E, F. Finally, up returns and mainscore plays a C.
- At this point the mainscore program is finished.
-
- 8.5. Repeats
- Repetition is important in both programming and music. To repeat a phrase, a
- special ``repeat'' construct is provided. Consider the following example:
-
- #include "cmtprog.h"
-
- mainscore()
- begin
- repeat(i, 5)
- note(48, 30);
- note(60, 30)
- endrep
- end
-
- Look at the two calls to note above. By themselves, these calls would play the
- phrase C4 C5. The repeat construct consists of the form
-
- repeat(counter, howmany) phrase endrep
-
- where counter is just the name you want the computer to give to a variable
- number that keeps track of which repeat is being played (more about this
- later), howmany is the number of repeats to take, and phrase is a sequence of
- calls to note or any other procedure. The example above will play the phrase
- C4 C5 C4 C5 C4 C5 C4 C5 C4 C5 because we wrote 5 for the number of repeats. If
- you like, you can repeat up to about 30,000 times.
-
- The phrase could just as well have been calls to other procedures. The next
- example uses repeat to play C4 D4 E4 F4 three times, using the up procedure
- used earlier.
-
- #include "cmtprog.h"
-
- mainscore()
- begin
- repeat(i, 3)
- up()
- endrep
- end
-
- up()
- begin
- note(48, 20);
- note(50, 20);
- note(52, 20);
- note(53, 20)
- end
-
- 8.6. Conditions
- Computer programs are made more flexible by the use of conditionals, that is,
- the ability to test a condition and act upon the result of the test. For
- example, suppose you want to repeat a phrase, but you want the phrase to have a
- first and second ending. In other words, the first time through you want the
- end of the phrase to be played one way, and the second time through, you want
- the ending to be played another way. How would you do this using just repeats
- and procedures? The following program uses a new construct (the when
- construct) that makes this programming task easy:
-
- #include "cmtprog.h"
-
- mainscore()
- begin
- repeat(i, 2)
- note(60, 30);
- note(59, 15);
- note(57, 15);
- note(55, 15);
- note(53, 15);
- note(52, 15);
- when i == 1 then
- note(53, 15);
- note(55, 120)
- otherwise
- note(50, 15);
- note(48, 120)
- endwhen
- endrep
- end
-
- This is a program with a repeat construct, but notice that the last part of the
- repeated phrase is of the form:
-
- when condition then phrase1 otherwise phrase2 endwhen
-
- The computer interprets this construct as follows: whenever a when is
- encountered, the computer evaluates the following condition. In this case the
- condition is ``i == 1'', which is true when the repeat counter (i) is equal to
- one (the first time through) and false when the repeat counter is not equal to
- one[The double equal symbol ``=='' is interpreted by C to mean ``is equal to''.
- A single equal symbol ``='' is called the assignment operator, and should never
- be used unless you know what you are doing. Even experienced programmers
- occasionally slip and write ``='' when they mean to write ``==''. It is a good
- idea to use the editor to search for all occurrences of ``='' to make sure your
- program is correct.]. If the condition is true (which happens the first time
- through in this example), the phrase following then is performed up to the word
- otherwise, and the phrase between otherwise and endwhen is skipped. If the
- condition is false, the phrase between then and otherwise is skipped, and the
- phrase between otherwise and endwhen is performed. As usual, these phrases can
- be calls to other procedures like up and down.
-
- The when construct is used to select between two alternatives where the
- selection is based on a condition. Useful conditions are:
-
- a == b -- true if a is equal to b
- a > b -- true if a is greater than b
- a < b -- true if a is less than b
- a >= b -- true if a is greater than or equal to b
- a <= b -- true if a is less than or equal to b
- a != b -- true if a is not equal to b
-
- Here, a and b stand for repeat counters (like i) or numbers (like 0, 1, etc.).
- Like the repeat construct, the when construct can be used anywhere in a phrase.
- The following example plays a phrase three times. On the second time through,
- the middle of the phrase is extended. The procedures p1, p2, and p3 are not
- shown.
-
- #include "cmtprog.h"
-
- mainscore()
- begin
- repeat(i, 3)
- p1();
- when i == 2 then
- p2()
- otherwise
- endwhen
- p3()
- endrep
- end
-
- In this example, the phrase between otherwise and endwhen is nonexistent. That
- means that on the first and third times through, the complete phrase will be
- equivalent to p1(); p3(). On the second time through, the phrase will be
- equivalent to p1(); p2(); p3().
-
- 8.7. Parameters
- It's time to confess: there is really no difference between mainscore, note,
- up, and down. They are all procedures, and every procedure has a list of
- parameters, which can serve to modify its behavior. For example, the
- parameters to note tell the note procedure what pitch and duration to use. You
- can easily write your own procedures that have (more than zero) parameters.
- Study the newup procedure below, which plays C4 D4 E4 F4. The procedure has
- one parameter, called dur, which determines the duration of each note:
-
- #include "cmtprog.h"
-
- mainscore()
- begin
- newup(25);
- newup(50)
- end;
-
- newup(dur)
- begin
- note(48, dur);
- note(50, dur);
- note(52, dur);
- note(53, dur);
- end
-
- When mainscore is played, it first calls newup with the parameter 25. The
- computer will then find the definition of newup and notice that the parameter
- is to be named dur. Now, whenever the computer finds the name dur within
- newup, it will substitute dur's value (25). Thus, the duration specified for
- all of the calls to note will be 25, or one quarter second.
-
- After the fourth note is played, the computer returns to mainscore, where the
- next thing in the sequence is another call to newup. But this time, the
- parameter is 50. The computer goes through the same steps as before: it finds
- the definition of newup, associates the value of 50 with dur, and substitutes
- 50 for dur throughout the definition of newup. The result is that the four
- notes (C4 D4 E4 F4) are now played with durations of 50, or one half second.
-
- Parameters may be named with any string of letters, just like procedures. It
- is a good idea to use mnemonic names, that is, names that remind you of their
- purpose. It makes no difference to the computer, but when you start writing
- large programs, you will find that it is important to make programs readable
- and understandable.
-
- Important: When you use parameters, the number of parameters in the
- definition must match the number of parameters in the call. The order of
- parameters in the call determines which parameter gets which value. Neither of
- these properties are checked by the C compiler, so very strange things will
- happen if you make a mistake here.
-
- 8.8. Producing Chords
- The C language is called a sequential language because programs are executed
- in sequence, performing only one operation at a time. This is a big limitation
- for music, and the next chapter will present some solutions to the problems of
- using C. In the meantime, there is a fairly simple way to get two notes
- sounding at once. The procedure pnote is just like note except that pnote does
- not wait for the specified duration. Instead, it schedules the end of the note
- to happen in the future but returns immediately without waiting. The following
- procedure plays a minor chord with the specified tonic and duration:
-
- minor(tonic, duration)
- begin
- pnote(tonic, duration);
- pnote(tonic + 3, duration);
- note(tonic + 7, duration)
- end
-
- The first two notes of the chord are played using pnote. Since pnote returns
- immediately, all three notes start very close to the same time. The third note
- uses the note routine, which will delay for duration before returning. Thus
- the minor procedure will also take duration before returning.
-
- 8.9. Low-level Procedures
- Up until now, we have concentrated on writing programs that control the high
- level structure of your music. By now, I hope you are beginning to enjoy some
- of the power available to you as a computer programmer. Now, it is time to
- learn about the lower levels of control, which concern direct control over the
- synthesizer. I mentioned earlier that note is just a procedure. Here it is:
-
- note(pitch, duration)
- begin
- midi note(1, pitch, 100);
- rest(duration);
- midi note(1, pitch, 0);
- end
-
- The note procedure first uses the procedure midi note to start a note. The
- parameters are the MIDI channel number (1), the pitch, and the key velocity
- (100).
-
- The rest procedure stops the program for the length of time specified by
- duration. This sustains the note.
-
- The third procedure call is another call on midi note. The key velocity of
- zero (the third parameter) indicates to turn the note off.
-
- Incidentally, the Adagio program also uses the same midi note procedure. You
- can find the C programs that make up Adagio in the directory ``\cmt''.
-
-
-
- 8.9.1. Other Procedures and Functions
- A complete list of music functions and procedures are listed in the file
- \cmt\mpu.c and in Appendix I. A summary of some useful ones, as well as some
- useful C procedures are given below. Italicized parameters stand for numbers
- that you supply when you call the function.
-
- printf("this is a string\n");
- writes "this is a string" on the screen when called. The two
- characters \n should be included after the text you want
- written. This tells the computer to ``write'' a newline after
- writing the line of text.
-
- rest(duration); does nothing for duration (expressed in hundredths of seconds).
-
- getkey(waitflag);
- gets a keyboard event. Returns a the key number (numbered
- starting at 0) when a key is pressed, and the key number plus
- 128 when a key is released. If waitflag is not zero, getkey
- will wait for a key to be pressed. If waitflag is 0, getkey
- may return -1 to indicate no key has been pressed. Example
- return values and their meaning are -1: no key was pressed, 48:
- middle C was pressed, 176: middle C was released (176 = 128 +
- 48).
-
- midi note(channel, pitch, velocity);
- sends a MIDI note-on command. The parameters are the MIDI
- channel (from 1 to 16), the key number (from -12 to 115), and
- the key velocity (from 0 to 127). If the velocity is 0, then
- the note is turned off.
-
- midi program(channel, program);
- changes the synthesizer program (preset) to the one indicated
- in the second parameter. The first parameter is the MIDI
- channel.
-
- random(low, high);
- a function whose value is a random number between low and high
- inclusive.
-
- 8.10. Command Line Options
-
- - -debug (or -d): turn on debugging code.
-
- - -help: print a list of command line options.
-
- - -miditrace (or -m): turn on MIDI byte trace.
-
- - -trace (or -t): turn on music operation trace.
-
- - -block: turns off the MPU-401 MIDI THRU function so that the input is
- not passed to the output.
-
- - -tune filename: tells Adagio to use filename to specify tuning.
-
-
-
- 8.10.1. Examples
- Assuming you have compiled a program named foo,
-
- foo -help
-
- will print a list of command line options.
-
- To run foo with a tuning specified in myscale.tun, with a printout of music
- operations as they are performed:
-
- foo -tune myscale -t
-
- 8.11. Conclusions
- Becoming a master programmer is like mastering an instrument; it takes years
- of hard work. Fortunately, you can make a lot of good computer music without a
- degree in computer science[Of course, you can make a lot of bad computer music
- with a degree in computer science.]. If you are confused about some point or
- about how to implement an idea, ask someone for help. It is often useful to
- write small programs to test out ideas before you write a magnum opus. Write
- small procedures and test them before putting them into a large confusing
- program.
-
- If you want to learn more about programming, consider taking a computer
- science course if you haven't already. Your instructors can suggest textbooks
- if you want to study more independently. There are many programming concepts
- that I have not even touched in this quick introduction.
-
- I designed this system so that students could have all the flexibility
- offered by programming in order to create new music. Phil Miller showed me how
- to distill the important concepts to the point where basic programming skills
- can be developed in a few weeks. Now it's up to you: let there be music!
-
-
-
- 9. Moxc: real-time programming package
-
- It is the cause, it is the cause, my soul:
- Let me not name it to you, you chaste stars!
- It is the cause.
- Othello V.2
-
- 9.1. What is Moxc?
- Moxc is a set of C procedures to help the programmer write programs that
- perform many tasks simultaneously. The most important procedure is called
- cause, which allows you to make things happen not now, but in the future. Moxc
- is a compatible extension of all the programming constructs you learned in the
- last chapter.
-
- Moxc is derived from a system called Moxie, written by Douglas Collinge of
- the University of Victoria. The original Moxie runs on a Synclavier I, and
- another version exists as an extension to the Forth language.
-
- 9.2. An example
- The following example uses Moxc to implement a simple performance instrument.
- A blow-by-blow commentary follows the example:
-
- /* an example program using moxc */
-
- #include <\cmt\musiprog.h>
-
- keydown(c, k, v)
- begin
- pnote(k+12, 100);
- end
-
- asciievent(c)
- begin
- when c == 'q' then quit()
- endwhen
- end
-
- hello()
- begin
- printf("hello\n");
- cause(300, hello);
- end
-
- mainscore()
- begin
- hello();
- end
-
- The first line is an optional comment which is ignored by the compiler. The
- next line of text tells the compiler to include some definitions from a file
- called \cmt\musiprog.h as described in the last chapter.
-
- The procedure keydown is called automatically by Moxc whenever a keyboard key
- is pressed. Three parameters, the MIDI channel, the key number, and the key
- velocity are passed to keydown. When a key is pressed, k will have a value
- where 48 corresponds to middle C, 49 is C-sharp, and so on.
-
- The procedure pnote takes two parameters: pitch and duration, and it is the
- same procedure described in the last chapter (see Section 8.8. Notice how I
- added 12 to k in the first parameter position to make the pitch always one
- octave higher than the key that was pressed. The second parameter is always
- 100, for a duration of one second.
-
- The next procedure definition is for asciievent. This procedure is called
- whenever a character is typed at the computer. The character typed is passed
- as a parameter to asciievent. To denote a character value in C, you enclose
- the character in single quotes as shown in the example. The asciievent in the
- example only responds to one letter, 'q', which results in a call to quit, a
- built-in procedure that tells Moxc to halt execution. Notice that 'q' is
- written in single quotes to denote the letter ``q''. Without quotes, q would
- refer to a parameter or procedure name. The exact same asciievent procedure is
- provided by default if you do not provide your own.
-
- With just these two procedures, a simple instrument has been implemented
- which doubles every note up one octave, and holds the octave for one second.
- When using the DX7 and TX816, everything you play on the DX7 will be sent
- directly to the TX816 as well as to Moxc. Thus, you always hear what is being
- played on the DX7 combined with any notes played by your Moxc program. (Unless
- you use the -block option in the command line.)
-
- Moxc provides a few more features. Look at the next procedure definition,
- for hello. The hello procedure prints ``hello\n'' on the terminal. (The
- ``\n'' code at the end means type a newline, putting the cursor at the
- beginning of the next line.) The next line is the interesting one: cause(300,
- hello); means that Moxc should, after 300 time units, cause the procedure hello
- to be called. In other words, travel 3 seconds into the future, call hello,
- and return to the present. In effect, we have realized time travel in the
- computer! If this makes you uncomfortable, what really happens is that Moxc
- saves a record of the procedure to be called, the time to call it, and any
- parameters that should be passed to it. When the time comes, the call is made
- automatically by Moxc. In the case of hello, the effect is that every 3
- seconds, ``hello'' is printed on the screen, and the performer may be
- simultaneously playing the keyboard. Why does hello print ``hello''
- repeatedly? Because after each printing, hello uses cause to schedule another
- call to hello in the future. This call will schedule yet another call, and so
- on.
-
- How does hello ever get started? It won't, unless someone calls it for the
- first time. This is done in mainscore, which is always called once at the
- beginning of the program, and therefore must be present in your program.
-
- 9.3. Compiling
- There are three simple steps to take you from a text file (created with the
- editor) to a running program. Let us assume your file is called test.c:
-
- 1. Compile your program by typing cmtc test.c. Any detected errors
- will be listed on the screen and must be corrected before the next
- step.
-
- 2. Link your program by typing cmtl test, without the ``.c''!
-
- 3. Run your program by typing test.
-
- That's all there is to it. You must repeat all three steps each time you
- edit your file.
-
- 9.4. More about cause
- What would have happened if mainscore (above) would have called hello twice?
- Would the characters ``h e l l o'' get scrambled together? Would ``hello'' be
- printed once or twice every three seconds? Would the computer get confused and
- blow up? In fact, what happens in Moxc is that every procedure runs to
- completion before any other procedure is called. If a procedure calls another
- directly, such as mainscore calling hello, then the caller is suspended as
- usual until the callee completes. Thus, if there were two calls to hello, they
- would execute in sequence, and letters would not be scrambled.
-
- Now, each of the calls to hello would also issue a call to cause, so Moxc
- would have two records telling it to call hello again at time 300. The Moxc
- system picks one of the two records at time 300 and calls hello. When this
- instance of hello completes, Moxc notices that there is another record for a
- call to hello at time 300 and makes that call too. By this time, Moxc has
- probably fallen behind schedule. In general, Moxc will call procedures as soon
- after the indicated time as possible. This time will be quite accurate unless
- something is keeping the computer very busy.
-
- The current version of Moxc will quit automatically when it has nothing
- scheduled to do. It will then prompt you to see if you want to run your
- program again. This can be rather annoying if you plan to give it something to
- do in the future, say by playing a note on a keyboard. The program example
- shows how a hello procedure can be used to make sure that Moxc is always
- waiting to do something (call hello), thus being content to run forever. Also,
- I find it helpful when debugging to be able to look at the screen and know Moxc
- is running normally, as indicated by the hello messages. The other way to halt
- Moxc is to call the quit procedure[You can also type CONTROL-C or CONTROL-BREAK
- to kill almost any process.]. This will abort any requests to cause procedure
- calls.
-
- You can pass parameters through cause to a future procedure call by listing
- up to 8 of them after the procedure name. Here is a version of hello that
- prints the number of times it has been called:
-
- hello(i)
- begin
- printf("hello: %d\n", i);
- cause(300, hello, i+1);
- end
-
- On each call to hello, i is created anew with a value that is one greater than
- the value of i in the previous call to hello. To print the value of i, the
- characters "%d" are placed anywhere within the first (string) argument to
- printf, and the number to be printed is passed as the second argument. The
- procedure printf will replace %d by a decimal representation of the number as
- it prints the string. If you do not understand this last example (it is not
- simple!), you will probably have trouble writing Moxc programs, so please ask
- your instructor for a more detailed explanation.
-
- The cause procedure does not use a fast algorithm for scheduling future
- events. In fact, cause does not really schedule anything; it merely puts
- events on a list of events to be scheduled at some later time. For every
- waiting event Moxc runs, Moxc takes at least one event from the list of events
- created by cause and inserts it into another list of events that are waiting to
- run. This waiting list is ordered by event time. If there are hundreds of
- events in the list and Moxc has to insert an event at the end (because the
- event happens later than the others), Moxc may delay a noticeable amount of
- time. So far, this behavior has been rather interesting, so no attempts have
- been made to make Moxc faster or more accurate under heavy loads.
-
- 9.5. Event Handlers
- Event handling procedures were described in the example above, including
- keydown and asciievent. A complete list of these is given below. If your
- program does not provide an event handler, the cmtl (link) step of preparing
- your program will provide a default handler which does nothing except for
- asciievent, which is given in the example above.
-
- asciievent(k) action for terminal input, k is the ascii key code.
-
- bendchange(ch, val)
- pitch bend handler; ch is the channel, and val is the new
- value.
-
- ctrlchange(ch, c, val)
- control change handler; ch is the channel, c is the control
- number, and val is the new value.
-
- keydown(ch, p, v)
- MIDI note on handler; ch is the channel, p is the pitch code
- (48 = middle C), and v is the velocity.
-
- keyup(ch, p) MIDI note off handler; ch is the channel, and p is the pitch
- code..
-
- mainscore() first action(s). This ``event'' is called once at the
- beginning of execution.
-
- peddown(ch) sustain pedal down handler; ch is the channel.
-
- pedup(ch) sustain pedal up handler; ch is the channel.
-
- touchchange(ch, val)
- aftertouch handler; ch is the channel, and val is the value.
-
- 9.6. Command Line Options
- The following options can be specified in the command line:
-
- - -debug (or -d): turn on debugging code.
-
- - -help: print a list of command line options.
-
- - -miditrace (or -m): turn on MIDI byte trace.
-
- - -trace (or -t): turn on music operation trace.
-
- - -block: turns off the MPU-401 MIDI THRU function so that the input is
- not passed to the output.
-
- - -tune filename: tells Adagio to use filename to specify tuning.
-
-
-
- 9.6.1. Examples
- Run Moxc program named echoes[Note that echo is a special DOS command, so
- that is why I named this program echoes. The echoes program and its source
- code are included on the CMT disks.]:
-
- echoes
-
- Run the echoes program with tuning file scale23.tun:
-
- echoes -tune scale23
-
-
-
- 10. 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
- I.
-
- 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.
-
- 10.1. Introduction
- 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.
-
- 10.2. Basic MIDI interface
- All programs in CMT that send or receive MIDI use the module mpu.c, which
- provides an interface between C programs and the MPU-401 MIDI Processing Unit.
- In theory, mpu.c could be replaced by another software module designed for
- another hardware MIDI interface.
-
-
-
- 10.2.1. Interface design issues
- A few words about the overall design of this interface are in order. To
- begin with, mpu.c is neither a complete interface to the MPU-401 nor to MIDI.
- Instead, 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 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 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 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 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.
-
- 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.
-
-
-
- 10.2.2. Interface implementation
- The mpu.c module is primarily responsible for MIDI output. For example, the
- midi note routine sends commands and data to the MPU-401 to cause it to send a
- MIDI note-on command. In contrast, mpu.c never reads data directly from the
- MPU-401. Input is handled by the interrupt handler in aintr.asm.
-
- The interrupt handler (aintr.asm) is invoked 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
- mpu.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. The aintr.asm module also
- receives acknowledgments for commands sent by mpu.c. Since mpu.c cannot read
- these acknowledgments directly (it might read a MIDI message), mpu.c waits for
- a global variable to be changed by aintr.asm when it wants to get an
- acknowledgment.
-
- A final function of aintr.asm is maintaining the time. In the current
- implementation, time is maintained in the MPU-401 by chosing a tempo that
- results in 400 ticks per second. Whenever the 8-bit timer overflows in the
- MPU-401, a timer overflow message is sent to aintr.asm, which increments a
- 32-bit time accumulator. The MPU-401 timer value is sent with each MIDI input
- message and the timer is then cleared. Therefore, aintr.asm must strip off the
- time from each MIDI input message and add it to the time accumulator as well.
- At all times, the current time is the sum of the 32-bit time accumulator and
- the 8-bit timer inside the MPU-401. Therefore, to get an accurate time
- reading, one must force the MPU-401 to send the value of its counter.
- Fortunately, there is an MPU-401 command for this. When a user calls gettime
- in mpu.c, the command is sent to the MPU-401, which responds by sending its
- counter value. This value is added to the time accumulator by aintr.asm. The
- gettime routine can then read the accumulator, which is now up to date, shift
- it right 2 bits to divide by 4, and return the result, which is absolute time
- in hundredths of seconds.
-
- A new timer has been implemented using the real-time clock on the IBM-PC.
- The new timer code is not compatible with an IBM-AT. This new code should
- reduce some of the load on the MPU-401 when the host computer needs to poll
- gettime. This timer is included in the first release of the system and can be
- enabled by defining TIMDIF in mpu.c and recompiling it. You will find the
- definition of TIMDIF commented out in the file mpu.c. Notice that with a
- little coding, one could get the MPU-401 to synchronize its internal clock to
- an external tape machine. In the hopes that someone will actually extend CMT
- to implement tape synchronization, the code that uses the MPU-401 timer will be
- left in the system even if it is disabled.
-
-
-
- 10.2.3. 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 an
- IBM XT could not 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 buffer) through which a user of mpu.c
- can provide a special buffer to be used by system exclusive messages. Most
- programs use the MPU-401 to filter out these messages, so what to do with them
- is not usually an issue. If exclusive messages are enabled and no buffer is
- supplied for them, mpu.c throws them away.
-
- 10.3. Command line parsing
- The module cmdline.c implements an interface to the command line, that is,
- the line that the user types to the operating system to start a program. There
- are several conventions enforced by cmdline.c. A command line must consist of
- three types of entities which must be separated by one or more blanks. In
- order to describe them, I have given the entities names, although they are not
- terribly mnemonic:
-
- 1. A switch is a sequence of non-space characters that begins with a
- dash (``-''). Normally, a switch is used to enable or disable some
- function in the program. An example is the ``-help'' switch, which
- causes most CMT programs to print a help message and quit.
-
- 2. An option looks just like a switch except it is followed by another
- sequence of non-space characters that do not begin with a dash.
- Options are used to give additional information to the program. An
- example is ``-tune myscale.tun'', which tells mpu.c to load the
- tuning definition file myscale.tun.
-
- 3. An argument is a sequence of non-space characters that do not begin
- with a dash. Arguments are usually pieces of information the
- program expects. An example is in the command line ``adagio bach'':
- ``Adagio'' is the command name, and ``bach'' is an argument, which
- in this case specifies a score file.
-
- Both switches and options are referred to in earlier chapters as ``command line
- options''. Switches, options, and arguments can be placed in the command line
- in any order, with the exception that arguments are numbered in the order in
- which they appear from left to right. An example of a command with several
- switches and arguments is:
-
- transcri -tune myscale -control off -block foo
-
- Taken one at a time, the entities in this command line are:
-
- - transcri is the name of the command.
-
- - -tune myscale is an option specifying a tuning definition file.
-
- - -control off is an option telling transcri to ignore control change
- data.
-
- - -block is a switch which turns off the internal MIDI thru of the
- MPU-401.
-
- - foo is an argument specifying a score file. Notice that ``-block
- foo'' has the same syntax as an option, but since -block is a switch,
- foo must be an argument.
-
- This module provides the following functions:
-
- - Syntax checking. The entire line is checked to make sure every token
- is recognized.
-
- - Testing for switches and options. Functions are provided to test
- whether the user typed a switch or option.
-
- - Argument access. Command line arguments can be retrieved by number.
- (The first argument after the command is argument number 1.)
-
- - Consistency checking. All legal switches or options must be declared
- when the cmdline.c module is initialized. Attempts to look up a
- switch or option that was not part of the initial declaration are
- detected and cause an error message.
-
- The only aspect of cmdline.c that is likely to be confusing is the
- initialization and consistency checking. Notice that a switch followed by an
- argument is syntactically identical to an option. Thus, cmdline.c must know in
- advance the complete list of switches and options in order to parse the command
- line. It is illegal for a switch to have the same name as an option, because
- this could lead to an ambiguous parse. Therefore, cmdlne.c must be initialized
- with a list of switches and a separate list of options.
-
- This is a somewhat error-prone operation because cmdline.c can be (and is)
- used by many modules, but there is no convenient way in C for these modules to
- make known what switches and options they look for. For example, suppose you
- write a program that uses cmdline.c and mpu.c. You initialize cmdline.c,
- passing it several switches and the ``-aardvark'' option, but you forget that
- mpu.c looks for a ``-tune'' option. Consequently, cmdline.c does not have
- enough information to properly parse the command line. Even worse, your
- program is booby-trapped! As soon as some poor sole tries to use the ``-tune''
- option, cmdline.c will report a syntax error. As far as it knows, ``-tune'' is
- not a valid switch or option.
-
- Fortunately, the situation is not as bad as it looks, because cmdline.c
- performs some internal consistency checks automatically. What will happen in
- this example is that as soon as mpu.c is initialized, it will go out and look
- for the ``-tune'' option by calling the appropriate routine in cmdline.c (cl
- option(), for example). Before searching the command line, cmdline.c checks to
- see if ``-tune'' is in its list of valid options. It is not, so cmdline.c
- prints an error message:
-
- internal error detected by cmdline module:
- '-tune' should be in valid lists
-
- Thus you, the implementor, will get a clear message that you made a mistake,
- and you will get the message whether or not ``-tune'' appears on the command
- line. If it is not obvious where the message came from, you can use grep to
- search the source code of all the modules you use for the string ``-tune''.
- That would tell you that ``-tune'' is an option used by the mpu.c module.
-
- In the best of all worlds, it should not be necessary for the implementor to
- keep track of options and switches used in other modules, but this is the best
- compromise I could come up with.
-
- 10.4. The record module
- Two programs in CMT record data from the keyboard and write Adagio scores.
- These are the transcri and record programs. Both programs use the record.c
- module to do most of the work. The interface to record.c is fairly simple.
- The routine rec init is called to initialize the module. Then rec poll is
- called (frequently) for the duration of the recording ``session''. This
- routine reads data from the input buffer and stores it in a data structure
- along with timing information. When the recording is finished, rec final is
- called to write the data to a file.
-
- Several tricks are used to improve the performance of record.c. First, the
- program does not try to record a time for every input event. This would waste
- processor time when bursts of data arrive. Instead, the current time is
- recorded only when something is found in the input buffer. Then the buffer is
- read until it is empty and all buffered events are assigned the same time.
- Thus, buffer reading occurs at maximum speed when bursts arrive.
-
- A second optimization deals with the form of the output file. It has been
- found that a DX7 will send large amounts of control information, particularly
- aftertouch data. The rec final routine filters the recorded data so that a
- given control will not change more than once per 0.01 second time period. This
- reduces the size of the output file, reduces the amount of data to be stored by
- the Adagio program, and has a minimal impact on the accuracy of reproduction.
-
-
-
- 11. What next?
- A number of improvements remain to be made to the CMU MIDI Toolkit. To
- encourage others to make these improvements, CMT is distributed with source
- code and documentation. In addition, the Center for Art and Technology at
- Carnegie Mellon University will help coordinate and integrate changes to this
- software. If you develop a new tool or enhance an existing one, you can
- incorporate it into CMT by sending it to me (Roger B. Dannenberg) at the Center
- for Art and Technology. Provided the changes or additions are consistent with
- the goals of CMT, I will integrate them into the next release and redistribute
- your code to other users. Thus others will benefit from your efforts as I hope
- you have benefited from mine.
-
- The following sections outline changes I would like to see in the CMU MIDI
- Toolkit. If you decide to tackle one of these, it might be a good idea to call
- me at (412) 268-3827 or write to find out if anyone else is working on the same
- thing.
-
- 11.1. Microsoft C conversion
- The current version of CMT uses the Lattice C compiler. Work is in progress
- to make CMT compatible with both Lattice and Microsoft C.
-
- 11.2. Large memory model conversion
- The most serious problem with CMT at the moment is that it was designed for
- use with the ``small memory model''. This means that only 16 bits are used to
- address code and data, so not all of the available memory can be used. This is
- a problem that limits Adagio to less than 4 thousand notes. To use another
- memory model, one would have to recode some of the assembler routines
- (particularly aintr.asm) to get the right values into the segment registers.
-
- 11.3. Multiple Midi Interfaces
- Another limitation of CMT is that it supports only one MPU-401. There are
- two reasons for using more than one. First, you might want to have more than
- one MIDI input to the system. A keyboard like the KX88 will ``mix'' the data
- it generates with its MIDI Input to form the MIDI Output. Thus, you can get
- input from a KX88 and at least one other device by connecting them in series.
- However, most MIDI devices cannot ``mix'' MIDI data, so one might want to have
- several MIDI interfaces to get input from several controllers. Notice that
- input data can be ``mixed'' internally by the IBM PC, and there is no reason to
- distinguish which physical input is the source of a given piece of data.
-
- The second reason for multiple interfaces is to overcome the maximum of 16
- MIDI channels or to obtain higher speed. A reasonable thing to do in this case
- is to implement ``logical'' MIDI channels. Logical channels 1 through 16 would
- correspond to MIDI channels 1 through 16 on the first MPU-401. Logical
- channels 17 through 32 would correspond to MIDI channels 1 through 16 on the
- second MPU-401, and so on. This presents no problems for Adagio, but there is
- a lot of CMT software that assumes only 4 bits are needed to store a channel
- number. Implementing logical channels is more work than the mixing idea
- described in the preceding paragraph.
-
- 11.4. Improve Adagio compilation (sorting) speed
- Currently, Adagio keeps a linked list of notes and control changes sorted by
- start time. If scores are roughly in time order, the performance is good.
- However, if a score is constructed by concatenating several files created using
- transcri or record, then notes are not in order and Adagio can spend several
- minutes loading a score. I believe this can be solved by two transformations.
- First, change the insert routines to insert notes in forward rather than
- reverse time order and take out the code that reverses the final score.
- Second, keep a pointer to the last point at which a note was inserted. When
- you go to insert a note, try searching forward from the saved pointer. Only if
- this fails should you search from the beginning of the list. The resulting
- program will still perform badly on perverse scores, but the expected
- performance should be quite good on normal scores.
-
- 11.5. Multi-track recording
- Not everyone has enough equipment to play an entire score, and not all scores
- will fit into the available memory. A solution to these problems is to use a
- multi-track recorder and to record a composition one track at a time. To do
- this, one must be able to enable one Adagio voice at a time. I suggest adding
- an option to the Adagio (and Record) command line of the form
-
- -v 1,5
-
- which would mean play only voices (MIDI channels) 1 and 5. Notes and control
- events on other channels would not be saved in memory for playing, so this
- facility would help get around memory restrictions.
-
- For long works and pieces where close synchronization of parts is important,
- it is essential to have some means of synchronizing Adagio output with a tape
- recorder. The MPU-401 has a tape-sync input and output which could be used for
- this purpose. Probably, a command-line switch (``-sync'') should be read by
- mpu.c. When the switch is present, mpu.c should tell the MPU-401 to
- synchronize to the tape input. Notice that CMT has optional code to derive
- time from the internal IBM-PC timer rather than the MPU-401. If that is the
- case, then the ``-sync'' switch should either cause mpu.c to revert back to the
- MPU-401 or there should be some way to cause MPU-401 clock input data to
- resynchronize the internal IBM-PC timer.
-
- 11.6. MIDI Continuous Controls
- Adagio supports the notion of continuous controls through its control change
- commands, but these are presently very limited. Three enhancements should be
- made. First, it should be possible to program how control change commands in
- Adagio are mapped into MIDI control change commands. For example, one might
- want to use the X command to send breath-controller values. This could be
- implemented by having an optional control specification file, just as there is
- now an optional tuning specification file. The same file format should be used
- by transcri and record to determine how Adagio scores are produced from MIDI
- input. One could use this same facility to tell record and transcri to ignore
- certain control information. For example, if no command is assigned to control
- aftertouch, then aftertouch data would be ignored in the recording
- (transcription) process.
-
- A second change would be to add new commands to Adagio to allow users to
- specify smooth, continuous changes without a huge amount of typing. This could
- be done by implementing a new special command. For example,
-
- !ramp x0 x100 q.
-
- would mean change the X control smoothly from 0 to 100 in the time of a dotted
- quarter note. This command would be translated into a single Adagio event and
- the stream of control change data would be computed from the event data in real
- time. Thus, in addition to save typing, the scheme would save on memory space
- wherever these special commands could be used in place of many control change
- commands.
-
- Finally, it would be very interesting to look into using control changes to
- modify MIDI programs in real-time. For example, you can put a DX7 in a mode
- where the inharmonicity of a tone can be controlled by a slider on the DX7
- control panel. By using system exclusive messages, one can control the
- inharmonicity by computer. The missing link here is to make the control
- specification file flexible enough that one can use Adagio to send system
- exclusive messages as well as conventional control change commands. It might
- be helpful to add yet another command to Adagio to send system exclusive
- messages directly.
-
- 11.7. Interacting with Moxc programs
- Every Moxc program I write has a big asciievent routine that calls different
- routines and sets values depending upon characters that get typed at run time.
- It should be possible to write a routine that could read the map file produced
- by the linker and figure out where variables and procedures are located. Then,
- a user interface could be designed such that you could type
-
- seti foo 2006
- call bar 100 572
-
- in order to set the integer foo to 2006 and then call procedure bar with
- parameters 100 and 572.
-
- 11.8. Code to play sequences from Moxc
- It is hard to write Moxc programs that play sequences of notes, and it would
- be nice to be able to write sequences in Adagio and trigger them in real time
- Moxc programs. I designed a module for this and wrote most of the code, but I
- have not tested anything yet. The idea is to use a modified Adagio to read
- scores and transform them into data files that can be input easily without
- resorting to a full-blown Adagio translator. Routines are then provided to
- read and play these sequences. Several parameters including transposition and
- rate can be changed in real-time to modify the performance of the sequence.
- The interface is as follows:
-
- seq read(name, filename);
- reads the sequence in file filename. Sequences are named
- internally by small integers, and name is the integer to
- associate with this sequence.
-
- seq play(name); plays sequence associated with the integer name.
-
- seq transpose(name, transposition);
- sets the transposition of the sequence associated with name to
- transposition.
-
- seq rate(name, rate);
- sets the rate of the sequence associated with name to rate. A
- rate of 100 gives the normal rate as specified in the Adagio
- file that generated the sequence.
-
- seq cycle(name, flag);
- sets the cycle flag of the sequence associated with name to
- flag. If the flag is non-zero, then the sequence will repeat
- (cycle) indefinitely.
-
- seq pause(name, flag);
- sets the pause flag of the sequence associated with name to
- flag. If the flag is non-zero, the sequence performance will
- be suspended until the flag is set to zero.
-
- seq at end(name, procedure);
- will cause the routine named by procedure to be called at the
- end of the performance of the sequence associated with name.
-
- This implementation of this interface is quite compact. A drawback is that
- there is no provision for recording sequences in real-time within the context
- of Moxc, so some more thinking and experimentation is probably in order. It
- has also been suggested that one should be able to combine rhythm from one
- sequence with pitches from another.
-
- 11.9. A player module
- Currently, Adagio and Record are very similar. The main difference is that
- in phase 2, in which Adagio plays a score, Record plays a score and calls on
- record.c to record MIDI input. It would be nice to design a module player.c
- that both Adagio and Record could call on to play a score. This would
- eliminate a lot of redundant code and would insure consistency between Adagio
- and Record when changes are made.
-
- For example, one might want to allow users to transpose scores, change the
- playback speed, and make other changes without editing the score. At present
- these sorts of changes would have to be made in both phase2.c for Adagio and
- trans2.c for Record.
-
- 11.10. User-defined note routines for Adagio
- Not only would it be nice to be able to invoke Adagio-defined sequences from
- Moxc, it would also be nice to be able to invoke Moxc routines from Adagio
- scores. One way to do this would be to separate the Adagio note-playing
- routines into a separate module. Then users could write their own note
- routines that would get parameters from Adagio scores, but that might have some
- complex behavior. For example, one could write a routine that produced drum
- rolls consisting of many MIDI notes, but which could be invoked by a single
- line in Adagio. One would have to be careful to smoothly integrate Adagio and
- Moxc; perhaps Adagio should be modified to use Moxc for its own scheduling.
-
- 11.11. DX7 Program Librarian
- In Adagio, one specifies timbre by numbers that correspond to MIDI programs.
- It is up to the user to make sure the proper programs are loaded into the
- synthesizer in the right locations. It would be nice to be able to write a
- file like
-
- Channels ProgramNumber ProgramName
- 1-8 1 marimba
- 1 2 harp
- 2 2 celeste
- 3-8 2 strings
-
- which would specify a correspondence between program numbers and program names.
- One could write a Program Librarian that could read such a file and use it to
- load up a TX816 or whatever with exactly the right programs for a particular
- piece. The program names would correspond to file names.
-
- 11.12. An Adagio editor
- It might be interesting to be able to extract sections of Adagio scores,
- stretch them, transpose them, copy them, merge them with other files, and so
- on. This can be done with a text editor, but a specialized editor,
- particularly one that could play the files as it edits them, might be more
- effective. Another idea for an editor is to try to use a combination of typed
- text and MIDI input to speed up the process of entering scores. This is a
- largely unexplored area that has applications in music typography systems as
- well as CMT.
-
- 11.13. Interface to XLISP
- An interpretive language like LISP can be an excellent teaching and composing
- tool. XLISP is a version of LISP implemented in C and in the public domain.
- It should be fairly simple to provide a LISP interface to mpu.c, allowing XLISP
- programs to make music.
-
- 11.14. A Sequencer
- Everyone else writes sequencers. Why not build one for CMT? This would be
- the first MIDI sequencer for small machines that users could modify to suit
- their special needs.
-
- 11.15. Ports
- There is very little in CMT that is specific to the IBM PC. It should not be
- too difficult to get CMT running on the Macintosh, Amiga, Atari, and other
- small machines. Work is under way at Brown University and Carnegie Mellon to
- port CMT to an IBM RT as well.
-
-
-
- I. The MIDI Interface
- This appendix contains documentation for calls in the module mpu.c. Type
- boolean is an int that takes on values of true or false, and type byte is an
- unsigned char.
-
-
- exclusive(onflag)
- boolean onflag;
- This procedure tells the MPU-401 to read exclusive messages into the
- buffer provided by a previous call to midi buffer. onflag is set to true
- to receive MIDI exclusive data, otherwise it is set to false.
-
-
- boolean getbuf(waitflag, p)
- boolean waitflag;
- byte * p;
- getbuf copies 4 bytes of data from buffer (the MIDI input buffer filled by
- the interrupt handler in aintr.asm) to *p. It will wait for buffer to
- become nonempty if and only if waitflag is true. It returns true if data
- was written to *p, and false if data was not written to *p.
-
-
- int getkey(waitflag)
- boolean waitflag;
- getkey tries to read a key. It returns the key number of the key which
- has been depressed, or the key number plus 128 of a key which has been
- released. It returns -1 if waitflag is false and no key has been pressed.
- If waitflag is true this routine will block until a key is pressed. Since
- getkey uses getbuf (see above), non-key events (e.g. pitch bend) may be
- read and discarded by getkey.
-
-
- long gettime()
- Return the time in 100ths of seconds since the last call to musicinit or
- timereset.
-
-
- l rest(time)
- long time;
- l rest waits until the amount of time specified by time has elapsed.
-
-
- l restuntil(time)
- long time;
- l restuntil waits until the specified time has been reached (absolute time
- as returned by gettime).
-
-
- metronome(onflag)
- boolean onflag;
- metronome enables (true) or disables (false) MPU-401 metronome function,
- as indicated by onflag. This procedure must be called before musicinit.
- The metronome is not started until musicinit is called.
-
-
- midi bend(channel, value)
- int channel;
- int value;
- Sends a MIDI pitch bend message; channel is the MIDI channel on which to
- send data, and value is the pitch bend value from 0 to 16383. The value
- 8192 is the value representing no pitch bend; smaller values bend pitch
- down, and higher values bend pitch up.
-
-
- int xbuffhead, xbufftail;
-
- int midi buffer(buffer, size)
- byte * buffer;
- int size;
- midi buffer tells interrupt routine to store system exclusive messages in
- buffer. The largest power of 2 bytes less than size will be used (a power
- of 2 is used so that masking can be used to cause wrap-around). xbuffhead
- and xbufftail will be initialized to zero, and xbufftail will be one
- greater than the index of the last system exclusive byte read from mpu401.
- midi buffer returns false if size is less than 16 or buffer is NULL,
- otherwise true.
-
-
- midi cont(onflag)
- boolean onflag;
- midi cont enables (true) or disables (false) continuous control info from
- the MPU-401 to the host, depending on the value of onflag.
-
-
- midi ctrl(channel, control, value)
- int channel;
- int control;
- int value;
- Sends a MIDI control change message; channel is the MIDI channel on which
- to send data, control is the control number, and value is the control
- value.
-
-
- midi exclusive(msg)
- byte * msg;
- Sends a MIDI exclusive message; msg is a pointer to a MIDI exclusive
- message, terminated by 0xF7.
-
-
- midi note(channel, pitch, velocity)
- int channel;
- int pitch;
- int velocity;
- Sends a MIDI note-on request out; channel is the MIDI channel on which to
- send data, pitch is the MIDI pitch code, and velocity is the velocity with
- which to sound it (0 means release). If read tuning has been called to
- define a tuning and velocity is not zero, then this procedure sends a
- pitch bend followed by a note-on message. The pitch bend and the note-on
- pitch are found by table lookup, using pitch as the table index. For zero
- velocity, the table lookup is done to get the pitch for a note-on message
- with zero velocity. No pitch bend message is sent since zero velocity
- means note-off.
-
-
- midi program(channel, program)
- int channel;
- int program;
- Sends a program change request; channel is the channel on which to send
- the MIDI program change request, and program is the program number to send
- (this number is decremented by 1 before being sent as MIDI data, so values
- should be in the range of 1 to 128.)
-
-
- midi thru(onflag)
- boolean onflag;
- Enables (true) or disables (false) MIDI thru info from MPU-401 to host,
- depending on the value of onflag. The default is enabled, but the command
- line switch -block will cause it to be disabled initially.
-
-
- midi touch(channel, value)
- int channel;
- int value;
- Sends a MIDI after touch message; channel is the MIDI channel on which to
- send data, and value is the after touch value.
-
-
- mpu error check()
- Reports any errors originating in the interrupt handler by printing them
- on stdout. If you do not call this routine, you do not find out about the
- errors.
-
-
- mpuexists(flag)
- boolean flag;
- If argument is false, this indicates no MPU-401 is on the machine, so
- simulate the mpu-401 (for debugging only).
-
-
- read tuning(filename)
- char *filename;
- Reads tuning information from filename and enables pitch bend to be sent
- by midi note to effect detuning.
-
-
- musicinit()
- Initializes the MPU-401 device driver and resets the MPU-401. The clock
- (see gettime) is reset to zero.
-
-
- musicterm()
- Cleans up; disables MPU-401 interrupts; resets MIDI devices. Call this
- upon finishing execution.
-
-
- int random(lo, hi)
- int lo, hi;
- Returns a pseudo-random number between lo and hi inclusive (lo <= result
- <= hi). This routine is reasonably fast, but it should not be trusted to
- be very ``random''.
-
-
- timereset()
- Resets the time on the MPU-401. The time returned by gettime is reset to
- 0.
-
-
- trace(flag)
- boolean flag;
- Turns tracing on (if flag is true) or off (if flag is false). Calls to
- mpu.c are traced.
-
-
- tracemidi(flag)
- boolean flag;
- Turns MIDI tracing on (if flag is true) or off (if flag is false). MIDI
- output bytes are printed.
-
-
-
- II. List of Files in CMT
- The following files are included in CMT. (The number following the file is
- its size in bytes. This data was obtained from the DOS directory command.)
-
- Volume in drive A is CMT DISK 1
- Directory of A:\
-
- README 508
- TUNING EXE 21072
- TRANSCRI EXE 27616
- MM EXE 24568
- RECORD EXE 36674
- DXPUT EXE 25110
- DXGET EXE 25834
- ADAGIO EXE 33320
- EXPORT BAT 709
- TEST <DIR>
- CMTL BAT 61
- CMTC BAT 18
- BIN <DIR>
- 13 File(s) 19456 bytes free
-
- Volume in drive A is CMT DISK 1
- Directory of A:\bin
-
- . <DIR>
- .. <DIR>
- MAKEEXE EXE 19200
- MAKE MAN 7595
- MAKE BAT 128
- GREP EXE 22400
- LS EXE 18176
- 7 File(s) 19456 bytes free
-
- Volume in drive A is CMT DISK 1
- Directory of A:\test
-
- . <DIR>
- .. <DIR>
- WIDE TUN 1276
- BACH GIO 5154
- STTHOMAS GIO 5143
- CONTIN GIO 172
- SCALE GIO 128
- ALL GIO 110
- RETUNE EXE 25974
- ECHOES EXE 25974
- 10 File(s) 19456 bytes free
-
- Volume in drive A is CMT DISK 2
- Directory of A:\
-
- MAKEFILE 5612
- MOXCPRGM C 95
- ADASPACE C 417
- RECMAIN C 4259
- RECORD C 18538
- TRANS2 C 10610
- USERIO C 4804
- MOXCTOUC C 97
- MOXCPDUP C 75
- MOXCPDDN C 79
- MOXCKYUP C 79
- MOXCKYDN C 86
- MOXCCTRL C 102
- MOXCASCI C 151
- MOXCBEND C 95
- CINTR C 9897
- NOTEOFF C 4504
- TRASPACE C 415
- MPU C 33966
- ADAGIO C 4236
- PHASE1 C 34033
- PHASE2 C 10380
- MM C 4485
- CMDLINE C 10779
- MOXC C 15736
- TUNING C 10005
- TRANSCRI C 5071
- RECSPACE C 420
- EXCLDESC C 1437
- DXGET C 6766
- DXPUT C 7536
- TIMDIF H 18
- CEXT H 141
- MOXC H 80
- TRANS2 H 16
- ADAGIO H 1192
- ATXT H 85
- CMDLINE H 121
- MAXSPACE H 280
- MIDICODE H 553
- MOXCPROG H 656
- MPU H 703
- MUSIPROG H 1039
- PHASE1 H 77
- PHASE2 H 71
- PITCH H 112
- RECORD H 62
- USERIO H 51
- CINTR H 149
- CMTPROG H 1060
- TIMDIF ASM 13318
- AINTR ASM 14949
- BREAK ASM 8292
- ATXT ASM 877
- CMT LNK 177
- MOXC OBJ 4471
- TIMDIF LIB 18
- MACSYM LIB 5006
- PRCSYM LIB 8399
- CMT LIB 27648
- DOS MAC 2059
- TEST <DIR>
- 62 File(s) 15360 bytes free
-
- Volume in drive A is CMT DISK 2
- Directory of A:\test
-
- . <DIR>
- .. <DIR>
- MOXCTEST C 1919
- ECHOES C 356
- PROG C 758
- RETUNE C 491
- 6 File(s) 15360 bytes free
-
-
-
- Index
- Accidentals 4
- Adagio 4
- Aftertouch 6
- Alternatives 14
- Amiga 21
- Append 11
- Asciievent 16, 20
- Asterisk 4
- Atari 21
- Attributes 4
-
- Backing up files 3
- Backup 3
- Bartok 5
- Begin 13
- Bendchange 16
- Blank 4
- Brown University 21
-
- Case 4
- Cause 16
- Character value 16
- Chord 14
- Clean 3
- Cleanobjs 3
- Cmtc 13
- Cmtl 13
- Cmusic 4
- Collinge, Douglas 16
- Commas 6
- Comment 4, 13
- Compiler 13
- Compiling 16
- Conditionals 13
- Copy 3, 11
- Ctrlchange 16
-
- Debug 20
- Debugging 6, 16
- Default 5
- Default durations 5
- Default time 4
- Dot 4
- Drum rolls 21
- Duration 4
- DX7 4, 21
- DXGet 12
- DXPut 12
- Dynamic markings 4
-
- Editor 21
- Eighth note 4
- End 13
- Endwhen 14
- Equal temperment 8
- Equal to 14
- Errors 1, 13
- Event handler 16
- Everything 3
- Exclamation point 4
- Exclusive 22
-
- F 4
- FF 4
- FFF 4
- Fileopen 3
- Files 3
- First ending 14
- Flat 4
- Flexible disks 3
- Floppy disks 3
- Foot pedal 6
- Future 16
-
- Getbuf 18, 22
- Getkey 14, 18, 22
- Gettime 18, 22
- Greater than 14
- Grep 3
-
- H 4
- Halt 16
-
- I 4
- IBM RT 21
- Include 13
- Insert 11
- Interrupt handler 18
-
- J 6
-
- K 6
- Keydown 16
- Keyup 17
-
- L 4
- L rest 22
- L restuntil 22
- Large memory model 20
- Lattice C 20
- Less than 14
- Link 13
- LISP 21
- Loudness 4
- Loudness, velocity 4
- Ls 3
-
- M 6
- Macintosh 21
- Mainscore 13, 17
- Make 3
- Makefile 3
- Memory model 20
- Merging two scores 11
- Metronome 22
- MF 4
- Microsoft C 20
- MIDI 1
- Midi Monitor 10
- MIDI program 4, 10
- Midi bend 22
- Midi buffer 18, 22
- Midi cont 22
- Midi ctrl 22
- Midi exclusive 22
- Midi note 15, 22
- Midi program 15, 22
- Midi thru 22
- Midi touch 22
- Mikrokosmos 5
- Miller, Phil 15
- Mistake 6
- MM 10
- Modulation wheel 6
- Moxc 16
- Moxie 16
- MP 4
- MPL 4
- Mpu error check 22
- Mpuexists 22
- Multi-track recording 20
- Multiple commands 6
- Multiple Midi Interfaces 20
- Multiple tempi 6
- MUSIC V 4
- Musicinit 22
- Musicterm 22
- Musiprog.h 13
-
- N 4
- Natural 4
- Nelson, Gary 4
- Next 4
- Not equal 14
- Note 13
-
- O 6
- Octave specification 4
- Omissions 1
- Otherwise 14
-
- P 4
- Parameters 14, 16
- Peddown 17
- Pedup 17
- Pitch 4
- Pitch bend 6, 8
- Pnote 14
- Polyrhythm 6
- Portamento rate 6
- Portamento switch 6
- PP 4
- PPP 4
- Preset 4, 22
- Printf 14
- Procedure 13
- Program change 4, 22
- Program Change Command 10
- Program Librarian 21
- Programming 13
-
- Q 4
-
- R 4
- Random 15, 22
- Rate 4, 5
- Read tuning 22
- Real-time clock 18
- Record 10, 11
- Recording 20
- Repeats 13
- Repetition 13
- Rest 14
- Rests 4
-
- S 4
- Saving files 3
- Second ending 14
- Sections 5
- Semicolon 6
- Semicolons 13
- Sequence 13
- Sequencer 21
- Sharp 4
- Small memory model 20
- Space bar 6, 11
- Special command 4
- Stopping programs 13
- Suggestions 1
- Synchronization 20
- Sys Info Avail 10
- System exclusive messages 12, 18
-
- T 4
- Tape-sync 20
- Tempo 4
- Terry Riley 13
- Then 14
- Timbre 4, 10
- Time 4, 5, 18
- Time travel 16
- Timereset 22
- Touchchange 17
- Trace 22
- Tracemidi 22
- Tracks 18
- Transcribe 10
- Triplet 4
- Tuning 8
-
- U 4
-
- V 4
- Voice 4
-
- W 4
- When 14
-
- X 6
- XLISP 21
-
- Y 6
-
- Z 4, 10
-
-
-
- Table of Contents
-
- 1. Introduction and Overview 2
-
- 1.1. Installing CMT 2
-
- 2. DOS Utilities 3
-
- 2.1. make 3
- 2.2. ls 3
- 2.3. grep 3
- 2.4. Backing up files 3
-
- 3. The Adagio Language 4
-
- 3.1. Specifying Attributes 4
- 3.1.1. Time 4
- 3.1.2. Pitch 4
- 3.1.3. Duration 4
- 3.1.4. Next Time 4
- 3.1.5. Rest 4
- 3.1.6. Loudness 4
- 3.1.7. Voice 4
- 3.1.8. Timbre (MIDI program) 4
- 3.1.9. Tempo 4
- 3.1.10. Rate 5
- 3.2. Default Attributes 5
- 3.3. Examples 5
- 3.4. Advanced features 6
- 3.4.1. Multiple notes per line 6
- 3.4.2. Control change commands 6
- 3.4.3. Multiple Tempi 6
- 3.5. Running Adagio 6
- 3.5.1. Debugging Adagio Scores 6
- 3.5.2. Command Line Options 6
- 3.5.3. Examples 7
-
- 4. Defining Nonstandard Tunings 8
-
- 4.1. The Tuning Program 8
- 4.1.1. Entering a range of pitches. 8
- 4.1.2. Entering an octave 8
- 4.1.3. Entering one pitch 8
- 4.1.4. Saving a tuning file. 8
- 4.2. The Retune Program 8
-
- 5. The Transcribe Program 10
-
- 5.1. Overview 10
- 5.2. Tutorial 10
- 5.3. Timbre 10
- 5.4. Command Line Options 10
- 5.4.1. Examples 10
-
- 6. The Record Program 11
-
- 6.1. Overview 11
- 6.2. Instructions 11
- 6.3. Merging Adagio Scores 11
- 6.3.1. Playing two scores in sequence 11
- 6.3.2. Playing two scores at the same time 11
- 6.4. Command Line Options 11
- 6.4.1. Examples 11
-
- 7. DXGet and DXPut 12
-
- 7.1. DXGet 12
- 7.2. DXPut 12
-
- 8. Programming in C 13
-
- 8.1. Introduction 13
- 8.2. Writing a Program 13
- 8.3. Stopping a Program 13
- 8.4. Writing a Procedure 13
- 8.5. Repeats 13
- 8.6. Conditions 13
- 8.7. Parameters 14
- 8.8. Producing Chords 14
- 8.9. Low-level Procedures 14
- 8.9.1. Other Procedures and Functions 14
- 8.10. Command Line Options 15
- 8.10.1. Examples 15
- 8.11. Conclusions 15
-
- 9. Moxc: real-time programming package 16
-
- 9.1. What is Moxc? 16
- 9.2. An example 16
- 9.3. Compiling 16
- 9.4. More about cause 16
- 9.5. Event Handlers 16
- 9.6. Command Line Options 17
- 9.6.1. Examples 17
-
- 10. System Details 18
-
- 10.1. Introduction 18
- 10.2. Basic MIDI interface 18
- 10.2.1. Interface design issues 18
- 10.2.2. Interface implementation 18
- 10.2.3. System exclusive messages 18
- 10.3. Command line parsing 18
- 10.4. The record module 19
-
- 11. What next? 20
-
- 11.1. Microsoft C conversion 20
- 11.2. Large memory model conversion 20
- 11.3. Multiple Midi Interfaces 20
- 11.4. Improve Adagio compilation (sorting) speed 20
- 11.5. Multi-track recording 20
- 11.6. MIDI Continuous Controls 20
- 11.7. Interacting with Moxc programs 20
- 11.8. Code to play sequences from Moxc 20
- 11.9. A player module 20
- 11.10. User-defined note routines for Adagio 21
- 11.11. DX7 Program Librarian 21
- 11.12. An Adagio editor 21
- 11.13. Interface to XLISP 21
- 11.14. A Sequencer 21
- 11.15. Ports 21
-
- I. The MIDI Interface 22
-
- II. List of Files in CMT 23
-
- Index 24
-