Skip to content

Fix x-runs on preset switch caused by IR loading on RT thread #213

@OpenSauce

Description

@OpenSauce

Context

Switching presets causes x-runs because the entire IR cabinet loading pipeline runs synchronously on the JACK real-time audio thread. The RT callback has a ~5ms deadline (256 samples @ 48kHz), but select_ir() performs disk I/O, WAV parsing, rubato resampling, silence trimming, and FFT convolver setup — totalling 100-250ms of blocking.

This is particularly noticeable when using a MIDI footswitch to change presets during performance.

Currently the GUI sends an IR name to the engine via crossbeam channel, and the engine does all the heavy work inside handle_messages() on the audio thread (engine.rs). Loading all IRs into memory at startup was tried previously but made startup noticeably slow due to loading IRs that aren't used by any preset.

Approach

Part 1 — Move IR loading off the RT thread

  • Load, resample, trim, and prepare IR data on a background thread (or GUI async task)
  • Send the ready-to-use IR data to the engine, not just a name
  • Engine swaps the convolver data in — no file I/O or allocation on the RT thread

Part 2 — Preset IR cache

  • At startup, scan saved presets for referenced IR names
  • Background-load those IRs into an in-memory cache
  • On preset switch: if the IR is cached, swap instantly; if not, fall back to background load (Part 1)
  • When saving a preset with a new IR, add it to the cache

Memory impact is minimal — a 2s IR at 48kHz is ~384KB, so even 50 presets with unique IRs ≈ 19MB.

Part 3 — Drain engine message channel (BUG-7)

handle_messages() uses if let Ok(message) = self.engine_receiver.try_recv() which processes at most one message per audio callback. Preset switches send multiple messages (amp chain + IR cabinet) — the IR message won't be processed until the next callback.

  • Change if let Ok to while let Ok to drain all pending messages per callback
  • Prevents multi-message preset changes from spanning multiple callbacks

Acceptance Criteria

  • IR file I/O, resampling, and FFT prep never run on the JACK RT thread
  • Switching presets does not cause x-runs
  • IRs referenced by saved presets are preloaded at startup in the background
  • Startup time is not noticeably impacted (only preset-referenced IRs are preloaded, not all available IRs)
  • Selecting an IR not in the cache still works (background load, no x-run)
  • Saving a preset with a previously-uncached IR adds it to the cache
  • Engine drains all pending messages per callback, not just one

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions