Recursive phrases and granular composite sounds
Pdef can be used as a global storage for event patterns. Here a way is provided by which these
definitions can be used as an instrument that consists of several events (a phrase),
such as a cloud of short grains. Furthermore, this scheme can be applied recursively, so that structures like a cloud of clouds can be constructed.
when the event type \phrase is passed in, the event looks for a pattern in Pdef.all if it can find a definition
- if it finds one it plays this pattern in the context of the outer pattern's event.
If there is no definition to be found there, it uses a SynthDef with this name, if present.
When passing a function to Pdef it creates a PlazyEnvir internally.
Its function is evaluated in the context of the outer environment (see PlazyEnvir ) which should return
a pattern or a stream.
(
s.boot;
SynthDef(\pgrain,
{ arg out = 0, freq=800, sustain=0.001, amp=0.5, pan = 0;
var window;
window = Env.sine(sustain, amp * AmpCompA.kr(freq));
Out.ar(out,
Pan2.ar(
SinOsc.ar(freq),
pan
) * EnvGen.ar(window, doneAction:2)
)
}
).store;
SynthDef(\noiseGrain,
{ arg out = 0, freq=800, sustain=0.001, amp=0.5, pan = 0;
var window;
window = Env.perc(0.002, sustain, amp * AmpCompA.kr(freq));
Out.ar(out,
Pan2.ar(
Ringz.ar(PinkNoise.ar(0.1), freq, 2.6),
pan
) * EnvGen.ar(window, doneAction:2)
)
}
).store;
Pdef(\sweep, { arg sustain=1, n=8, freq=440, ratio=0.1;
Pbind(
\instrument, \pgrain,
\dur, sustain.value / n,
\freq, Pseq((1..n)) * ratio + 1 * freq.value // freq is a function, has to be evaluated
)
});
Pdef(\sweep2, { arg sustain=1, n=8, freq=440, ratio=0.1;
Pbind(
\instrument, \noiseGrain,
\dur, sustain.value / n, // sustain is also a function, has to be evaluated
\freq, Pseq((1..n).scramble) * ratio + 1 * freq.value,
\recursionLevel, 2
)
});
Pdef(\sweep3, { arg freq=440;
Pbind(
\type, \phrase,
\instrument, \sweep,
\freq, Pfunc({ rrand(0.8, 1.3) }) * freq.value,
\dur, 0.3,
\legato, 1.3,
\n, 5
)
});
)
// the pattern that is found in Pdef.all (or your own defined library) is truncated in time
// using the sustain provided by the outer pattern.
(
Pbind(
\type, \phrase, // phrase event from global library
\instrument, \sweep,
\n, 15,
\degree, Pseq([0, 4, 6, 3], inf),
\sustain, Pseq([1.3, 0.2, 0.4],inf)
).play
)
// multichannel expansion is propagated into the subpatterns
(
Pbind(
\type, \phrase, // phrase event from global library
\instrument, \sweep,
\n, 15,
\degree, Pseq([0, 0, 6, 3], inf) + Prand([0, [0, 3], [0, 5], [0, 15]], inf),
\ratio, Prand([ 0.1, 0.1, [0.1, -0.1] ], inf)
).play
)
// various instruments and synthdefs can be used on the same level
(
Pbind(
\type, \phrase,
\instrument, Pseq([\sweep, \default, \sweep2, \sweep3, \pgrain, \pgrain], inf),
\degree, Pseq([0, 3, 2], inf),
\dur, Pseq([1, 0.5], inf) * 0.7,
\n, Pseq([4, 6, 25, 10], inf),
\ratio, Prand([0.03, 0.1, 0.4, -0.1],inf) + Pseq([0, 0, [0, 0.02]], inf),
\legato, Pseq(#[0.5, 1, 0.5, 0.1, 0.1],inf)
).play;
)
//////// of course also a patten can be used directly in a Pdef
(
Pdef(\sweep,
Pbind(
\instrument, Pseq([\pgrain, \noiseGrain],inf),
\dur, Pseq([1, 2, 1, 3, 1, 4, 1, 5]) * 0.05,
\legato, Prand([0.5, 0.5, 3],inf)
)
)
)
// play directly, emebdded in stream (see Pdef.help)
Pn(Pdef(\sweep), 2).play;
Pdef(\sweep).fork; // play without changing player state (see Pdef.help)
// play within a pattern
(
Pbind(
\type, \phrase,
\instrument, \sweep,
\degree, Pseq([0, 1b, 4, 2, 3, 1b], inf),
\pan, Pfunc(#{ 1.0.rand2 })
).play
)
//////// recursion examples //////////
// the given pattern can be recursively applied to itself
// resulting in selfsimilar sound structures, like lindenmeyer systems (see also Prewrite)
// special care is taken so that no infinite loops can happen.
// just like with non recursive phrasing, new values override old values,
// any values that are not provided within the pattern definition
// are passed in from the outer event.
(
Pdef(\sweep, { arg dur=1, n=4, freq=440, ratio=0.3;
Pbind(
\instrument, \pgrain,
\dur, dur.value / n, // now dur is dependant on outer dur.
\freq, Pseries(1, 1, inf) * ratio + 1 * freq.value % 17000
)
});
)
// no recursion
(
Pbind(
\type, \phrase,
\instrument, \sweep,
\degree, Pseq((0..5),inf)
).play;
)
// no recursion, with legato > 1.0 and varying notes
// note how subpatterns are truncated to note length
// provided by outer pattern (in this case determined by legato)
(
Pbind(
\type, \phrase,
\instrument, \sweep,
\degree, Pseq((0..5),inf),
\legato, Pseq([1.2, 2.8, 0.3], inf)
).play;
)
// to block the proliferation of \legato into the phrase, set \transparency to 0
(
Pbind(
\type, \phrase,
\instrument, \sweep,
\transparency, 0,
\degree, Pseq((0..5),inf),
\legato, Pseq([1.2, 2.8, 0.3], inf)
).play;
)
// recursion over one level
(
Pbind(
\type, \phrase,
\instrument, \sweep,
\degree, Pseq([0, 1, 2, 3], inf),
\recursionLevel, 1
).play
)
// recursion over one level: legato is recursively applied
(
Pbind(
\type, \phrase,
\instrument, \sweep,
\degree, Pseq([0, 1, 2, 3], inf),
\legato, Pseq([0.5, 1, 1.5, 1.8], inf),
\recursionLevel, 1
).play
)
// to block the proliferation of properties such as \legato and \degree
// into the phrase, set \transparency to 0.
(
Pbind(
\type, \phrase,
\instrument, \sweep,
\degree, Pseq([0, 1, 2, 3], inf),
\legato, Pseq([0.5, 1, 1.5, 1.8], inf),
\recursionLevel, 1,
\transparency, 0
).play
)
// recursion over 3 levels: legato is recursively applied
(
Pbind(
\type, \phrase,
\instrument, \sweep,
\degree, 1,
\legato, Pseq([0.5, 1, 1.3], inf),
\recursionLevel, 3,
\n, 3
).play
)
// to block the proliferation of \legato into the phrase, set \transparency to a level at which
// to stop passing the value.
(
Pbind(
\type, \phrase,
\instrument, \sweep,
\degree, 1,
\legato, Pseq([0.5, 1, 2.3], inf),
\recursionLevel, 3,
\n, 3,
\transparency, Pstutter(8, Prand([0, 1, 2], inf))
).play
)
// to modify this recursion, assign values explicitly:
(
Pdef(\sweep, { arg dur=1, n=4, ratio=0.5, freq=440;
var legato;
freq = freq.value;
legato = freq % 200 / 200 * 3 + 0.2;
Pbind(
\instrument, \pgrain,
\dur, dur.value / n,
\legato, legato,
\freq, Pseq((1..n) * ratio + 1 * freq)
)
});
)
// recursion over one level: degree is assigned to each phrase,
// because freq is calculated internally and overrides degree on the second level
(
Pbind(
\type, \phrase,
\instrument, \sweep,
\degree, Pseq((0..10),inf),
\recursionLevel, 1
).play
)
// recursion over two levels
(
Pbind(
\type, \phrase,
\instrument, \sweep,
\degree, 0,
\recursionLevel, 2
).play
)
// recursion over three levels with variable number of grains
(
Pbind(
\type, \phrase,
\instrument, \sweep,
\degree, -5,
\n, Pseq([1, 2, 3],inf),
\recursionLevel, 3
).play
)
// "zoom" in
TempoClock.default.tempo = 0.2;
TempoClock.default.tempo = 1.0;
// recursion over variable levels
(
Pbind(
\type, \phrase,
\instrument, \sweep,
\n, Prand([2, 7, 3], inf),
\degree, -5,
\recursionLevel, Prand([0, 1, 2],inf)
).play
)
// replace the frequency based pattern with a degree based pattern
(
Pdef(\sweep, { arg sustain=1, n=8, degree=0, ratio=1;
Pbind(
\instrument, \pgrain,
\dur, sustain.value / n,
\degree, Pseq((1..n)) * ratio + 1 + degree.value
)
});
)
// drunken master
(
Pbind(
\type, \phrase,
\instrument, \sweep,
\n, Prand([2, 4, 3, 8], inf),
\degree, Pseq([-5, 0, -2], inf),
\legato, Pseq([1.4, 0.5, 2], inf),
\scale, #[0, 2, 5, 7, 10],
\recursionLevel, Prand([0, 1, 2],inf)
).play
)
(
Pbind(
\type, \phrase,
\instrument, \sweep,
\synthDef, Prand([\pgrain, \default, \noiseGrain],inf),
\n, Prand([2, 4, 3, 8], inf),
\degree, Pseq([-5, 0, -2], inf),
\recursionLevel, Prand([0, 1],inf)
).play
)
// use a different parent event in the inner pattern
(
e = Event.default;
e.use { ~sustain = { 2.0.exprand(0.05) } };
Pdef(\sweep, { arg sustain=1, n=8, degree=0, ratio=1;
Pbind(
\parent, e, // replace by some other event
\instrument, \pgrain,
\dur, sustain.value / n,
\degree, Pseq((1..n)) * ratio + 1 + degree.value
)
});
)
(
Pbind(
\type, \phrase,
\instrument, \sweep,
\n, Prand([2, 4, 3, 8], inf),
\degree, Pseq([-5, 0, -2], inf),
\recursionLevel, Prand([0, 1],inf)
).play
)
// pass in a pattern from outside
(
Pdef(\sweep, { arg sustain=1, n=8, degree=0, ratio=1;
n = n.value;
Pbind(
\instrument, \pgrain,
\dur, sustain.value / n,
\degree, Pseq([ 1, 2, 3, 4, 5 ] * ratio + 1 + degree.value) )
});
)
(
Pbind(
\type, \phrase,
\instrument, \sweep,
\n, { Pshuf([2, 4, 3, 8, 16, 32], inf) }, // use a function to insulate from embedInStream
\degree, Pseq([-5, 0, -2], inf),
\recursionLevel, Prand([0, 1],inf)
).play
)
// recursion inside the pattern definition
(
Pdef(\sweep2, { arg sustain=1, n=2, degree=0, ratio=1;
Pbind(
\type, \phrase,
\instrument, \sweep,
\dur, sustain.value / n,
\degree, Pseq((1..5).scramble * ratio + 1 + degree.value),
\recursionLevel, 2
)
});
)
(
Pbind(
\type, \phrase,
\instrument, \sweep2,
\n, 3,
\degree, Pseq([-5, 0, -2], inf)
).play
)
// instruments do not crossfade while they play (to make phrasing more efficient).
(
Pbind(
\type, \phrase,
\instrument, \sweep,
\n, 3,
\degree, Pseq([0, 2b, 3, 4], inf),
\dur, 2,
\legato, 2
).play
)
// change pattern definition while playing:
(
Pdef(\sweep,
Pbind(
\instrument, \pgrain,
\dur, exprand(0.01, 0.1),
\legato, rrand(0.01, 2.0),
\octave, rrand(5, 7)
)
)
)
// koch "snowflake"
(
Pdef(\koch, { arg dur=1, freq=440;
Pbind(
\dur, dur.value / 3,
\freq, freq.value * Pseq([1, 1.2, 1])
)
});
)
(
Pbind(
\type, \phrase,
\instrument, \koch,
\synthDef, \pgrain,
\dur, 9,
\recursionLevel, 2,
\legato, 1.1
).play
)
(
Pbind(
\type, \phrase,
\instrument, \koch,
\synthDef, \pgrain,
\dur, 9,
\recursionLevel, 4,
\legato, 1.1
).play
)
(
Pdef(\koch, { arg dur=1, degree=0;
Pbind(
\dur, dur.value / 3,
\degree, degree + Pseq([0, 2, 0])
)
});
)
// soundfile example
(
SynthDef(\play_from_to, { arg out, bufnum, from=0.0, to=1.0, sustain=1.0;
var env;
env = EnvGen.ar(Env.linen(0.01, sustain, 0.01), 1, doneAction:2);
Out.ar(out,
BufRd.ar(1, bufnum,
Line.ar(from, to, sustain) * BufFrames.kr(bufnum)
) * env
)
}).store;
)
s.sendMsg("/b_allocRead", 170, "sounds/a11wlk01.wav");
(
Pdef(\poch, { arg sustain=1.0, from=0.0, to=1.0, n=3;
var step;
sustain = sustain.value;
step = (to - from) / n;
Pbind(
\instrument, \play_from_to,
\from, Pseries(from, step, n),
\to, Pseries(from, step, n) + step,
\legato, 1.0,
\dur, sustain / n
)
})
)
// this plays it straight
(
Pbind(
\type, \phrase,
\instrument, \poch,
\recursionLevel, 3,
\from, 0,
\to, 1,
\dur, 3,
\bufnum, 170
).play
)
// now turn round every middle part of every middle part
(
Pdef(\poch, { arg sustain=1.0, from=0.0, to=1.0, n=3;
var step, f, t, i;
sustain = sustain.value;
step = (to - from) / n;
f = Array.series(n, from, step) +.t [0.0, step];
i = n div: 2;
f[i] = f[i].reverse;
Pbind(
\instrument, \play_from_to,
[\from, \to], Pseq(f),
\legato, 1.0,
\dur, sustain / n
)
})
)
// varying recursion
(
Pbind(
\type, \phrase,
\instrument, \poch,
\recursionLevel, Prand([0, 1, 2, 3], inf),
\from, 0,
\to, Prand([-1, 1], inf),
\dur, 3,
\n, Prand([1, 2, 3], inf),
\bufnum, 170,
\amp, 0.2
).play
)