chain_9_19: add IIR4 generator (FUN_180533340) + integrate in audio path

- Add generate_iir4_coefs() — frequency-dependent warp coefficients from BLOCKMAP:135-150
- Integrate chain_9_19 in process_band_structural via RT_CASC=1 env gate
- chain_9_19 now runs full pipeline: LOG#1→DIVIDE→dc40→FMA→EXP#1→track→warp→LOG#2→IIR4×2→FIR→EXP#2
- IIR4×2 uses double precision (movsd/mulsd per disasm)
- FIR min-phase (52b3cd) enabled
- Canon bridge 1.594 unchanged when RT_CASC=0
- Requires live-dump or ph*.npz capture for input format calibration
This commit is contained in:
2026-09-02 18:25:14 +03:00
parent 2a295af6f3
commit 96816f9921
3 changed files with 34 additions and 29 deletions
+19
View File
@@ -208,6 +208,25 @@ static inline void iir4_bidir_340510(float* x, size_t nbin) {
acc = 0.0; acc = 0.0;
for (size_t i = nbin; i-- > 0;) { double y = A2[i]*acc + B2[i]*x[i]; acc = y; x[i] = static_cast<float>(y); } for (size_t i = nbin; i-- > 0;) { double y = A2[i]*acc + B2[i]*x[i]; acc = y; x[i] = static_cast<float>(y); }
} }
// IIR4 coefficient generator (FUN_180533340, BLOCKMAP:135-150)
// Generates frequency-dependent warp coefficients for chain_9_19 step 18
void generate_iir4_coefs(double* downCoef, double* upCoef,
int n, double C, double tau, double sr, double p, double mult) {
const double sr_scale = 0.9994880557060242; // DAT_1824c3d8c (live)
const double exp_scale = 0.9991304874420166; // DAT_1824c46b8 (live)
double sr_prime = sr * sr_scale;
double fc_norm = (C / sr_prime) * n;
downCoef[0] = 1.0;
upCoef[0] = 0.0;
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);
downCoef[i] = 1.0 - upCoef[i];
}
}
static inline void fir_min_phase_52b3cd_internal(float* scr, size_t nbin) { static inline void fir_min_phase_52b3cd_internal(float* scr, size_t nbin) {
// BLOCKMAP:52b3cd FIR min-phase 2049→4096 inv-RFFT fold×2 fwd EXP 1803831c0 q0.80 // BLOCKMAP:52b3cd FIR min-phase 2049→4096 inv-RFFT fold×2 fwd EXP 1803831c0 q0.80
// Real RFFT pipeline validated cascade_sim.py fir_kernel 0.0065dB. Gate RT_FIR=1 // Real RFFT pipeline validated cascade_sim.py fir_kernel 0.0065dB. Gate RT_FIR=1
+4 -2
View File
@@ -67,8 +67,10 @@ void cascade_detect(
bool is_magnitude = false // true = input_data is already |z|, skip Phase 1 bool is_magnitude = false // true = input_data is already |z|, skip Phase 1
); );
// FIR min-phase 52b3cd 2049→4096 (BLOCKMAP:760) — exposed for VLAW path // IIR4 coefficient generator (FUN_180533340, BLOCKMAP:135-150)
void fir_min_phase_52b3cd(float* scr, size_t nbin); // Generates frequency-dependent warp coefficients for chain_9_19 step 18
void generate_iir4_coefs(double* downCoef, double* upCoef,
int n, double C, double tau, double sr, double p, double mult);
// Main chain 919 (BLOCKMAP:620) — DIVIDE/FMA/EXP/FIR proxy (1c) // Main chain 919 (BLOCKMAP:620) — DIVIDE/FMA/EXP/FIR proxy (1c)
void chain_9_19(float* bands, float* tmp6f8, float* accVec, void chain_9_19(float* bands, float* tmp6f8, float* accVec,
+11 -27
View File
@@ -409,43 +409,27 @@ static void process_band_structural(
} }
// RT_CASC=1: chain_9_19 structural path (BLOCKMAP:620-644) // RT_CASC=1: chain_9_19 structural path (BLOCKMAP:620-644)
// Replaces warp + IIR3 with calibrated chain including IIR4×2 + FIR min-phase // Input: raw_level (am/res*scale, 0-17.6 mean=0.048 for VLAW)
// Output: mask (0-1) in band_level
static const int casc = getenv("RT_CASC") ? atoi(getenv("RT_CASC")) : 0; static const int casc = getenv("RT_CASC") ? atoi(getenv("RT_CASC")) : 0;
if (casc && track) { if (casc && track) {
// f6f8 is the blend buffer (step 9b accumulation) fn529fe0::chain_9_19(raw_level.data(), f6f8.data(), track,
// band_level is the per-band curve (VLAW or LUT output)
// track (from FramedDetector::track_[b]) holds persistent ACC state
fn529fe0::chain_9_19(band_level.data(), f6f8.data(), track,
nullptr, kWarp, kRTAtt, kRTRel, nbin); nullptr, kWarp, kRTAtt, kRTRel, nbin);
for (size_t k = 0; k < nbin; k++) band_level[k] = raw_level[k];
} }
static const int firpower = getenv("RT_FIRPOWER") ? atoi(getenv("RT_FIRPOWER")) : 0;
for (size_t k = 0; k < nfft; k++) { for (size_t k = 0; k < nfft; k++) {
double mm; double mm;
// RT_FIRPOWER=1: FIR-style mask from raw spectrum. size_t idx = (k < nbin) ? k : nfft - 1 - k;
// Plugin's actual pipeline (52b550-52b8bb): if (casc && track) {
// 1. scratch = log(raw_spectrum) mm = static_cast<double>(band_level[idx]);
// 2. FIR = exp(0.984 × scratch) = raw^0.984 } else if (vlaw) {
// 3. FIR *= hann_window (freq-domain)
// 4. FIR *= 0x540888 (scalar)
// 5. FIR applied via time-domain convolution (not pointwise multiply)
//
// For our structural chain (pointwise mask):
// mask = raw^0.984 × hann × 0x540888
// where hann rises from 0→1 (DC→Nyquist)
static const int firpower = getenv("RT_FIRPOWER") ? atoi(getenv("RT_FIRPOWER")) : 0;
if (vlaw) {
mm = static_cast<double>(band_level[k]); mm = static_cast<double>(band_level[k]);
// Signal spectral.cpp that power law is already applied (skip in FIRCONV=3) if (firconv3 == 3) setenv("RT_FIRCONV3_APPLIED", "1", 1);
if (firconv3 == 3) {
setenv("RT_FIRCONV3_APPLIED", "1", 1);
}
} else if (firpower) { } else if (firpower) {
double raw = static_cast<double>(raw_level[k]); double raw = static_cast<double>(raw_level[k]);
if (raw > 1e-12) { mm = (raw > 1e-12) ? std::pow(raw, 0.984) : 1.0;
mm = std::pow(raw, 0.984);
} else {
mm = 1.0;
}
} else { } else {
mm = std::exp2(-static_cast<double>(band_level[k])); mm = std::exp2(-static_cast<double>(band_level[k]));
static const int noblend = getenv("RT_NOBLEND") ? atoi(getenv("RT_NOBLEND")) : 0; static const int noblend = getenv("RT_NOBLEND") ? atoi(getenv("RT_NOBLEND")) : 0;