Common Music Reference Manual |
 |
|
5 Patterns
Patterns are containers that generate data according to pattern specific
ordering rules. Patterns can organize any type of lisp data
and may also include nested subpatterns that define
different local orderings inside the surrounding pattern.
Patterns organize their data into chunks. The period length
of a pattern determines the number of elements that make up each chunk of data.
Elements can be read one at a time or in chunks using
the next function.
Patterns may also have repeat factors that set a ceiling
on the number of periods, or chunks, that the pattern returns. If a pattern
reaches its repeat limit it will return an end of data marker for all
subsequent calls to next.
Pattern properties such as the period length and repeat limit are specified
when the pattern is created with new.
Most pattern properties may be specified as single values or as
patterns of values. Property patterns are read once each period of the pattern.
See the section Working with Patterns for information
about creating patterns and accessing elements from patterns.
5.1 Pattern Classes
The pattern class is the root for a number of genericn pattern classes:
- cycle
- line
- palindrome
- heap
- random
- markov
- graph
- funcall
- accumulation
- rotation
- rewrite
In addition to this set of generic pattern classes there are several
specialized pattern classes that implement more
restricted functionality:
- range
- transposer
- chord
- pval
All patterns support the following slot initializations:
-
of list
-
Sets the elements of the pattern to the data in list.
-
notes list
-
Like of but parses list as notes.
-
keynums list
-
Like of but parses list as keynums.
-
rhythms list
-
Like of but parses list as rhythms.
-
amplitudes list
-
Like of but parses list as amplitudes.
-
for {number | pattern}
-
Sets the period length of the pattern to number or pattern of numbers.
-
repeat {number | pattern}
-
Sets the repetition factor of the pattern to number or pattern of numbers.
-
name {string | symbol}
-
Sets the name of the pattern to string or the print name of symbol.
A named pattern can be references as an element inside another pattern using the
#! read macro.
-
parsing function
-
Sets the pattern parser to function. This function is called on successive
elements passed to the pattern when the pattern is created. The function should accept
one argument, the element to parse.
-
returning function
-
Sets the pattern's return function to function.
This function is called each time an element is read from the pattern
and should return a value to use in place of the element.
The function is passed one or two arguments, depending on the number of lambda parameters
the function has. If function has one lambda parameter it is passed
the pattern value that will be returned. If function has two lambda parameters it
is passed the value and the state of the pattern.
Enumerates data in sequential order and loops back to the first element after the last
element has been reached.
Example 5-1
|
? (setf x (new cycle of '(a b c d)))
#<cycle @ x112323>
? (next x 12)
(a b c d a b c d a b c d)
? (setf x (new cycle keynums '(c5 d e f g a) for 12))
#<cycle @ x112323>
?(next x t)
(72 74 76 77 79 81 72 74 76 77 79 81)
| | |
Enumerates data in sequential order and sticks on the last element once it has been reached.
Example 5-2
|
? (setf x (new pattern of '(a b c d) in line))
#<line @ x112323>
? (next x 12)
(a b c d d d d d d d d d)
? (setf x (new line of (list 'a 'b 'c (new random of '(d e)))))
#<line @ x112323>
? (next x 12)
(a b c e e d e d e d d d)
| | |
Enumerates data in palindromic order. Subpatterns continue to produce their own
ordering.
palindrome supports the following slot initializations:
-
elide {t | :first | :last}
-
If elide is t then the first and last elements
in the pattern are not directly repeated when the pattern reverses
direction. If the value is :first then only the first
element is elided, otherwise if the value is :last then
only the last element is elided.
Example 5-3
|
? (setf x (new palindrome of '(a b c d)))
#<palindrome @ x54F5AD6>
? (next x 16)
(a b c d d c b a a b c d d c b a)
? (setf x (new palindrome a b c d elide t))
#<palindrome @ x54F5AD6>
? (next x 12)
(a b c d c b a b c d c b a b c d)
| | |
Enumerates data by random permutation (sampling without replacement).
heap supports the following slot initializations:
-
state random-state
-
Sets the random state object of the pattern to random-state. Defaults to *random-state*.
Example 5-4
|
? (setf x (new heap notes '(a b c d)))
#<heap @ x54F5AD6>
? (next x 12)
(a4 b4 c4 d4 b4 c4 a4 d4 d4 b4 a4 c4)
| | |
Enumerates data in random order (sampling with replacement).
random supports the following slot initializations:
-
state random-state
-
Sets the random state object of the pattern to random-state. Defaults to *random-state*.
By default, each element in a random pattern has an equal probability of
selection and each element may be repeated in direct succession any number of times.
This behavior can be modified for any element by specifying the element as a
node, a list of the element to be returned by
the pattern followed by zero or more properties and values:
(element {property value}*)
random supports the following node properties:
-
weight {number | pattern}
-
Sets the probability of the node relative to the probabilities of
the other nodes to number. The default weight for each node is 1.
The weight may also be specified as a pattern of numbers, in which case a new
weight will be selected for each period in the random pattern.
-
min number
-
Sets a floor on how many direct repetitions element must be made
before a new element might be selected.
-
max number
-
Sets a ceiling on how many direct repetitions of the element might be made
before a new element must be selected.
Example 5-5
|
? (setf x (new random of '((a max 1)
b
(c weight 4)
d)))
#<random @ x554816E>
? (next x 12)
(a c c c a c c c d b c c)
| | |
Implements 0 to nth order Markov chains.
markov supports the following slot initializations:
-
past ({id}*)
-
Initializes the pattern with an explicit list of past choices expressed as node identifiers.
Each element in a markov pattern is specified as transition rule:
({past}* -> {next | (next weight)}+)
past is zero or more identifiers that define
the "left side" of the transition rule. Values nearer the -> are
more recent past choices. The number of past values in the left-hand side
determines the Markov order of the pattern. Any order is possible but every transition
rule must have the same number of past values. Values to the right of
->
define the set of outcomes. By default each outcome has the same probability
of being selected. To alter the weight of an outcome specify it in a list
together with its weight. For example the transition rule:
(c -> a (b 2) c)
defines a 1st order Markov transition whose outcomes a,
b or c are triggered if c was the last value generated.
Outcome b has twice the probability of being selected as either
a or c. The transition rule:
(q w a -> e r (d 3) g)
describes a third-order transition in which a is the most recent past outcome.
The transition rule:
(* x a -> foo bif zuz)
demonstrates the * "wildcard" that matches any
value in its position. * allows multiple transitions with
identical outcomes to be collapsed to a single rule. Finally, the transition rule:
(-> a (b .1) c)
describes a 0th order Markov transition, equivalent to weighted
random selection. Only a single transition rule should be specified in
a 0th order Markov pattern.
Example 5-6
|
;; a second order Markov pattern of Happy Birthday
(setf x (new markov
of '((d4 c4 -> (f4 .5) (g4 .5))
(d4 bf4 -> bf4)
(c4 d4 -> c4)
(c4 c4 -> (d4 .667) (c5 0.333))
(c4 f4 -> e4)
(c4 g4 -> f4)
(c4 c5 -> a4)
(f4 c4 -> c4)
(f4 e4 -> (c4 .5) (d4 .5))
(f4 g4 -> f4)
(e4 d4 -> bf4)
(e4 c4 -> c4)
(g4 f4 -> c4)
(c5 a4 -> f4)
(a4 f4 -> (e4 .5) (g4 .5))
(bf4 a4 -> f4)
(bf4 bf4 -> a4))))
#<markov @ x558488E>
? (next x 20)
(g4 f4 c4 c4 d4 c4 g4 f4 c4 c4 d4 c4 f4 e4 d4 bf4 bf4 a4 f4 e4)
| | |
See markov-analyze
for more information about markov patterns.
Enumerates data according to transition rules associated with each element.
graph supports the following slot initializations:
-
selector function
-
Sets the node selection function of the graph. The function is passed three values,
the pattern, the last node and the list of ids representing the past selections.
Defaults to the system's graph traversal function #'default-graph-node-select.
-
props list
-
Sets the property list of the graph to list. This list can be used to cache
information for a specific selector function.
-
last ({id}*)
-
Initializes the graph to a specific list of ids representing past node choices.
Elements in a graph are represented as nodes. Each node must be specified
as a list:
(element {property value}+)
where element is the element to return from the node.
graph supports the following node properties:
-
-> {id | pattern}
-
Sets the transition link for the graph node. This option is required for
each node. The value may be a single identifier or a pattern of identifiers.
-
id datum
-
Sets datum to be the unique identifier for the node in the pattern. The
identifier may be any LISP datum as long as its uniquely represented in
the pattern. If omitted, the identifier defaults to the element itself. It is good
practice to provide each node with an explicit id that is
independent of the actual element returned by the node.
Implements user defined patterns by calling a function each time a new
period of items is needed. The function is passed no arguments and should return a
list of elements representing the
next period in the pattern or else nil if there are no more elements.
Example 5-7
|
? (setf x (new funcall of #'(lambda () (list 1 2 (random 10000)))))
#<funcall @ x560EDA6>
? (next x 12)
(1 2 9693 1 2 1292 1 2 1777 1 2 9518)
| | |
Enumerates data together with the set of items that have been enumerated
so far. The process starts over when all the items have
been accumulated.
Example 5-8
|
? (setf x (new accumulation of '(a b c d)))
#<accumulation @ x560EDA6>
? (next x t)
(a a b a b c a b c d)
| | |
Enumerates items in a rotation. Elements are rotated each period in the pattern by
swapping pairs of elements belonging to a specific rotational scheme.
rotation supports the following slot initializations:
-
rotations (start step width end)
-
The list that describes the rotational characteristics of the pattern. The list
contains up to four independent parameters:
start is the starting index (zero based) in the elements for swapping to begin,
step is the distance to move after each swap.
width is the distance between each pair to swap, and end marks the
position to end element swapping.
The rotation list defaults to (0 1 1 *), which causes elements in the pattern
to rotate leftward.
Example 5-9
|
? (setf x (new rotation of '(a b c d)))
#<rotation @ x565D46E>
? (loop repeat 4 collect (next x t))
((a b c d) (b c d a) (c d a b) (d a b c))
| | |
The file "cm:examples;ring.cm" contains
example rotations that implement change ringing patterns developed by
church bell ringers in England.
Enumerates elements from successive generations of elements
according to user specified rewrite rules.
rewrite supports the following slot initializations:
-
rules list
-
Sets the rewrite rules of the pattern to list.
-
generations number
-
Sets the number of generations to actually generate. After number of generations
the pattern simply reuses elements from the last generation, as if the pattern were a cycle.
Rewrite rules are expressed in terms of nodes and node identifiers. Two different
styles of rule specification are supported.
1. Context-free Rules (rules associated with nodes)
The first style of rule specification associates a rewrite rule
with each node in the pattern. This method is capable of describing many
sorts of context-free morphologies. The form of each node is similar
to the graph pattern:
({element} {property value}+)
where element is the element to return from the pattern followed
by one or more property value pairs.
rewrite supports the following node qualifiers:
-
id datum
-
Sets datum to be the unique identifier for the node in the pattern. The
identifier may be any LISP datum as long as its uniquely represented in
the pattern. If omitted, the identifier defaults to the element itself. It is good
practice to provide each node with an explicit id that is
independent of the actual element returned by the node.
-
-> {id | ({id}+) | pattern | nil}
-
Sets the rewrite expression for the node. The value may be a single identifier,
a list of identifiers, a pattern or nil. If the value is nil
the node is terminal, ie. it produces no successor(s) in the pattern's
next generation. If the value
is a pattern then the pattern is read to produce a successor term each
time the node is rewritten. Otherwise the value should be an id or list
of ids that identify successor node(s) in the next generation.
2. Context-sensitive Rules (rules applied to nodes)
The second style of rule specification permits context-sensitive
rules (rules involving more than one node in their left hand side) to be defined. In
this method a list of rules is associated with the entire pattern rather
than with the nodes in the pattern. This means that there may be more or
fewer rules than there are nodes. The rule list is interpreted as
an ordered set; to produce a new generation, each node in the current
generation is matched against the rule list to find the successor rule
to apply to the node. The first rule that matches is triggered and the id(s)
in the right-hand side of the rule produce the successor node(s) in the
next generation.
Node specification for the second method is similar to the first except that:
- the -> option is not part of the node declaration.
- if the node's id value is the same as the element itself
then the element itself can be specified in place of the node.
Each rule in the second style of rule specification is a list of the form:
({id}+ -> {id}*)
The -> operator divides each rule into two sides. The left-hand side
of the rule defines the "matching target" and the right-hand side defines
the rewrite succession.
Either or both sides may contain more than one id. If the left-hand side
of the rule is a single id then the rule matches any node with the same
id. If the left-hand side has more than one id (a context-sensitive rule)
then the rule matches if the "strict predecessor" in the left-hand side
matches the current node and the nodes around the current node in the generation
match the ids around the strict predecessor in the left-hand side. The
strict predecessor id is marked as a list. Every context rule must contain
exactly one strict predecessor in its left hand side.
Three examples of context sensitive rules:
-
(1 (1) 2 -> 3)
-
Means node 1 rewrites to node 3 wherever 1 is preceded by itself and followed by 2
in the current generation.
-
(1 * (2) -> 1 2)
-
means node 2 rewrites to 1 and 2 whenever 1 occurs two positions
earlier in the current generation.
-
(5 (3) 3 4 ->)
-
means node 3 rewrites to nothing if preceded by 5 and followed by itself and 4 in the current
generation. Note that the right-hand side may be empty and that the left-hand
side may contain the wild card * which matches any single element in the
current generation.
Example 5-10
|
? (setf x (new rewrite
of '((a -> (a b a))
(b -> (b b a)))
initially 'b))
#<rewrite @ x555746E>
? (next x 20)
(b b b a b b a b b a a b a b b a b b a a)
| | |
5.2 Specialized Pattern Classes
Enumerates numbers in a range.
range supports the following slot initializations:
-
from {number | pattern}
-
The start value to return from the range. Defaults to 0. from
is reset each time it exceeds range boundaries or at the end of each period
if there are no boundaries on the range.
-
initially {number}
-
Like from but specifies that the
value should not reset at the end of each period.
initially can only appesar if the range has no upper
or lower boundary.
-
to {number | pattern}
-
Optional inclusive upper bound on the range. If this bound is exceeded the
the range is reset to from.
-
below {number | pattern}
-
Like to except that the upper bound is exnclusive.
-
downto {number | pattern}
-
Optional inclusive lower bound for the enumeration. If this bound is exceeded the
range is reset to from.
-
above {number | pattern}
-
Like downto except that the lower bound is exlusive.
-
by {number | pattern}
-
The increment between numbers in the range. If by
is a pattern its value is reselected each time from is reset.
-
stepping {pattern}
-
Like by but the increment value changes each selection.
For bounded ranges the default period length is the number of
values enumerated between the boundaries. For unbounded ranges
the default period length is 1. Note that a single range may contain
both an upper and a lower bounds. Combining these with a random
stepping value implements bounded random walks.
Example 5-11
|
? (setf x (new range to 10))
#<range @ x4050B9E>
? (next x t)
(0 1 2 3 4 5 6 7 8 9 10)
? (setf x (new range from 60 for 5))
#<range @ x4050B9E>
? (next x 10)
(60 61 62 63 64 60 61 62 63 64)
? (setf x (new range initially 60 for 5))
#<range @ x4050B9E>
? (next x 10)
(60 61 62 63 64 65 66 67 68 69)
? (setf x (new range from 10 downto -10 by 2))
#<range @ x4050B9E>
(10 8 6 4 2 0 -2 -4 -6 -8 -10)
? (setf x (new range from (new cycle 1 5) to 10))
#<range @ x4050B9E>
? (next x t)
(1 2 3 4 5 6 7 8 9 10)
? (next x t)
(5 6 7 8 9 10)
? (setf x (new range from 60
stepping (new random -2 -1 1 2)
to 65 downto 55))
#<range @ x4050B9E>
? (next x t)
(60 59 58 59 60 62 64 62 64 65)
? (next x t)
(60 61 62 64 62 64)
| | |
A pattern that return notes, keynums or lists of the
same by combining transposition data
with a transposition offset.
Transposed data may be optionally retrograded and inverted.
transposer supports the following slot initializations:
-
of {list | pattern}
-
The data to transpose. If the data is a pattern then successive
elements are read from the pattern and transposed. These elements can
be notes, keynums or lists of the same. List are treated as single
units by the transposer.
-
by {note | keynum | pattern}
-
Sets the transposition offset. If by is a
pattern a new offset is selected each period of the
transposition data. by may also be specified as on.
-
stepping {pattern}
-
Like by execept that the transposition offset is
read each time an element is transposed rather than each period.
-
form {p i r ri | pattern}
-
A symbol or pattern of symbols that specifies the "row form" for
list data returned by the transposer. p stands for prime,
i for inversion, r for
retrogade and ri for retrograde-inversion. Either
symbols or keywords can be used to specify the row form.
The row form is read once each period or once each element according
to by or stepping.
-
mod {number | pattern}
-
Optional modulus on list data.
-
scale {scale}
-
The scale to use to transpose data in. Detaults
to *scale*, the standard chromatic scale.
A chord is a special type of pattern that
returns a list of chord data each time it is
read by the next function.
If chord data is specified as a single pattern the chord
can generate different data each time it is read.
The braces [] are a read macro that creates a
chord pattern out of the enclosed items..
Example 5-12
|
;; a process that plays mostly chords. The middle chord selects
;; different chord members each time it is picked.
(defprocess dochords ()
(process with pat = (new heap
[c4 e4 g4]
[(new heap df4 ef4 gf4 af4 bf4 df5 ef5 for 3)]
[e4 a4 cs5]
(new cycle bf6 bf2 for 1))
repeat 32
do (doeach (k (next pat))
(output (new midi keynum k time (now))))
wait .5))
? (events (dochords) "midi.port")
| | |
Holds a LISP expression to be evaluated each time it is read from the pattern.
Example 5-13
|
? (setf x (new cycle
a
(new pval (between 1000 5000))
b))
#<cycle @ x57EDACE >
? (next x 12)
(a 2760 b a 3589 b a 1175 b a 1515 b)
| | |
5.3 Working with Patterns
Patterns are created using make-instance or the new macro.
(new heap of '(a b c))
(make-instance 'heap :of '(a b c) )
Once a pattern has been created successive elements
can be enumerated, or read, using the next function.
next pattern &optional length
|
[Function] |
Returns one or more elements from pattern according to length.
The default value of length is nil which means that
just the next element from pattern is returned together with a
second value marking the pattern's state as a result of the read.
(The second value can simply be ignored if it is not of interest to
the caller.) If length is t then next returns
a list containing the next period chunk from the pattern.
Otherwiselength should be the number of elements to return
in a list.
Example 5-14
|
? (setf x (new cycle of '(a b) repeat 2))
#<cycle @ x112323>
? (next x)
a
nil
? (next x)
b
:end-of-period
? (next x t)
(a b)
? (next x )
:end-of-data
:end-of-period
| | |
pattern? object
|
[Function] |
Returns true if object is a pattern.
Returns true if state is at end-of-period. state
can be the state returned from a pattern or the pattern object itself.
Returns true if value is at end-of-data. value
can be the value returned from a pattern or a pattern object itself.
pattern-last-value pattern
|
[Function] |
Returns the last value returned by the pattern.
pattern-last-state pattern
|
[Function] |
Returns the last state returned by the pattern.
map-pattern-data function pattern
|
[Function] |
Maps function over each element in pattern. (Note: the elements
in a pattern may be stored in a different that what the user specified to the pattern.)
The list of implemented pattern classes.
Common Music Homepage | © 2002 Heinrich Taube |
Last Modified: 20 May 2002
|