Overview
Here are some notes on Patterns and Pbinds in SuperCollider
Patterns and the Event Class
Patterns
Patterns define sequences, which can be played and canc 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 valuesPseq
- takes a list as input and cycles over itPrand
- picks random values from a listPwhite
- creates random values between a lower and higher borderPser
- likePseq
but describes the total number of values you get when cycling over the listPxrand
- likePrand
but without repitition of valuesPshuf
- shuffles the list and cycles over the shuffled listPslide
- makes segments out of a list and steps through the segmentsPgeom
- creates a series of values similiar to a geometric seriesPn
- creates a Pattern out of the repetition of another Pattern
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. 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;
)
The Event
class defines a set of reserved keys that are interpreted in a special way, such as \freq
, \amp
, or \dur
. Besides those, you can freely use any argument name that you’ve defined in your own SynthDef
.
The pitch slot can be described with different key arguments, which all aspect a different pitch description:
\freq
- value as frequencie\degree
- value as scale degree, with default scale major, while 0 is middle C\note
- value as note, while 0 is middle C\midinote
- value as midinote
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 \srtum
argument, 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;
Tempo
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 are introduced through the Rest
class inside the values for the \dur
key.
(
Pbind(
\degree, Pwhite(0, 10),
\dur, Pseq([0.1, Rest(0.1), 0.3, 0.6, Rest(0.3), 0.25], inf);
).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 .play