Skip to content

perf: stabilize audio engine for infinite-loop playback#5902

Open
7se7en72025 wants to merge 4 commits intosugarlabs:masterfrom
7se7en72025:perf/stabilize-infinite-playback-engine
Open

perf: stabilize audio engine for infinite-loop playback#5902
7se7en72025 wants to merge 4 commits intosugarlabs:masterfrom
7se7en72025:perf/stabilize-infinite-playback-engine

Conversation

@7se7en72025
Copy link
Contributor

Summary

This PR resolves four compounding audio engine bottlenecks that resulted in
progressive crackling, main thread stalls, and eventual crashes during long or infinite Music Blocks sessions.

Changes

js/utils/synthutils.js

  • POLYCOUNT 3 → 6: The polyphony limit of 3 voices was saturated
    instantly by two turtles playing chords, resulting in silent voice
    stealing and missing notes.
  • _performNotes fast-path guard: paramsEffects is always a
    non-null object (always contains doPartials: true), so the existing
    paramsEffects === null fast-path was never taken. Every plain note
    re-wired the Web Audio graph via disconnect()/chain(). The fix
    checks whether any real effect nodes are needed; if not, in-place
    mutations are applied and triggerAttackRelease is called directly.
  • +500 ms disposal buffer: Effect nodes were disposed at exactly
    beatValue * 1000 ms, coinciding with the note end. Any audio-clock
    jitter caused premature disposal (crackling). A 500 ms buffer absorbs drift.

js/turtle-singer.js

  • Unhighlight timer deduplication: A new setTimeout for
    unhighlight(blk) was spawned on every note regardless of whether a
    previous one was still pending. In tight loops this accumulates
    thousands of stale timers and stalls the main thread. A
    _unhighlightTimers map now cancels the previous timer before
    setting a new one.## Testing
  • No regressions found on basic note playback, effects (vibrato, chorus, tremolo), and drum patterns.
  • Infinite "forever" loop with 4 turtles: did not crash after prolonged execution.

Criticality Scores (pre-fix)

Issue Score
Rewiring audio graph per note 9/10
Polyphony exhaustion (POLYCOUNT=3) 8/10
GC thrashing / premature garbage collection 8/10
Timer queue flood (unhighlight) 7/10

@github-actions
Copy link
Contributor

✅ All Jest tests passed! This PR is ready to merge.

@github-actions
Copy link
Contributor

✅ All Jest tests passed! This PR is ready to merge.

@7se7en72025 7se7en72025 force-pushed the perf/stabilize-infinite-playback-engine branch from cfb8dce to e82616d Compare February 25, 2026 09:16
@github-actions
Copy link
Contributor

✅ All Jest tests passed! This PR is ready to merge.

@github-actions
Copy link
Contributor

❌ Some Jest tests failed. Please check the logs and fix the issues before merging.

Failed Tests:

synthutils.test.js
turtle-singer.test.js

Refactor unhighlight logic for note value blocks to ensure minimum highlight duration and prevent timer accumulation.
@github-actions
Copy link
Contributor

✅ All Jest tests passed! This PR is ready to merge.

@7se7en72025
Copy link
Contributor Author

Hi, @walterbender
this PR resolves audio crashes and buffer underruns for long/infinite playback:

synthutils.js: Increased POLYCOUNT from 3 to 6 to avoid voice starvation; introduced a fast path that bypasses audio graph rewiring for simple notes (the primary cause of underruns); introduced a 500 ms buffer for cleanup timers to avoid early synth garbage collection.
turtle-singer.js: Introduced timer deduplication (_unhighlightTimers) to cancel stale unhighlight timers in tight loops, preventing JS timer queue exhaustion. Together with upstream's MIN_HIGHLIGHT_DURATION_MS (400 ms), fast notes still yield a visible highlight.
All 117 test suites are passing. Rebased on the latest master.
Thanks for mainataining

Copy link
Contributor

@kartikktripathi kartikktripathi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@walterbender, approving. Changes are technically sound and improve stability under sustained/infinite playback without introducing regressions.
Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants