This is not actually a totally awful way of doing this - there is a LOT of subtlety to how Pdef
incorporates changes to a playing pattern (e.g. using quant
to change on beat, etc) - if you want a sort of Ableton Live style hot swapping of patterns, this is a straightforward way to take advantage of all that subtle playback stuff. The code is simple and comprehensible, and does what it looks like it does, which is never bad.
However, there are many other ways to do this as well - here are some suggestions, maybe one of these is a better fit for your workflow. I had to modify your patterns slightly in some cases, because a few things (e.g. a series with a pattern as it’s length
parameter) are tricky and would confused the example
[1] Pull parameters from Pdefn’s
This is nice b/c you can then use patterns in place of fixed values for each Pdef, which becomes compositionally very powerful - and you can set individual quant
values for each parameter, which is cool.
(
Pdefn(\steps, 8);
Pdefn(\beats, 3);
Pdefn(\offset, 0);
Pdefn(\size, 4);
Pdefn(\grow, 1);
)
(
Pdef(\bass, Pmono(
\default,
\dur, Pbjorklund2(
Pdefn(\beats),
Pdefn(\steps),
) * 1 / Pdefn(\steps),
\degree, Pfin(
Pdefn(\beats),
Pseries(0, Pdefn(\steps), 4).repeat
),
\scale, Scale.dorian,
).trace).play;
)
[2] Compose with another event stream
Similar to [1], but stick all your params in one event stream and access via Pkey. This is better if you want a parameter to change to be applied “all at once”, and (for me) the code is a little clearer.
(
Pdef(\params, Pbind(
\steps, 8,
\beats, 3,
\offset, 0,
\size, 4,
\grow, 1,
))
)
(
Pdef(\bass).clear;
Pdef(\bass, Pmono(
\default,
\dur, Pbjorklund2(
Pkey(\beats).trace,
Pkey(\steps),
) * 1 / Pkey(\steps),
\degree, Pseries(0, Pkey(\steps), 4).repeat,
\scale, Scale.dorian,
) <> Pdef(\params)).play;
)
[3] Use a function in your Pdef
Some of your original code is hard to reproduce entirely with patterns (e.g. some parameters expect numbers and not streams), so “building” the entire thing in a function is still easier. Pdefs with a function will pull that functions arguments from whatever the incoming event is, so you can compose it with Pdef(\params)
(as in [2]) to fill them in.
Some notes:
-
the function is only called when the pattern inside it has run out of events - if it’s repeating infinitely, it won’t ever reset. This can be an advantage because it means you have coherent phrases, and parameters won’t be changed until the end of the phrase… So basically, make your inner Pdef pattern finite, and then if you want to repeat it, repeat it where you use it (with repeat
, cyc
, Pn
etc)
-
I changed beats
to numBeats
- I think the beats
key has special meaning and can get obliterated in some cases? I didn’t track down exactly where…
-
I composed \bass
into a Pmono
- if the Pmono
is inside of the function, then your note basically gets reset every time that function is called (a new Pmono is created) - this may be desirable behavior, or maybe not…
-
There’s nice thing I do sometimes where you can wrap the pattern in \bass
in a Pfindur
, which means it will play an exact amount of time, and then finish - then, you can do really complex poly-rhythm stuff, but the pattern and it’s parameters are always reset at at predictable metric, so it doesn’t turn into algorithmic soup.
-
You can use events of type: phrase
to do almost exactly what I’m doing in this example. This gives you some nice things “for free”, but is also less flexible and less obvious - look at the help for recursive phrasing for more info.
(
Pdef(\params,
Pbind(
\steps, 8,
\numBeats, 3,
\offset, 0,
\size, 4,
\grow, 1,
)
)
(
Pdef(\bass, {
|steps=8, numBeats=3, offset=0, size=4, grow=1|
[steps, numBeats, offset, size, grow].postln;
Pbind(
\dur, Pbjorklund2(numBeats, steps, offset: offset) * 1 / steps,
\degree, Pfin(numBeats, Pseq(Array.series(size, 0, grow)), inf).repeat(4),
\scale, Scale.dorian,
)
}
);
Pdef(\player, Pmono(\default) <> (Pdef(\bass) <> Pdef(\params)).cyc).play;
)