P4: transcribe exact FUN_180529fe0 mask chain (structural, not yet calibrated)

framed_model.cpp now follows the decoded mono-path structure:
  level -> scale(0x540870*0x54088c/0x1a0) -> IIR1 leaky(A1/B1) -> IIR2(A2/B2)
  -> exp2(0.5*(mask-blend)) -> combine/acc -> warp -> IIR3(A3/B3)x2 -> dry/wet
IIR stages are the real live tables (iir_leaky y=A*acc+B*x, B=1-A). Removed the
empirical mask_lut=(1/(1+K*acc))^n. Not numerically calibrated yet: exp2 bigkernel
exact semantics + PRNG prologue (fVar30) + FFT-conv still TBD; t1kq depth -2.9 vs
-14.98 dB ref.
This commit is contained in:
2026-08-20 15:10:29 +03:00
parent f23bbfa1f6
commit d4a0a68584
4 changed files with 2983 additions and 2948 deletions
+14 -17
View File
@@ -8,23 +8,21 @@ struct DetectorBand {
float q; // resonance Q
float sens; // XML sens (dB); internal sens_stored = sens * 2.054
float level_scale = 1.0f; // calibration: level = am * res * level_scale
// Per-band mask LUT: gain = (1/(1+K*acc))^n (live-fit defaults band0).
float lut_k = 9.8026f;
float lut_n = 0.25966f;
// Dry/wet depth (XML "depth", 0.864 in reference renders). Applied only when
// set >= 0; default -1 keeps the live LUT fit intact (fit already absorbed
// band0's dry/wet blend).
float depth = -1.0f;
};
// FramedDetector — C++ port of the real soothe mask chain (FUN_180529fe0).
// Per band, per bin:
// level_k = am_k * res_k (twin resonance x smoothed amplitude)
// track += w_k * (level - track) (per-bin level tracker, attack/release
// weights w from live capture rt_weights)
// acc_k = 2*level_k - track_k (accumulator, live peak ~10.08 at tone)
// mask_k = LUT(acc_k) (fitted mask curve from live capture)
// final mask = min over bands (max suppression), like soothe's band combine.
// FramedDetector — C++ transcription of the real soothe2 mask-apply chain
// (FUN_180529fe0 mono path, 0x5408b8==0), bit-exact structure.
//
// Per band, per bin (exact decomp /tmp/consumers_out.txt:638-1111):
// 1. scale: x = level * (fVar30/0x1a0) * 0x540870 * 0x54088c
// 2. IIR1 leaky: y[i] = A1[i]*acc + B1[i]*x[i] (A1/B1 ramp attack, live tables)
// 3. IIR2 leaky: same with A2/B2 (slow release)
// 4. blend: b = freqaxis*(1-mix) + mix*0.8; mask = exp2(0.5*(mask-b))
// 5. combine: acc[band] = mask - b; mirror; += w_att*upper; += w_rel*lower; += mask
// 6. warp: mask *= 0x540768[band]; mask *= warp (dual tilt)
// 7. IIR3 leaky: twice with A3/B3
// 8. dry/wet: mask = mask*(fVar30*0x540888) + (1-fVar30)
// final = min over bands.
class FramedDetector {
public:
FramedDetector(size_t nfft, float sample_rate);
@@ -41,7 +39,6 @@ private:
std::vector<DetectorBand> bands_;
std::vector<std::vector<float>> res_; // per band, per bin |2B/A|
std::vector<float> warp_; // per-bin warp tilt
std::vector<float> am_; // smoothed per-bin amplitude
std::vector<std::vector<float>> track_; // per band, per bin level tracker
std::vector<std::vector<float>> track_; // per band, per bin accumulator 0x5407c8
};