The "Common" family of sound and music software resides at the Center for Computer Research in Music and Acoustics at Stanford University (CCRMA, pronounced "karma"). This group of applications makes up a complete environment for the composition, synthesis, notation, and recording/editing of sound and music. The family circle is comprised of these programs :
Each program is a complete application, but they have all been designed for a high degree of interaction. Note-lists created by Common Music can be processed by synthesizers in Common LISP Music. CM can then call Snd and pass CLM's synthesized output directly to the editor. Snd can pass the edited data back to CLM for further treatment there, and finally the entire note- and event-list can be exported to Common Music Notation for rendering to MIDI file and/or the production of a human-readable traditionally notated score.
All members of the Common family utilize the LISP programming language as a basic element of their designs. For CM, CLM, and CMN the language is the way into the programs themselves, i.e., they are all essentially specialized sets of LISP. Even the Snd soundfile editor includes a LISP Listener window for entering commands for actions upon the edited file(s). LISP comes in a variety of implementations: AGNULA's choice is the Carnegie-Mellon University Common LISP (CMUCL), a completely free open-source implementation of the language. Recent versions of Snd and CM also support the Guile and Ruby languages (Guile is a dialect of LISP, Ruby is a relatively new object-oriented scripting language). We will meet Guile again when we learn more about Snd, but we'll begin our tour with the Common LISP Music software synthesis language.
COMMON LISP MUSIC
Common LISP Music is a software sound synthesis environment similar to Csound, Cmix/RTCmix, and cmusic. Like them, CLM's basic design derives from Max Mathew's famous MusicV language. Among its other innovations, MusicV introduced the concept of the unit generator, a software "black box" that performed a particular function on its input data and could be linked to other such generators to create a complex digital audio synthesizer or signal processor.
MusicV-derived systems are generally easy to learn, so let's take a quick hands-on tour of CLM to see what we can actually do with it. In the following example we will perform the following tasks :
* (load "all.lisp")This will compile the various parts of CLM into what are called 'fast-load' files. Under CMUCL those files will have an extension of '.x86f'. When you first run the load command it may take some time to compile a large number of files, but subsequent loads will be much quicker with the fast-load files.
Now type in this instruction to load a CLM instrument synthesis file :
* (compile-file "piano.ins")You will again see some activity similar to your previous command output. If you look closely at the process you will see that the interpreter loads the piano.ins file, creates a C-language file from it, then compiles the C file to an object file that CLM can now load with the 'load' function again :
* (load "piano.cmucl")Your CLM documentation may advise that (load "piano.x86f") is the correct invocation, but when using CMUCL you must load the '*.cmucl' file instead of loading the '*.x86f' file directly (i.e., piano.cmucl provides a mechanism to call the fast-load file).
Stop now and consider what you have achieved so far: you have started the LISP image, you have compiled the CLM functions, and you have compiled and loaded an instrument that makes use of those functions. At this point you are ready to run the instrument with a note-list. To do so we will use some slightly modified examples from the CLM documentation.
Copy and paste the following short script at the LISP prompt :
(with-sound (:output "my_piano.snd") (loop for i from 0 to 7 do (p (* i .5) :duration .5 :keyNum (+ 24 (* 12 i)) :strike-velocity .5 :amp .4 :DryPedalResonanceFactor .25 )))In reverse order this script establishes the following conditions:
Copy the script to the prompt, press Enter and watch as the interpreter calls the necessary CLM functions and processes the script. When LISP is finished, you will see either a 'T' symbol or the 'NIL' message. Both of these reports indicate a successful run, and you should now have a new soundfile named my_piano.snd residing in your starting directory.
Let's make a couple of small changes to our script and try sending the output directly to the soundcard DAC (digital-to-analog converter) for realtime audition :
(with-psound () (loop for i from 0 to 7 do (p (* i .5) :duration .5 :keyNum (+ 24 (* 12 i)) :strike-velocity .5 :amp .4 :DryPedalResonanceFactor .25 )))Press Enter and you should hear the output rendered to sound in realtime.
Okay, we're almost done with our task-list. At the LISP prompt invoke the Snd editor with this command :
(start-snd)Next we'll rewrite the (with-sound) example to send the piano synthesis output directly to Snd :
(to-snd (:output "my_piano.snd") (loop for i from 0 to 7 do (p (* i .5) :duration .5 :keyNum (+ 24 (* 12 i)) :strike-velocity .5 :amp .4 :DryPedalResonanceFactor .25 )))The synthesis will run as in our previous examples, creating an output file named my_piano.snd, but instead of playing the file it will be loaded into Snd, and from there you can proceed to slice and dice it in whatever way you desire. It is also worth mentioning that many other aspects of Snd can be controlled from within CLM. For example, the following code will create a new three-stage envelope in Snd's graphic envelope editor :
(defvar heya '(0 0 .35 1 .75 .66 1 0)) (clm-envelope heya) (setf heya (snd-envelope heya))Note that Snd must be opened (using start-snd) for this example to work. Open the envelope editor and you will see a named envelope (heya) in the 'envs' box (Figure 1). Select 'heya' and you should see the graphic representation of the envelope you defined in CLM. For more details about working with Snd please see Chapter XX of the AGNULA documentation.
Now let's look more closely into an instrument file to see how CLM performs its synthesis magic. CLM's own documentation includes many interesting examples of instrument design, but here we will look only at the example bell.ins file, a relatively simple instrument found in the CLM home directory.
Let's break the bell instrument's code into its logical blocks and examine its structure. First, some definitions :
(definstrument fm-bell (startime dur frequency amplitude amp-env index-env index &optional (degree 0.0) (distance 1.0) (reverb-amount 0.005))The heart of the matter is the definstrument function where we define the instrument name (fm-bell) and its parameters. The parameters list for this instrument includes a start-time and duration, indicating that some aspects of a performance score may also be included in a CLM instrument definition. Next we see the actual synthesis parameters for an FM (frequency modulation) instrument, such as frequency and amplitude, a modulation index, and envelopes for amplitude and the modulation index. A group of optional parameters has been added to this instrument for panning and reverb effects.
The next block starts the instrument computations, defining its sample rate (srate), modulation indices (fmInd), and the FM envelope initialization (fmenv) :
(let* ((beg (floor (* startime *srate*))) (end (+ beg (floor (* dur *srate*)))) (fmInd1 (hz->radians (* 32.0 frequency))) (fmInd2 (hz->radians (* 4.0 (- 8.0 (/ frequency 50.0))))) (fmInd3 (* fmInd2 0.705 (- 1.4 (/ frequency 250.0)))) (fmInd4 (hz->radians (* 32.0 (- 20 (/ frequency 20))))) (fmenv 0.0)Now the code proceeds to create instances of the panning function (make-locsig), the carrier and modulator oscillators (make-oscil), and the amplitude and index envelopes (make-env) :
(loc (make-locsig :degree degree :distance distance :reverb reverb-amount)) (mod1 (make-oscil :frequency (* frequency 2))) (mod2 (make-oscil :frequency (* frequency 1.41))) (mod3 (make-oscil :frequency (* frequency 2.82))) (mod4 (make-oscil :frequency (* frequency 2.4))) (car1 (make-oscil :frequency frequency)) (car2 (make-oscil :frequency frequency)) (car3 (make-oscil :frequency (* frequency 2.4))) (indf (make-env index-env index dur)) (ampf (make-env amp-env amplitude dur)))Finally the parts are called together in the 'run' block
(run (loop for i from beg to end do (setf fmenv (env indf)) (locsig loc i (* (env ampf) (+ (oscil car1 (* fmenv fmInd1 (oscil mod1))) (* .15 (oscil car2 (* fmenv (+ (* fmInd2 (oscil mod2)) (* fmInd3 (oscil mod3)))))) (* .15 (oscil car3 (* fmenv fmInd4 (oscil mod4)))))))))))Obviously this kind of instrument design is a non-trivial undertaking, similar to writing opcodes for Csound and the other MusicV-derived languages. Fortunately a good selection of pre-built instruments can already be found in the CLM distribution. Those instruments may be used "as-is" by composers or they may be used as the basis for new instruments. Sound-designers will want to study the existing instruments for more details of instrument design in CLM.
Now that we understand a little more about this instrument's design, how can we deploy it in CLM ? Just start LISP in the CLM directory, run (load "all.lisp"), then compile and load the instrument with these commands :
(compile-file "bell.ins") (load "bell.cmucl")Now we want to output a test file demonstrating the FM bell sound. This command will play the bell and create a file named "bell.snd" in your CLM home directory :
(with-sound (:output "bell.snd") (fm-bell 0 3 100 .5 '(0 1 1 0) '(0 0 1 1) .8))The parameters for this FM bell sound are as follows :
0 start time 3 duration 100 frequency in Hz .5 amplitude normalized (between 0.0 and 1.0) '(0 1 1 0) amplitude envelope, starts at max and fades to 0 '(0 0 1 1) envelope for index of modulation, starts at 0 and increases to max .8 index of modulationNote that an envelope in CM is a standard LISP array in normalized time|value pairs. Note also that in the original bell.ins file the optional parameters have already been assigned values so it was not necessary to supply them.
At this point we can again start Snd (start-snd), send our new soundfile to it for editing (to-snd), then get it back from Snd for more treatment in CLM (with receive-snd; see the CLM documentation for instructions).
COMMON MUSIC NOTATION
CMN is the music notation member of the Common family. However, it is not a direct music scoring program a la Finale or Sibelius: instead, CMN provides a very flexible specification system for rendering Western music notation scores as elegant ready-for-printing encapsulated PostScript files (eps files). CMN's language and syntax are again LISP-based, fitting neatly into the family circle along with CLM and CM (which we'll explore later). A full complement of typical music symbols is supplied along with such scoring amenities as score sizing and text underlay. CMN-produced scores may be viewed with standard PostScript viewers such as GhostView and ghostscript or you can invoke CMN's own xcmnw, a handy score presentation utility included with the CMN package.
Open an xterm, start the LISP interpreter, then load CMN. Here's how it's done :
[[email protected] dlphilp]$ lisp CMU Common Lisp 18d, running on localhost.localdomain Send questions to [email protected] and bug reports to [email protected] Loaded subsystems: Python 1.0, target Intel x86 CLOS based on PCL version: September 16 92 PCL (f) * (load "/home/dlphilp/CCRMA/cmn/cmn-all.lisp") ;;; Running /usr/bin/ld... ;;; Done. ;; Loading #p"/home/dlphilp/CCRMA/cmn/cmn-init.x86f". ... ;; Loading #p"/home/dlphilp/CCRMA/cmn/quarter.x86f". T * (in-package :cmn) # [The CMN package, 3175/6314 internal, 0/2 external] *The package is ready for use.
Thanks to its LISP heritage, CMN's syntax is very close to a "natural language" score description. Consider the following code fragment :
(cmn staff treble c4 q)A musician familiar with standard Western music typography might correctly infer that this code instructs CMN to create a treble clef followed by a quarter note on middle C. This code :
(cmn (output-type :x) staff treble c4 q)will call CMN's xcmnw viewer and immediately display the results as in Figure 2.
The next example further illustrates CMN's conformance to the conventions of standard music notation terminology :
(cmn (output-type :x) (size 40) (system brace (staff treble (meter 6 8) (c4 e. tenuto) (d4 s) (ef4 e sf) (c4 e) (d4 s) (en4 s) (fs4 e (fingering 3))) (staff treble (meter 3 4) (c5 e. marcato) (d5 s bartok-pizzicato) (ef5 e) (c5 e staccato tenuto) (d5 s down-bow) (en5 s) (fs5 e))) (system bracket (staff bar bass (meter 6 16) (c4 e. wedge) (d4 s staccato) (ef4 e left-hand-pizzicato) (c4 e tenuto accent rfz) (d4 s mordent) (en4 s pp) (fs4 e fermata))))Figure 3 displays the output from this example. Clearly the use of terms such as brace, staff, meter, tenuto, marcato, etc., should make it easy for musicians to understand the meaning of a CMN score specification file.
Large code listings can be entered directly into CMN at the LISP prompt, but such a method quickly becomes unmanageable. Better ways of handling large scores include copy/paste operations from an open xterm, utilizing Emacs or Xemacs to evaluate and run the code, or simply saving the code as a .cmn file and loading it into CMN in this manner:
(load "my_new.cmn")CMN supplies various performance-practice indicators (such as the down-bow and the Bartok pizzicato directives in the example above) as well as the full range of note types, rests, and other musical (and some not-so-musical) symbols. These symbols can be arranged in almost any fashion (upside-down if your score requires it!), and you can even colorize them. If the program's default palette is insufficient for your needs, you can create your own collection of graphic symbols for use in CMN.
Of course CMN interfaces nicely with the other Common family members. Later in this chapter we shall see how you can create a CMN score algorithmically in Common Music while simultaneously rendering a MIDI file of the same score. The CMN score specification is easy to learn and employ, and your scores can be written and edited with any standard UNIX text editor (such as vi or Emacs). Scores are rendered to EPS graphics using an attractive music symbols font (designed by CMN author Bill Schottstaedt) and may be printed with any PostScript-capable printer. Despite its lack of a mouse-powered point & click GUI, CMN is most definitely a powerful addition to the AGNULA arsenal.
According to its author Common Music is
"... an object-oriented music composition environment... [that] produces sound by transforming a high-level representation of musical structure into a variety of control protocols for sound synthesis and display... [and] defines an extensive library of compositional tools and an API through which the composer can easily modify and extend the system."
Common Music might be more simply described as a music composition utility typically used to create note-lists or event-lists that comprise Csound or CLM score files. The routines supplied by CM include a variety of functions designed to produce lists with a wide degree of user-control over the output, from the completely controlled and tightly specified to the completely random. CM's output formats include standard MIDI files, AIFF and SND soundfiles, and score files suitable for Csound, CLM, and CMN.
Before we jump into CM we need to know a few things about how it operates with the LISP interpreter. You'll run LISP as usual, starting it from the CM home directory, then run (load "src/cm.lisp") to generate the fast-load files (they'll be dumped into $HOME/cm/bin). Once the fast-load files have been generated you should quit LISP, start it again and reload cm.lisp. This time you'll watch the interpreter compile those fast-load files into a file named cm.core that also gets dumped into $HOME/cm/bin. Now all you need to do is restart LISP in this manner to autoload CM :
lisp -core bin/cm.coreAt the LISP prompt run (in-package :cm) and you're ready to utilize the powers of CM (i.e. you won't need to load cm.lisp again). Incidentally, you can go ahead and load the CLM and CMN packages at the same time as you're running CM, essentially putting all three environments under one instance of the LISP interpreter. Later we'll see how this arrangement creates a powerful music and sound production environment, but for now we'll stick to our presentation of CM.
The simplest way to understand what CM does is to study and use some of the example files in the distribution. The following code is an annotated version of a fragment from cm/etc/examples/intro.cm :
;; First we create an object named simp (defobject simp () ((ins :initform 'simp :accessor object-name) ; instantiate the object (beg :accessor object-time) ; give it a start-time (dur :initform 1) ; a duration in seconds (amp :initform .5) ; some volume in the normalized range (0-1) (freq :initform 440)) ; a pitch in Hz (:parameters beg dur amp freq)) ; and define them as the parameters taken by a simp object ;; Next we define a process to output simps (define (simp-1 num) ; call it simp-1 and have it run num times (process repeat num ; run it for num output (new simp ; call a simp into being and hand it its parameter values :beg (now) :dur 1 :amp .5 ; start-time, duration, and volume are all predetermined (now is delta-time from 0) :freq (between 220 440)) ; pitch can be anywhere between 220 and 440 Hz wait (pick 0 1 2))) ; wait for 0, 1, or 2 seconds before the next run ;; Now we call an event creator to run the simp-1 process 20 times and send the output to a CLM score file (events (simp-1 20) "test.clm")This simple example illustrates CM's basic use and syntax. Its forms are easy to comprehend but very powerful, as we shall see in the next section...
THE FAMILY PLAYING TOGETHER
A high degree of interoperability exists among the Common family units. You can build a single LISP image that includes the CLM, CMN, and CM environments, with all of their powers and functions available from within the same LISP image. Assuming your Common programs are all living in a single directory (I keep mine in /home/dlphilp/CCRMA) here's how it's done :
lisp -core cm/bin/cm.coreYou can also specify a start-up configuration in the cminit.lisp that's in the same directory as your cm.core file. My cminit.lisp looks like this example :
;;; Forms in this file will be evaluated when Common Music starts. (set-midi-output-hook! #'oss-play-midi-file) ; set MIDI file play to the OSS/Free-compatible player (defun cmn-load (file &rest args) ; set CMN output to autoload its PostScript (EPS) file args (load file)) (set-cmn-output-hook! #'cmn-load)Your configuration may vary. In fact, this file is not necessary to run your CLM/CMN/CM core file, but it can be handy for setting up various aspects of its performance, particularly with regard to output hooks (they determine how a file will be handled after it's been created). You can then invoke your personal configuration with this command line :
lisp -core cm/bin/cm.core -init cm/bin/cminit.lispIt would be wonderful if that's all you had to do, but a small bug requires one more line entered at the LISP prompt. This line :
(setf *readtable* *cm-readtable*)ensures that CMUCL will correctly interpret and expand CM's macro notation.
Now within a single LISP image it is possible to create an environment for music composition, sound synthesis, traditional notation, and audio editing. Let's take a look at this system in action, using the same hands-on approach we've taken so far.
UNCOMMON COOLNESS: ALGORITHMIC MIDI SEQUENCING WITH COMMON MUSIC
As a demonstration of the family working together we'll create a Common Music program to carry out the following tasks :
CM's default MIDI file player is playmidi. Playmidi is a good program, but its sound quality depends on your hardware. Soundcards such as the SoundBlaster AWE and the SBLive are equipped with on-board synthesizers, so if your system includes one of these cards you can safely ignore the rest of this section. If your soundcard does not include an on-board synth, or if you just want to improve your available MIDI sound, I suggest using TiMidity++ (aka TiMidity), a MIDI-to-WAV renderer. TiMidity is covered in more depth in Chapter XX of this documentation, but right now we need only know enough about it to set it up within CM. You'll need to make a change in one CM source file, so fire up your text editor and open cm/src/midi2.lisp. Search for the reference to playmidi in this line :
(shell "/usr/bin/playmidi~a ~a > /dev/null &" opts file)))and replace it with this line :
(shell "timidity~a ~a > /dev/null &" opts file)))By default TiMidity utilizes a General MIDI patch set comprised of of PAT-format sounds (PAT was the native format for the Gravis Ultrasound cards). In Chapter XX I describe how to use soundfonts with TiMidity, and because I like the Fluid set I've set up a configuration for TiMidity and the Fluid set. Thus, my change to midi2.lisp includes a configuration flag :
(shell "timidity -ig -c /home/dlphilp/timidity-sf2.cfg~a ~a > /dev/null &" opts file)))I've also flagged TiMidity to appear in its Gtk GUI (-ig). Other TiMidity options can be passed to the program, but I leave that as an exercise for the diligent reader.
Now set up the GhostView PostScript file viewer to autoload the score from each new run of our CM program. Simply open an xterm, type in 'gv -watch foo.eps'. That's it, you're now prepared to explore an interesting aspect of Common Music. Let's run the code first to see and hear what the code creates. From the LISP prompt enter these commands :
* (in-package :cm) * (compile-file "$CM_HOME/etc/examples/cmn-test.cm") * (load "$CM_HOME/etc/examples/cmn-test.x86f")If everything works correctly GhostView will display your newly-created score while TiMidity renders the MIDI file output. Subsequent runs of the load statement will re-run the randomization functions, creating a new score and MIDI file with each run.
The code to make it all happen is surprisingly sparse. It is based on $CM_HOME/etc/examples/intro.cm, and I invite the reader to freely add his own hands-on alterations. Let's see how it's done :
;;; cmn-test.cm ;;; ;;; We define a processing function named testit. It takes three parameters: ;;; a staffing directive (stf) ;;; the number of note events for output (len) ;;; the note event (define (testit stf len nts) ;;; Now make a 'machine' to produce the MIDI output. ;;; It first selects a musical note from the array in the event statement (see below). (let ((nts (new heap :notes nts)) ;; Now choose rhythm values of quarter, two eighths, two sixteenth or two thirty-second notes. ;; The cycling arrays ensure that the pair of values is called, ;; the repetition of a value weights or favors its selection. (rhy (new random :of (list 1 1 (new cycle :of '(1/2 1/2)) (new cycle :of '(1/4 1/4)) (new cycle :of '(1/8 1/8)) )))) ;;; Now apply the pitch and rhythm selection to form the MIDI event. ;;; Note that the staff number is used to define the MIDI channel. ;;; Repeat the process in a while loop len times. (process while (< (now) len) for n = (next nts) for r = (next rhy) output (new midi :time (now) :duration r :keynum n :channel stf) wait r))) ;;; We'll need this stuff for our staffing parameter. ;;; (It comes from Common Music Notation). (define staffs '((0 :name "Instr 3" :clef :bass :meter (4 4)) (1 :name "Instr 2" :clef :alto :meter (4 4)) (2 :name "Instr 1" :clef :treble :meter (4 4)))) ;;; The event statements create the whole event, i.e., they run the testit function with the given parameter data. (events (list (testit 0 31 '(g2 a bf c3 d f)) (testit 1 31 '(a3 bf c4 d e g)) (testit 2 31 '(bf4 c5 d f g a))) ;;; Thus (testit 0 31 '(g2 a bf c3 d f)) breaks down from right to left : ;;; Select notes from the array (g2 a bf c3 d f) ;;; Do it 31 times ;;; Send the output to staff 0 ;;; Process everything with the testit function ;;; Now generate a MIDI file and its score output from the same run. ;;; First, declare a container (seq) for the output from the testit runs. (new seq :name 'two-ways)) ;;; Create the CMN file from the contents of the seq container, ;;; specifying various CMN event keyword values : (events #$two-ways "cmn-test.cmn" :staffing staffs :size 20 :title "Trio" :exact-rhythms t) ;;; Then make the MIDI file from the same contents : (events #$two-ways "cmn-test.mid")Figure 4 shows the output from a successful compile and load of this small program routed to GhostView and TiMidity. Subsequent runs of the load function will create newly randomized output, i.e. new MIDI and new EPS files.
Now that you've seen how it works try changing values wherever you like. You may be quite surprised at what CM comes up with, but remember that it only processes what's given to it. Go ahead and change things, then recompile and reload the program to hear and see the effect of your alterations. Note that the CMN file can be edited and saved on its own to further refine the appearance of the EPS output. You can reload it with (load "cmn-test.cmn") to review your edits, but you should save it under a new name to avoid overwriting it with subsequent runs of our example program.
Common Music is a powerful music composition environment. It can be used to create completely deterministic works, for exploring arbitrarily complex output algorithms, or for any combination of these approaches. Music generation may take place anywhere from the phrase level to an entire large-scale composition, and with a reasonably fast machine the composer can rapidly test and review his ideas in MIDI file, standard music notation, and software synthesis score. Output from each of these formats can be edited further in common sequencers, text editors, and soundfile editors. With the promise of MIDI file import and a Linux version of the plotter (a GUI for CM available for the Mac) the power and utility of CM will grow even greater.
CM can be thought of as the glue that holds together the CLM/CMN/CM/Snd family; however, the true binding force behind all this interoperability is the LISP programming language. Fortunately the amount of LISP required by the composer is easily learned and amply documented. If you would like to learn more about using LISP in CM I suggest reading Rick Taube's Notes From The Metalevel, a superb introduction to computer music and sound composition via Common Music.