Common Music Reference Manual |
 |
|
1 Objects and Musical Structure
Common Music is an object oriented system that represents compositional
data in the Common Lisp Object System (CLOS). An object
is a unit of storage that is created out of a more general description called
a class. A class declares the set of characteristics that are
instantiated whenever an object of that class is created. These characteristics
are referred to as slots or instance variables.
When a class is created it may be declared to be a specialization of one or
more classes. These other classes are called superclasses and
the specialization is called the subclass.
The superclass-to-subclass relationship says that every characteristic
defined in the superclass is automatically inherited by the subclass. Of course,
the subclass may add additional characteristics not found in the superclass.
Figure 1-1:
A graph of Common Music's superclass->subclass hierarchy. |
 |
As one gains familiarity with the system it becomes natural to want to
add new class definitions. The defobject macro
provides a simple mechanism to do this. Look at the files
"cm:examples;beep.lisp" and
"cm:examples;fm.ins" for examples of creating
new event classes for Csound and CLM.
1.1 Creating Objects
Use the Lisp function
make-instance or the new macro to create objects:
new class {init value}*
|
[Macro] |
Allocates and initalizes a new CLOS object. class
is the unquoted class name (symbol) of the type of object to create. Following
class comes zero or more slot initialization pairs
where init is the unquoted symbol or keyword name of the initialization
and value is its value. For each pair init is not evaluated
and value is evaluated.
Slot initializations for all objects:
-
time number
-
Sets the start time of object. time can also be specified as start.
Slot initializations for all container classes:
-
name {string | symbol}
-
An optional name for the object. name can also be specified as named.
Other initializations are possible based on the class of object being created.
Example 1-1
|
? (new seq name 'foo)
#<SEQ: Foo>
? (new midi keynum (between 32 89) time 1 duration 3)
#E(midi :time 1 :duration 3 :keynum 53 :amplitude 64 :channel 0)
? (new pattern q w e h e.. in random returning #'rhythm)
#<RANDOM @ x4C357A6>
? (new i ins 22 time 33 duration .2)
#<I22 33 0.2>
| | |
#e (class {slot value}*)
|
[Macro] |
Creates a musical event from the specified class and initialization
pairs. The print-object method for event subclasses prints
events as #e expressions. The format of this expression
can be controlled using the *e-format* variable. If the value is t
all bound slots in the event are printed. If the value is :terse
then only those slots whose values differ from their :initform values
are printed. If the value is :parameters
then only bound slots that are parameters are printed.
If the value is :terse-parameters then only parameters
whose values differ from their :initform values are printed. The default
value of *e-format* is :parameters.
copy-object object
|
[Function] |
Returns a copy of object. Slot values in the
new and old objects are identical, that is the slot
values are transferred not copied. copy-object uses
allocate-instance to create the new object and
fill-object to
set its slot values.
1.1.1 Setting Slot Values
Slot values in events can be changed using Lisp's
setf with
slot-value
or by using CM's terser sv macro:
sv object slot &optional value &rest others
|
[Macro] |
Returns or sets the value of slot in object.
slot is the unevaluated symbol name of the slot. If value
is provided it becomes the value of slot. others
are additional slots and values to set in the object. sv
returns the value of the last form evaluated.
Example 1-2
|
? (setf x (new midi time 0 keynum 23 duration 4))
#E(midi :time 0 :duration 4 :keynum 23 :amplitude 64 :channel 0)
? (sv x keynum)
23
? (sv x keynum 40 amplitude .4 channel 3)
3
? x
#E(midi :time 0 :duration 4 :keynum 40 :amplitude 0.4 :channel 3)
| | |
fill-object new old
|
[Function] |
Fills slots in new with slot values from old.
1.1.2 Referencing Named Objects
Instances of most composite classes can be named. A named object
can be referenced
using the #! macro or the find-object function:
Returns the object named name. #!
references may be included in quoted lists.
Example 1-3
|
? (new seq named 'foo)
#<SEQ: Foo>
? (setf x '(a v #!foo 4))
(A V #<SEQ: Foo> 4)
? (io "test.midi")
#<MIDIFILE: "home:test.midi">
? #!test.midi
#<MIDIFILE: "home:test.midi">
| | |
find-object name &optional error
|
[Function] |
Returns the object named name. If error
is t then find-object signals an error if there is no
object in the dictionary, otherwise nil is returned if an object
is not found.
list-named-objects &optional type
|
[Function] |
Returns a list of objects from the system dictionary. If type
is specified only objects of that type will be returned.
Example 1-4
|
? (list-named-objects)
(#<MIDI-FILE "home:test.midi"> <SEQ: Foo> <process: Bif>)
? (list-named-objects 'seq)
(#<SEQ: Foo>)
| | |
1.2 Event Classes
An event is an object that represents musical sound. The
slots of an event represent the various attributes of sound
that the event describes. Some slots in an event are declared
to be output parameters that produce values in musical output.
Common Music defines several event classes to use with
synthesis languages such as CLM, CSound and MIDI. These event
classes can be specialized by the user and new event classes
can be defined using the defobject
macro.
Creates a MIDI Note On and Note Off pair out of a more general
representation of frequency, duration and amplitude.
midi supports the following slot initializations:
-
time number
-
Sets the start time of object. time can also be specified
as start.
-
keynum {keynum | note}
-
Frequency expressed as a keynum or note.
The treatment of floating point keynums
depends on the current value of divisions-per-semitone
in the MIDI file or port. If the value is 1 (the default)
then floating point key numbers are rounded to the closest MIDI keynum.
If the value is between 2 and 16 then floating point key numbers
produce microtones at the specified resolution. In this case the channel
of the MIDI note is ignored and data is automatically routed to the
proper microtuned channel.
-
duration number
-
The duration of the note in seconds.
-
amplitude number
-
A logical amplitude 0.0 < 1.0 or an integer velocity 0 to 127. Defaults to 64.
-
channel integer
-
A MIDI channel number between 0 and 31. Defaults to 0.
An event class for CSound i-statements.
i provides the following initializations:
-
ins number
-
Sets the i-statement number. ins can also be specified as p1.
-
time number
-
Sets the start time of object. time can also be specified
as start or p2.
-
duration number
-
Sets the duration of object. duration can also be specified
as p3.
Use defobject to define i-statements for orchestra specific
instruments. Subclasses
of i can be named anything as long the ins slot has a
value. See the file
"cm:examples;beep.cm" and
"cm:examples;beep.orc" for an example.
An event class that implements CSound f-statements.
f provides the following initializations:
-
number number
-
Sets the f number. number can also be specified as p1.
-
time number
-
Sets the start time of object. time can also be specified
as start or p2.
-
size number
-
Sets the size of the ftable. size can also be specified
as p3.
An event class that implements output to CLM score files (.clm) and
sound files (.aiff). definstrument automatically declares a subclass
of ins with the same name as the instrument and with slots defined for
every lambda parameter in the instrument.
1.3 Container Classes
Container classes implement aggregation of musical material.
The seq, pattern, process, io
classes all implement different containment strategies.
A seq holds time sorted subobjects.
seq supports the following slot initializations:
-
subobjects list
-
A list of subobjects.
Example 1-5
|
? (new seq named 'foo time 32
subobjects (for i below 10 collect (new midi time i)))
#<SEQ: Foo>
| | |
process implements the description of music in terms of
programming code. The process object automatically creates a new
process function each time it is scheduled to produce events.
Processes can be created using the
defprocess macro.
process supports the following slot initializations:
-
closure function
-
A function to call to produce a process function. The closure
must accept one argument, the process object.
1.4 Object Utilities
There are a number of functions to support the creation and manipulation of objects.
defobject name supers slots &rest options
|
[Macro] |
Defines a new class of object. name is the name for
the new class. supers a list of superclasses or ().
slots is a list of slot specification or ().
Each slot can be either the name of a slot or a list in the form:
(slot &key :initform :accessor :reader :writer :initarg)
defobject automatically declares slot and
its keyword as initialization names for new and make-instance.
Following slots comes an optional :parameters
specification:
(:parameters &rest slots)
slots determines both the order and slot names
that are to be process as output parameters in score file generation.
The slots listed in slots are considered required parameters
unless preceded by a lambda keyword &optional, &key
or &rest. A required parameter means that an error is
signaled if the slot is unbound during score generation. &optional
parameters are ignored if unbound. &key parameters are also
optional but the slot value is preceded by its keyword in the output file.
A single &rest parameter is a list of values that are "spread"
over a number of parameters in the output file. See the file
beep.cm
for an example CSound defobject.
subobjects seq
|
[Function] |
Returns the subobjects of seq. Use (setf subobjects)
to set the subobjects of seq.
Example 1-6
|
? (new seq named 'foo)
#<SEQ: Foo>
? (setf (subobjects #!foo) (for i below 10 collect (new midi time i)))
| | |
subholders seq
|
[Function] |
Returns the subobjects of seq that are holders.
list-subobjects seq &key :start :end :start-time :end-time :stream
|
[Function] |
Lists subobjects of seq to stream, which
defaults to the standard output. :start and :end
are optional start and end positions (zero based) to list. :start-time
and :end-time are optional starting and ending times to list.
Positions and times are mutually exclusive.
map-subobjects function seq &key :recurse :key :test :type
|
[Function] |
Maps function over the subobjects of seq. If
:recurse is t then mapping is recursively applied to all
subcontainers of seq. If :test is supplied then only those objects
for which :test returns true are mapped. If :type is supplied
instead of :test then only objects of that type are mapped. If :key
is supplied it is first applied to each mapped object and the results are passed to
function. map-subobjects does not return a value.
Example 1-7
|
;; collect keynums of all midi notes in #!foo.
? (let ((nums '()))
(map-subobjects #'(lambda (x) (push x nums)) #!foo :key #'midi-keynum :type 'midi)
(nreverse nums))
| | |
map-subholders function seq &key :recurse :key
|
[Function] |
Maps function over the composite objects in seq. If
:recurse is t then mapping i recursively applied to
subholders of seq. If :key is supplied it is first applied
to each mapped subholder and the results are passed to function.
insert-object object container
|
[Function] |
Inserts object into subobject of container.
objectmust have a time value.
append-object object container
|
[Function] |
Appends object to the subobjects of container.
append-object does not check time values.
remove-object object container
|
[Function] |
Removes object from the subobjects of container.
remove-subobjects object
|
[Function] |
Removes all subobjects from object.
save-object object file
|
[Function] |
Saves object and all its subobjects to file.
object can be a seq or a list of seqs.
Common Music Homepage | © 2002 Heinrich Taube |
Last Modified: 20 May 2002
|