Stopping an EventStreamPlayer does not free any of the Synths that have already been created by it. It only stops the process of creating new Synths. Your ‘dur’ value is 100, which means each Synth produced by the EventStreamPlayer will be released 100 beats after it was created. If you want to fade these Synths earlier, one option is to do it manually:
It’s creating one new group at the time of creating the pattern object, and hard coding a reference to that one group into the pattern. Every event produced by that Pbind will keep a reference to the single group.
Similarly:
// hardcode the result of an operation into the pattern
p = Pbind(
\a, rrand(1, 10)
).asStream;
p.next(());
-> ( 'a': 4 )
p.next(());
-> ( 'a': 4 ) // well that doesn't seem very random
// the pattern includes a reference to the operation itself
// instead of the operation's result
p = Pbind(
\a, Pfunc { rrand(1, 10) }
).asStream;
p.next(());
-> ( 'a': 5 )
p.next(());
-> ( 'a': 2 )
The first case computes the result ofrrand and puts this result into the definition of the Pbind. The second one includes the operation, but not its result, in the Pbind – so the resulting events get different numbers every time.
Note also that if you plan to have a new group per Event, then the SynthDef(s) should use doneAction: Done.freeGroup. Otherwise empty groups will leak on the server.
SynthDef(\sinblip, { |out, freq = 440, amp = 0.1|
var eg = EnvGen.kr(Env.perc(0.01, 0.1), doneAction: Done.freeGroup);
Out.ar(out, (SinOsc.ar(freq) * eg * amp).dup);
}).add;
p = Pbind(
\instrument, \sinblip,
\group, Pfunc { Group.new },
\freq, Pexprand(200, 800, inf),
\dur, 0.125
).play;
// 3 or 4 groups active at any time
p.stop; // back down to 2 groups
FWIW, it’s simple to free the Synth when the stream player is stopped. When .stop is called, all cleanup actions for all events are called immediately, so all you need to do is free your Synth as a cleanup action (via the \addToCleanup key).
Q: Why do I set the \addToCleanup key in the \callback function? A: Because \callback is called after the event is played - at this point, the Event knows about any running Synths on the server, so you can call Event:free. The event is passed in as the first arg to callback - we NEED this finished Event to call free on it.