#pragma once #include #include #include struct DetectorBand { float fc; // band center freq (Hz) 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 }; // 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); ~FramedDetector(); void setParams(const std::vector& bands); void processFrame(const std::complex* spectrum, float* mask); private: size_t nfft_; float sample_rate_; double wsum_; std::vector bands_; std::vector> res_; // per band, per bin |2B/A| std::vector am_; // smoothed per-bin amplitude std::vector> track_; // per band, per bin accumulator 0x5407c8 };