A single pattern by itself is not so exciting. But patterns can be used together to get more complex results.
We saw list patterns ( Pseq, Prand, etc.) that returned numbers from a preset list, either in the order given or rearranged randomly. The list may also include other patterns. When a list pattern encounters another pattern in its list, the inner pattern is embedded into the stream. That is, the inner pattern takes over until it runs out of values to return. Then, control returns to the outer list pattern. This is like calling a function in the middle of another function.
There is no preset limit to the number of levels of embedding.
If a single pattern is like a word, a list pattern that uses other patterns could be more like a sentence or phrase. You can alternate between different behaviors, either in a predictable order as in the example below, or randomly by using one of the random-order list patterns.
But it gets even more fun -- list patterns don't care whether they're enclosing value patterns (as in the previous example) or event patterns. That means you can write a set of Pbind-style patterns, each one representing a phrase, and string them together. This next example is longer, but that's only because of a larger number of phrase patterns. The structure is very simple, though: Pxrand([Pbind(), Pmono(), Pmono()...], inf)
. Some of the phrases are written with Pmono to slide between notes.
Shortcut notation : Just like you can concatenate arrays with ++, you can also concatenate patterns the same way. Writing pattern1 ++ pattern2
is the same as writing Pseq([pattern1, pattern2], 1)
.
If this sounds a bit like a Markov chain, that's because the Pfsm implementation is a special case of a Markov chain where there is an equal probability of choosing the next state from the valid successors. In a Markov chain, the probabilities are weighted according to analysis of a real-world data stream.
The Pfsm help file includes very good examples of organizing single values and pattern phrases. Also see Pattern Guide Cookbook 06: Phrase Network for an application of Pfsm to generate a corny jazz solo.
The name Pdfsm stands for "deterministic finite state machine," where there is no random selection.
- Third-party extension alert : A good Markov chain implementation for SuperCollider exists in the MathLib quark.
One very effective way to manage phrases is to make a library, or more precisely Dictionary, of sub-patterns, and then call them up one at a time. Psym is the pattern to do this. The advantage here is that you can store the phrases in a separate place, while the pattern that you actually play is much simpler and describes the musical intent at a much higher level.
A complicated pattern with lots of embedding can be hard to read because it's more work to separate note-level details from the larger structure. The pattern choosing the phrases -- Pxrand(#[repeated, octave, tritone, dim], inf)
-- is self-explanatory, however, and Psym fills in the details transparently.
Psym(**, (pattern1: Pbind(**))
Pbind(\someValue, Pnsym(**, (pattern1: Pwhite(**)))
Pbind(\someValue, Psym(**, (pattern1: Pwhite(**)))
In the examples above, if a list pattern encounters another pattern in its input values, the subpattern is embedded in its entirety before the list pattern is allowed to continue. Sometimes you might want to get just one value out of the subpattern, and then choose a different subpattern on the next event. Pswitch, Psym and Pnsym have cousins that do exactly this: Pswitch1, Psym1 and Pnsym1.
Compare to the following:
With Pswitch, one of the items is chosen from the list and keeps playing until it's finished. But the length of both Pwhite patterns is infinite, so whichever one is chosen first retains control. Pswitch1 does the coin toss on every event and embeds just one item.
Psym1 and Pnsym1 behave similarly, choosing the name to look up the pattern for each event.
Pif supports this kind of structure: If the next value from a Boolean pattern is true, return the next item from pattern A, otherwise take it from pattern B. Another way to write the Pswitch1 example is to use a Boolean test directly on Pwhite, instead of writing a Pfunc for the coin toss. This might be clearer to read. However, this works only when there are two alternatives. Pswitch1 and Psym1 allow any number of choices.
We will see in Pattern Guide 06e: Language Control that Pif can be used on values that were previously calculated in the Pbind. It adds considerably to the intelligence Pbind can manage, when its value streams are aware of other values in the event.
Previous: Pattern Guide 03: What Is Pbind
Next: Pattern Guide 05: Math on Patterns