Skip to content

Mobile audio performance: crackle/late hits reported by HN users #2

Description

@stackdump

The blog post Petri Nets as a Music Sequencer hit Hacker News (discussion, 66 pts / 21 comments) and drove ~1.4k sessions in a week — roughly 60% of them on phones (nginx UA split: ~15.5k Android + ~13.2k iPhone requests vs ~18.6k desktop).

Several commenters reported broken audio: no sound at all, "disorienting delay" on kick hits, and triggers visibly firing at the wrong token position. These symptoms match mobile audio-thread underruns, not scheduler bugs — the worker tick loop + 80 ms lookahead architecture is sound. The DSP load is the problem:

Proposed fixes (ranked)

  1. Bypass idle master-chain FX. Every sample currently passes through PitchShift (phase vocoder!) → Distortion → BitCrusher → LP(-48 dB) → Phaser → HP(-48 dB) → Compressor plus Freeverb/FeedbackDelay buses even at wet: 0 (public/audio/tone-engine.js ~1338–1360). Tone's wet/dry crossfade still runs the effect DSP at wet 0. Disconnect and hard-wire around idle effects until a macro raises wet; take care the reconnect doesn't click mid-ramp.
  2. Set latencyHint: 'playback' on mobile. No latencyHint is set anywhere, so the context runs at interactive (~128-sample callbacks). This is a generative player, not a live instrument — playback buys 4–8× per-callback headroom at no perceptible cost. Companion change: raise LOOKAHEAD_MS (80 → ~150–200) on mobile (public/sequencer-worker.js, public/lib/backend/index.js).
  3. Mobile voice budget. maxPolyphony = 256 per PolySynth (~15 instrument defs, tone-engine.js ~1655) lets busy sections exceed what a phone's audio thread can render before the buffer deadline. Cap at 8–16 per instrument on mobile; the voice-recycle machinery from the oscillator-leak fix is there to build on.
  4. Throttle visuals on phones. SVG token/grid updates fire per worker message on the main thread; coalesce to rAF and skip offscreen nets under max-width: 720px.

Verification

Use the CDP profiling harness in ~/Workspace/beats-profile/ with Chrome CPU throttling (4–6×) to simulate a phone; success = no underruns/crackle through a full Auto-DJ cycle.

Not fixable here: bottom-tier Androids with 8 parallel synth tracks, and the iOS tap-to-start gesture requirement.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions