I cleaned up and added comments to some recent code if anyone is interested - this is a more complex version of this design pattern where patterns in individual keys (in this case, \degree
, \octave
, and \lpf
) only pull new values when a downstream pattern signals them to via a \stepOctave
key.
In this case, the patterns for individual keys can be de-synchronized. It’s a little easier to do this by using something like Pstutter
- BUT stutter requires a fixed number of repetitions, which is a bit less flexible. For example, \step2
pulls the \lpf
parameter randomly based on Prand
.
Code
(
// A dumb pluck synth
SynthDef(\ring, {
var in, trig, freq, sig, env, trigEnv;
trig = \trig.tr(0);
freq = \freq.kr(220).lag3(0.02);
env = Env.adsr.kr(gate:\gate.kr(1), doneAction:2);
trigEnv = Env.perc(0, 0.2, curve:\exp).ar(gate:trig);
trig = Trig.ar(trig, SampleDur.ir);
in = LFSaw.ar(freq * 3.015);
in = in + WhiteNoise.ar(0.2);
in = BLowPass4.ar(
in,
\lpf.kr(100),
0.3
);
sig = Pluck.ar(
in, trig,
0.2,
freq.reciprocal,
8,
\coef.kr(0.7)
);
// sig = (sig * 4).tanh;
sig = sig - FreqShift.ar(
sig, freq / (-2.015)
// sig, freq / trigEnv.linlin(0, 1, -2.015, -1.8)
);
sig = LeakDC.ar(sig);
sig = env * sig;
sig = Pan2.ar(sig, \pan.kr(0), \amp.kr(1));
Out.ar(\out.kr(0), sig)
}).add;
// Some simple parameter patterns
Pdefn(\octave, Pseq([3, 4, 3, 6, 5], inf));
Pdefn(\degree, Pseq([0, 4, 2, 9, -2], inf));
Pdefn(\lpf, Pexprand(80, 19000));
Pdefn(\dur, {
Pseq([1]) ++ Pgeom(
2/4,
rrand(0.81, 0.84),
[12, 16, 32, 64].choose
)
});
// alt version, more controlled durations
// Pdefn(\dur, {
// (
// Pseq([1])
// ++ Pgeom(
// 1/4,
// 1 + rrand(-0.001, 0.001),
// [12, 16, 32, 64].choose
// )
// )
// });
// Combine our param patterns and Pclutch them with restart keys
Pdef(\ringMono, Pmono(
\ring,
\amp, 0.02,
\dur, Pdefn(\dur).repeat,
\scale, Scale.partch_o6,
\octave, Pclutch(Pdefn(\octave), Pkey(\stepOctave)),
\degree, Pclutch(Pdefn(\degree), Pkey(\stepDegree)),
\lpf, Pclutch(Pdefn(\lpf), Pkey(\stepLpf)),
));
// One true and count-1 falses
Pdefn(\stepper, Plazy({
|count|
Pseq([true]) ++ Pseq([false], count - 1)
}).repeat);
// Different reset patterns for each parameter - these will be passed to the Pclutch
// of each of these streams.
Pdef(\step1, Pbind(
\stepOctave, Pdefn(\stepper) <> Prand([24, 16], inf),
\stepDegree, Pdefn(\stepper) <> Prand([3, 6, 9], inf),
\stepLpf, Pdefn(\stepper) <> Pwhite(8, 15),
));
Pdef(\step2, Pbind(
\stepOctave, Pdefn(\stepper) <> 8,
\stepDegree, Pdefn(\stepper) <> 6,
\stepLpf, Prand([true, false, false], inf),
));
Pdef(\stepSlow, Pbind(
\stepOctave, Pdefn(\stepper) <> 64,
\stepDegree, Pdefn(\stepper) <> 64,
\stepLpf, Pdefn(\stepper) <> 64,
));
// Compose our patterns above, \ringMono and a step pattern,
// and four streams running in parallel panned.
// Vary some of the parameters (coef and freq) over time.
Pdef(\player,
Ppar(
4.collect {
|i|
Pbind(
\pan, i.linlin(0, 3, -1.0, 1.0)
)
<> Pdef(\ringMono)
<> Pdef(\stepSlow) // <-- try different restart patterns
}
)
// .finDur(6).repeat // <-- reset everything every 6 beats
<> Pbind(
\coef, Pseg([0.9, 0.4, 0.9], [16, 16], \exp).repeat,
\freq, Pkey(\freq) * Ptuple([
1,
Pseg([1, 1.03, 1], [16, 16], \exp).repeat
])
)
).play
)