610 lines
12 KiB
Text
610 lines
12 KiB
Text
|
#lang scribble/manual
|
||
|
@(require (for-label racket))
|
||
|
|
||
|
@title{recursive_phrasing}
|
||
|
Recursive phrases and granular composite sounds@section{categories}
|
||
|
Libraries>JITLib>Tutorials
|
||
|
@section{related}
|
||
|
Overviews/JITLib, Classes/Pdef, Classes/PlazyEnvirN
|
||
|
|
||
|
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 emphasis::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
|
||
|
@racketblock[\phrase:: is passed in, the event looks for a pattern in ]
|
||
|
|
||
|
@racketblock[Pdef.all:: if it can find a definition.
|
||
|
]
|
||
|
@section{list}
|
||
|
|
||
|
## if it finds one it plays this pattern in the context of the outer pattern's event.
|
||
|
## f there is no definition to be found there, it uses a link::Classes/SynthDef:: with this name, if present.
|
||
|
::
|
||
|
|
||
|
When passing a emphasis::function:: to Pdef it creates a PlazyEnvirN internally. Its function is evaluated in the context of the input event (see link::Classes/PlazyEnvirN::) which should return a pattern or a stream. Note that this doesn't allow the usual access of the outer environment from within the function.
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
(
|
||
|
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: Done.freeSelf)
|
||
|
)
|
||
|
}
|
||
|
).add;
|
||
|
|
||
|
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: Done.freeSelf)
|
||
|
)
|
||
|
}
|
||
|
).add;
|
||
|
|
||
|
|
||
|
|
||
|
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, embedded 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: Done.freeSelf);
|
||
|
Out.ar(out,
|
||
|
BufRd.ar(1, bufnum,
|
||
|
Line.ar(from, to, sustain) * BufFrames.kr(bufnum)
|
||
|
) * env
|
||
|
)
|
||
|
|
||
|
|
||
|
}).add;
|
||
|
)
|
||
|
|
||
|
b = Buffer.read(s, Platform.resourceDir +/+ "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, b
|
||
|
).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, b,
|
||
|
\amp, 0.2
|
||
|
).play
|
||
|
)
|
||
|
::
|
||
|
]
|
||
|
|
||
|
|