Algorithmic Composition
5.3 Pattern Objects and Item Streams
In order to do something musically interesting, we certainly need to produce scores that have more than one pitch! The easiest way to create scores that have more than one pitch is to use item streams. Item streams are sequences of values generated by pattern objects. Pattern objects are created by functions to be described below. Once created, the next function causes a pattern object to generate the next
item in an infinite sequence.
Example 5.3.1: pitch-cycle.sal
set pitch-cycle = make-cycle(list(c4, d4, e4, f4)) set pitch-cycle-score =
score-gen(score-len: 8,
pitch: next(pitch-cycle), dur: 0.4)
In Example 5.3.1, we use make-cycle to make a cycle pattern.
The cycle pattern circularly selects items from the list, reading left to right for as many items are required. The cycle is assigned to the
5.3 Pattern Objects and Item Streams 65
global variable pitch-cycle using set. score-gen is then used to
build a score. Notice the value for pitch: is an expression to retrieve
the next item of pitch-cycle. This expression is evaluated once for
each note in sequence, so each note will have a new pitch value. Try printing and playing the result. Manipulating patterns using item streams is a simple yet very powerful approach to algorithmic com- position.
Let’s consider another example.
Example 5.3.2: item-streams.sal
set pitch-cycle = make-cycle(list(c4, c6, nil)) set vel-cycle = make-cycle({75 100 125}) set dur-cycle = make-cycle({0.3 0.5 0.7}) exec score-gen(save: quote(item-streams), score-len: 10,
pitch: next(pitch-cycle), vel: next(vel-cycle), ioi: next(dur-cycle))
This example introduces the save: keyword, which means set the following variable (which is quoted because we want the variable
name, not its value) to the computed score. This is equivalent to us-
ing set as in the previous example. After evaluating these expres- sions, the value of item-streams is the following:
Example 5.3.3: Output from item-streams.sal
SAL> exec score-print(item-streams) ((0 0 (SCORE-BEGIN-END 0 NIL)) (0 0.3 (NOTE vel: 75 pitch: 60)) (0.3 0.5 (NOTE vel: 100 pitch: 84)) (0.8 0.7 (NOTE vel: 125 pitch: NIL)) (1.5 0.3 (NOTE vel: 75 pitch: 60)) (1.8 0.5 (NOTE vel: 100 pitch: 84)) (2.3 0.7 (NOTE vel: 125 pitch: NIL)) (3 0.3 (NOTE vel: 75 pitch: 60)) (3.3 0.5 (NOTE vel: 100 pitch: 84)) (3.8 0.7 (NOTE vel: 125 pitch: NIL)) (4.5 0.3 (NOTE vel: 75 pitch: 60)) )
Notice that the pitch: keyword parameter is an expression that gets the next item from pitch-cycle. The expression is evaluated for every note and the cyclic pattern continues for the ten events speci- fied by the score-len: slot. When the pitch: is nil, no note is per-
formed, so in musical terms, this is a rest. Even when the pitch: is nil, the other parameters, vel: and dur:, are computed from their cy-
cles. The rest gets a duration of .7 seconds from the dur-cycle pat-
tern. Since time: is not specified explicitly, it defaults to the end
time of the previous note.
Table 5.3.1 and Table 5.3.2 describe the different pattern classes. In each case, you make a pattern object with a function make-
patternclass and store the pattern object in a variable with set.
Then, you access successive items from the pattern with the expres- sion next(patternobject). The pattern classes in Table 5.2.1 all take a
list of items as a parameter and deliver the items according to dif- ferent rules.
Other pattern objects operate on the stream of items retrieved from another pattern. Pattern objects of this type are created by a function of the form make-patternclass, which takes another pat-
tern object as input.
Often, these pattern objects operate on groups of items. Items re- trieved from pattern objects are grouped into periods. For example, each repetition of a cycle pattern is one period. In a heap pattern, one period is some permutation of all the items of the input list. The pe- riod length can also be specified by the for: keyword parameter, which we will see in later examples.
5.3 Pattern Objects and Item Streams 67
Table 5.3.1 : Pattern objects that take item lists as input
Pattern Class Description
Example in Accompanying
Media Notes
cycle Circles through the data items provided
in a list parameter. cycle.sal
heap
Plays through the data items in random order but will not repeat an item until all items have been played.
heap.sal
palindrome
Plays through the data item list forwards and backwards.
palindrome. sal
The keyword
parameter elide: may have a value of first:,
last:, #t, or #f and
determines if events are repeated when the pattern changes direction.
random
Each successive item is selected randomly from the input list.
random.sal
Items may be paired with weights for a weighted random selection.
line
Iterates through a list and repeats the last element until no more events are required.
line.sal
markov Generate items from a Markov
model.
markov- graph.sal
The markov pattern is
covered in a later chapter.
accumulation
For each item in the input list, output all the items up to and including the item
accumulation. sal
Example: (a b c) generates a a b a b c, and then repeats.
Table 5.3.2: Pattern objects that take pattern objects as input
Pattern Class Description
Example in Accompanying
Media Notes
accumulate
Each output item is the sum of the previous output item and the next item of an input stream.
accumulate. sal
Items from the input stream must be numbers.
copier
Copies periods of the input stream to the output stream.
copier.sal
The repeat:
parameter tells how many copies to make.
The merge:
parameter tells whether repeated periods should be output as one period (#t) or separate
periods (#f).
length
Regroups items from the input stream into periods of a specified length.
length.sal
The first parameter is the input pattern, the second is the period length.
window
Outputs items in a sliding window
over input items. window.sal
Parameters are input pattern, window size and window skip.
eval Re-evaluates expression for
each item. pwl-pat-fm.sal
Parameter is a Lisp expression.