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 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

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