From b41d7a40cb51b8ca422b132accc55f9d22ad6655 Mon Sep 17 00:00:00 2001 From: Matiq Date: Wed, 2 Sep 2026 21:38:44 +0300 Subject: [PATCH] chain: wire IIR4 generator (RT_IIR4_GEN) + add chain smoke test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - iir4_bidir: env-gated generate_iir4_coefs (C/tau/p/mult/sr) vs proxy kIIR - fix exp sign: up=exp(-c*g*tau/mult) → down=1-up in 0..1 (was Inf) - fn529fe0_check: chain_9_19 smoke + generate_iir4 smoke (down0=1 up0=0 ok) - Gates: bridge 1.594, structural 2.689 (RT_CASC=0) unchanged --- dsp/fn529fe0.cpp | 39 +++++++++++++++++++++++++++++++-------- dsp/fn529fe0_check.cpp | 20 ++++++++++++++++++++ 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/dsp/fn529fe0.cpp b/dsp/fn529fe0.cpp index e738a95..e596e6f 100644 --- a/dsp/fn529fe0.cpp +++ b/dsp/fn529fe0.cpp @@ -196,13 +196,35 @@ void cascade_detect( static inline void iir4_bidir_340510(float* x, size_t nbin) { // BLOCKMAP:52af09 IIR4×2 bidir log-domain base 0x340510 - // Uses DOUBLE precision (movsd/mulsd in disasm) - // Coefficients from FUN_180533340 generator (frequency-dependent warp) - // For now, use kIIR_A1/B1 as proxy (structure is correct) - extern const double kIIR_A1[]; extern const double kIIR_B1[]; - extern const double kIIR_A2[]; extern const double kIIR_B2[]; - const double* A1 = ::kIIR_A1; const double* B1 = ::kIIR_B1; - const double* A2 = ::kIIR_A2; const double* B2 = ::kIIR_B2; + // Uses DOUBLE precision (movsd/mulsd/cvtpd2ps in disasm 1191-1201) + // When RT_IIR4_GEN=1, generate via FUN_180533340 (freq-warp g=fc_norm/i|pow), else use proxy kIIR_A1/B1 + static std::vector genDown, genUp; + static int genN = 0; + const double* A1; + const double* B1; + const double* A2; + const double* B2; + static const int useGen = getenv("RT_IIR4_GEN") ? atoi(getenv("RT_IIR4_GEN")) : 0; + if (useGen) { + if ((int)nbin != genN) { + genDown.assign(nbin, 0.0); genUp.assign(nbin, 0.0); + double C = getenv("RT_IIR4_C") ? atof(getenv("RT_IIR4_C")) : 1000.0; + double tau = getenv("RT_IIR4_TAU") ? atof(getenv("RT_IIR4_TAU")) : 1200.0; + double p = getenv("RT_IIR4_P") ? atof(getenv("RT_IIR4_P")) : 0.5; + double mult = getenv("RT_IIR4_MULT") ? atof(getenv("RT_IIR4_MULT")) : 360.0; + double sr = getenv("RT_IIR4_SR") ? atof(getenv("RT_IIR4_SR")) : 48000.0; + generate_iir4_coefs(genDown.data(), genUp.data(), (int)nbin, C, tau, sr, p, mult); + genN = (int)nbin; + } + // down=1-up, so A=down, B=up + A1 = genDown.data(); B1 = genUp.data(); + A2 = genDown.data(); B2 = genUp.data(); + } else { + extern const double kIIR_A1[]; extern const double kIIR_B1[]; + extern const double kIIR_A2[]; extern const double kIIR_B2[]; + A1 = ::kIIR_A1; B1 = ::kIIR_B1; + A2 = ::kIIR_A2; B2 = ::kIIR_B2; + } double acc = 0.0; for (size_t i = 0; i < nbin; i++) { double y = A1[i]*acc + B1[i]*x[i]; acc = y; x[i] = static_cast(y); } acc = 0.0; @@ -223,7 +245,8 @@ void generate_iir4_coefs(double* downCoef, double* upCoef, for (int i = 1; i < n; i++) { double g = (i <= fc_norm) ? (fc_norm / i) : std::pow(fc_norm / i, p); double c = 1.0 / (g * tau / mult + 1.0); - upCoef[i] = std::exp(c * g * tau * exp_scale); + // state[2] ≈ mult per BLOCKMAP, so normalize: exp(-c*g*tau/state2) → 0..1 + upCoef[i] = std::exp(-c * g * tau / mult * exp_scale); downCoef[i] = 1.0 - upCoef[i]; } } diff --git a/dsp/fn529fe0_check.cpp b/dsp/fn529fe0_check.cpp index a2fc7ec..4e5c25d 100644 --- a/dsp/fn529fe0_check.cpp +++ b/dsp/fn529fe0_check.cpp @@ -195,6 +195,26 @@ int main() { if (!ok) fail = 1; } + // --- chain_9_19: gated pipeline smoke (LOG#1→DIVIDE→dc40→FMA→EXP-1→*track→*warp→LOG#2→IIR4→FIR→EXP#2) --- + { + std::vector bands(nbin, 0.5f), tmp(nbin, 0.1f), acc(nbin, 0.0f); + std::vector warp(nbin, 1.0f), att(nbin, 0.0f), rel(nbin, 0.0f); + std::vector bands0 = bands; + fn529fe0::chain_9_19(bands.data(), tmp.data(), acc.data(), nullptr, warp.data(), att.data(), rel.data(), nbin); + bool ok = true; + for (size_t i = 0; i < nbin; i++) if (!std::isfinite(bands[i]) || bands[i] < 0.0f || bands[i] > 5.0f) ok = false; + std::printf("chain_9_19 smoke: in0=%.3f out0=%.3f outmid=%.3f finite=%d (%s)\n", + bands0[0], bands[0], bands[nbin/2], ok, ok ? "OK" : "MISMATCH"); + if (!ok) fail = 1; + // IIR4 generator smoke + std::vector down(nbin), up(nbin); + fn529fe0::generate_iir4_coefs(down.data(), up.data(), (int)nbin, 1000.0, 1200.0, 48000.0, 0.5, 360.0); + bool gok = std::fabs(down[0]-1.0)<1e-9 && std::fabs(up[0])<1e-9 && down[1] < 1.0 && down[1] > 0.0; + std::printf("generate_iir4: down0=%.3f up0=%.3f down1=%.4f up1=%.4f (%s)\n", + down[0], up[0], down[1], up[1], gok ? "OK" : "MISMATCH"); + if (!gok) fail = 1; + } + std::printf("fn529fe0 check %s\n", fail ? "FAIL" : "PASS"); return fail; }