Skip to content

feat(dsp): non-uniform partitioned convolution — IR cap 2 s → 10 s#49

Merged
ealtun21 merged 2 commits into
masterfrom
feat/convolution-nonuniform
Jul 2, 2026
Merged

feat(dsp): non-uniform partitioned convolution — IR cap 2 s → 10 s#49
ealtun21 merged 2 commits into
masterfrom
feat/convolution-nonuniform

Conversation

@ealtun21

@ealtun21 ealtun21 commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Closes #41.

What

Two-stage Gardner partitioning in the convolution engine:

  • Head — unchanged uniform 256-sample partitions covering the first 8192 taps: latency stays exactly BLOCK (256 frames).
  • Tail — 4096-sample partitions (FFT 8192) for everything past 8192 taps. HEAD_LEN = 2 × TAIL_BLOCK is load-bearing: a completed tail block finishes one full 16-sub-block cycle before its earliest output is due, so the tail FFT + frequency-delay-line MAC are spread across the cycle's sub-blocks — no CPU spike, no worker thread, deterministic allocation-free RT path (audiodg-safe).
  • MAX_IR_SECONDS 2.0 → 10.0. Short IRs (≤ 8192 taps) allocate no tail state and behave byte-for-byte as before.

Public API, IPC protocol, APO IR-blob format and latency are unchanged.

Measured (release, per 256-frame stereo call)

IR before after
2 s @48 kHz ~1 ms (750 partitions) 54 µs
10 s @48 kHz rejected 165 µs
10 s @96 kHz worst-case sub-block 492 µs vs 2.67 ms budget

Memory note: FDL + kernel ≈ 32 B/tap/ch each (10 s stereo @96 kHz ≈ 90 MB); a realfft follow-up can halve it.

Tests

  • 6 new DSP tests: sparse-delta long IR vs analytic reference across the head/tail boundary, 10 k-tap dense IR vs direct convolution, long-IR block-size invariance, 3 s no-longer-truncated, tail-state reset on re-enable, rebind + channel-resize with a long IR. All 16 existing convolution tests unchanged and green.
  • New daemon IPC test: 100 001-tap WAV loads end-to-end, tail tap convolves at the exact frame.
  • benches/chain.rs: convolution bench at 0.1 s / 2 s / 10 s.
  • Ignored manual RT-budget test (worst_case_block_time_fits_rt_budget).

Verified on

  • Linux: make check green (fmt, clippy -D warnings, full workspace suite).
  • macOS (arm64, 26.2): full workspace suite green.
  • Windows (Win10 VM): dsp 145 + apo 27 green; live in audiodg — 144 001-tap IR accepted (+5.3 ms reported), identity 3 s IR bit-transparent vs baseline, and a 0.5-amplitude echo at 2.5 s (past the old cap, deep in the tail stage) measured in WASAPI loopback at exactly the predicted comb: 700 Hz +3.52 dB, 900.2 Hz −6.02 dB.
  • Linux live long-IR run deferred to the scheduled audio-cut window (live daemon must not be restarted until then).

ealtun21 added 2 commits July 2, 2026 10:43
Uniform 256-sample partitions made per-block cost linear in IR length,
forcing the 2 s cap that rejects hall/church reverb IRs. Split at 8192
taps: head keeps 256-sample partitions (latency unchanged), tail uses
4096-sample partitions with the FFT + delay-line MAC spread across the
16 sub-blocks of each tail cycle, so no callback pays for the whole
line. Head length = two tail blocks buys exactly one cycle of slack —
no worker thread, deterministic RT path (audiodg-safe).

Measured per 256-frame stereo call: 2 s IR 54 us (was ~1 ms), 10 s IR
165 us; worst-case sub-block 492 us vs the 2.67 ms 96 kHz budget.

Closes #41
@ealtun21 ealtun21 merged commit 18e5322 into master Jul 2, 2026
3 checks passed
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.

convolution: non-uniform partitioning for IRs longer than 2 s

1 participant