.so ../ADM/mac .XX music 477 "Computer Music Under the 10th Edition UNIX System" .nr dP 1 .nr dV 1.5p .de FG .ce Figure \\$1. \\$2 .SP .5 .. .TL Computer Music under the 10th Edition .UX System .AU T. J. Killian .AI .MH .AB We describe an evolving computer music system that draws upon many of the novel facilities in the Research .UX system, as well as the standard repertoire of familiar tools. The Teletype 5620 bitmap display serves both as the user's terminal and real-time controller. The .I mux window system is used to download a .SM MIDI interface driver that services other windows (by direct code sharing) and host processes (which write on the driver's control stream). We presently support several .SM MIDI devices: the Yamaha .SM DX7 , .SM TX816 , .SM FB01 , and .SM SPX90 . .PP Window programs include a piano-roll-style score facility and a virtual keyboard. Host programs include a music compiler, .I m , that converts an .SM ASCII score notation into .SM MIDI events; it is based on .I lex and .I yacc, making it very easy to modify in response to user needs. There are also several filters that perform simple transformations (e.g., time and pitch translation) on .SM MIDI files. The latter are .SM ASCII , so that text filters (especially .I awk , .I sed , and .I sort) can be used for sound manipulation. .AE .2C .NH Introduction \- the .SM MIDI standard. .PP Computer-music applications have taken off in recent years, largely due to the introduction of the .SM MIDI (Musical Instrument Digital Interface) standard |reference(midi standard). .SM MIDI has made it possible, with very modest hardware, to interface a computer to synthesizers and other equipment, with broad compatibility among manufacturers. A full discussion of the .SM MIDI standard is out of place here; we will simply give some of its essential characteristics. .PP .SM MIDI uses an asynchronous serial protocol at 31.25 Kbaud to transmit \%8-bit data bytes over a \%5-mA current loop (thus, to the programmer, it looks like an .SM RS232 line). Data flow on any given cable is unidirectional. .I Status and .I data bytes are distinguished by the high-order bit being set or clear, respectively. A status byte encodes a .I function, and (usually) a .SM MIDI .I "channel number" in the range 1 to 16. Bytes are grouped logically into .I messages that consist of a status byte and (except as noted below) 1 or 2 data bytes. For example, the \%3-byte message (\c .CW 0x90,\ 0x3c,\ 0x40 ) says, ``On channel 1, turn on note number 60 (middle C) with a volume of 64 (mf).'' In most cases the size of a message is determined by its status byte, so the latter may be omitted if it is the same as the status byte most recently transmitted. .PP The messages most commonly used in performance, such as those that select a synthesizer's pre-programmed voices, or turn notes on and off, are fixed by the .SM MIDI standard. An escape mechanism is provided to allow control sequences peculiar to the equipment of a given manufacturer. This .I "system exclusive" message has the form (\c .CW 0xf0, .I "ident, data," \&..., .CW 0xf7 ");" .I ident is a manufacturer's code assigned by the standards committee; the .I data is arbitrary (and can be of any length). .PP A device typically has three .SM MIDI sockets, labeled .SM IN , .SM OUT , and .SM THRU . Messages received at the .SM IN socket are acted upon in real time if the device's .SM MIDI channel number matches that of the message. In any case, the data are buffered directly to the .SM THRU socket to allow daisy-chaining. An instrument such as a keyboard may send an independent stream of messages to its .SM OUT socket. A typical .SM MIDI performance consists of (mostly) note-on and note-off messages emitted by the ``performer'' with proper timing. .PP There are several problems with .SM MIDI , the most serious of which is probably its limited bandwidth. Chords consisting of, say, ten or twelve notes become noticeably arpeggiated, and changes in timbre that might require a long system-exclusive message cannot be fitted into fast passages. Lack of flow control makes this problem even worse. .SM MIDI is also tightly bound to the twelve-tone Western scale; it is sometimes possible to work around this, again at the expense of bandwidth. .NH The .SM MIDI device driver. .PP Mark Kahrs and I built a .SM MIDI interface board that plugs into the parallel .SM I/O port of the Teletype 5620 bitmap terminal |reference(kahrs 5620). The 5620 has a \%32-bit microprocessor with 1 Mb of memory, and runs the .I mux window system |reference(blit bstj). Using the 5620 as the real-time controller, we are able to place a synthesizer under the control of a host computer (in this case, a .SM VAX 750), without a large amount of systems programming. .PP The .SM MIDI device driver (\c .I midiblt ) is down-loaded into a .I mux window, where it takes over interrupt handling on the parallel .SM I/O port. Three types of interrupts are handled: .SM UART transmitter and receiver ready, and a \%5-msec clock. .SM MIDI data are organized into three queues. Incoming messages are time-stamped and placed on the .I receiver queue, where they are available to other software. At clock interrupt, the .I scheduler queue is examined for messages with time less than or equal to the current time; such messages are moved from the scheduler queue to the .I transmitter queue, from which they are sent to the hardware as quickly as possible. .PP There is a sharp division between routines that control the .SM UART directly (and handle single characters) and those that manipulate .SM MIDI messages. For example, the .SM MIDI transmitter is a finite-state machine that understands things like elided status bytes; it is called by a lower-level routine and produces the next byte to be sent by the .SM UART . .PP Routines that empty the receiver queue and fill the scheduler queue are available from outside the driver. .I Midiblt places their entry points in a name table maintained by .I mux ; since there is no memory mapping in the 5620, they are immediately available to other programs down-loaded in the terminal. This code-sharing mechanism is used to implement a virtual-keyboard program, .I jx7 , which provides the functionality of a one-fingered mouse-pianist, with slide controls for volume, vibrato, pitch bend, etc. .NH Communication with the host. .PP Host communication takes place via the .I streams mechanism |reference(latest streams). Briefly, each window is associated with a host control stream managed by .I mux ; when a program down-loaded in the terminal does a read or write, .I mux performs the appropriate operation on the stream associated with the window. The program at the other end of the stream can be the shell (this is how multiple virtual terminals are implemented), or a special-purpose program (as in the case of a text editor). .I Midiblt falls into the second category. It mounts its stream under the name \&\c .CW .MIDI in the user's home directory, in effect creating a character-special file for the .SM MIDI driver. The terminal side of .I midiblt reads characters as they appear from the host, assembles them into .SM MIDI messages, and places the messages on the scheduler queue. (The host side of .I midiblt does not look at this data; error correction and flow control are performed by .I mux ). .PP We have followed a time-honored .UX tradition by formatting the .SM MIDI file in .SM ASCII . Such a file consists of a series of lines, one per .SM MIDI message. Each line is a sequence of blank-separated decimal numbers, viz.: event time (msec), status byte, and data. (Backslash-newline can be used to break long system-exclusive messages.) In this form, the entire panoply of .UX text-processing tools can be brought to bear in rough-and-ready fashion. .PP On the other hand, this format is not well suited for direct transmission to the 5620, since bandwidth is at a premium. The program .I midi , which compresses the data, is used; it replaces (and has similar semantics to) .CW "cat >.MIDI" . In addition, .I midi attaches itself to the .I "process group" associated with the \&\c .CW .MIDI stream. This allows the .I midiblt window to send signals to the .I midi process so that, e.g., if the user does a reset from the .I midiblt menu, there is proper coordination between the host and the driver. .PP The .CW "midi | midiblt" pattern is repeated in the programs .I score and .I scoreblt , which produce a pitch vs. time graph. .I Scoreblt manages a terminal window and draws the display. Through the code-sharing mechanism mentioned earlier, it has access to .I thinkblt which drives a HP ThinkJet dot-matrix printer. .NH Synthesizer control. .PP The system described was first used to run a Yamaha .SM DX7 and, later, a .SM TX816 . Both produce sound via .SM FM synthesis |reference(chowning), a voice being described by around 100 (digital) parameters, all settable by system-exclusive .SM MIDI messages. The .SM DX7 has internal memory for 32 pre-loaded voices that can be selected by number (via the .SM MIDI .I "program change" message). It is a keyboard instrument with additional controls for editing voice parameters (the current voice, whether internal or downloaded, is always copied into an editing buffer). Although the .SM DX7 is limited to playing in one voice at a time, up to 16 simultaneous notes can be produced. The .SM TX816 is a rack-mounted unit consisting of eight .SM TF1 "'s." Each .SM TF1 is essentially a .SM DX7 without keyboard, and can be set to a different .SM MIDI channel, so that orchestral and multi-track effects are possible. .PP A number of C programs are used for synthesizer configuration. .I Txchan assigns channel numbers to the .SM TF1 "'s." .I Mecho is used to send ``constant'' data (such as to select an internal voice, or alter single parameters of a voice). .I Dxvoice downloads voice data from a library file on the host. Figure 1 is an example of a shell script that sets up the .SM TX816 with five instruments, one of which (the harpsichord) uses two .SM TF1 "'s" in parallel. The violin voice needs to be downloaded; the rest are already stored in the proper .SM TF1 "'s" (they came from the factory this way). Percent signs delimit comments to .I mecho . .1C .KF top .P1 txchan 1 1 3 4 5 6 7 8 mecho init \e prog -c1 28 % harpsichord chan 1 % \e -c4 3 % reeds chan 4 % \e -c6 24 % flute chan 6 % \e -c8 3 % bass pipes chan 8 % \e dx -c8 p144 24 % move up an octave % \e parm -c4 p4 127 % foot control reeds % \e -c6 p2 127 % breath control flute % \e -c8 p4 127 % foot control pipes % dxvoice -c3 -v2 tx816.8 # solo violin chan 3 .P2 .FG 1 "Setting up the TX816" .KE .2C .PP This scheme is complete in that it allows access to any .SM MIDI or .SM DX parameter, but it is not altogether satisfactory. The user must know, for example, that voice 3 is ``reeds'' in the fourth unit, but ``bass pipes'' in the eighth. Simply assigning names to numbered parameters does not reduce the complexity, however. Ideally, one would like an interactive ``orchestration editor'' supported by a large database. .1C .KF bottom .P1 main() { int c, x, y, z, magic = 13, size = 64; int mask = 2*size-1; for (c = z = 0; c <= mask; c++, z += magic) for (newfile(), y=0; y < size; y++) if ((x = (y ^ z) & mask) < size) play((x+y), (x-y)); } .P2 .FG 2 "Munching squares" .KE .2C .NH Musical examples in C and the shell. .PP The first piece to be played on our system was written by Cynthia P. Killian using a combination of C and the Bourne shell. The composer took raw material produced by the ``munching squares'' algorithm and manipulated it by splicing and dubbing techniques. Figure 2 shows the heart of the algorithm. .I X and .I y trace out short diagonal segments, which are rotated by 45 degrees and passed to .I play . The resulting vertical coordinate is mapped onto a tone row, and the length of the segment (as determined by a sequence of points at the same height) determines the length of time the tone is held. .I Newfile breaks the output into separate small files (\c .CW smunch.\fI?? ) for convenience. The latter are then processed by shell scripts like that shown in Figure 3. The unfamiliar commands in the script are either shell scripts or trivial C programs. .I Sed and .I "sort\ \-n" form the basis for cutting and pasting. Operators that do a lot of arithmetic (e.g, .I retro , which time-reverses its input) are written in C. The shell syntax for operator precedence and the semantics of the .UX filter are extremely well matched to this application. .1C .KF .P1 (divider <smunch.06 3 4; divider <smunch.07 1 2 divider <smunch.07 1 2 | invert 0 1120 0 | retro) | ttrans 0 280 >tmp$$ (cat tmp$$ divider <smunch.08 7 8) | ttrans `endtime <tmp$$` -1260 rm tmp$$ .P2 .FG 3 "Shell script for processing munching squares" .KE .KF bottom .P1 /* Inventio 4 (BWV 775) */ 8 = 120 /* tempo: 120 eighth notes/min */ 3 / 8 /* time signature */ { treble : 1 < 6(16) | 6(16) > | F60: d3 e f g a b@ | c# b@ a g f e | bass : 1 < 4. | 4. > | F60: r | r | treble < 3(8) | 3(8) | 6(16) > | f a d4 | g3 c4# e | d e f g a b@ | bass < 6(16) | 6(16) | 3(8) > | d2 e f g a b@ | c# b@ a g f e | f a d3 | \&... } .P2 .FG 4 "The beginning of a Bach invention" .KE .2C .NH The M language. .PP The need for a closer tie with standard musical notation led to the development of the M language. We will try to give a feel for the language with a short example shown in Figure 4. .PP An M file consists of ``front matter'' followed by text enclosed in matching curly braces. The comment convention is similar to C's, except that comments nest. The music is divided into .I lines formed by a .I "voice name" , an optional colon and .SM MIDI channel number, a .I "rhythm list" , and corresponding .I "note list" . Voice names are arbitrary alphanumeric strings. Within rhythm and note lists, measures are delimited by barlines. A rhythm list consists of .I "time values" (\c .CW \%1 "\&\ =\ whole note," .CW \%2 "\&\ =\ half note," .CW \%4 "\&\ =\ quarter note," .CW \%4. "\&\ =\ dotted quarter note," etc.) and .I rests, possibly with repeated groups (\c .CW "3(16 16r)" means .\".fp 9 MU Musicpi .\"\f(MU\N'140'\fP\ \f(MU\N'24'\fP .\"\f(MU\N'140'\fP\ \f(MU\N'24'\fP .\"\f(MU\N'140'\fP\ \f(MU\N'24'\fP). .fp 8 MU Sonata \f(MU\N'120'\fP\ \f(MU\N'197'\fP \f(MU\N'120'\fP\ \f(MU\N'197'\fP \f(MU\N'120'\fP\ \f(MU\N'197'\fP ). A note list consists of .I notes , .I rests , and .I modifiers . Notes specify .I "pitch class" and, optionally, .I "octave number" . Pitch class is indicated in standard letter notation, with accidentals .CW # , .CW @ (flat), and .CW = (natural). The octave is given by a number appearing after the letter name, e.g., .CW c3 is middle c, and .CW c3# , .CW c#3 are a half-tone above. The octave number changes between b and c, so a half-tone below middle c is .CW b2 . A missing octave number defaults to that of the previous note in the same voice. Rests have time value only and are indicated by .CW r . .PP Modifiers are used to set ``environmental'' parameters; in the example, the modifier .CW F60 specifies a ``key force'' (volume) of 60 units. .PP Not shown in the example are notations for ties and more complicated rhythms. Ties map particularly easily onto .SM MIDI events. Observe that a note usually generates two .SM MIDI events, note-on and note-off. A note with a tie going out (e.g., .CW \%c- ")," simply loses its note-off event, and one with a tie coming in (e.g., .CW _c ")" loses its note-on event. Time values may contain multiplicative expressions, e.g., .CW 3(3*4) is a triplet to a quarter note. Finally, values that are inconvenient to generate otherwise can be specified with numerator and denominator, e.g., .CW 9/17 . .PP Also not shown in the example are possibilities for grouping in the note list. Parentheses group a .I sequence , and square brackets group a .I chord . E.g., all of the notes in .CW "[c\ e\ g]" are sounded simultaneously, and groupings may be nested, so that .CW "[(c\ d\ c) (e\ g\ e) (g\ b\ g)]" has three sequences running in parallel to make a \%I-V-I progression. .PP To facilitate machine generation of M code, an alternative rhythm notation is allowed: the rhythm list can be omitted, and time values prefixed to the corresponding notes. This is readable to humans, but less convenient for keyboard input (see below). .PP M is based on .I lex and .I yacc , and its continuing development depends heavily on them. M is intended to be used by musicians who are not computer scientists, and who can't always pass on the merits of a feature without testing it. Hence the ability to experiment is most important. .I Lex in particular has been justly criticized on performance grounds, given that lexical analyzers are fairly easy to write by hand. But this is the case only for a static language, and M is still changing rapidly, particularly in the area of dynamics control. .PP M produces a .SM MIDI file on its standard output, so that .CW "m bach\ |\ midi" is an example of a common invocation. It also has options to restrict the output to certain voices or a range of measures, as a debugging aid. .NH The M keyboard interface. .PP It is possible to generate the notes of an M program by playing at the .SM DX7 keyboard. First the note-on and note-off events are collected by .I midiblt and written into a file on the host. This file is then converted into a list of note names by .I unmidi . We have used the conventions that the .SM DX7 "'s" .SM YES button generates a newline, and the .SM NO button produces the comment .CW "/*?*/" . This gives the user some control over the format and the ability to flag errors. We also use the ``portamento'' pedal to generate a barline. .I Unmidi has an ``output key'' option to direct it towards desired enharmonic spellings. The output from .I unmidi is fed to an .I awk script which adds voice names. Now only the rhythm is missing. Since it is separate from the notes, it can be typed in quickly by making a second pass over the score. .NH Conclusions. .PP Twelve-tone pieces such as the one in section 5, and serialized pieces particularly, would be easier and faster to develop with the aid of specialized tools. These could range anywhere from a library of C routines to a complete language implementation. We expect to begin on a modest scale with the former and enlist the efforts of interested composers. .PP It is clear that we have barely scratched the surface of an immensely challenging class of problems. The .UX system, originally crafted as a home for programmers, has proven remarkably robust, flexible, and downright hospitable as a base for a very different application. .NH References. .LP |reference_placement