#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++ 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. 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 warp_; // per-bin warp tilt std::vector am_; // smoothed per-bin amplitude std::vector> track_; // per band, per bin level tracker };