TLDR: this might be the wrong way to go about things but I think I need something like
var sig = PlayBuf.ar(2, bufnum),
doneTrig = Done.kr(sig);
// somehow call buf.free() + output diagnostics when Done fires
Longer version:
I am playing a large number of samples (thousands, too much to fit in RAM at once) for a durational installation. My basic setup with a Routine/SystemClock works, but after a while I run out of bufnums. I’ve discovered that this is because PlayBuf’s doneAction: freeSelf doesn’t free the Buffer, only the synth, presumably because normally you’d want to keep buffers cached for next playback.
with a simple synth I can do what I want fairly easily:
Buffer.read(s, path, 0, -1, { |buf|
("playing buffer " + buf.bufnum).postln;
{ PlayBuf.ar(2, buf, 1.0, doneAction: Done.freeSelf) }.play.onFree({
("freeing buffer " + buf.bufnum).postln;
buf.free;
});
})
However, in a more complex patch I can’t call whenFree
on the whole thing because only the PlayBuf node gets freed, not the subsequent ones (GVerb, Splay, etc). I don’t want to free the whole chain, because I want reverb tails to remain, etc. I also can’t call whenFree
on PlayBuf itself because it isn’t actually a Node yet (not playing), as far as I understand.
The closest thing I can see is the suggestion from here: Msg from Server upon PlayBuf completion?
a = { |bufnum|
var sig = PlayBuf.ar(2, bufnum),
doneTrig = Done.kr(sig);
// [0]: little trick, doneTrig is actually 2 channels; only need 1
// if it's mono, leave out '[0]'
SendReply.kr(doneTrig[0], '/sampleDone', [bufnum]);
FreeSelf.kr(doneTrig);
sig
}.play(args: [bufnum: b]);
this sends a reply when Done happens on sig, all I want to do instead is to run a block that says buf.free
with the correct buffer reference retained, which is probably not possible with messages like this
so:
(1) is there a way to run a Function from a Done?
(2) is there a much simpler way of doing this? it feels a bit too roundabout to achieve something that should be relatively commonplace (freeing buffers)