Next Chapter
Previous Chapter
Table of Contents

Working with CMN

To work with the examples in this chapter you must have built Common Music with the CMN syntax enabled.

About Common Music Notation (CMN)

Common Music Notation, by William Schottstaedt (bil@ccrma.stanford.edu), is a program that processes Lisp expressions like:

(cmn staff treble c4 q)
and outputs traditional music notation as postscript images. The above example would generate a file named "aaa.eps" in your home directory that displayed one staff line with a treble clef and a quarter-note Middle C. Visit the CMN home page for more information.

The CMN output syntax

The CMN syntax writes postscript output or CMN input from normal event data in Common Music. It is not a substitute for working with CMN directly to produce manuscript quality output.

Open a file with a ".eps" file extension cases output to be sent to an eps file. .eps files contain a postscript image of compositional data in common music notation. Opening a ".cmn" file causes an CMN input file to be generated. A .cmn file contains input expressions for the CMN program. These expressions can be edited to produce a high quality manuscript. There is no backward link from .cmn to .cm files, so its best to delay creating .cmn input files until the composition is finished.

A Simple Example

In this first example we create a thread called foo with four midi notes and generate a postscript image of the data:

(thread foo ()
  (doitems (n (notes c4 d ef f g) )
    (object midi-note note n rhythm 1 duration .5
            amplitude .5)))

Stella [Top-Level]: open aaa.eps
Stella [Top-Level]: mix foo

Creating cmn score...
Manuscripting /user/hkt/aaa.eps...
Done!
Display file /user/hkt/aaa.eps? (<cr>=Yes)
<cr>
Stella [Top-Level]:

The CMN Display Object

The cmn object holds CMN graphic directives (cmn variables and/or function calls). It does not replace the compositional values for frequency, rhythm and amplitude which constitute the raw manuscript information. Cmn provides a slot called data to hold a single CMN variable or a list of directives. Here are a few examples of CMN data:

begin-beam variable
(begin-beam) variable in list
(begin-beam (meter 2 4)) variable and a function call in list
A single function call directive must be specified as an element in a list because the function call is itself a list.

The next example adds a 2/4 meter and a CMN object to draw a double bar. The values for data are quoted because they are meaningful only as CMN directives and not as Lisp expressions to evaluate.

