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:
@@ -208,6 +208,25 @@ static inline void iir4_bidir_340510(float* x, size_t nbin) {
|
||||
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); }
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// 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
|
||||
|
||||
+4
-2
@@ -67,8 +67,10 @@ void cascade_detect(
|
||||
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
|
||||
void fir_min_phase_52b3cd(float* scr, size_t nbin);
|
||||
// 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);
|
||||
|
||||
// Main chain 9–19 (BLOCKMAP:620) — DIVIDE/FMA/EXP/FIR proxy (1c)
|
||||
void chain_9_19(float* bands, float* tmp6f8, float* accVec,
|
||||
|
||||
+11
-27
@@ -409,43 +409,27 @@ static void process_band_structural(
|
||||
}
|
||||
|
||||
// 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;
|
||||
if (casc && track) {
|
||||
// f6f8 is the blend buffer (step 9b accumulation)
|
||||
// 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,
|
||||
fn529fe0::chain_9_19(raw_level.data(), f6f8.data(), track,
|
||||
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++) {
|
||||
double mm;
|
||||
// RT_FIRPOWER=1: FIR-style mask from raw spectrum.
|
||||
// Plugin's actual pipeline (52b550-52b8bb):
|
||||
// 1. scratch = log(raw_spectrum)
|
||||
// 2. FIR = exp(0.984 × scratch) = raw^0.984
|
||||
// 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) {
|
||||
size_t idx = (k < nbin) ? k : nfft - 1 - k;
|
||||
if (casc && track) {
|
||||
mm = static_cast<double>(band_level[idx]);
|
||||
} else if (vlaw) {
|
||||
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) {
|
||||
double raw = static_cast<double>(raw_level[k]);
|
||||
if (raw > 1e-12) {
|
||||
mm = std::pow(raw, 0.984);
|
||||
} else {
|
||||
mm = 1.0;
|
||||
}
|
||||
mm = (raw > 1e-12) ? std::pow(raw, 0.984) : 1.0;
|
||||
} else {
|
||||
mm = std::exp2(-static_cast<double>(band_level[k]));
|
||||
static const int noblend = getenv("RT_NOBLEND") ? atoi(getenv("RT_NOBLEND")) : 0;
|
||||
|
||||
Reference in New Issue
Block a user