Skip idle voice pools per block — fix playback dropouts (v0.4.6)
fillBlock rendered EVERY pooled voice every sample: 32+32 sequencer + 32+32 bus-audition + 16 live/audition voices, render() called ~144× per frame × 96 frames per callback — even at idle. The bus-audition pool (64 voices) is only used by the Toolbox MIDI piano yet ran every sample during normal playback. This fixed cost, not active-voice count, dominated the render budget. Now the pools are scanned once per block into per-bus active flags, and the per-sample mix loop skips whole idle buses and the entire bus- audition pool when nothing is being auditioned. The sequencer sets the flag the instant it triggers a note mid-block, so newly-started notes still sound sample-accurately within the same block. On-device profiling (moto g84, 98% battery, real busy track, ~11 sample voices, 96-frame/2.0ms callback): before: avg 2.00 ms, xruns +250..+515 per ~500 callbacks (audible drops) after: avg 1.44 ms, xruns +0 (steady) Fast-tapping the audition keyboard during playback: avg 1.1-1.4 ms, xruns +0, voices peaked at 16 then drained cleanly — no stuck notes. With this, under-load render time equals idle, so voice rendering is no longer the bottleneck; the remaining ~1.4 ms is fixed JNI + per-channel FX overhead. A block-based per-voice refactor was evaluated and dropped as unnecessary (it would not reduce that fixed cost). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -22,8 +22,8 @@ android {
|
||||
// (android.media.midi) and AAudio low-latency audio we rely on.
|
||||
minSdk = 26
|
||||
targetSdk = 34
|
||||
versionCode = 12
|
||||
versionName = "0.4.5"
|
||||
versionCode = 13
|
||||
versionName = "0.4.6"
|
||||
|
||||
// We provide our own instrumentation runner if/when tests are added.
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
Reference in New Issue
Block a user