(thread foo ()
  (meter 2 4)
  (doitems (n (notes c4 d ef f g) )
    (object midi-note note n rhythm 1 duration .5
            amplitude .5))
  (object cmn data 'double-bar))
Stella [Top-Level]: list foo
Foo:
      1.    #<Meter 2/4>    
      2.    #<MIDI-NOTE | C4|     1| 0.500| 0.500| 0|>    
      3.    #<MIDI-NOTE | D4|     1| 0.500| 0.500| 0|>    
      4.    #<MIDI-NOTE |DS4|     1| 0.500| 0.500| 0|>    
      5.    #<MIDI-NOTE | F4|     1| 0.500| 0.500| 0|>    
      6.    #<MIDI-NOTE | G4|     1| 0.500| 0.500| 0|>    
      7.    #<CMN double-bar>
Stella [Top-Level]: mix foo
Start time offset: (<cr>=None) <cr>
Output file:(<cr>=/user/hkt/aaa.eps) <cr>

Creating cmn score...
Manuscripting /user/hkt/aaa.eps...
Done!
Display file /user/hkt/aaa.eps? (<cr>=Yes) <cr>
Stella [Foo]:
When viewing the resulting aaa.eps file, note that CMN has also drawn internal bar lines at the appropriate places. This is because we told CMN that our material was in 2/4 meter. In its normal operating mode, CMN makes a whole host of decisions about rules involving metering and layout. We can control these automatic decisions (and much more) by customizing the CMN output stream, which we will lean about in the next two sections.

The Edit command

In this next example we invoke edit on the Midi stream. The Io-Streams system container holds all of the streams currently defined in the editor:

Stella [Foo]: list io-streams
Io-Streams:
      1.    #<Port: Midi to A>
      2.    #<File: "/user/hkt/aaa.eps">
Stella [Foo]: show io-streams[1]

Object:   #<Port: Midi to A>
Type:     Midi-Stream
Status:   Normal
Slots:
          Flags     0
          Stream    A
          Syntax    #<Syntax: MIDI>
          Port      A
          Direction :IO

Stella [Foo]: edit io-streams[1]

Editing #<Port: Midi to A>
Type ? for help.
Edit: ?

?                 Show this help.
DIRECTION         Set value of named slot.
FLAGS             Set value of named slot.
PORT              Set value of named slot.
QUIT              Quit Edit.
SHOW              Show slots and values.
STREAM            Set value of named slot.
SYNTAX            Set value of named slot.

Edit: show

FLAGS             0
STREAM            A
SYNTAX            #<Syntax: MIDI>
PORT              A
DIRECTION         :IO

Edit: q
Stella [Top-Level]:
Edit behaves like the top level loop in Stella because they are really the same program with different command sets. Edit builds its command set "on the fly", from the slot names defined in the object to be edited. To change a slot value simply type the name of the slot and its new value.

Common CMN Customizations

As mentioned in an earlier section the CMN output stream produces either .eps or .cmn output, depending on the file name extension we specify to write. The stream can be customized to any of the CMN score attributes listed on page 3 of the CMN manual. There are three common situations where this is necessary.

To customize the size slot to the overall size of the manuscript. The default value is 24.

To customize the metronome "parsing tempo". The default value is 60. The parsing tempo defines how CMN interprets time values..

In the next example the size and metronome values in "aaa.eps" are changed and the manuscript is regenerated:

[Specify the appropriate index for "aaa.eps" in your Io-Streams container]

Stella [Foo]: edit io-streams[2]
Editing #<File: "/user/hkt/aaa.eps">
Type ? for help.
Edit: metro 120
The value of METRONOME is 120
Edit: size 40
The value of SIZE is 40
Edit: q
Stella [Foo]: write foo
Start time offset: (<cr>=None) <cr>
Output file:(<cr>=/user/hkt/aaa.eps) <cr>

Creating cmn score...
Manuscripting /user/hkt/aaa.eps...
Done!
Display file /user/hkt/aaa.eps? (<cr>=Yes) <cr>
Stella [Foo]:
The third common customization for CMN output streams is the specification of staff descriptions. By default, every container that outputs data is displayed in its own staff, with its name appearing as the staff label in the CMN manuscript and CMN automatically decides which clefs and how many staves should be used. So we only need staff descriptions to specify a staff label different than a container's name, to specify the clef(s) that CMN should use to display data in a staff, or to specify that a sub container should appear in the same staff as its superior. These situations are all addressed by providing a staff description to the staves command inside edit. In the next example a staff named X draws data from the Foo container using the bass clef:

Stella [Foo]: edit io-streams[2]

Editing #<File: "/user/hkt/aaa.eps">
Type ? for help.
Edit: staves (staves (foo :name "x" :clef bass))
Edit: q
Stella [Foo]: write foo
Start time offset: (<cr>=None) 
Output file:(<cr>=/user/hkt/aaa.eps) 

Creating cmn score...
Manuscripting /user/hkt/aaa.eps...
Done!
Display file /user/hkt/aaa.eps? (<cr>=Yes) 
Stella [Foo]:
See staves in the Common Music Dictionary for more information.

Advanced CMN Customizations

All attributes of a CMN score are available for customization using edit or open, but attributes other than the common cases of staves, size and metronome must be prefixed with the cmn package name:

Stella [Top-Level]: {open aaa.eps size 12 metronome 90
                       cmn::redundant-accidentals nil}
The meter, staffer and marker stream attributes control the manner in which data is passed from Stella to CMN. The simplest of these attributes is meter, which allows the global specification of a parsing meter. For example,

Stella [Top-Level]: open aaa.eps meter (meter 2 4) size 16
initialize aaa.eps to parse using 2/4 meter. A global meter may be overridden for a particular staff using the staves macro.

staffer controls the mapping of musical data to CMN staves. The value of staffer must be a function. There are currently two staffing functions supplied by Stella. By default, CMN streams use container-staff to map event data to CMN staves. This staffer function places each event in a CMN staff corresponding to the event's container. The staffer function channel-staff places midi notes in CMN corresponding to midi channel information.

The marker slot holds an function that will be called on each event after it has been sent to CMN. The purpose of a marker function is to implement programmatic addition of marks to a CMN note that has just been placed in its CMN staff.

Here is an example of a marker function that was used to output a large section of a string orchestra piece. The music was composed using midi notes in two generators, with channel information representing violins 1 and 2, viola and cello.

;;; this marker adds a wedge to all notes with amplitude > .5

(defun marker2 (stream object)
  (when (and (typep object 'midi-note)
             (>  (slot-value object 'amplitude)  .5))
    (let ((staff (gethash (slot-value object 'channel)
                          *cmn-staves*)))
      (cmn::add-data-1 stream staff (cmn-eval 'wedge)))))

Stella [Top-Level]: {open darkling2.cmn staffer channel-staff
                       metronome 75 size 16 meter (meter 24)
                       marker marker2
                       staves (staves (0 :clef treble)
                                      (1 :clef treble)
                                      (2 :clef (alto treble))
                                      (3 :clef tenor))}
  
Stella [Top-Level]: syn cmn
Stella [Top-Level]: seq sec2a,sec2b

Defining CMN output methods

To produce CMN manuscript output for user defined note classes, provide a method on write-event that passes parameter data from the object to CMN via cmn::add-note-to-staff, which takes as its arguments the stream, the staff of the current object, the current values for time and duration and frequency. For example, here is the output method for midi notes:

(defmethod write-event ((object midi-note) (stream cmn-stream))
  (cmn::add-note-to-staff 
    stream 
    (container-staff stream (slot-value object 'container))
    (slot-value object 'time)
    (slot-value object 'duration)
    (cmn-eval (slot-value object 'note))))
Musical objects have not explicit notion of "staff". The link between an object in Stella and its CMN staff is properly managed by the cmn output stream, which maintains a "dictionary" of staves indexed by object container. To find the staff of an object, use container-staff, passing it the output stream and the object's container. Cmn-eval evaluates a lisp expression in the context of the CMN program. The value of each midi note's note slot is filtered through cmn-eval because the value may be symbolic "note names" like C4 and DS5, which are treated as variables in CMN. C4 is not a variable in Stella and has no meaning other than as a name of a scale degree in the standard chromatic scale. Cmn-eval insures that the C4 symbol in Stella produces the value of the C4 variable in CMN:

Stella [Top-Level]: ,c4
The symbol C4 has no value.
Stella [Top-Level]: (cmn-eval 'c4)
#<CMN::WRITE-PROTECTED-NOTE 35514351> 
Finally, before leaving this section switch back to the MIDI syntax. If we were to try to Listen to material while the CMN syntax was current we would not hear anything because the CMN syntax has output methods defined for notation, not listing.

Stella [Top-Level]: syn midi
Current syntax is MIDI.
Stella [Top-Level]: 

Next Chapter
Previous Chapter
Table of Contents

Last Modified: 6-Mar-1998