Indeed. But for Pdef.envir, luckily it’s an exposed object so creating “shortcuts” for setting those is a easy as assigning the envir to some var etc.
d = Pdef(\pah).envir
d.dur = 0.2
And likewise for gui-ing stuff by Pdef name, e.g. I have a helper (much stripped down here):
// normally part of a bigger gui
~tb2 = TabbedView2.new().resize_(5);
// "gui envir" method
(~ge = { |pdefname, numlines=10| var tabv = ~tb2.add(pdefname);
ParamGui(Pdef(pdefname).envir, numlines, tabv, tabv.bounds.origin_(0@0)) })
~ge.(\pah)
// in fact I have a Symbol method extension so I just do
\pah.ge
(The fact that you have to recompile the classlib for something as trivial as the last line is quite annoying in my opinion! Maybe Symbol at least should have some kind of custom runtime-registration of “extensions” like Event does.)
Also, I sometime (ab)use the envir
for (short!) functions. The event system auto-evaluates quite a few things as functions few so e.g. the following “just works”
Pdef(\meh, Pbind()).play.set(\dur, 0.2)
// then, e.g. (this is fully editable as cs in gui)
Pdef(\meh).set(\degree, { rrand(1,8) })
// also streams, but these don't gui well at all
Pdef(\meh).set(\degree, (1..8).iter.repeat)
// oh noes, there's stream-pattern code in my "pure data"
Pdef(\meh).set(\degree, Pseq((8..1), inf).iter)
Alas it’s not possible two switch from a number to a function in the present EnvirGui itself, but it works the other way around when you type a number in a cs-text field, albeit the spec gets weird sometimes. You need send an explicit signal to the right ParamView to change view type to cs-text if there’s simple number it it.
There are some gotchas when using this hack if values are used as inputs in other patterns, but surprisingly everything that gets sent as a synth arg as functions gets evaluated. It’s a bit obscure how that works but basically everything sent to the server as synth args gets asControlInput
called on it and for the whole class tree of AbstractFunctions that does value
e.g.:
{3}.asControlInput // -> 3
(degree: {rrand(1,8)}, dur: 0.2).play // hit a few times
The last line actually makes 'freq': a BinaryOpFunction
because it plugs the degree
function we gave into a formula, but eventually it gets resolved ok, at least in this case, when there are no arguments passed to the function. For args that get sent more directly to the server (i.e. synth controls with uncommon names) there are fewer gotchas.
But yeah, there’s an asymmetry here between Pdef.envir
where you can at best have stream/routines and Pder.source
which can have patterns. Although you can define some simple helper that turns patterns into streams upon insertion, I don’t quite see the point since you can also do
Pdef(\duh, Pbind()).play.set(\dur, 0.2)
Pdef(\before, Pbind(\degree, Pfunc { rrand(1,8) }))
Pdef(\duh, Pdef(\duh).source <> Pdef(\before))
It works because the chain is now
Pdef(\duh).source <> Pdef(\before).source <> Pdef(\duh).envir
Doing this will stop play though if \before is no bound to something.
And of course, I can spiffy Pdef(\before) so it reads its random interval endpoints from some keys, which can be set in its own envir. This is where having a tabbed gui of envirs helps…
Pdef(\before).set(\degLo, 4, \degHi, 16)
~ge.(\before)
Pdef(\before, Pbind(\degree, Pwhite(Pkey(\degLo), Pkey(\degHi))))
The chain is now
Pdef(\duh).source <> Pdef(\before).source <> Pdef(\before).envir <> Pdef(\duh).envir
Although it’s still a bit clunky compared to what an ideal “merged” interface would be. But one has to decide how much clutter wants into a single list of params… If want to move the new params (degLo & degHi) to the latter, e.g. they are important enough I don’t want them on a separate tab, I can do e.g. “move over”
Pdef(\duh).envir.putAll(Pdef(\before).envir)
To make the envir/sliders in \duh effective, those in \before’s envir need to be gone. Its “Pbind code” (Pdef.source) can read/receive them from Pdef(\duh).envir now.
Pdef(\before).envir.clear
If you just do Pdef(\before).envir = () that will work sound-wise, but the gui gets stuck with the old object not part of the sound chain anymore, which can definitely be confusing.
Side note: when you clear a Pdef (with Pdef(\bah).clear
), its envir
is not actually cleared; you need to do that separately.