Optimization B, superseding v0.4.6's per-bus skip. Instead of iterating each active bus's whole POLYPHONY pool per sample (calling render() on idle slots, which merely early-out), fillBlock now builds compact lists of the voices that are actually sounding — once per block — and the per-sample mix loop touches only those. Correctness for mid-block starts: the sequencer can trigger a note part way through a block, so the allocators queue the chosen voice into this block's list (queueSeq/queueSmp), keeping note timing sample-accurate. A per-voice generation stamp dedups the append so a voice that finishes and is re-allocated within one block is never rendered twice (which would double its amplitude). Live/bus-audition voices are snapshotted at block start (a manual press mid-block sounds at the next block, ≤2 ms later — imperceptible, and the pre-existing ~30 ms output buffer dwarfs it). On-device (moto g84, 98% battery, real busy track, ~13 voices, 2.0 ms budget), avg render callback: baseline 2.00 ms (xruns +250..+515) → A 1.44 ms (+0) → B ~1.00 ms (+0) B removes ~51 inactive-slot render() calls per sample; ART's virtual dispatch makes each ~90 ns, so this is a real ~30% gain over A (not the ~1% first estimated from the sample track — measurement corrected it). Fast-tapping audition during playback stays ~1.0-1.3 ms, xruns +0, voices drain cleanly (no stuck notes, no double-render). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
5.0 KiB
5.0 KiB