I thought that only Pproto has this bug, but it’s more widespread:
p = Pfset({}, Pbind(\dur, Pseq([1], 1)), { "cute!".postln })
p.play // cute!
p = Pbind() <> Pfset({}, Pbind(\dur, Pseq([1], 1)), { "cute!".postln })
p.play // two times cute!
p = Pbind() <> Pbind() <> Pfset({}, Pbind(\dur, Pseq([1], 1)), { "cute!".postln })
p.play // not thrice though!
The architecture of the EventStreamCleanup seems rather troubled. Basically an EventStreamCleanup instance keeps a local copy of the cleanups in its functions
array and also “sends a copy downstream”, or more precisely copies individual cleanup messages into an Event-serialized form (\addToCleanup
), so that a downstream consumers (with the EventStreamPlayer
typically being the final consumer) can also keep copies.
Consequently there are lotsa copies of cleanups in a stream chain under some conditions. (Pchain always keeps a local copy for instance because any of its sub-streams can decide to call it quits.) The problem with this design is that any Pattern can introduce downstream-transmission (obviously) and cleanup-execution bugs.
Basically, methinks a cleanup generated once should not be executed several times. But because a lot of streams keep copies, this can happen if one is not careful with the “sharing of responsibilities” when Patterns classes are written.
Since EventStreamCleanup is in such widespread use throughout the Pattern library, I think it would be quite hard to fix the conceptual problem by “rewiring” the whole library to a less duplicative design (e.g. a only a per-player cleanup list with no local copies kept in stream nodes).
So are there some good suggestions of how to do a minimal fix on the present design so that “double frees” are not so easily made?