Overview
Here are some notes on Patterns and Pbinds in SuperCollider
Patterns
Patterns define sequences, which can be played and can produce Event-Stream-Player. Patterns are like recipies for musical scores, which can produces sequences of values or other fundamental type of data. Patterns, which produces that kind of values are also called Value-Patterns
To use a Pattern like you would use a Rountine with .next and .rest you have to translate it to a Stream, which is a Superclass to Routine. You can do it .asStream.
There are a few helpfull Pattern Objects to create value patterns. Every Pattern Object class begins with a capital P. Here are a few examples:
Pseries
: creates a artihmetic like series of values
Pseq
: takes a list as input and cycles over it
Prand
: picks random values from a list
Pwhite
: creates random values between a lower and higher border
Pser
: like Pseq but describes the total number of values you get when cycling over the list
Pxrand
: like Prand but without repitition of values
Pshuf
: shuffles the list and cycles over the shuffled list
Pslide
: makes segments out of a list and steps through the segments
Pgeom
: creates a series of values similiar to a geometric series
Pn
: creates a Pattern out of the repetition of another Pattern
Pseg
: creates an envelope like Pattern, which is indepent of the rhythmic content and acts more like a breakpoint envelope
Pkey
: allows connecting Key-Values to interact with each other or make some values dependend on other values
Pfunc
: can take a Function as Input, which is evaluated for every Event. When an argument is declared, the current event is the input to the function
Here are some examples to use Patterns in non-realtime maner:
// value patterns
p = Pwhite(0, 15, 4);
q = p.asStream; //
q.next;
q.reset;
p = Pwhite(0, 15, inf); // makes this Pattern infinite long
q = p.asStream; //
q.next;
// math with patterns / composite patterns
p = Pwhite(0.0, 1.0, inf) * Pseq([-1, 1], inf);
q = p.asStream;
q.next;
// nest patterns
p = Pseq([1, 2, Pwhite(10, 20, 1), 7, Pseq([3, 4], 2)], inf);
q = p.asStream;
q.next;
// insert a Routine-Function into a pattern
(
~notesFunc = {
var num = 50;
while {num <= 105} {
num.yield;
num = num + 5;
}
};
)
p = Prout(~notesFunc);
q = p.asStream;
q.next;Patterns in SuperCollider are similar to a musical score. They are used to create one or several event streams, which in turn trigger one or more SynthDef instances.
The class Pbind can combine multiple key-value patterns into a single event stream - this is called Note-Event Pattern. A key-value pattern consists of a key, which refers to an argument of the SynthDef the values will be sent to, and a value, which is typically generated using a pattern class like Pseries or Pseq.
If no \instrument key is specified, Pbind will use the default SynthDef, which is usually named default.
A basic example:
(
Pbind(
\degree, Pseq([-12, 3, 4, 5], inf),
\dur, Pseq([0.2, 0.1, 0.1, 0.1, 0.5], inf),
\legato, 0.5
).play;
)Pattern Length
Every Pattern-Object does have a defined length, described by a number or the symbol inf, which means, the pattern has an infinite length. Does a Pbind hold Patterns of different lengths, the shortest pattern length defines the length of the Pbind.
You can also wrap a Pbind in a Pfin, which takes a Pattern and a count, which describes the total length of the Pattern. A common way to work with this approach is to set all the Patterns to inf and define the length via a Pfin.
(
p = Pbind(
\degree, Pseq([-12, 3, 4, 5], inf),
\dur, Pseq([0.2, 0.1, 0.1, 0.1, 0.5], inf),
\legato, 0.5
);
p = Pfin(12, p);
q = p.play;
)
q.stop;or
(
p = Pfin(12, Pbind(
\degree, Pseq([-12, 3, 4, 5], inf),
\dur, Pseq([0.2, 0.1, 0.1, 0.1, 0.5], inf),
\legato, 0.5
));
q = p.play;
)
q.stop;Another way to define the length of a Pattern is to describe the length in Beats. This is different to the previous approach, which describes the length in Event-Counts. This can be done with Pfindur.
(
p = Pfindur(8, Pbind(
\degree, Pseq([-12, 3, 4, 5], inf),
\dur, Pseq([0.2, 0.1, 0.1, 0.1, 0.5], inf),
\legato, 0.5
));
q = p.play;
)
q.stop;Keys of the Event Type \note
The Event type \note defines a set of reserved keys that are interpreted in a special way,
such as \freq, \amp, or \dur.
Besides these reserved keys, you can freely use any argument name that you’ve defined
in your own SynthDef, provided you set \instrument to that SynthDef’s name.
Pitch-related keys
The pitch can be described using different keys, each representing a different way to specify pitch:
\freq
: value in Hertz
\degree
: scale degree, default scale is major, 0 is middle C
\note
: chromatic note number, 0 is middle C
\midinote
: MIDI note number
Duration-related keys and Tempo
The duration of a \note Event can be described using different keys, that are mostly doing the same, but have different names for a more musical description of their function. These key-values are interacting with each other.
By default, when you play a \note Event, you are creating Synth based on the default SynthDef, which has a gated envelope. The \note Event has a key named sendGate which has a default value of true, which is responsible vor sending a gate off value corresponding to the duration of the \note Event. When this is happening is depending on these key-values:
\sustain
: sustain a number of beats, since the event is created; describing the overall length, composite of the following keys
\legato
: default value of 0.8, describing the overlap of \note Events
\stretch
: scales the \sustain value and timing
\dur
: time distance of \note events in beats, based on the used tempo clock
Per default a Pbin has a tempo of 60 BPM. Every value you provide to the \dur key is a number of beats, that is, 1 means one beat, 0.5 means half a beat, and so on. You can change the tempo of you Pbind with the introduction of a TempoClock.
(
Pbind(
\degree, Pseq([0, 0.1, 1, 2, 3, 4, 5, 6, 7]),
\dur, 1;
).play(TempoClock(120/60)); // 120 beats over 60 seconds: 120 BPM
)Rests
Rests can be introduced in different ways, but the most common ways us through the Rest class inside the values for the \dur key.
(
Pbind(
\degree, Pwhite(0, 10),
\dur, Pseq([
0.25, Rest(0.25), 0.25, 0.25,
Rest(0.25), 0.25, 0.25, 0.25], inf);
).play;
)But you can put a Rest object anywhere you want.
(
Pbind(
\midinote, Pseq([
60, Rest(), 64, 62,
Rest(), 60, 62, 64], inf),
\dur, 0.25;
).play;
)Another way would be to choose the Event-Type.
(
Pbind(
\type, Pseq([
\note, \rest, \note, \note,
\rest, \note, \note, \note
], inf),
\degree, Pwhite(0, 10),
\dur, 0.25;
).play;
)Chords with Patterns
You can write Chord Events via encapsulating them as a sublist in square brackets. It is also possible to to introduce the \strum key, which allows arpeggiating the chord.
(
Pbind(
\note, Pseq([[0, 3, 7], [2, 5, 8], [3, 7, 10], [5, 8, 12]], 3),
\dur, 0.15
).play;
)
(
Pbind(
\note, Pseq([[-7, 3, 7, 10], [0, 3, 5, 8]], 2),
\dur, 1,
\legato, 0.4,
\strum, 0.4
).play;
)Scale
When you use \degree for your pitches, you can introduce the Scale class, for selecting a Scale.
(
Pbind(
\scale, Scale.prometheus,
\degree, Pseq([0, 1, 2, 3, 4, 5, 6, 7], 1),
\dur, 0.15
).play;
)
// get a list of avaible scales:
Scale.directory;
// chromatics can be introduced with this:
(
Pbind(
\degree, Pseq([0, 1, 2, 3, 3.1, 4], 1),
).play;
)Transposition
You can transpose your pitches (not frequencies) with the \ctranspose keyword.
(
Pbind(
\note, Pser([0, 2, 3, 5, 7, 8, 11, 12], 11),
\ctranspose, 12, // transpose an octave above (= 12 semitones)
\dur, 0.15;
).play;
)
Microtones
Microtones can be used with \note and \midinote.
Pbind(\note, Pseq([0, 0.5, 1, 1.5, 1.75, 2], 1)).play;
Pbind(\midinote, Pseq([60, 69, 68.5, 60.25, 70], 1)).play;Multiple Pbinds
To start a few Pbinds together, you just have to enclose them in a single block.
In order to play Pbinds in a time-ordered fashion, you can use { }.fork. fork returns a Routine, which encapsulates a series of tasks, which are executed step by step.
(
t = TempoClock(76/60);
{
Pbind(
\note, Pseq([[4, 11], [6, 9]], 32),
\dur, 1/6,
\amp, Pseq([0.05, 0.03], inf)
).play(t);
2.wait;
Pbind(
\note, Pseq([[-25, -13, -1], [-20, -8, 4], \rest], 3),
\dur, Pseq([1, 1, Rest(1)], inf),
\amp, 0.1,
\legato, Pseq([0.4, 0.7, \rest], inf)
).play(t);
2.75.wait;
Pbind(
\note, Pseq([23, 21, 25, 23, 21, 20, 18, 16, 20, 21, 23, 21], inf),
\dur, Pseq([0.25, 0.75, 0.25, 1.75, 0.125, 0.125, 0.80, 0.20, 0.125, 0.125, 1], 1),
\amp, 0.1,
\legato, 0.5
).play(t);
}.fork;
)For more advanced ways of plaing Pbinds, check out Ppar and Pspawner.
Via Variables we can make our live easier when multiple Pbinds are using the same data.
~scale = [0, 1, 2, 3, 4, 5, 6, 7];
~durs = [0.4, 0.2, 0.2, 0.4, 0.8, 0.2, 0.2, 0.2];
(
Pbind(
\degree, Pslide(~scale.reverse, inf, 3, 1),
\dur, Pseq(~durs * 2, inf)
).play;
Pbind(
\degree, Pxrand(~scale + 21, inf),
\dur, Pseq(~durs, inf),
\amp, 0.02
).play;
Pbind(
\degree, Pxrand(~scale - 14, inf),
\dur, Pseq(~durs * 4, inf)
).play;
)Assignment to multiple keys
We can also write data pairs, to keep some data connected to each other.
(
Pbind(
#[midinote, dur], Pseq([
[60, 0.75],
[67, 0.25]
], inf),
\amp, 0.7
).play;
)Controlling Pbinds
When you call .play on a Pbind, you are generating an object called EventStreamPlayer. Via assigning this object to a variable, you can control the playing of your Pbind.
Here is a more advanced example of this:
// Define the score
(
var myDurs = Pseq([Pn(1, 5), 3, Pn(1, 5), 3, Pn(1, 6), 1/2, 1/2, 1, 1, 3, 1, 3], inf) * 0.4;
~upperMelody = Pbind(
\midinote, Pseq([69, 74, 76, 77, 79, 81, Pseq([81, 79, 81, 82, 79, 82], 2), 82, 81, 79, 77, 76, 74, 74], inf),
\dur, myDurs
);
~lowerMelody = Pbind(
\midinote, Pseq([57, 62, 61, 60, 59, 58, 57, 55, 53, 52, 50, 49, 50, 52, 50, 55, 53, 52, 53, 55, 57, 58, 61, 62, 62], inf),
\dur, myDurs
);
)
// Play the score
(
~player1 = ~upperMelody.play;
~player2 = ~lowerMelody.play;
)
// Stop the voices separately
~player1.stop;
~player2.stop;
// Other available messages
~player1.resume;
~player1.reset;
~player1.play;
~player1.start; // same as .playQuantizing Patterns
You can quantize patterns, so that they will start on a predefined beat on a choosen clock (check also SuperCollider - Events, Routines, Tasks and Sequencing on Clocks for this).
(
p = Pbind(
\degree, Pseq([-12, 3, 4, 5], inf),
\dur, Pseq([0.2, 0.1, 0.1, 0.1, 0.5], inf),
\legato, 0.5
);
)
q = p.play(TempoClock.default, quant: 4) // this will start the playback on the next beat multiplied by 4 on the default TempoClockPdef and Pbindef need a other syntax for this. We apply the clock and quantization information to the Pattern instead of putting it into the .play method.
(
Pdef(\p,
Pbind(
\degree, Pwhite(0, 12, inf),
\dur, Pwhite(0.25, 0.5, inf),
\legato, Pwhite(0.9, 1.25, inf),
\db, Pwhite(-32, -20, inf),
)).quant_(4).clock_(TempoClock.default).play;
)
Pdef(\p).stop;
Pdef(\p).clear;Pattern-Envelopes
You can create Envelope-Like Patterns with Pseg, which draws segements between levels in defined times.
(
p = Pmono(
\default,
\dur, 0.25,
\db, Pseg(
levels: [-32, -16, -32],
durs: [3, 3],
curves: \exp,
repeats: 5
),
\freq, Pwhite(100, 400, inf);
);
)
q = p.play;
q.stop;The same thing can be done with an Env object and the method .asPseg.
(
p = Pmono(
\default,
\dur, 0.25,
\db, Env(
levels: [-32, -16, -32, -16],
times: [3, 3],
curve: \exp
).asPseg,
\freq, Pwhite(100, 400, inf);
);
)
q = p.play;
q.stop;Pattern-Proxys and interactive Patterns
Pdefn allows you to wrap a Value-Pattern and creates a Pattern Proxy from it.
This means that the EventStreamPlayer, which is created on the server when you play a pattern,
can be accessed from the language side. To acces it, you will need to define a symbol for this proxy.
This can be used to change the Pattern for a key or to stop an infinite long Pattern.
(
p = Pmono(
\default,
\dur, 0.25,
\freq, Pdefn(\def_freq, Pwhite(100, 400, inf));
);
)
q = p.play;
Pdefn(\def_freq, Pexprand(200, 800, 8)); // change pattern and make it stop after 8 events
q.stop;This can be helpfull to let a pattern perform a fade-out.
(
p = Pmono(
\default,
\dur, 0.25,
\freq, Pdefn(\def_freq, Pwhite(100, 400, inf));
);
)
q = p.play;
Pdefn(\def_freq, Pexprand(200, 800, 8)); // change pattern and make it stop after 8 events
q.stop;Pdef allows a similiar thing, but wraps a complete Event-Pattern. This eliminates the need to implement for every Pattern-Value a Pdefn. The Pdef get’s one symbol and can be performed in a live-coding manner, to change and add key-values on the fly.
( // change values and re-evaluate this block
Pdef(\p,
Pbind(
\degree, Pwhite(0, 12, inf),
\dur, Pwhite(0.25, 0.5, inf),
\legato, Pwhite(0.9, 1.25, inf),
\db, Pwhite(-32, -20, inf),
)).play;
)
Pdef(\p).stop; // stop it
Pdef(\p).clear; // clear the pattern when done with itPbindef is similiar to Pdef, but does not need a Pbind. It just needs proxy symbol. Another feature of Pbindef is, that you can access all values outside of the original Pbindef and change values outside. But it has some problems with replacing values on the fly when they access the same parameter like \freq, e.g. first using \midinote and after this \degree.
(
Pbindef(\p,
\degree, Pwhite(-5, 7, inf),
\dur, Pwhite(1.0, 1.5, inf),
\legato, Pwhite(1.0, 1.5, inf),
\db, Pwhite(-32, -20, inf),
).play;
)
Pbindef(\p, \legato, Pwhite(2.0, 4.0, inf), \degree, Pwhite(-12, 12, inf), \ctranspose, [0, 0.1]);
Pbindef(\p).stop;
Pbindef(\p).clear;Set-Event Patterns
There is a group of Set-Event Pattern Objects like Pmono and PmonoArtic which create a single Synth Event and is setting it’s values with key-value patterns. Unlike Pbind, which creates note-event after note-event, Pmono only creates one note-event, which lives until the last value via a Pattern Object is send. After this, Pmono sends a gate off message.
(
p = Pmono(
\default,
\dur, 0.25,
\freq, Pwhite(100, 400, inf);
);
)
q = p.play;
q.stop;
PmonoArtic in comparison checks the legato value and creates a new note-event if the legato value < 1.0. Otherwise the Synth instance will be set to a new value.
(
p = PmonoArtic(
\default,
\dur, 0.5,
\legato, Pwhite(0.75, 1.5, inf),
\freq, Pwhite(100, 400, inf);
);
)
q = p.play;
q.stop;