I’m trying to trigger some action when a pattern has finished. In my example: stop a 2nd pattern from running and playing:
(
x=Pbind(\dur,Pwhite(3,5),\freq,Pn(440,4));
y=Pbind(\dur,Pwhite(1,5),\degree,Prand(Scale.minor.degrees,inf));
x.play;
y.play;
)
when x has finished, I’d like to stop y and release any synth running from that pattern.
Is there a way to attach some kind of “onEnded” function to the x pattern similar on the onFree of the Synth object ?
Today, I’m able to stop any running Synth but not the pattern:
(
~last=nil;
x=
Pseq(
[Pbind(\dur,Pwhite(3,5),\freq,Pn(440,4)),
Pbind(\type,\off,\id,Pfunc({~last['id'][0]})) // <-- Add an extra Step to release the last Synth played under y.
]
);
y=Pmono(\default,\dur,Pwhite(1,5),\degree,Prand(Scale.minor.degrees,inf));
x.play;
y.collect({|event| ~last=event; }).play; // <-- remember the last played event, hence the last played Synth
)
1 Like
I still haven’t found a real “onEnded” for patterns, but I’ve got kind of a solution:
(
~last=nil;
~stream2=nil;
x=Pseq(
[Pbind(\dur,2,\freq,Pn(220,2)),
Pbind(\type,\off,\id,Pfunc({~stream2.stop;~last['id'][0]}) // <-- release last synth and stop the pattern
,\dummy,Pn(1,1)) // <-- to have this Pbind running only once
]
);
//y=Pmono(\default,
y=Pbind(
\dur,3,\degree,Prand(Scale.minor.degrees,inf));
x.play;
~stream2=y.collect({|event| ~last=event; }).play;
)
But if someone has more info or another approach for a ´´´pattern.onEnded´´´ I’m still interested…
This is possible, but admittedly well-nigh impossible to figure out only from the documentation.
When you play a pattern, you get an EventStreamPlayer – this is the object scheduled on the clock, which gets events from the stream and plays them.
So, point #1 – it’s impossible to have ‘onEnded’ for patterns. Patterns define behavior, but don’t execute it. Only the “pattern performer” can end – so the responder would have to be installed on the performer instead.
Then… EventStreamPlayer is a subclass of PauseStream. PauseStreams (including Task) use dependent notifications to communicate their state. This is documented briefly in the Task help file, but without an example.
So…
(
// you can't do any of what you're asking about
// without variable references to the players!
var xPlayer, yPlayer;
var updater;
x = Pbind(\dur, Pwhite(3, 5), \freq, Pn(440, 4));
y = Pbind(\dur, Pwhite(1, 5), \degree, Prand(Scale.minor.degrees, inf));
xPlayer = x.play;
yPlayer = y.play;
updater = SimpleController(xPlayer)
.put(\stopped, {
updater.remove;
yPlayer.stop;
});
)
hjh
3 Likes
Or, another way (probably easier):
(
var yPlayer;
x = Pbind(\dur, Pwhite(3, 5), \freq, Pn(440, 4));
y = Pbind(\dur, Pwhite(1, 5), \degree, Prand(Scale.minor.degrees, inf));
x = Pfset(pattern: x, cleanupFunc: { yPlayer.stop });
x.stretch(0.2).play;
yPlayer = y.stretch(0.2).play;
)
And with early note release for y:
(
var yPlayer;
var yGroup = Group.new;
x = Pbind(\dur, Pwhite(3, 5), \freq, Pn(440, 4));
y = Pbind(\dur, Pwhite(1, 5), \degree, Prand(Scale.minor.degrees, inf));
x = Pfset(pattern: x, cleanupFunc: {
yPlayer.stop;
yGroup.set(\gate, 0); // release synths
{ yGroup.free }.defer(0.5); // depends on synth release time
});
y = Pbindf(y, \group, yGroup);
x.stretch(0.2).play;
yPlayer = y.stretch(0.2).play;
)
hjh
2 Likes