One way to use patterns is to write everything into the pattern up front. This has the advantage of clarity and ease of understanding. Another way is to modularize the behavior by creating smaller, simpler patterns and combining their results into single events that have keys and values from all the component patterns.
This is related to the computer science concept of "function composition," in which a complex calculation can be written not as a single large function, but as several smaller functions that are then chained together into a single function. Since Functions are normal objects in SuperCollider, it's easy to do an operation on a function that returns a composite function (which may then be used like any other function). http://en.wikipedia.org/wiki/Function_composition_(computer_science)
In mathematics, the ·
operator represents function composition.
g · f
means to evaluate f
first, then pass its result to g
. The ·
operator is written as <>
in SuperCollider.
Event patterns can be similarly composed.
Pbindf(pattern, pairs)
Pbindf(Pbind(\a, patternA), \b, patternB, \c, patternC)
gets the same result as Pbind(\a, patternA, \b, patternB, \c, patternC)
.Pchain(patterns)
a = Pbind(\a, patternA)
and another part creates b = Pbind(\b, patternB, \c, patternC)
, you could append \b
and \c
into the \a
result using Pchain(b, a)
. The subpatterns evaluate in reverse order, in keeping with function composition notation.
For musical purposes, you could have one part of your code create a pattern defining rhythm and another part defining pitch material, then combine them with Pchain.
That in itself has some good potential for algorithmic composition. Introducing EventPatternProxy into the mix makes it possible to swap different melody and rhythm components in and out on the fly, with no interruption. We can even change the type of pattern ( Pbind, Pmono, PmonoArtic ) with no ill effect.
A group of pattern classes allow single event keys to be overwritten, or one addition or multiplication to be performed. Pkey, in combination with the Pchain or Pbindf "pattern composition" classes, can do everything the following classes can do (though this alternate notation may be more convenient in certain cases).
Pset(name, value, pattern)
pattern
, and then put the next value from the value
pattern into the name
key. If the source pattern specifies a value for the same name, the value from the source will be replaced with the new one.Padd(name, value, pattern)
name
value with its existing value +
the next number from value
.Pmul(name, value, pattern)
name
value with its existing value *
the next number from value
.These patterns remain in the library mainly for reasons of backward compatibility, since their behavior can be replicated easily using Pbindf.
Pset(name, value, pattern) | Pbindf(pattern, name, value) |
Padd(name, value, pattern) | Pbindf(pattern, name, Pkey(name) + value) |
Pmul(name, value, pattern) | Pbindf(pattern, name, Pkey(name) * value) |
The patterns Psetpre, Paddpre, and Pmulpre reverse the order of evaluation. Pchain is able to duplicate this functionality.
Psetpre(name, value, pattern)
value
and put it into the event prototype before evaluating pattern
.Psetpre(name, value, pattern) | Pchain(pattern, Pbind(name, value)) |
Paddpre(name, value, pattern) | Pchain(pattern, Pbind(name, Pkey(name) + value)) |
Similar for Pmulpre
.
A third group -- Psetp, Paddp, Pmulp -- behave slightly differently, nesting pattern evaluation.
Previous: Pattern Guide 06b: Time Based Patterns
Next: Pattern Guide 06d: Parallel Patterns