@pragma(doinclude) THE CMU MIDI TOOLKIT Version 3 Roger B. Dannenberg 26 February 1998 Copyright 1993 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. The CMU MIDI Toolkit (CMT) is copyrighted and owned by Carnegie Mellon University. CMT is available free by FTP or for a nominal fee by mail. You may copy and redistribute CMT or applications that use CMT so long as the redistribution is not for profit. To distribute software created for profit using CMT, you must obtain a license from Carnegie Mellon University. Any derivative work based on CMT should carry a copy of this entire copyright notice. . 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 Versions 3.12 and higher. 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@CS.CMU.EDU (internet) via computer mail, or by campus mail to Roger B. Dannenberg, Computer Science Department, SCS, or by ordinary mail to Roger B. Dannenberg, Computer Science Department, Carnegie Mellon University, Pittsburgh, PA 15213-3890, USA. A bug report form can be found at the end of this manual. Acknowledgments Many people have contributed to CMT, which grew out of early 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. The Step program was written by Dean Rubine. Early 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. John Maloney ported CMT to the Macintosh. Jean-Christophe Dhellemmes ported CMT to the Commodore-Amiga, using MIDI software originally part of Harmony, a program developed by Carnegie Mellon and Cherry Lane Technology. Ralph Bellofatto wrote much of Harmony. The Amiga port was made possible through support from Commodore-Amiga. Apple provided the machines on which most of the Macintosh porting was done. CMT was ported back from the Amiga to the Mac by Damon Horowitz and to DOS by George Logemann. John Williams assisted in these ports. Leigh Smith reimplemented the DOS/MPU-401 drivers, and Lorin Grubb has provided additional bug fixes and support for the DOS version. The ports to the IBM RS/6000 under AIX and to Mach for the i386 were supported by IBM as part of the Multimedia Testbed project, and were performed primarily by Jim Zelenka. George Logemann has worked extensively with CMT and has contributed enormously to its development. He contributed several Adagio score examples, the Cascades demo directory tree, and most importantly, he uncovered innumerable bugs by giving CMT a thorough workout. In many cases, this led to new and better design and documentation as well as bug fixes. The Midiprint application (see Section 7) and alternative interface support for the PC versions of CMT (see Appendix II were also contributed by George Logemann. Collaboration with Ken Bookstein resulted in the Conduct program. Ken's combination of a very demanding application, technical expertise, and infinite patience made the Conduct program possible. The cover design for the published version of this manual is by Kay Kowalski, and the music manuscript is from Peter Velikonja's score to ``Spomin.'' I also wish to acknowledge support from CMU through the Music Department, the Computer Science Department, the Center for the Design of Educational Computing, the Information Technology Center, and especially the Studio for Creative Inquiry (formerly the 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(or 0.087 seconds if a time unit of 1 millisecond was selected.). Adagio also supports arbitrary tuning systems and standard MIDI files. - EXGet and EXPut 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. - Conduct is a program for conducting MIDI sequences by tapping beats on a keyboard or other MIDI controller. - Cornucopia is a program for mapping incoming MIDI messages to notes, chords, or sequences of MIDI messages. - MM is a midi monitor program that can filter out or display notes, control changes, real-time messages, and system exclusive messages. - MidiPrt converts a standard MIDI file into a human-readable ascii file. This is useful for debugging and for finding out what is really in a MIDI file. - Step provides handy conversions among MIDI pitch numbers, frequency, sample rates, sample periods, and other useful units of measure. - Also provided are routines (in C) that allow direct production of MIDI output. Other routines are available to read MIDI data and to get the current time with 0.01 second or better resolution. 1.0.1. Required Hardware and Software CMT runs on: 1. Any Commodore-Amiga computer with an added MIDI interface. You need the CAMD Midi Driver and library software from Commodore to use CMT. To use Moxc, you should have an Aztec or Lattice C compiler and preferably a hard disk. Note: The author still uses CMT on some old Amiga computers to run some legacy compositions, but CMT is no longer maintained or tested on Amigas. 2. Any Macintosh (with Think C) and any MIDI interface. You need Apple's MIDI Manager from Apple's APDA to use CMT. 3. IBM PC/XT/AT clones (with either Borland C, Turbo C, Microsoft C, or Quick C). PC versions will require a Roland or compatible MIDI interface. 4. See Section 1.3 for information about other interface possibilities for the PC platform. 5. At Carnegie Mellon University, there are two Unix implementations, one for AIX running on RS6000 machines, and one for Mach 3.0 running on i386 architecture machines. Unix requires special device drivers for MIDI; contact the author for details. Note: a C compiler is required to use the Moxc programming environment. No compiler is needed (for any machine type) to use Adagio, Step, Cornucopia, or Conduct. The entire CMU MIDI Toolkit occupies 5 to 10MB of disk space, although this could be trimmed considerably by not compiling all the examples. 1.0.2. Other Details CMT is distributed by Roger B. Dannenberg, Computer Science Department, Carnegie Mellon University, Pittsburgh, PA, 15213-3890, USA. 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 Software installation procedures are described in the file named README on the distribution disk. With the computer powered off, install your (hardware) MIDI interface. Connect your keyboard MIDI OUT to the interface MIDI IN. Connect the interface MIDI OUT to your keyboard MIDI IN. Hardware procedures should be described in the documentation with your interface. This manual does not discuss hardware installation. MIDI THRU is likely to cause some confusion at some point, so please read this and the next paragraph carefully. MIDI THRU means that MIDI IN data is copied to MIDI OUT. For example, an MPU-401 interface normally implements MIDI THRU when CMT is not running. Some synthesizers cannot handle having output data returned to their input, so you may have to disconnect one of the MIDI cables to avoid the adverse effects of MIDI THRU. On the other hand, if you connect your computer's MIDI OUT to a sound module, you may depend upon MIDI THRU to route MIDI from your keyboard to your sound module. In the current releases (but check for documentation updates), - DOS programs shut off MIDI THRU when they run, but restore the MPU-401 default MIDI THRU when they terminate. - Macintosh does not support MIDI THRU whether CMT programs are running or not. - Amiga MIDI THRU is off when no CMT program is running, and by default turns MIDI THRU on when a CMT program is running. If you want MIDI THRU on all the time, you can take advantage of multitasking: start a CMT program such as Adagio in a spare shell and just leave it running. 1.2. DOS IRQ and Base Address The CMU MIDI Toolkit currently supports only Roland MPU-401 compatible interfaces on PC compatible computers. These interfaces are now available from several manufacturers. Usually, these interfaces are used on interrupt 2 at base address 330 , and this is where CMU MIDI Toolkit programs expect to find 16 an interface. If the interface is not there, CMT will search interrupt levels and addresses for an MPU-401, but there is no absolutely safe way to do this. In the process of searching, CMT writes to various I/O locations, and if non-MPU-401 hardware responds to the write, a device may be reset and/or your machine may crash. To avoid the search when your interface is not at the default interrupt level and location, you can set two environment variables, MPUIRQ and MPUBASE. For example, to specify an IRQ level 6 and base address 360 , place the following in your autoexec.bat file: 16 set MPUIRQ=6 set MPUBASE=360 Be sure the values of these environment variables correspond to the actual hardware. Consult your MIDI interface hardware documentation to determine the proper values. 1.3. Other Interface for PCs In addition to Roland MPU-401 interfaces, there are many options for MIDI on PCs. Some interfaces are MPU-401 compatible, and may require no changes (or at most putting the IRQ number and base address in the environment as described in the previous section). Other interfaces, including Rev. 4.xx Sound Blasters from Creative Labs, claim to be MPU-401 compatible but only support the MPU-401 UART mode. This can be handled easily as described in the next section (1.3.1). Another possibility is that you have an earlier version of Sound Blaster, a Voyetra VP11, or a Keytronics MIDIator. These all require recompilation of CMT, and the full process is described in Appendix II. 1.3.1. SoundBlaster and MPU Compatible Interfaces If you have an "MPU Compatible" MIDI interface, it may be compatible only with UART mode. If so, we have bad news and good news. The bad news is that CMT uses the ``intelligent'' mode to determine whether or not you actually have an MPU-401 installed in your system, and this will fail if your MIDI interface supports UART mode only. The good news is that you can set the MPUUART environment variable to disable the code that checks for an MPU-401. More good news is that CMT uses UART mode for everything else. So, to use a SoundBlaster or other UART-mode MIDI interface, place the following in your autoexec.bat file: set MPUUART=1 and reboot. If you set MPUUART, then you must have the proper MPUIRQ and MPUBASE settings (see the previous section). CMT will not check these settings and will not operate if they are incorrect. This procedure allows you to use the SoundBlaster MIDI interface only. You need an adapter cable to convert from the small sound card connector to MIDI connectors (see your sound card manual for details). Unfortunately, this procedure does not support the use of the synthesis capabilities of your sound card. 1.4. Files and Naming Different operating systems use different naming conventions and terminology for files and directories or folders. This manual will use the slash character (``/'') to separate directory names and will use the term directory to mean a Macintosh folder. For Macintosh users, app/util/step means the step program in the folder util, which is within the folder app. All directory paths are assumed to start in the directory in which the toolkit is installed. For DOS users, substitute ``\'' for ``/'' in paths. Within your main CMT directory you will find four main folders (with names greater than two letters) and a bunch of folders with one- and two-letter names. The main folders are: /app Sources and makefiles for application programs. /bin Executable programs for the applications. /lib Sources for code libraries that are shared by application programs and makefiles for the libraries. /music Sample Adagio files, both compositions and tests. The one- and two-letter directories are the details for individual platforms, i.e. a compiler and/or operating system; you can delete the ones you don't need. (Also, by the way, you can delete the makefiles for platforms you don't use from the individual library and applications directories.) Within /app there are folders for specific applications and several general directories: /contrib some complete, fairly complex compositions. /template a program "outline", discussed in ch. 10. /test some simple applications involving MIDI. /util some useful programs not working with real-time MIDI. Macintosh users may not be familiar with command lines. Since the toolkit developed from a command-line interface, parameters called options can be passed to programs by typing them on the command line. On the Macintosh, a dialog box appears when a program is started, prompting for a command line. If you install and compile CMT, you will find that compiled programs are left in the same directory as the source (C) code. You may wish to copy these to a single directory such as bin. A set of compiled programs is included with the release. 1.4.1. Command Help Typing "?" to any toolkit program will cause it to display the complete set of command line options. Any command line option may be abbreviated with a single letter if no other options start with the same letter. 1.5. Software Structure For programmers intending to write new applications, the shear volume of code in CMT may be a bit overwhelming. This section gives a brief overview of the software, which is covered in greater detail in Chapters 10 through 12, 15, and Appendix I. 1.5.1. Support Modules In order to maintain portability, CMT is based on a number of support modules: - midifns.c provides an interface to MIDI input and output. - userio.c provides system-independent functions to print text, read user type-in, test for input ready, and open files. - cmdline.c provides a standard way to read and parse command lines. - cleanup.c provides a way to register functions that perform cleanup operations such as removing interrupt handlers, closing windows and files, and freeing memory. An EXIT function automatically invokes the cleanup operations. - mem.c provides fast constant-time allocation and freeing of small blocks of memory. 1.5.2. Moxc The programs Step, MM, Exget, Exput, and Tuning are built directly on this foundation, but most MIDI programs in CMT are based on a programming system called Moxc. Moxc depends upon the support modules listed above, and Moxc is in turn implemented in three modules: - timebase.c provides a data structure, call_type, that holds a function pointer, a set of parameters for the function, and a time at which to call the function. A timebase_type is a structure that holds a sorted queue of call_type's and maintains a mapping from real time to virtual time, which can run faster or slower than real time. - moxc.c implements cause, which schedules a function to be called in the future. Moxc manages a set of timebases and also parses MIDI input and ASCII (console) keyboard input, calling application- specific handlers when input arrives. - moxcmain.c is a default main program. It is intended to be linked with application-specific handlers to implement an interactive MIDI program. 1.5.3. Sequences Sequences are built on top of Moxc and account for a large fraction of the CMT code. The important modules are: - seq.c implements the seq_type data structure, with operations for creating empty sequences, inserting events, playing sequences, and deallocating sequences. - seqread.c is the Adagio score language parser. - seqmread.c is the standard MIDI file reader, it translates the contents of a standard MIDI file into a seq_type. It relies on midifile.c to parse the MIDI file, and tempomap.c to convert beat number and tempo information into absolute real time in milliseconds needed for seq_type. - seqwrite.c writes a sequence as an Adagio file. - seqmwrite.c writes a sequence as a standard MIDI file. 1.5.4. Applications Some applications build upon both the seq_type structure and Moxc. These include Adagio, Cornucopia, and Conduct, described at the beginning of this chapter and more fully in chapters of their own. There are also a few small demonstration and test programs in app/test. @pragma(doinclude) @pragma(doinclude) 2. 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 2.3 starting on page 4 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 articulation. 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. Adagio has been extended to allow MIDI controller data such as modulation wheels, pitch bend, and volume, MIDI program commands to change timbre, and System Exclusive messages. 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, semicolon, or space) 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. Here are some examples: * This is a comment. T150 G4 * This is a comment too! T150 G4 ;* So is this. 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 specify zero attributes and 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. Special commands follow the ``!'' with no intervening spaces and extend to the end of the line, for example: !TEMPO 100 4. Control change commands are used to control parameters like pitch bend, modulation, and program (timbre). Control change commands can be specified along with notes or by themselves. A command that specifies control changes without specifying a pitch 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. 2.1. Specifying Attributes A note is indicated by a set of attributes. Attributes are indicated by a string of characters with no intervening spaces because spaces separate attributes. The attributes are described below. th The default unit of time is a centisecond (100 's), but this can be changed th to a millisecond (1000 's) using the !MSEC command and reset to centiseconds with !CSEC (see Section 2.4.1). In the descriptions below, the term ``time unit'' will be used to mean whichever convention is currently in effect. 2.1.1. Time The time attribute specifies when to start the note. A time is specified by a ``T'' followed by a number representing time units or by a duration (durations are described below). Examples: T150 ** 1.5 sec (or .15 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 2.1.4.) Time is measured relative to the time of the most recent Tempo or Rate command. (See the examples in Section 2.3 for some clarification of this point.) 2.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). Note that there are no bar lines, and accidentals to not carry forward to any other notes as in common practice notation. 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. (Adagio octave numbering follows the ISO standard, but note that this is not universal. In particular, Yamaha refers to middle C as C3.) 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 P60, CS4 is P61, etc. 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. 2.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), S (sixteenth, 1/4 beat), % (thirtysecond, 1/8 beat), and ^ (sixtyfourth, 1/16 beat). Note that E is a pitch, so eighth-notes use the duration code I. The default tempo is 100 beats per minute (see Section 2.1.10). These codes may be followed by a T (triplet), indicating a duration of 2/3 the normal. A dot (.) after a duration code extends it by half to 3/2 the normal. An integer after a note multiplies its duration by the indicated value (the result is still just one note). Finally, a slash followed by an integer divides the duration by the integer. Like all attributes, duration attributes may not have embedded spaces. 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) Q3/7 3/7 beats th A duration may be noted by Un, where n is an integer indicating 100 's of a th second (or 1000 's), see Section 2.4.1. For example, U25 is twenty-five time units. Durations may be combined using a plus sign: Q+IT ** a quarter tied to an eighth triplet Q/7+W+Q2/7 ** a 7th beat tied to a whole tied to 2/7th beat Q+U10 ** a quarter plus 10 time units 2.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 time units, 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 this one N50 ** start the next note 0.5 seconds after this one NQT ** start the next note 2/3 beat after the current one NU10+Q ** start after 0.1 seconds plus a quarter A comma has an effect similar to N0 and is explained in Section 2.4.2. Articulation effects such as staccato can be produced using N, but it is more convenient to use the articulation attribute described in Section 2.1.6. 2.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 H by space(s) Because some synthesizers (e.g. a DX7) cannot change programs (presets) rapidly, it may be desirable to change programs in a rest so that the synthesizer will be ready to play by the end of the rest. See Section 2.1.9 for an example. 2.1.6. Articulation Articulation in Adagio refers to the percentage of time a note is on relative to the indicated duration. For example, to play a note staccato, you would normally play the note about half of its indicated duration. In Adagio, articulation is indicated by # followed by an integer number indicating a percentage. The articulation attribute does not affect the time of the next command. This example plays two staccato quarter notes: C Q #50 D To produce overlapping notes, the articulation may be greater than 100. Be aware that overlapping notes on the same pitch can be a problem for some synthesizers. The following example illustrates this potential problem: !TEMPO 60 C Q #160 * starts at time 0, ends at 1.6 sec D I * starts at time 1, ends at 1.8 sec C Q * starts at time 1.5, ends at 3.1 sec? At one beat per second (tempo 60), these three notes will start at times 0, 1, and 1.5 seconds, respectively. Since these notes have an articulation of 160, each will be on 160% of its nominal duration, so the first note (C) will remain on until 1.6 seconds. But the third note (another C) will start at time 1.5 seconds. Thus, the second C will be started before the first one ends. Depending on the synthesizer, this may cancel the first C or play a second C in unison. In either case, a note-off message will be sent at time 1.6 seconds. If this cancels the second C, its actual duration will be 0.1 rather than 1.6 seconds as intended. A final note-off will be sent at time 3.1 seconds. 2.1.7. 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 1 to 127 may be used. The loudness attribute is the MIDI note velocity. (Note that a MIDI velocity of 0 means ``note-off,'' so the minimum loudness is 1.) 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 2.1.8. 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. 2.1.9. Timbre (MIDI Program) A MIDI program (synthesizer preset) can be selected using the attribute Zn, where n is the program number (from 1 to 128). Notice that in MIDI, changing the program on a given channel will affect all notes on that channel and possibly others. Adagio treats MIDI program changes as a form of control change. 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 Check how your synthesizer interprets program numbers. For example, the cartridge programs on a DX7 can be accessed by adding 32 to the cartridge program number. Cartridge program number 10 is specified by Z42. As in MIDI, the Adagio timbre is a property of the voice (MIDI channel), so the timbre will not be inherited by notes on a different channel; to change the timbre on multiple voices (channels), you must explicitly notate each change. 2.1.10. 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 !TEMPO command is associated with a time, computed as if the !TEMPO command were a note. The time attribute (T) of all succeeding notes is now measured relative to the time of the !TEMPO command. The new tempo starts at the !TEMPO command time and affects all succeeding notes. Durations specified in time units (for example U58, N15) are not affected by the !TEMPO command, and numerical times (for example T851) are computed relative to the time of the last !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 numerically in time units. If the duration is the sum of a symbolic and a numeric specification, the inherited duration after a !TEMPO command is undefined. 2.1.11. 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 !TEMPO or !RATE command. Two !RATE commands do not combine, so a !RATE command only affects the rate until the next !RATE command. Although !TEMPO and !RATE can occur in the middle of a note (using N, T, etc.) they do not affect a note already specified. This property allows multiple tempi to exist simultaneously (see Section 2.4.4). 2.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 Articulation #100 Loudness LFFF Voice V1 Tempo !TEMPO 100 Rate !RATE 100 Control changes (including timbre or MIDI program, specified by Z) have no default value and are only sent as specified in the score. Important: the rules for determining when a command will play a note are as follows (and this has changed slightly from previous versions): 1. If a special (!) command or nothing is specified, e.g. a blank line, do not play a note. 2. If R (for ``rest'') is specified, do not play a note. 3. Otherwise, if a pitch is specified, do play a note. 4. Otherwise, if no control changes (or program changes) are specified (so this is a command with non-pitch attributes and no control changes), do play a note. Another way to say this is ``Special commands and commands with rests (R) do not play notes. Otherwise, play a note if a pitch is specified or if no control is specified.'' 2.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, default octaves are used to reduce typing. *Example 2 ** Bartok *voice 1, right hand R Q Z10 V1 ** extra rest for program change 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 ** extra rest for program change 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 * note that Z10 is still in effect for V1 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 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. Because of the large intervals, octave numbers (3 and 4) are necessary to override the default octave for these pitches. 2.4. Advanced Features Beyond the simple notation described above, Adagio supports a number of features. (See also the next chapter.) 2.4.1. Time Units and Resolution th The default time unit is 10ms (ten milliseconds or one centisecond or 100 th of a second), but it is possible to change the basic unit to 1ms, or 1000 of a second. The time unit can be specified by: th !CSEC centisecond time units = 100 th !MSEC millisecond time units = 1000 The time unit remains in effect until the next !CSEC or !MSEC command. 2.4.2. 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. In other words, the next note after a comma will start at the same time as the note before the comma. In general, use commas to separate the notes of a chord. A semicolon is equivalent to starting a new line. In general, use semicolons to group notes in a melody. 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. Note how semicolons make the two lines of music stand out. The next example is similar to Example 4, except commas are used and four bars are notated. The music below is treated as a sequence of 2-note chords, with each chord on a separate line: *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 2.4.3. Control Change Commands Any control change can be specified using the syntax ``~n(v)'', where n is the controller number (0 - 127), and v is the value. In addition, Adagio has some special syntax for some of the commonly used control changes (note that Pitch bend, Aftertouch, and MIDI Program Change are technically not MIDI control changes but have their own special message format and status bytes): K Portamento switch M Modulation wheel O Aftertouch X Volume Y Pitch bend Z Program Change 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, the portamento switch, and MIDI Program Change, all values range from 0 to 127. Pitch bend is ``off'' or centered at 128, and has a range from 0 to 255 (MIDI allows for more precision, but Adagio does not). Turn on portamento with K127 and off with K0. Programs are numbered 1 to 128 to correspond to synthesizer displays. About volume: Midi volume is just a control, and the Midi standard does not say what it means. Typically it does what the volume pedal does; that is, it scales the amplitude in a continuously changeable fashion. In contrast, Midi velocity, which is controlled by the L (loudness) attribute, is part of a Midi note-on command and is fixed for the duration of the note. Typically, these two ways of controlling loudness and amplitude operate independently. In some low-cost synthesizers the numbers seem to be added together internally and volume changes are ignored after the note starts. About pitch bend: Midi pitch bend is a number from 0 to 16383, where 8192 is the center position. To convert to Midi, Adagio simply multiplies your number by 64, giving values from 0 to 16320. Note that Y128 translates exactly to 8192. The meaning of pitch bend depends upon your synthesizer and its setting. Most synthesizers let you specify a ``pitch bend range.'' A range of one semitone means that Y255 will produce a bend of approximately one semitone up, and Y0 will bend one semitone down. If the range is 12 semitones, then the same Y255 will bend an octave. Typically, pitch bend is exponential, so each increment in the pitch bend value will bend an equal number of cents in pitch. 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 10 unit intervals, the pitch bend is decreased by 10. The last line sets the portamento time (controller 5) to 80: *Example 7 C4 LMF M50 Y120 U100 N10 Y110 N10; Y100 N10; Y90 N10; Y80 N10; Y70 N10; Y60 N10; Y50 N10 ~5(80) See Section 2.2 on page 4 for rules on whether or not a command will play a note. 2.4.4. 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. This is tricky because a !TEMPO command cannot have a time (T0) attribute, and a T0 by itself would create a note with a duration. T0 R N0 says: ``go to time 0, do not play a note, and do not advance the time before the next command''. 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. 2.4.5. MIDI Synchronization The Adagio program can synchronize with external devices using MIDI real time messages. Adagio can act as either a master or slave. As a master, Midi real time messages are generated according to the score. As a slave, the program uses incoming Midi messages to control the timebase against which notes and other events are scheduled. In this way, an external device such as a drum machine or other sequencer can start, stop, and control the tempo of Adagio scores. Note: the current implementation of synchronization to an external source is very simplistic; it effectively quantizes the score to units of 1/24 of a beat. Since Adagio supports multiple tempi, and Midi clock is based on beats, it is necessary to be explicit in the score about where the clock should start and what is the duration of a quarter note. The !CLOCK command in Adagio turns on a 24 pulse-per-quarter (PPQ) clock at the current tempo and time: !TEMPO 100 !CLOCK A !CLOCK command must also be inserted for each tempo change that is to be reflected in the Midi clock. Typically, each !TEMPO command will be followed by a !CLOCK command. Clock commands and thus tempo changes can take place at arbitrary times. It is th assumed that tempo changes on an exact 24 of a beat subdivision (for example, exactly on a beat). If not, the tempo change will take place on the nearest th exact 24 of a beat subdivision. This may be earlier or later than the requested time. To synchronize other systems, e.g. a drum machine, to Adagio, you should make the device a ``slave'' and start Adagio. Adagio will sent a MIDI Start message and 24 Timing Clock messages per quarter note. When you stop Adagio by typing either the space bar or by reaching the end of the score, Adagio will send a MIDI Stop message, which should stop the slave device. To synchronize Adagio to another system, type c to enable external clock synchronization (see Section 2.5), and type RETURN as if to start the Adagio score. Adagio will wait for a MIDI Start message and will then synchronize to MIDI Clock messages. A MIDI Stop message will stop the playback as if the space bar were typed. To synchronize one Adagio to another, be sure the ``slave'' is ready and waiting before starting the ``master''. 2.4.6. System Exclusive Messages Adagio has a definition facility that makes it possible to send system exclusive parameters. Often, there are parameters on Midi synthesizers that can only be controlled by system exclusive messages. Examples include the FM ratio and LFO rate on a DX7 synthesizer. The following example defines a macro for the DX7 LFO rate and then shows how the macro is used to set the LFO rate for a B-flat whole note in the score. The macro definition is given in hexadecimal, except v is replaced by the channel (voice) and %1 is replaced by the first parameter. A macro is invoked by writing ``~'' followed by the macro name and a list of parameters: !DEF LFO F0 43 0v 01 09 %1 F7 Bf5 W ~LFO(25) In general, the !DEF command can define any single MIDI message including a system exclusive message. The message must be complete (including the status byte), and each !DEF must correspond to just one message. The symbol following !DEF can be any name consisting of alphanumeric characters. Following the name is a hexadecimal string (with optional spaces), all on one line. Embedded in the string may be the following special characters: v Insert the 4-bit voice (MIDI channel) number. If v occurs in the place of a high-order hexadecimal digit, replace v with 0v so that the channel number is always placed in the low-order 4 bits of a data byte. In other words, v is padded if necessary to fall into the low-order bits. %n Insert a data byte with the low-order 7 bits of parameter number n. Parameters are numbered 1 through 9. If the parameter value is greater than 127, the high-order bits are discarded. ^n Insert a data byte with bits 7 through 13 of parameter number n. In other words, shift the value right 7 places then clear all but the first 7 bits. Note that 14-bit numbers can be encoded by referencing the same parameter twice; for example, %4^4 will insert the low-order followed by the high-order parts of parameter 4 into two successive data bytes. Parameters are separated by commas, but there may be no spaces. The maximum number of parameters allowed is 9. Here is an example of definitions to send a full-resolution pitch bend command and to send a system exclusive command to change a DX7 parameter[My TX816 Owner's Manual gives an incorrect format for the change parameter sysex command (according to the manual, there is no data in the message!) I am assuming that the data should be the last byte before the EOX and that there is no byte count. If you are reading this, assume that I have not tested this guess, nor have I tested this example.]. * Define macro for pitch bend commands: !DEF bend Ev %1 ^1 A ~bend(8192) ** 8192 is "pitch bend off" * Change the LFO SPEED: * SYSEX = F0, Yamaha = 43, Substatus/Channel = 1v, * Group# = 01, Parameter# = 9, Data = 0-99, EOX = F7 !DEF lfospeed F0 43 1v 01 09 %1 F7 * now use the definitions: G4 ~bend(7567) N40 ~lfospeed(30) N35 2.4.7. Control Ramps The !RAMP command can specify a smooth control change from one value to another. It consists of a specification of the starting and ending values of some control change, a duration specifying how often to send a new value, and a duration specifying the total length of the ramp. !RAMP X10 X100 Q W2 !RAMP ~23(10) ~23(50) U20 W !RAMP ~lfo(15) ~lfo(35) U10 The first line says to ramp the volume control (controller number 7) from 10 to 100, changing at each quarter note for the duration of two whole notes. The second line says to ramp controller number 23 from value 10 to value 50, sending a new control change message every 20 time units. The overall duration of the ramp should be equivalent to a whole note (W). As shown in the third line, even system exclusive messages controlled by parameters can be specified. If the system exclusive message has more than one parameter, only one parameter may be ``ramped''; the others must remain the same. For example, the following would ramp the second parameter: !RAMP ~mysysex(4,23,75) ~mysysex(4,100,75) U10 W A rather curious and extreme use of macros and ramps is illustrated in the following example. The noteon macro starts a note, and noteoff ends it. Ramps can now be used to emit a series of notes with changing pitches or velocities. Since Adagio has no idea that these macros are turning on notes, it is up to the programmer to turn them off! !DEF noteon 9v %1 %2 !DEF noteoff 8v %1 %2 ~noteon(48,125) ~noteoff(48,126) * turn on some notes !RAMP ~noteon(36,125) ~noteon(60,125) Q W NW * turn them off !RAMP ~noteoff(60,50) ~noteoff(36,50) Q W NW 2.4.8. The !End Command The special command !END marks the end of a score. Everything beyond that is ignored, for example: * this is a score C; D; E; F; G W !END since the score has ended, this text will be ignored See Section 12.2.1.1 for a further discussion. 2.4.9. Calling C Routines It is possible to call C routines from within Adagio scores. The routine must be written in C, the name must be entered into a special table, and the compiled routine must be linked into Adagio or some application that uses Adagio sequences. Only the command syntax will be described here. (See Section 12.3 for more information.) The !CALL command calls a C routine that can in turn invoke a complex sequence of operations. Below is a call to a trill routine, which is a standard routine in Adagio. The parameters are the base pitch of the trill, the total duration of the trill, the interval in semitones, the duration of each note of the trill, and the loudness. Notice that both numbers and Adagio notation can be used as parameters: !CALL trill(A5,W,2,S,Lmf) T278 V1 The parameter list should have no spaces, and parameters are separated by commas. Following the close parenthesis, you may specify other attributes such as the starting time and voice as shown in the example above. A parameter may be an Adagio pitch specification, an Adagio duration, an Adagio loudness, a number, or an ASCII character within single quotes, e.g. 'a' is equivalent to 97 because 97 is the decimal encoding of ``a'' in ASCII. The !CALL may be followed by a limited set of attributes. These are time (T), voice (V), and next time (N). The !CALL is made at the current time if no time is specified, and the time of the next adagio command is the time of the !CALL unless a next time is specified. In other words, the default is N0. 2.4.10. Setting C Variables In addition to calling C routines, there is another way in which scores can communicate with C. As with !CALL, specific C code must be linked before these commands can be used. (See Section 12.4 for details.) The !SETI command sets an integer variable to a value, and the !SETV command sets an element of an integer array. For example, the next line sets the variable delay to 200 and sets transposition[5] to -4 at time 200: !SETI delay 200 !SETV transposition 5 -4 T200 As with the !CALL command, these commands perform their operations at particular times according to their place in the Adagio score. This makes it very easy to implement time-varying parameters that control various aspects of an interactive music system. 2.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 (depending on the operating system), and .gio is a hint that this is an Adagio score. Alternatively, you can play a MIDI file with Adagio. MIDI files should end with the extension .mid. To listen to the score, type adagio something Where something is the name of a score file as discussed above. You may omit the file name, in which case you will be prompted for it. There are also many optional command line switches. Type adagio ? for a listing. When Adagio is ready, you should see this prompt: *** ADAGIO *** type p=play, t=transcribe, r=record, q=quit : Adagio has several modes of operation. In this chapter we will cover only the playing of score files. Type p and then RETURN to select Play mode. (Note: the RETURN key may be labeled CR, ENTER, or simply with an arrow.) If you have not already specified a file name, you will see this prompt: input adagio file : Type the name of the adagio file you prepared. Notice that typing the .gio is optional with Adagio, but if you want to read a MIDI file, you must include the .mid extension. If all goes well, you will get the following prompt: PLAY MODE: type to play, ? for help, q to quit : If you type ``? return'', you get a complete list of commands: q quit e set channel enable f set channel mute b set beginning time n new input file c toggle using external clock r change rate (play mode only) t set transposition (play mode only) l set loudness offset (play mode only) m toggle MIDI byte trace mode d toggle music operation mode s report operation mode u read a tuning file w write a file ?, display this message If you type RETURN to start your piece, Adagio pauses exactly 1 second after typing RETURN, then starts playing your score. If you type ``q RETURN'', you will exit play mode. The ``e'' command allows you to enable a previously disabled channel. The ``f'' command allows you to disable a channel. The ``b'' command allows you to start playing from any time point in the score. The ``n'' command prompts you for a new file to play. The default extension is .gio, but if a .mid extension is specified, Adagio will read a standard MIDI file. The ``c'' command switches between ``master'' (clock sender) and ``slave'' (clock receiver) mode. The score must be a standard MIDI file or have an embedded !CLOCK command in order to use clocks. The ``r'' command lets you change the playback rate to some percentage of the original rate. The ``t'' command lets you transpose the output by some offset. The ``l'' command lets you offset the loudness (MIDI velocity) of notes. The ``m'' command causes Adagio to print a trace of all MIDI data. This is useful for debugging changes to Adagio and seeing exactly what is being transmitted. It is equivalent to using the -miditrace flag on the command line. Another ``m'' command turns tracing off. The ``d'' 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. This is equivalent to using the ``-trace'' flag on the command line. Another ``d'' command turns off the music operation trace. The ``s'' command reports what data will be traced. If you type ``u'', you will get a prompt for a tuning file (see Chapter 5). This command is useful for playing a single score with different tunings. The "w" command writes the current score as a MIDI or Adagio file. For Adagio files, it prompts for relative (N notation) or absolute time (T notation). 2.5.1. Midi Files and Adagio Files Adagio can write files in either standard MIDI file or Adagio format. The default is to write an Adagio (.gio) file, but if the file is specified with the .mid extension, it is written as a standard MIDI file. Note that Adagio can be used to convert from standard MIDI to the plain text Adagio format and back again. 2.5.2. 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 load the .gio file into an editor. Move the cursor to line number 123. If the mistake is not found, go to line 259. 2.5.3. Pausing While Adagio is playing a score, you can pause the performance by typing p. You can then continue by typing a space. @pragma(doinclude) 3. Adagio in Transcribe Mode 3.1. Overview The Transcribe mode of Adagio is used to record performances via MIDI and to translate them into Adagio score files. Rather than attempt to guess musical durations (like a dotted-quarter), Transcribe records all times and durations in milliseconds. This mode, 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. 3.2. Tutorial To use Transcribe mode, start up Adagio as before (see page 2.5) and type "t RETURN" to select Transcribe mode. You will then get the following prompt: TRANSCRIBE MODE: type to transcribe, ? for help, q to quit : Type RETURN and you will be prompted for a file name for the score you will create: output file : Type a file name. If the file already exists you will be asked whether you really want to overwrite the file with new data. If you do not provide an extension, .gio will be appended to your file name automatically. Next, Transcribe will ask you if you want to record continuous controller data. The default (no) will produce shorter files but will filter out information such as pitch bend, volume control, modulation wheel and aftertouch: Enable recording of pitch bend, etc.? [n] Type y, n, or just RETURN for the default n. Generally, you should type RETURN. When you have finished what you want to play, type the space bar. This signals the program to stop and write out the notes. This file can now be played (in Play mode) and what comes out will be very similar to what you just heard yourself play. 3.3. Timbre MIDI has the problem that a computer cannot inquire the current program selections. Thus if a synthesizer is set to program 23 and a passage is recorded by Transcribe, the resulting file will not contain a Z23 command, and there is no guarantee that the synthesizer will be set to program 23 when the file is played in the future. The best solution is to press program 23 on the keyboard before playing any notes. This will send a program change command that will be recorded into the file and replayed later. Transcribe and Record modes 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 notable 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''. @pragma(doinclude) 4. Adagio in Record Mode 4.1. Overview Record mode is a combination of Play and Transcribe modes. 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 4.3 discusses how you can combine several Adagio scores into one. 4.2. Tutorial Before using Record mode, 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. Start Adagio and type ``r'' to get into Record mode. You will be prompted for a file as in Play mode. Type ``old'' to load the score. Record then prompts you with: RECORD MODE: type to record, ? for help, q to quit : The possible responses are described in detail in Section 2.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: output file: Type new. The extension .gio will be added automatically if you do not provide any extension. As with Transcribe you will be asked about recording continuous controller information. Then, 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: RECORD MODE: type to record, ? for help, q to quit : 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. 4.3. Merging Adagio Scores A few tricks are helpful in merging two scores into one. This section 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 using an editor and figure out where the problem is. 4.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 hear 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 (PC) DOS copy command. The following appends score2.gio to score1.gio. copy score1.gio+score2.gio DOS knows nothing about Adagio, so the .gio extensions must be specified. 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. The corresponding Amiga DOS command is: join score1.gio score2.gio as score3.gio There is no corresponding Mac command, so you must join files using a text editor. 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. 4.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). 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 synthesizers often assume 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 or that you can play several channels at once.) @pragma(doinclude) 5. Defining Nonstandard Tunings Tuning in MIDI is normally twelve-tone equal temperament. 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, 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/100) + 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 the Tuning program 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 (60 is middle C) between 0 and 127. The second is a pitch, also between 0 and 127, 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-temperament 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. 5.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: 5.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 type-in is underlined): Command >>r Adagio note range is 0..127 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 = 0 .. 127, 60 is middle C Adagio Note 48 pitch >>49 bend >>10 Adagio Note 49 pitch >>50 bend >>10 Adagio Note 50 pitch >>51 bend >>10 5.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 5.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 0..127. 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 = 0 .. 127, 60 is middle C Adagio note 57 pitch >>69 bend >>0 Adagio note range is 0..127. Which note would you like to enter? (type return to quit) Note >> 5.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, and Moxc to control tuning. 5.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 keyboard (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 in the app/test directory. Also notice that since pitch bends apply to the whole keyboard, polyphonic notes interfere with one another. @pragma(doinclude) 6. MM - Midi Monitor MM is a program that displays incoming MIDI messages. MM has several display modes that allow you to filter out certain types of messages and control how much text is printed for each message. MM has no special flags or switches and takes an optional argument. Typing ``mm ?'' will display the standard switches pertaining to all CMT applications. The optional argument is a string of command letters, e.g. mm xc. The letters are interpreted as if they were typed to mm, as described below. While MM is running, there are fourteen ``commands'' accessed by typing a letter. Typing any other letter generates a help message describing the commands and their current status, where applicable. The commands are: b Toggle the display of pitch bend and aftertouch. When disabled, nothing is printed for these messages. c Toggle the display of continuous control. h Toggle the display of program changes. k Toggle the display of clocks and active sensing data. m Toggle the display of channel mode messages (controller messages for controller numbers 121 through 127.) n Toggle the display of notes, e.g., in order to feature controls. q Quit the program. r Toggle the display of real-time (such as MIDI clock) and SMPTE messages. s Display the clock and sense count since the last k. t Display noteon count since last t. v Toggle the display of verbose text. If verbose text is enabled, each message is printed on a separate line, and a human-readable description is printed for each message. w Toggle the diaplay of discrete/switch controller data. x Toggle the display of system exclusive messages. When a message arrives, the message is first displayed in hexadecimal. If ``verbose'' mode is on, then a text description of the message is written to the right of the message. Long system exclusive messages are displayed as many lines of hexadecimal followed by the optional verbose description ``System Exclusive.'' @pragma(doinclude) 7. Midiprt, A Standard Midi File Printer Midiprt is a utility program to display the contents of a MIDI file. It uses no specific CMT modules and can be built as an ordinary C program. Midiprt was contributed by George Logemann. Running Midiprt involves a dialog as follows (each response is followed by ): Parameter file name: Type file name (as explained below) followed by ; if none, only, then: MIDI file name Type entire file name including any extension. Output file name Type a file name to receive output, otherwise only displays output on monitor. Show all? Type y for maximum output; otherwise, n is followed by: Show messages? Type y to show MIDI messages other than sysex. Show meta events? Type y to show meta data. Show sysex occurences? Type y to show where sysex's appear. In the case of each of the three types of items, responding y asks: Show details? Type y to show the entire text of this type of item. If you reply y to showing MIDI messages, then the system asks: Expand running status? Reply y to expand running status, i.e., generate artificially the status byte that pertains, usually note on's and note off's Otherwise, system displays exactly what is in the file. If you reply y to showing details, the system asks: Show delta times? Replying y shows the elapsed time preceding events (as reported in the file). Show running times? Replying y shows the total elapsed time to the event (as calculated by summing delta times). 7.1. Notes: If you intend to repeat a specific series of reponses, you may find it convenient to type the responses in a file, then type the file name at the first prompt. Times are measured in pulses. The track header indicates ppq = pulses per quarter note; the "set tempo" meta event indicates microseconds per quarter note. The first byte of a message is followed by the number of bytes in the message enclosed in parentheses, then the remaining bytes of the message. Message bytes are in hex, quantities (times, numbers of bytes) are in decimal. Midiprt does not use a standard file open dialog on the Macintosh. The easiest way to use the program on the Macintosh is to put the executable program file into the folder with the parameter and .mid files. The output will go there too if you request an explicit output file. @pragma(doinclude) 8. EXGet and EXPut EXGet and EXPut are used to store and recall programs for synthesizers. These are generally voice patches, but in general they can be any sequence of MIDI system exclusive messages. 8.1. EXGet The EXGet program is used to record MIDI system exclusive messages and store them in files. To run EXGet, type exget filename where filename is the name of a file you want to create. If you leave off the extension, EXGet will use the extension .syx (for System Exclusive). If you do not specify a file, you will be prompted for one. EXGet has several options that may be specified on the command line: - ?: this switch prints out a list of command line options. - -block: normally, MIDI thru will be enabled. The -block switch turns it off. - -miditrace: turn on MIDI byte trace. Use the -trace switch instead if you prefer the trace in a more human-readable form. - -noalloff: Normally, an all-notes-off command is sent on each channel when you exit. This switch prevents this action. - -trace: turn on trace of MIDI output commands (printed in text form). - -tune filename: load the indicated tuning file (irrelevant for EXGet). - -inport hexstring: listen to the ports named in hexstring, where hexstring is a string of hexadecimal digits indicating the input ports. For example, the string ``169ac'' says to listen to ports 1, 6, 9, 10, and 12. (Currently only valid for Amiga version.) - -outport N send to output port N, where N is a decimal or hexadecimal number (this is not ambiguous because the largest port number is 15 decimal). Note that only one port number is allowed. (Currently only valid for Amiga version.) - -help: print the instructions. - -binary: save data in binary rather than hexadecimal format. This results in a factor of three compression, but don't try to read the output as text! Note: in implementations (including CMT for DOS) that do not support MIDI Thru (-block), you can use -b as a shorthand for -binary. - -size number: allocate at least number bytes for the system exclusive message(s). The actual space allocated will be a power of 2. If number bytes cannot be allocated, the program prints an error message and exits. After EXGet 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 MIDI system exclusive messages to a file. When you get the prompt: "Ready for your data...", send one or more sysex messages from your synthesizer. See the CMU Midi Toolkit Manual or your synthesizer operator's manual for instructions on this. Use the exput program to send sysex messages recorded by exget. 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 EXGet will not request information automatically. This would require EXGet to know about types of synthesizers. To be more general, EXGet is very simple. Consequently, you must manually cause your synthesizer to send the desired information to EXGet. 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, EXGet will check to make sure the data has not been garbled. A warning will be printed if any errors are detected. EXGet will also try to print a description of the exclusive messages it received. You can send the data back to your synthesizer using the EXPut program described below. NOTE: If you find that you are sending two messages instead of one when you use EXGet, here is what is probably happening (we will use the DX7 as an example, but this may apply to others as well): 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 computer's MIDI IN port and has been forwarded to the MIDI OUT port. If the 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 EXGet. At present, only the Amiga version of CMT implements MIDI THRU whereby MIDI IN can be forwarded to MIDI OUT, but this is likely to change in future releases. 8.2. EXPut The EXPut program takes files created by EXGet and sends them as MIDI output. To run EXPut, type exput filename where filename is the file created by EXGet. A default extension of .syx is assumed if you do not specify one. EXPut has several options that may be specified on the command line: - ?: this switch prints out a list of command line options. - -block: normally, MIDI thru will be enabled. The block switch turns it off. - -miditrace: turn on MIDI byte trace. Use the trace switch instead if you prefer the trace in a more human-readable form. - -noalloff: Normally, an all-notes-off command is sent on each channel when you exit. This switch prevents this action. - -trace: turn on trace of MIDI output commands (printed in text form). - -tune filename: load the indicated tuning file (irrelevant for EXPut). - -inport hexstring: listen to the ports named in hexstring, where hexstring is a string of hexadecimal digits indicating the input ports. For example, the string ``169ac'' says to listen to ports 1, 6, 9, 10, and 12. (Currently only valid for Amiga version.) - -outport N send to output port N, where N is a decimal or hexadecimal number (this is not ambiguous because the largest port number is 15 decimal). Note that only one port number is allowed. (Currently only valid for Amiga version.) - -help: print the instructions. - -size number: allocate at least number bytes for the system exclusive message(s). The actual space allocated will be a power of 2. If number bytes cannot be allocated, the program prints an error message and exits. After starting, EXPut will ask: Do you want instructions? [y] The instructions are as follows: This program sends system exclusive messages previously saved by the exget program. You must set up your synthesizer to receive the system exclusive messages. See the CMU Midi Toolkit Manual for more details. EXPut can read binary or default ASCII files. The files are distinguished automatically by looking at the first byte (if the file is binary, the first byte will have its high order bit set). 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 EXPut knows will cause a major change, you will be asked for confirmation before the data is sent. At present EXPut 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. 9. Step Step is a program that converts between various representations of pitch. It is good for answering questions like ``what MIDI pitch value corresponds to A above middle C?'' and ``what's the period, in samples, of a 440Hz tone recorded at 16KHz?''. Step assumes equal temperament, with A above middle C equal to 440 Hz. 9.1. Sample Dialogue Step has a simple interface. The easiest way to learn about it is just to run the program. The following is a sample dialogue with Step. User input is underlined, computer output in constant width typeface, and comments are shown in italics. % step Invoke the program. pitch midi freq Period rate nharm c4 60 261.626 61.1561 16000 10 ? ? Type `?' for help f - enter frequency in Hz s - enter half step number (60 = middle C) p - enter pitch name (example: Df4 for D flat above middle C) P - enter period in samples per second n - change number of harmonics r - change sample rate h - print harmonics v - print out variables q - quit ? p A4 Set the pitch to A4. pitch steps freq Period rate nharm a4 69 440 36.3636 16000 10 We see that A4 is 69, in midi pitch notation. ? s 0 What pitch is midi note 0? pitch steps freq Period rate nharm c-1 0 8.1758 1957 16000 10 We see that 5 octaves below middle C (c-1) and that is has a frequency of 8.2 Hz. ? f 256 What note has a frequency of 256 Hz? pitch steps freq Period rate nharm ~c4 59.6237 256 62.5 16000 10 C4 is the nearest pitch. ? p C4 What frequency is C4 really? pitch steps freq Period rate nharm c4 60 261.626 61.1561 16000 10 Oh, 261.6 Hz ? P 100 At a 16000Hz sample rate, what note has a period of 100 samples? pitch steps freq Period rate nharm ~d#3 51.4868 160 100 16000 10 Oh, D#3 ? r 50000 What would be its period at 50000Hz sample rate? pitch steps freq Period rate nharm ~d#3 51.4868 160 312.5 50000 10 ? n 3 I'm interested in the first 3 harmonics ? h Print out their frequencies, step numbers, and periods at the current sample rate (50000 Hz) harmonic freq steps period 1 160.000000 51.486821 312.500000 2 320.000000 63.486821 156.250000 3 480.000000 70.506371 104.166667 ? q Bye 9.2. Commands Step maintains a number of variables. These are named pitch, steps, midi, freq, Period, rate, and nharm. A command may change the value of one of these variables. This causes the other variables to be updated so that they all represent the same pitch. The following is a list of commands, and how they affect the variables maintained by Step. p pitch sets the character string representation of the pitch. The general form of pitch is: pitch-letter [ accidental ] [ octave ] where the brackets indicate optional parameters. The pitch letter is one of a, b, c, d, e, f, or g (lower or upper case). The accidental may be one of s, #, f, or b, where s and # mean ``sharp'', and f and b mean ``flat''. No accidental means ``natural''. The octave is an integer representing an octave. The octave from middle C to B above middle C is octave 4. If the octave is omitted, 4 is presumed. Here are some example pitches: c4 (middle C), c#3 (c# below middle C), Df (D flat above middle C). Whenever a ``~'' is output before a pitch name, it means that the pitch name is the closest pitch to the displayed frequency, but does not exactly equal the displayed frequency. s steps sets the steps variable. This is the midi representation of pitch, with 60 representing middle C, and each increment by one increases the pitch by a single half step (100 cents). Thus A above middle C (A 440) is 69 steps. Note that a synthesizer may have a transpose function built into it, causing it to sound a different pitch than the one you have sent to it. f freq sets the freq variable. The value of freq is the frequency of the pitch in Hertz. P Period sets the Period variable. Period is the number of samples in one period of the current pitch. It depends on both the pitch and the current sample rate. r rate sets the current sample rate. Changing rate changes Period, leaving the pitch constant. n nharm sets the number of harmonics to be displayed by the h command. h prints out the harmonics of the current pitch. For each harmonic the frequency in Hertz, pitch (in step notation), and period (in samples with respect to the current sample rate) is printed. q quits Step. 9.3. Formulae Step uses the following formulae to convert between the various representations of pitch. 9.3.1. Pitch Name To/From Half Steps steps##=##l#(pitch )+a#(pitch )+12+12*pitch letter accidental octave where ------------------------------------- | | | | | | | | | - - - | - | - | - | x | a | b | c | d | e---f---g--------------------------------------------- | | | | | | || | | | | | | | | - - |--------------------------|--x---| |s | # | f | b | otherwise | | | | | | | || | | | | | | | | - | - | - | - | l(x) | 9 | 11 | 0 | 2 | 4|--5---7--------------------------------------------| | | | | | | || | | | | | | | | - ---- - ---------------------------|-a(x)-|--1 | 1 | -1 | -1 | 0 | | | | | | | | --------------------------------------------------------- true### if steps# is an integer pitch ##=##B approx false## otherwise isteps pitch ##=##|------| octave 12 pitch ##=##pn#(isteps###mod ##12) class pitch ##=##pa#(isteps###mod ##12) accidental where##isteps##=##|steps+0.5| --------------------------------------------------------------------- | | | | | | | | | | | | | | | x | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | | | | | | | | | | | | | | | |----------------------------------------------------------------- | | | | | | | | | | | | | | | | pn(x) | c | c | d | d | e | f | f | g | g | a | a | b | | | | | | | | | | | | | | | |----------------------------------------------------------------- | | | | | | | | | | | | | | | | pa(x) | | # | | # | | | # | | # | | # | | | | | | | | | | | | | | | | --------------------------------------------------------------------- 9.3.2. Half Steps To/From Frequency #steps##.#p+q ln (freq)-q freq##=##e steps##=##----------- p ln (2.0) where##p##=##--------,#######q##=##ln (440.0)#-#69*p 12 9.3.3. Frequency To/From Period (In Samples) rate rate Period##=##---- freq##=##------ freq Period 9.4. Deficiencies Step was written quickly, and could be improved. One thing that would be nice to have is pitch-bend values for pitches which are not integral midi pitches. (Unfortunately, these pitch value numbers would be synthesizer dependent.) This would be useful for playing alternative tunings on synthesizers which do not support such tunings. Also, other representations of pitch (e.g. period in seconds) could be supported. @pragma(doinclude) 10. Programming in C 10.1. Introduction This chapter is not about how to write in C Major, nor is it about how to realize 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 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. 10.2. Compiling a Program We will start with a simple program that has already been written. The purpose of this exercise is to learn how to run a program once it is written. We will start with a working program to minimize the number of possible problems. The directory app/template has a simple program named template.c. Before experimenting with this program, back up the template directory so the original files can be recovered. Template is designed to serve as a template that you add to in order to build a program that does something. Another example program is app/test/prog.c. This one actually plays some MIDI, so if you have trouble with app/template/template.c, try getting prog.c to run. To hear the results of a program, you have to compile your program, then link it, and then execute it. The C compiler and linker are run by typing make. (With Amiga Lattice C, type lmk; for Microsoft C, type nmake /F template.mak). The resulting file, named template (or template.exe under DOS) can then be executed, meaning that the machine instructions in the file are loaded into working memory, and the computer then carries them out. On the Macintosh with Lightspeed C, the procedure is different. You should consult your Lightspeed C manual for instructions, run the project called template, and proceed to Section 10.4. Under DOS, you may prefer to use a more integrated programming environment, for example the bc command of Borland C, or pwb in Microsoft C. Consult your compiler documentation for details. 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. (template.c does not have any errors, so it should compile and link without errors.) To run your program (except for Macintosh systems), type template The template program prompts you to type RETURN, but does nothing. To run your program again, you need not recompile unless you change your program with the editor. On the Macintosh, there is a Run menu item in Think C, or you can build an application, save it, exit Think C, and double click on the application to run it. As with other systems, you must recompile and save the application after you edit the program. 10.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 system in a state that would cause problems later on. Instead, the flag is checked within the CMU MIDI Toolkit library, which carefully exits your program if the flag is set. ] 10.4. Writing a Program Let's say you want to modify template to play a couple of notes. In template.c, find the word "mainscore". You should see a section of the file that looks like this: void mainscore() { while (askbool("Type RETURN to play, or N RETURN to quit", true)) { /* PUT YOUR SCORE HERE */ } } Now, add some new lines as shown below: void mainscore() { while (askbool("Type RETURN to play, or N RETURN to quit", true)) { note(60, 100); note(62, 50); note(64, 50); note(65, 100); } } 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 60 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, and is bracketed by braces: { and }. Also notice that calls to note end with semicolons (;). All of these details are essential, and C is not very forgiving of even trivial mistakes. On the first line of the file and in various other places, you will see what 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. 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. Your program will have a number of additional lines copied from template.c. Do not delete or change these for now. Use make or the equivalent to recompile and relink template, and run it by typing template. You should hear a 4-note sequence. If you have problems, try typing template -trace to get a printout of the outgoing MIDI messages. If you see messages but do not hear anything, then check your MIDI and audio connections. 10.5. 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: -- initial part of template.c omitted from this listing -- /* these declarations are necessary to keep most compilers from complaining: */ void up(); void down(); void mainscore() { while (askbool("Type RETURN to play, or N RETURN to quit", true)) { up(); down(); up(); note(60, 100); } } void up() { note(60, 20); note(62, 20); note(64, 20); note(65, 20); } void down() { note(67, 20); note(65, 20); note(64, 20); note(62, 20); } -- remainder of template.c omitted from this listing -- Notice that up and down obey the same rules as mainscore: procedure names are preceded by void and followed by a pair of parentheses and an open brace. Then there is a list of calls to note or other procedures terminated 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 a close brace. Notice the appearance of up and down near the beginning of the file. These tell the compiler that up and down are procedures that will be defined later. Notice the semicolons in these lines. 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. 10.6. Repeats Repetition is important in both programming and music. To repeat a phrase, a special ``repeat'' construct is provided. Consider the following example. (In the remaining examples, only the relevant changes to template.c are shown. You will need the entire file, with changes as shown, in order to compile and run the program: void mainscore() { repeat(i, 5) note(60, 30); note(72, 30); endrep } 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. 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. void up(); void mainscore() { repeat(i, 3) up(); endrep } void up() { note(60, 20); note(62, 20); note(64, 20); note(65, 20); } 10.7. 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 if construct) that makes this programming task easy: void mainscore() { repeat(i, 2) note(72, 30); note(71, 15); note(69, 15); note(67, 15); note(65, 15); note(64, 15); if (i == 1) { note(65, 15); note(67, 120); } else { note(62, 15); note(60, 120); } endrep } This is a program with a repeat construct, but notice that the last part of the repeated phrase is of the form: if (condition) { phrase1 } else { phrase2 } The computer interprets this construct as follows: whenever an if 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 the first open brace ({) is performed up to ``} else {'', and the second phrase (after else) is skipped. If the condition is false, the first phrase is skipped, and the phrase in braces after else is performed. As usual, these phrases can be calls to other procedures like up and down. The if 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 if 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. mainscore() { repeat(i, 3) p1(); if (i == 2) { p2(); } else { } p3(); endrep } In this example, the phrase after else is empty (has no statments). 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();. The empty else part can be omitted, resulting in: mainscore() { repeat(i, 3) p1(); if (i == 2) { p2(); } p3(); endrep } 10.8. 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 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: void newup(int dur); void mainscore() { newup(25); newup(50); } void newup(int dur) { note(60, dur); note(62, dur); note(64, dur); note(65, dur); } 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. Notice that parameters in the procedure definition are preceded by the word int. This declares the type of the parameter to be an integer value. For now, we will use nothing but integers, so all parameter declarations should be of the form ``int parametername.'' 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. If you use a procedure (e.g. in mainscore) before defining it, you must declare the procedure as illustrated in the top line of this example. The declaration is similar to the definition, but the entire body of the definition delineated by braces is replaced by a semicolon. The parameters in the declaration must match the parameters in the full definition. 10.9. 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(int tonic, int duration) { pnote(tonic, duration); pnote(tonic + 3, duration); note(tonic + 7, duration); } 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. 10.10. Low-level Procedures Up until now, we have concentrated on writing programs that control the high level structure of your music. By now, 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. Recall that note is just a procedure. Here it is: void note(int pitch, int duration) { midi note(1, pitch, 100); rest(duration); midi note(1, pitch, 0); } 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 to 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 directories app/adagio and lib. 10.10.1. Other Procedures and Functions A complete list of music functions and procedures are listed in the file midifns.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 values that you supply when you call the function. gprintf(TRANS, "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. gprintf is portable among versions of CMU Midi Toolkit. It is similar to fprintf which is described fully in any C programming manual. 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 true, getkey will wait for a key to be pressed. If waitflag is false, getkey may return -1 to indicate no key has been pressed. Example return values and their meaning are -1: no key was pressed, 60: middle C was pressed, 188: middle C was released (188 = 128 + 60). 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 0 to 127), 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. 10.11. Command Line Options CMU MIDI Toolkit programs automatically interpret the command line and implement the following options. See Section 15.3 about adding new options. - -block (or -b): turn off MIDI THRU - -miditrace: turn on MIDI byte trace. - -noalloff (or -n): do not sent alloff message when done - -trace: turn on music operation trace. - -tune filename: tells Adagio to use filename to specify tuning. - -debug (or -d): turn on debugging code. - -moxc: enable moxc debug mode. - ?: print this list. 10.11.1. Examples Assuming you have compiled a program named template, template ? will print a list of command line options. To run template with a tuning specified in myscale.tun, with a printout of music operations as they are performed: template -tune myscale -trace 10.12. 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! @pragma(doinclude) 11. 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 11.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. 11.2. An Example The following example uses Moxc to implement a simple performance instrument. A blow-by-blow commentary follows the example. Only the important lines are listed here. For a complete but still fairly simple example, see the file moxctest.c. void keydown(int c, int k, int v) { pnote(k+12, 100); } void asciievent(char c) { if (c == 'q') { quit(); } } void hello() { gprintf(TRANS, "hello\n"); cause(300, hello); } mainscore() { hello(); } 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 60 corresponds to middle C, 61 to 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 10.9. 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. 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. 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. 11.3. More About cause What would have happened if mainscore (above) would have called hello twice? Would the characters hello 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. Warning: the C compiler does not check the types of these parameters. Here is a version of hello that prints the number of times it has been called: hello(i) { gprintf(TRANS, "h