Here’s a wrapper-way to do almost this (i.e. group-based solution) for an existing Pbind without changing its source code… “Almost” because it kills the group rather than gate it out, I think:
(~gwrap = { |pat| Pproto(
{ ~newgroup = (type: \group).yield; },
Pset(\group, Pkey(\newgroup), pat))})
p = ~gwrap.(Pbind(\dur, inf)).trace.play
p.stop // stops it!
This simplified version works too:
~gwrap2 = { |pat| Pproto({ ~group = (type: \group).yield; }, pat); }
p = ~gwrap2.(Pbind(\dur, inf)).trace.play
p.stop // works too
It’s because the Pproto’s prototyped stuff gets passed to the event, but unlike the longer version it won’t override \group
if there’s already one in pat
. (I’m not sure in general if this is preferable or not.)
I can confirm that group is indeed killed, not released. There “magic” happens in the EventTypesWithCleanup
class, which has group: \kill
(Pproto does a lookup there to construct its default cleanup). Now I’m pondering if this can be changed to release…
Probably the selling point of this is that since it changes what stop does on the resulting ESP, it can be seamlessly combined with Pdef
s further upstream.
Pdef(\heh, ~gwrap2.(Pbind(\dur, inf)))
Pdef(\heh).play
Pdef(\heh).stop //works
Surprisingly (for me), this works too
p = ~gwrap.(Pfunc({ |ev| ev[\dur] = inf })).play
p.stop // works somehow
I was expecting that to fail because Pproto does this conversion internally
stream = Pfpar(pattern.asArray).asStream;
I’m not sure exactly what the limitations stemming from that are (I guess I’d better ask separately.)
Another issue that’s perhaps worth mentioning here is that Pgroup
is useless for this scenario, but at least it’s obvious why: it tries to schedule its group cleanup after all the events from the stream have finished so that clearly is a no-op with a dur: inf
event.