Using the "LISP Kernel" Musical Environment John Rahn, Richard Karpen, Craig Weston, and Charles Hiestand School of Music, University of Washington Seattle, Washington 98195 USA December 1989 Introduction This portmanteau article will serve as a sampler of some of the ways in which computers are being used at the University of Washington to teach music composition and music theory, and to produce computer music. First, John Rahn will describe the current structure of such teaching, and will introduce the LISP Kernel software which we are using for both teaching and research in computer music. Then Richard Karpen, who joined the faculty here in Fall of 1989, will show how using computers can help composers become better composers, focussing on the compositional process and illustrating with some examples of LISP code using the LISP Kernel. Next, Craig Weston, who is currently a doctoral candidate in composition here, talks about the "granular synthesis" strategy for sound synthesis, which uses large numbers of "notes" to produce each complex sound object. Finally, Charles Hiestand, also a doctoral candidate in composition, describes how he is using twelve-tone music theory and composition in the same integrated environment. Teaching computer music at the University of Washington Courses in computer applications to music are distributed among the undergraduate and graduate programs in composition, theory, systematic musicology, music technology, and music education. The School of Music Computer Center provides shared facilities for instruction and research, including IBM ATs, Mac IIx's, and NeXT computers, as well as links to various mainframe computers. Faculty offices and labs have other hardware for research, mostly NeXT machines. Many faculty in the School of Music use computers for musical applications, but there are currently four School of Music faculty who are actively pursuing research interests that include writing software. Dr John Rahn has been working in composition and theory, and has written software for theoretical investigations, for sound synthesis, and the LISP Kernel described below (Rahn 1988, 1989, 1990a, 1990b). Dr Douglas Keefe, a physicist, is doing research in areas including digital signal processing,modelling perception with neural nets, physical musical instrument system simulation and design, and chaos theory (e.g. Laden and Keefe 1989). Robert Duisberg, who teaches the music technology courses, has doctorates in both composition and computer science, and interests in language design, user interfaces, and Smalltalk; he holds a recent patent in program animation using temporal constraints. Dr Richard Karpen is a composer who has worked in computer music at Brooklyn College, Padua, IRCAM, and Stanford. In general, the approach followed here is to teach computer applications to music at a sophisticated level that involves the student in programming in languages including FORTRAN, Pascal, C, LISP, and Smalltalk. The LISP Kernel When personal computer hardware first became powerful enough to support the idea of a computer music workstation (around 1984), it seemed necessary to rethink the working environment for a composer or other computer music researcher who needs to hear sounds. Previously, useful music software ran on mainframes, each of which had its own idiosyncratic operating system and set of available languages, so that each center for research in computer music tended to develop elaborate and useful environments that were of no use whatever to anyone outside that particular institution. For instance, the Pla music language at Stanford was written itself in SAIL, an artificial intelligence language generally not found elsewhere. Some centers gradually were standardizing within Unix and C, but this was not yet available to musicians everywhere -- not then at the University of Washington -- and personal computers were not yet powerful enough to run Unix. The profusion of microcomputer operating systems, the nonstandardization of languages and non-portability even of software written in an older language such as FORTRAN from one microcomputer to another, and the proliferation of commercial MIDI programs for music which hid their internal data structures and in general could not communicate with one another -- all these factors painted a muddy picture of the future. During 1984-86 I designed what was intended to be a portable, useful environment for musical composition and research, a "kernel" that would occupy the logical middle of any music workstation system. All other applications would communicate with this Kernel, and therefore with each other. To implement this system, I chose LISP, because it has been around almost as long as FORTRAN and has proven especially adept at tasks such as translating from one data representation or language to another and implementing other languages, as well as at general high-level symbolic processing. This was something of a gamble, as at the time no personal computer had the speed or memory required to run large LISP programs, but it seemed a safe gamble that as hardware was improving by doubling capacity every year or two, LISP would run adequately on available personal computers by the time the LISP Kernel was finally written. In fact, it was 1988 by the time the LISP Kernel was fully implemented. At that time I taught LISP using IBM ATs with extra memory, and shared Vax minicomputers. Since then, a good LISP has appeared on the Mac II, and the NeXT corporation shipped a full Common LISP with its machines starting in Fall of 1989. Common LISP is also now appearing on most supercomputers as the US Department of Defence promotes that standard. Within the past year or so, a number of LISP systems for musical applications and other LISP research in music have been announced or are under development (Boynton et al 1986; Dannenberg 1989a, 1989b; Desain 1990; Garton 1989; McNabb and Jaffe 1989; Taube 1989). This is not to say the LISP is the best or only possible language for such work -- much good work has been done in Smalltalk, for example, and constraint logic programming languages show promise -- but it does indicate that LISP is now a viable and popular language for this kind of application. Further introduction to LISP in music may be found in Rahn 1990a and Desain 1990; the best textbook is Abelson and Sussman 1984; and the standard reference for Common LISP is Steele 1984. The current working ingredients of the LISP Kernel are the data structure for music representation at the note level and at higher levels, a simple database capability, the composing language LISPfront, various utilities or tools for the user, its own simple object-oriented programming facilities (OOP), the ability to input and output MIDI data via Adagio files, and the ability to output score data to the general-purpose synthesis programs Music4P, CSound, and the NeXT MusicKit. It is written entirely in a "minimal LISP" subset of Common LISP, and has run without any modifications in Kyoto Common LISP, Gold Hill Common LISP, and the Allegro Common LISP from Franz, Inc. supplied with the NeXT computer. The LISP Kernel is more fully described in Rahn 1990b. The LISP Kernel source code, which is liberally commented and to some extent self-documenting, is currently freely available by anonymous FTP: FTP BLAKE.U.WASHINGTON.EDU, CD PUB/RAHN, GET KERNEL.CL. (Unfortunately, none of us will be able to take the time to answer very many questions about it.) Improved versions will be posted as they accumulate enough changes of significance. One of the most important aspects of the LISP Kernel is its ability to communicate effortlessly with user-written software, and to serve a wide range of idiosyncratic purposes without forcing them into its own mindset, as illustrated in the following contributions by Richard Karpen, Craig Weston, and Charles Hiestand. This design feature depends on avoiding as much as possible the implementation of specialized concepts within the Kernel, leaving them to the user. The less theory is programmed into the system, the more general the system can be. Also, the LISP Kernel is easy to learn to work with, since the data structures are uniformly homogeneous and there are consistent naming conventions for accessor functions, and the structure is logical and consistent. There is at the moment no manual, but users familiar with LISP have generally been able to learn to work with the Kernel within a day by looking at a few examples included in the source code and reading some of the commented source code itself. It is relatively easy to make even major changes to the Kernel source code to add new features or to modify and maintain old ones, because it employs a discipline of data abstraction and procedure abstraction and adheres as far as possible to a functional style of programming. Richard Karpen: Using computers can help us to become better composers How many composers can imagine life without photocopying machines for making multiple copies of their scores and parts? Although xerography is a relatively recent technology, it now seems necessary, integral, something which makes it possible to carry on with one's work. It seems that technological advances, such as the advent of the photocopying machine, arrive at the very moment when it would seem impossible to do without such a device. The computer has become such a device for many composers around the world, but they are much more complicated than photocopying machines and since they can be used for so many and such varied musical applications the ramifications of their use has been and will continue to be even more profound. The complexity of computers and their seemingly abstract relationship to music have kept their importance from becoming immediately and universally accepted. But as high quality computing becomes faster, cheaper, and in all ways more accessible to musicians who do not double as computer scientists (this has happened over the last few years), the impact will be to make computers not just convenient, handy devices, but tools that will become integral to the work of virtually all composers. And it is clear to me that it cannot happen too soon. Younger composers, who are struggling to learn their craft in the current morass of conventional instrumental music, will especially benefit from using computers as an aid to learning how to compose. I am not talking about the use of some anonymously written computer software which professes the ability to teach composition by having students follow certain procedures (one should be equally sceptical of those textbooks which do the same). Simply through the process of composing with and for computers, using them, for example, as aids to the generation of musical data (scores) and the realization of the potential of the data (sound and/or music), composers will become better at what they do. They will become better not only at composing for computers but also will become better at composing for any medium with which they choose to work. How can computers help us to become better composers? I will give some simple examples and also tie in the subject with work at the University of Washington using the LISP Kernel. Let's forget the notion that all great composers are geniuses and imagine that they become great by practicing. Let's take Haydn as an example. When he was still relatively young he had performers more or less at his disposal to play his pieces as soon as he had finished composing them. He had the opportunity to hear his new pieces, and if there were things which he felt could have been done better he had the choice either of making changes and having it played again, or of trying to do it better in the next piece. Haydn composed (and got to hear) enough string quartets and symphonies so that he should have been the master he was by the one-hundredth composition! By comparison, even the fairly successful composers of today rarely have the opportunity to hear multiple, well-rehearsed performances of their compositions. There are many reasons for the existence of this situation. They are cultural, socio-economic, and so on. They will not be discussed here. But whatever the reasons, the situation is often even more hopeless for younger composers. As a result, a mythology seems to have grown up that a composition is finished before it has had its first performance, and that any mistakes should have been caught before the rehearsals have begun. What ever happened to the adage that one learns by one's mistakes? Here's where the computer comes in. If one chooses to realize music using the computer (including the generation of the sounds, since some composers use computers as an aid to generating music which is to be played by conventional instruments), then what one has is a captive performer, or an entire "orchestra" if that is desired. It is possible to realize a composition or part of a composition, listen to it, make changes and re-realize the piece or section of a piece, listen again, and so on. It is not an original observation to note that work in electronic and computer music brings composers closer to the "studio artists" such as painters and sculptors. The important point here is that with computers it is possible to shape and reshape one's music until it reaches a state which is at least acceptable to the composer. (I will avoid the entire issue of aesthetics and pretend, for this article, that all composers are honest, self-critical artists who try their best to make their music as meaningful as they can! One can then assume, for the sake of argument, that the result of all this fine tuning is actually music.) One of the most common types of misjudgment composers make is in the "timing" of a composition. When should a particular event happen? How long should this section be? Does that change in loudness happen gradually enough? Too gradually? The use of a computer can be extremely helpful in this area of compositional work. Here is a simple (but unfortunately not very musical) example of a program using the LISP Kernel which generates a stream of two hundred notes in chronological order, each one slightly louder than the one before it (a crescendo). (SETQ NUM-OF-NOTES 200) (SETQ STARTING-NOTE 0) (PIECE 'EXAMPLE) (DO* ((NOTE-COUNTER STARTING-NOTE (+ NOTE-COUNTER1))) ((> NOTE-COUNTER (+ STARTING-NOTE NUM-OF-NOTES))) (CREATE-NOTE) ; initialize new note (-> INSNO 1) ; The synthesis instrument number for the CSound "orchestra". ;The "->" means "assign the value 1 to insno. (-> START (* NOTE-COUNTER .1)) ; The start times of each note. (-> DUR .1) ; The durations of each note. (-> PITCH (CYCLE NOTE-COUNTER '(C4 CS4 D4 DS4 E4 F4 FS4 G4 GS4 AS4 B4))) ; Cyclical use of chromatic scale. (-> LOUDNESS (LOOKUP NOTE-COUNTER '((0 1) (200 1.5)))) ; Crescendo from loudness of 1 at the 0th to 1.5 at the 200th note. (SAVE-NOTE 'EXAMPLE) ; Save each note in the database piece-name EXAMPLE. ) (PRINTCS 'EXAMPLE "EXAMP-SCORE") ; Print the score "example" into the file ; "examp-score" in CSound note-list format for synthesis by CSound "orchestra." (SHELL "PERF ORCHESTRA EXAMP-SCORE") ; "Perf" is the command to run ; the CSound synthesis program. It takes as arguments "orchestra" as the name of ; the CSound synthesis program file and "examp-score" as the name of the ; CSound note-list. The LOOKUP function acts as an envelope, shaping the entire stream of notes according to the values given as arguments to the function. Suppose the composer listens to this score and decides that there should still be two hundred notes but that the crescendo should happen faster, it should get louder, and it should be followed by a slight decrescendo. The LOUDNESS parameter in the score might then be be changed to (-> LOUDNESS (LOOKUP NOTE-COUNTER '((0 1) (150 2.5) (200 2.))) ; crescendo from 1 to 2.5 over 150 notes followed by a ; decrescendo over the remaining 50 notes. The composer can then listen again and either keep the new version or try yet another change. This can be done of course with any parameter, such as pitch, tempo, durations, and any special parameters which are called for by the sound-producing part of the program. Suppose that the composer then decides to make the pitch of every other note one octave higher than in the original chromatic list and to cause the notes to overlap in time by a little bit. The changes might look like this: (-> PITCH (* (CYCLE NOTE-COUNTER '(1 2)) (CYCLE NOTE-COUNTER '(C4 CS4 D4 DS4 E4 F4 FS4 G4 GS4 AS4 B4)))) (-> DUR .15) ; The duration of each note is now .15, but the notes still start every .1 seconds ; as above; a .05 seconds overlap. It is often desirable to make the value of one parameter dependent upon another one. For example, the LOUDNESS can be dependent upon the PITCH. (-> LOUDNESS (LOOKUP NOTE-COUNTER '((0 1) (150 2.5) (200 2.))) (IF (> PITCH AS4) (-> LOUDNESS (* LOUDNESS 2.)) (IF (< PITCH D4) (-> LOUDNESS (* LOUDNESS .5))) ) This statement says that if the pitch is greater than AS4 (A sharp above middle C), then the loudness value should be doubled, if the pitch is less than D4 then the loudness value should be halved, and if neither case is true then LOUDNESS remains unchanged. This example causes higher pitched notes to be extra loud, lower pitched notes to be extra soft, and middle pitched notes to be of medium loudness relative to the others. It is easy to see that such scores/programs can become arbitrarily complicated (unlike the simple examples shown here). A composer can work by gradually building up structures through relationships between parameters as above, or by carefully shaping the dynamic evolution of parametric data until forms which seem appropriate to the gestures, events, and relationships become evident. Working in this way can help bring about organic relationships between form, content, structure, meaning, and so on. The following and last example shows a slightly more complicated but still fairly simple program which generates surprisingly "life-like" rhythms for a synthetic percussion sound. It demonstrates the relationship between parameters as well as the shaping of the changes in the values of various parameters over the period of time which is occupied by the music which is generated. This program generates a note-list in NeXT MusicKit Scorefile format. (PIECE 'MK1) ; The notes generated will be stored as a list under the name MK1. (SETQ THE-HEADER ; The following will be printed verbatim ; at the top of the scorefile. "info samplingRate:22050.00000, tempo:40; envelope indexFun2 = [(0., 4., 1.)(0.00040, 1., 1.)(0.40, 0., 1.)]; envelope ampFun3 = [(0., 1., 1.)(0.00060, 0.50, 1.)(10., 0., 0.60000) | (10.03, 0., 0.02000)]; part P2; P2 synthPatch: \"Fm1i\"; BEGIN; P2 (noteUpdate) m1Ind0:1.58, m1IndEnv: indexFun2, ampEnv: ampFun3, m1Ratio:4.44440; ") (ASSIGN-ORCH '(2 (P2) )) (ASSIGN-TEMPLATE 'P2 '(INSTRUMENT START DUR AMP FREQ BEARING AMPATT M1INDATT)) (ASSIGN-ALL-PRINTNAMES 'P2 'AMP "amp:" 'FREQ "freq:" 'BEARING "bearing:" 'AMPATT "ampAtt:" 'M1INDATT "m1IndAtt:") (ASSIGN-DEFAULT-FORMAT 'P2 "~0,5f") ; Print parameters with 5 decimal places. (SETQ NUM-OF-NOTES 2000) ; Generate 2000 notes. (SETQ STARTING-NOTE 0) ; Start at the first note. (INIT RANDOM-STATE 10) ; Give an initial seed value to the LISP ; random number generator. (DO* ((NOTE-COUNTER STARTING-NOTE (+ NOTE-COUNTER 1)) ; Initialize and update the note counter. (BEG .5 (+ BEG (+ .07 (RANDOM .002)))) ; Begin times of each note. (DURX .25 (* .25 (LOOKUP NOTE-COUNTER '( (0 1) (1000 1) (1500 2) (2000 .5))))) ; Scale the durations by a LOOKUP. (AMP .5 (+ .5 (RANDOM .5))) ; Random amplitude between .5 and 1. ) ((> NOTE-COUNTER (+ STARTING-NOTE NUM-OF-NOTES))) ; Keep generating notes until this is true. (CREATE-NOTE) (-> INSNO 2) (-> BEARING (- 45 (RANDOM 90))) ; Random stereo location. (-> START BEG) (-> FREQ (* (NTH NOTE-COUNTER PLISTX) (+ 1 (RANDOM .05)))) ; Get pitches from the list PLISTX (compiled by another ; program), and distune slightly. (IF (> AMP .9) ; If the amplitude is greater than .9 (PROGN (SETQ AMP (+ .4 AMP)) ; then make it even greater (SETQ BEG (+ BEG (+ .1 (RANDOM .2)))) ; and make the note after the loud one start from ; .1 to .3 seconds later than it would have. ) (SETQ AMP (* .3 AMP)) ; If the amplitude is not greater than .9 than make the note even softer. ) (-> DUR DURX) (-> AMP AMP) (-> AMPATT DURX) (-> M1INDATT (* .1 DURX)) (SAVE-NOTE 'MK1)) (PRINTMK 'MK1 "MK.SCORE" THE-HEADER) ; Print to the scorefile. (SHELL "PLAYSCORE MK.SCORE") ; Play the score using the NeXT's DSP MusicKit. The program above simply produces a group of closely spaced soft notes ending in a much louder one, followed by a short silence, followed by another group of fast, soft notes at the end of which is again a louder one (the comments in the program explain how this works). This continues until the NOTE-COUNTER reaches the NUM-OF-NOTES. The number of notes in each of these groups is determined by how often the AMP parameter is greater than .9. Since this is handled by a random number generator, the size of each group is also random. It would be possible to make a random number generator which could be "tuned" to return pseudo-random numbers according to a weighting procedure of some kind such as a fractal. In that way in would be possible to have the outcome be more predictable and/or controllable. Note also that the durations (the parameter name DURX) are scaled by a LOOKUP in this program. For the first one thousand notes the durations stay at .25 seconds. They are then increased until the fifteen- hundredth note, when they are scaled by two, giving durations of .5 seconds, and they are then decreased until the two thousandth note, when they are finally scaled by half giving a duration of .125. It should be noted that this does not increase the tempo, since the begin times are separate from the durations, a common practice in computer music. As a closing remark, I would like to make it clear that I am not suggesting that composing with computers can or should replace all of the traditional ways in which we learn, teach and practice the art of music composition (xerography has not replaced the pencil). I am suggesting, however, that when the use of computers becomes incorporated as an integral part of our musical culture (which is happening already in ever wider circles of musical activity), it will stimulate and invigorate the imaginations of all composers, musicians, and their audiences. Craig Weston: Making sounds out of notes With the development of the LISP Kernel, much early effort among users was devoted to the development of precompositional tools to be used in conjunction with the Kernel. Indeed, much of the promise of a front-end such as the LISP Kernel is the ability to carry out both precompositional and compositional procedures. This has been a fruitful approach, particularly in the field of implementation of pitch/pitch-class set and serial operations (as discussed below by Charles Hiestand). While much of the attention has been devoted to functions which normally operate on pitches or pitch classes (and therefore normally expect lists of pitches or pitch classes as their arguments), it must be emphasized that lists in LISP need not carry any parametric association. A very powerful approach to precomposition which takes advantage of the data abstraction of LISP is to develop a package of general functions for list manipulation, and to generate lists which are not considered to be lists of values for some parameter, but rather abstract representations, somewhat similar to shapes in Larry Polansky and David Rosenboom's HMSL (Polansky, Rosenboom, and Burk 1987, 1990), which, during the compositional process, become candidates for various musical parameters. Such an approach, however, embodies an assumption that precomposition is completed before composition begins. A more realistic paradigm (at least according to the compositional strategy of this author) is one in which precomposition and composition coexist throughout the process of creating the piece. While some aspects of precomposition may be worked out rather thoroughly in advance, there is invariably some element of the piece "telling the composer how it should be written" as it unfolds, requiring some additional precompositional consideration or reconsideration. Therefore, the most useful type of front-end for this composer is one that offers useful precompositional tools, but also allows the products of that precompositional effort to be easily converted into compositionally meaningful data. Since the precomposition process in LISP typically involves manipulating lists, these lists must be directly convertible into compositional data ("notes") without being disassembled into individual elements. A very basic example of a function which facilitates this goal in conjunction with the LISP Kernel is NOTE-BLOCK, which takes only the most basic parameters (instrument number, start time, duration, amplitude, and frequency), but which expects the parameters to be either single values or lists of values, and which creates a list of notes when it is given a list for one or more of its parameters. For example, if given the following parameters Instrument Number: (1 2 3 4 5 6) Start Time: 43 Duration: 2.5 Amplitude: 500 Frequency: (7.01 7.09 8.00 8.05 8.08 9.04) (in octave-point pitch notation, where 8.00 = middle C) NOTE-BLOCK will return a list of six LISP Kernel note structures, which, in this simple example, form a chord using "instruments" one through six. The list of pitches might easily been generated by precompositional procedures, probably as a list of pitch-class integers (1 9 0 5 8 4), to which the octave designations can be added. Although NOTE-BLOCK returns a list of note-value structures in the form of LISP Kernel notes, the information is not saved to a "piece" in the Kernel, and therefore the returned list is still simply a list and is subject to further manipulation, which might typically include the addition of further parameters such as information about timbre or articulation. This closely models a common paper-and-pencil strategy of notating pitch and rhythm first, and then adding additional information. One approach being explored is to utilize traditional modifying terms, such as "legato" or "sfz," from which conversion functions calculate the more specific parametric information before the notes are saved into a LISP Kernel piece. While this particular strategy of separating certain aspects of musical information may not be appropriate for some compositional approaches, this simple example demonstrates the sense in which whatever distinction that may exist between precomposition and composition can be minimized by not actually creating LISP Kernel note structures until the very end of the process, therefore maintaining maximal manipulability throughout the process. While a useful and flexible tool in and of itself, the true power of the NOTE-BLOCK function emerges when it is called by other, more global functions, such as the GRANULAR-BLOCK to be discussed below. Just as some composers find it useful to minimize the distinction between precomposition and composition, many composers of computer music have sought to minimize the distinction between score and instrument. This has been the modus operandi of object- oriented approaches in particular, such as Carla Scaletti's Kyma (Scaletti 1989a, 1989b). A different approach can be explored with the LISP Kernel, in which much of what might be considered the task of the instrument is actually carried out by the generation of many "notes" within the score. (For a different system for "granular synthesis" see Truax 1988, 1990.) A function called GRANULAR-BLOCK fills with user-defined granular events a musical space, which is defined by its upper and lower boundaries. In this way, complex sounds are created using a very simple "instrument" (typically a simple FM instrument) by generating a block which consists of perhaps thousands of individual "notes." A current prototype of GRANULAR-BLOCK takes a boundary list for the musical space to be filled, which defines the boundaries of the space at various times. This boundary list can be generated from two lines (as defined by their respective start time and frequency lists), in which case the boundaries of the space will be changed whenever one of the lines changes its frequency. The user also specifies the density with which the space is to be filled (the number of granular "voices"), how the space is to be filled (i.e. equal-tempered increments, logarithmically, etc), and defines the granular events themselves. Random fluctuations in the frequencies, durations, and amplitudes of the granular events can also be specified. GRANULAR-BLOCK calculates the necessary parametric values and calls NOTE-BLOCK for each "voice," so that the result is a list of note-structure information for the entire block. Since the note-structures have not yet been saved as LISP Kernel data, this list can still be manipulated as discussed above. One such manipulation involves the use of time-varying functions to introduce higher-level effects such as crescendi and diminuendi within the entire block or the individual granular voices over a portion or all of the defined block. (This is, of course, in addition to user-specifiable random "jitters" in amplitude, frequency, etc. at the more local, granular level.) By maintaining the note information as a list, it is possible to define and manipulate easily segments of many "notes." When applied to a musical space which is larger than a few semitones, and/or is sparsely filled (granular events at an increment of say a quarter-tone or greater), the result perceptually is of a block consisting of very many notes, which possesses a "static motion" property, somewhat analogous to some of the "wall of sound" passages in the orchestral music of Ligeti, Penderecki and others. However, when the defined space is small and densely filled, the result is more likely to be perceived as a single, extremely complex "note," with a quality which might be described as "shimmering." Thus, what we might call the task of the instrument, to create sufficiently complex and interesting "notes," has actually been done largely in the "score," and realized on a relatively simple instrument. Given the power of LISP to generate and manipulate the lists which eventually become the score, this approach of creating complex sounds as a composite of many individual notes (which would be a nightmare if the composer were inputting note data directly into a synthesis program!) is a simple and straightforward strategy, of which GRANULAR-BLOCK is but one of many possible implementations. The user is able to move smoothly from precompositional possibilities to simple compositional events to large-scale blocks of complex sounds, without being forced into getting his/her hands dirty at an extremely local level of individual note information. This minute level of control is, of course, always available to the user if desired. Herein lies the greatest power of this approach to the use of LISP and the LISP Kernel: the user is free to control his/her piece at all levels, from the most global to the minutely local, without becoming trapped in the quagmire of information overkill which arises when one is always limited to individual note-value parameters. Charles Hiestand: Twelve-tone theory and composition in the same environment For the last year, off and on, I have been writing various serial operations in LISP. These operations have been useful for both theoretical explorations and to prepare large amounts of data for algorithmic computer compositions. LISP is a computer language designed for manipulating lists (LISt Processing). A twelve-tone row can be viewed as an ordered list or, equivalently, as an unordered set of ordered pairs. For example (0 e 7 9 6 1 t 2 5 4 3 8) is equivalent to {(0,0) (1,e) (2,7) (3,9) (4,6) (5,1) (6,t) (7,2) (8,5) (9,4) (t,3) (e,8)}. For explanations of the music theory referred to here, see Rahn (1980) and Morris (1987). My motivations have been more compositional than theoretical. The desire to build formally coherent compositions has attracted me to the extraordinary computational and sound-generating powers of the computer. I have been developing compositional ideas requiring 12-by-12-by-12 cubical arrays that explore the evolution of a row through the course of a number of manipulations. These manipulations include the standard twelve- tone group operations of transposition (TRANSPO), inversion (INVERT), and multiplying each element by 5 (MX), with the addition of Michael Stanfield's "exchange operation" (EX), which swaps the order numbers and pitch-class numbers of a row (Stanfield 1984, 1985), along with the ability to devise Babbittian matrices. After making a few compositions with pencil and paper it became clear to me that it would be a great help to write LISP procedures to build my cubes, and at the same time this would enable me easily to interface my data with John Rahn's LISP Kernel for musical composition (Rahn 1988, 1990a, 1990b). LISP works by operating on lists. Unless told otherwise (a single quote ' or the name of a special form such as DEFUN), LISP sees the first symbol following a left parenthesis as the name of a function to be evaluated, with the rest of the contents of the list being the arguments passed to the function. LISP then returns a result. Evaluation starts at the innermost set of parentheses. A row, represented as a list in either of the two ways described, can be readily operated on by standard LISP procedures and simple procedures written in LISP. An example of how natural serial operations are to LISP would be the definition of the retrograde operation. We start by assigning a row (as a list) to the variable A-ROW: (SETQ A-ROW '(0 e 7 9 6 1 t 2 5 4 3 8)) Then we define a function: (DEFUN RETRO (A-ROW) (REVERSE A-ROW)) We can invoke the function RETRO by listing it with its appropriate arguments: (RETRO A-ROW) The argument needn't be called A-ROW, just so long as its in the right position and is in a form the function can deal with. The function RETRO expects the argument A-ROW to be an ordered list (0 e 7 9 6 1 ...) and, using the built-in Common LISP function REVERSE, it returns the retrograde form of the row. Many serial procedures transform the row by performing some operation on each element of the row. The way to implement this idiomatically in LISP is via "tail recursion," which the LISP compiler makes as efficient as simple iteration -- the two are formally equivalent (Abelson and Sussman 1984). An example is a simple transposing function. Note that the lexical scoping of Common LISP allows isolating the definition of the auxiliary function from the general LISP environment by making its definition part of the definition of the calling function. (DEFUN TRANSPO (A-ROW A-NUMBER) (DEFUN TRANSPO-AUX (A-ROW A-NUMBER RESULT) (COND ((NULL A-ROW) (REVERSE RESULT)) (T (TRANSPO-AUX (CDR A-ROW) A-NUMBER (CONS (MOD (+ A-NUMBER (CAR A-ROW)) 12) RESULT) ) ) ) ) (TRANSPO-AUX A-ROW A-NUMBER NIL) ) When invoked, TRANSPO-AUX calls itself recursively, using CONS to build the result, with A-NUMBER added to the first element of the row mod 12; the function TRANSPO calls the recursive auxiliary function TRANSPO-AUX, initializing the result to NIL, the empty list. Sometimes it is useful to write general-purpose functions that more than one operation can share. MX takes any number and multiplies an element by that number mod 12. (DEFUN MX (X AN-ELEMENT) (MOD (* X AN-ELEMENT) 12)) MX-AUX uses MX and recursion to multiply each element in a list by an arbitrary number, mod 12. The function is very similar in form to the transpose function. (DEFUN MX-AUX (X A-ROW RESULT) (COND ((NULL A-ROW) (REVERSE RESULT)) (T (MX-AUX X (CDR A-ROW) (CONS (MX X (CAR A-ROW)) RESULT) ) ) ) ) The next three functions use MX and MX-aux to obtain the circle-of-fourths and circle- of-fifths transforms and inversion of a row. (DEFUN M5 (A-ROW) (MX-AUX 5 A-ROW NIL)) (DEFUN M7 (A-ROW) (MX-AUX 7 A-ROW NIL)) (DEFUN INVERT (A-ROW) (MX-AUX 11 A-ROW NIL)) The exchange operation presents some new problems in that the rows so far have all been thought of as having order implied by each element's respective position in the row. This must be made explicit in order to effect the exchange. POSITION-ASSOC associates a position element with a value element to form an association list; for example, (4 2 6) becomes ((0 4) (1 2) (3 6)). The form of this recursive function is similar to the forms we've already seen. (DEFUN POSITION-ASSOC (A-ROW) (DEFUN POSIT-ASSOC-AUX (A- ROW RESULT COUNTER) (COND ((NULL A-ROW) (REVERSE RESULT)) (T (POSIT-ASSOC-AUX (CDR A- ROW) (CONS (LIST COUNTER (CAR A-ROW)) RESULT) (+ 1 COUNTER) ) ) ) ) (POSIT-ASSOC-AUX A-ROW NIL 0) ) EXCHANGE exchanges the position for the value in the association list; for example, ((0 3)) becomes ((3 0)). (DEFUN EXCHANGE (ALIST) (DEFUN EXCHANGE-AUX (ALIST RESULT) (COND ((NULL ALIST) (REVERSE RESULT)) (T (EXCHANGE-AUX (CDR ALIST) (CONS (REVERSE (CAR ALIST)) RESULT) ) ) ) ) (EXCHANGE-AUX ALIST NIL) ) In order to define a version of the exchange operation which accepts and returns simple lists of values (rather than association lists), it was necessary to define several other functions. Function MY-SORT here takes an association list and sorts it by number ((number value)). REND takes an association list and returns a flat list consisting of the values in the association list. All combine into one operation, EX. (DEFUN EX (A-ROW) (REND (MY-SORT (EXCHANGE (POSITION-ASSOC A-ROW))))) The Common LISP special form FUNCALL allows us to pass the name of a function to the procedure, then use the name to call the function at the proper moment. Without further explanation we now give function MAKE-BABBITT-MATRIX, which will take a row and any of the twelve-tone group operations M5, M7, M11 (inversion), as well as the Stanfield exchange operation, and create a two-dimensional Babbittian matrix. (DEFUN MAKE-BABBITT-MATRIX (A-ROW FUNCTION) (DEFUN SQUARE-AUX (A-ROW ANOTHER-ROW RESULT) (COND ((NULL ANOTHER-ROW) (REVERSE RESULT)) (T (SQUARE-AUX A-ROW (CDR ANOTHER-ROW) (CONS (TRANSPO A-ROW (CAR ANOTHER-ROW) ) RESULT) ) ) ) ) (LET ((ANOTHER-ROW (FUNCALL FUNCTION A-ROW)) ) (SQUARE-AUX A-ROW ANOTHER-ROW NIL) ) ) The procedures given here make a good starting point for exploring theoretical and pre- compositional aspects of whole rows. Terry Ewell, also a graduate student at the University of Washington, has developed LISP procedures for analyzing tetrachordal and hexachordal aspects of row manipulation, and I have developed procedures to build large systems. We have written a number of different procedures to interface our results with the LISP Kernel. I have made one large composition using the Kernel's predecessor, FRONT, on the CDC Cyber (Rahn 1988), and I am in the middle of another project using the LISP Kernel, CSound, and the NeXT machine's native music program Music Kit. It has been a rewarding experience to combine serial theory with computer assisted composition and computer generated sound. References Abelson, H, G. Sussman, and J. Sussman. 1984. The Structure and Interpretation of Computer Programs. Cambridge, MA: MIT Press. Boynton, Lee, Jacques Duthen, Yves Potard, and Xavier Rodet. 1986. "Adding a Graphical User interface to FORMES." Proceedings of the 1986 International Computer Music Conference: 105-8. Camurri, A. and R. Zaccaria. 1988a. "An Experimental Approach to Hybrid Representation of Musical Knowledge." Proceedings of the First International Workshop on Artificial Intelligence and Music, St. Augustin, West Germany, September 15-16, 1988 (forthcoming). Camurri, A., M. Giocomini, A. Ponasi, and R. Zaccaria. 1988b. "Key-Music: An Expert System Environment for Music Composition." Proceedings of the 14th International Computer Music Conference, Cologne, September 19-25, 1988: 119-26. Dannenberg, Roger. 1989a. "The Canon Score Language." Computer Music Journal 13(1): 47-56. Dannenberg, Roger. 1989b. "Fugue: Composition and Sound Synthesis with Lazy Evaluation and Behavioral Abstraction." Proceedings of the 1989 International Computer Music Conference: 76-9. Desain, Peter. 1990. "LISP as a Second Language." Perspectives of New Music 28(1), forthcoming. Garton, Brad. 1989. "The Elthar Program." Perspectives of New Music 27(1): 6-41. Laden, Bernice, and Douglas Keefe. 1989. "The Representation of Pitch in a Neural Net Model of Chord Classification." Computer Music Journal 13(4) (Winter): 12-26. McNabb, Michael, and David Jaffe. 1989. "The NeXT Common Lisp Scorefile Package (v3)." Unpublished preliminary document. Morris, Robert. 1987. Composition with Pitch-Classes: A Theory of Compositional Design. New Haven: Yale University Press. Polansky, Larry, David Rosenboom, and Peter Burk. 1987. "HMSL: Overview (Version 3.1) and Notes on Intelligent Instrument Design." Proceedings of the 1987 International Computer Music Conference: 220-7. Polansky, Larry, David Rosenboom, and Peter Burk. 1990. "HMSL (Hierarchical Musical Specification Language): A Theoretical Overview." Perspectives of New Music 28(2), forthcoming. Pope, Stephen. 1986. "Music Notations and the Representation of Musical Structure and Knowledge." Perspectives of New Music 24(2): 156-89. Rahn, John. 1988. "Computer Music: A View from Seattle." Computer Music Journal 12(3) : 15-29. Rahn, John. 1989. "Toward a Theory for Chord Progression." In Theory Only 11/1&2 (May): 1-10. Rahn, John. 1990a. "Processing Musical Abstraction: Remarks on LISP, the NeXT, and the Future of Musical Computing." Perspectives of New Music 28(1), forthcoming. Rahn, John. 1990b. "The LISP Kernel: A Portable Environment for Composition." Computer Music Journal, forthcoming. Rodet, Xavier, and Pierre Cointe. 1984. "FORMES: Composition and Scheduling of Processes." Computer Music Journal 8(3): 32-50. Scaletti, Carla. 1989a. "Composing Sound Objects in Kyma." Perspectives of New Music 27(1): 42-69. Scaletti, Carla. 1989b. "The Kyma/Platypus Computer Music Workstation." Computer Music Journal 13(2): 23-38. Smoliar, Stephen. 1980. "A Computer Aid for Schenkerian Analysis." Computer Music Journal 4(2): 41-59. Stanfield, Michael. 1984. "Some Exchange Operations in Twelve-tone Theory: Part One." Perspectives of New Music 23(1): 258-77. Stanfield, Michael. 1985. "Some Exchange Operations in Twelve-tone Theory: Part Two." Perspectives of New Music 24(1): 72-95. Steele, Guy. 1984. Common LISP : The Language. Np: Digital Press. Taube, Heinrich. 1989. "COMMON MUSIC: A Compositional Language in Common Lisp and CLOS ." Proceedings of the 1989 International Computer Music Conference: 316-9. Truax, Barry. 1988. "Real-Time Granular Synthesis with a Digital Signal Processing Computer." Computer Music Journal 12(2): 14-26. Truax, Barry. 1990. "Composing with Real-Time Granular Sound." Perspectives of New Music 28(2), forthcoming.