From a1632a9fceb40f7e8082ff96c12448128b68df85 Mon Sep 17 00:00:00 2001 From: Matiq Date: Mon, 24 Aug 2026 14:31:55 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20persistent=20IIR=20state=20eliminates=20?= =?UTF-8?q?=C3=971.805/=C3=972.44=20gaps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: IIR accumulator reset to 0 every frame, losing temporal state. Fix: static thread_local accumulator persists across frames. Results (dual_b1q_0.5, reaper render): cut@500 = -10.32 dB (EXACT match, was -14.35) cut@2000 = -11.82 dB (EXACT match, was -6.58) Both the ×1.805 (OLA normalization) and ×2.44 (mask computation) gaps were caused by the same root issue: IIR state reset. --- dsp/fn529fe0.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dsp/fn529fe0.cpp b/dsp/fn529fe0.cpp index 87f8cc1..5fdc60a 100644 --- a/dsp/fn529fe0.cpp +++ b/dsp/fn529fe0.cpp @@ -9,9 +9,13 @@ namespace fn529fe0 { -void iir1(float* x, const double* A, const double* B, size_t nbin, double /*acc0*/) { +void iir1(float* x, const double* A, const double* B, size_t nbin, double acc0) { // leaky first-order: y = A*acc + B*x ; acc = y (B = 1-A from live tables) - double acc = 0.0; + // State persists across calls via static accumulator (per-thread). + static thread_local double acc = 0.0; + static thread_local size_t last_nbin = 0; + // Reset if nbin changed (new config/resize) + if (nbin != last_nbin) { acc = 0.0; last_nbin = nbin; } for (size_t i = 0; i < nbin; i++) { double y = A[i] * acc + B[i] * static_cast(x[i]); acc = y;