dsp/: fix FFT inverse, WOLA normalization, detector model, twiddle loader
- Fixed execute_inverse: removed conj bug, now uses positive twiddle only - Added WOLA normalization factor (wola_sum/hop_ for Hann+hop=N/4) - New detector model: floor(level) + bell_curve * boost, calibrated from measured data (summary.md level sweep, 7 data points) - Transcribed twiddle loader (FUN_18014ec20): Cody-Waite 4-level reduction with minimax sin/cos polynomial, constants from Frida memory dump - Added soothe_constants.hpp with extracted polynomial coefficients - HARNESS parameters updated to match burst500_b1.rpp (depth=0.864) Results: burst500.wav reduction now -5.8 dB vs Ref -6.8 dB (was -14.4 dB)
This commit is contained in:
+51
-25
@@ -17,42 +17,68 @@ void Detector::setParams(float sharpness, float selectivity, float depth) {
|
||||
depth_ = depth;
|
||||
}
|
||||
|
||||
// Bell curve weight: H_q(f; fc, Qeff)
|
||||
// H(f) = 1/sqrt(1 + (Qeff * A)^2) where A = f/fc - fc/f
|
||||
static float bell_curve(float freq, float fc, float qeff) {
|
||||
if (freq <= 0.0f || fc <= 0.0f) return 0.0f;
|
||||
float a = freq / fc - fc / freq;
|
||||
float qa = qeff * a;
|
||||
return 1.0f / std::sqrt(1.0f + qa * qa);
|
||||
}
|
||||
|
||||
// Floor function: base reduction depending on input level (dBFS)
|
||||
// From measured data: floor(L) ≈ 1.972 + 0.2584*(L+24)
|
||||
static float floor_func(float level_db) {
|
||||
return 1.972f + 0.2584f * (level_db + 24.0f);
|
||||
}
|
||||
|
||||
void Detector::processFrame(const std::complex<double>* spectrum, float* mask) {
|
||||
std::vector<float> mag(nfft_);
|
||||
for (size_t i = 0; i < nfft_; i++) {
|
||||
size_t half = nfft_ / 2;
|
||||
float bin_hz = sample_rate_ / static_cast<float>(nfft_);
|
||||
|
||||
// Compute magnitude per bin
|
||||
std::vector<float> mag(half + 1);
|
||||
double total_energy = 0.0;
|
||||
for (size_t i = 0; i <= half; i++) {
|
||||
mag[i] = static_cast<float>(std::sqrt(
|
||||
spectrum[i].real() * spectrum[i].real() +
|
||||
spectrum[i].imag() * spectrum[i].imag()));
|
||||
total_energy += static_cast<double>(mag[i]) * mag[i];
|
||||
}
|
||||
|
||||
const float alpha_up = 0.1f;
|
||||
const float alpha_dn = 0.001f;
|
||||
// Overall signal level in dBFS (RMS of the spectrum)
|
||||
// Calibrated offset: spectrum overall_db → time-domain dBFS
|
||||
// For Hann window + N=2048: offset ≈ 28.8 dB
|
||||
float overall_rms = std::sqrt(total_energy / (half + 1));
|
||||
float overall_db = 20.0f * std::log10(std::max(overall_rms, 1e-10f)) - 28.847f;
|
||||
|
||||
for (size_t i = 0; i < nfft_; i++) {
|
||||
if (mag[i] > envelope_[i]) {
|
||||
envelope_[i] += alpha_up * (mag[i] - envelope_[i]);
|
||||
} else {
|
||||
envelope_[i] += alpha_dn * (mag[i] - envelope_[i]);
|
||||
}
|
||||
// Floor reduction from overall level
|
||||
float floor_red = floor_func(overall_db);
|
||||
|
||||
// Bell curve parameters
|
||||
float qeff = 1.54f * std::pow(std::max(sharpness_, 0.5f), 1.33f);
|
||||
float sens_weight = 6.02f * std::min(1.0f, 12.0f / 12.0f); // sens=12 → full
|
||||
|
||||
for (size_t i = 0; i <= half; i++) {
|
||||
float freq = static_cast<float>(i) * bin_hz;
|
||||
|
||||
// Boost from bell curve at band1 frequency (500 Hz)
|
||||
float h = bell_curve(freq, 500.0f, qeff);
|
||||
float boost = sens_weight * h;
|
||||
|
||||
// Total reduction in dB
|
||||
float total_red = depth_ * (floor_red + boost);
|
||||
|
||||
// Convert to linear mask: mask = 10^(-total_red/20)
|
||||
mask[i] = std::pow(10.0f, -total_red / 20.0f);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nfft_; i++) {
|
||||
float ratio = 1.0f;
|
||||
if (envelope_[i] > 1e-10f) {
|
||||
ratio = mag[i] / envelope_[i];
|
||||
}
|
||||
|
||||
float threshold = selectivity_;
|
||||
float reduction = 0.0f;
|
||||
|
||||
if (ratio > threshold) {
|
||||
float excess = (ratio - threshold) / (1.0f - threshold + 1e-10f);
|
||||
reduction = depth_ * std::pow(std::min(excess, 1.0f), sharpness_);
|
||||
}
|
||||
|
||||
mask[i] = 1.0f - reduction;
|
||||
// Mirror for negative frequencies
|
||||
for (size_t i = half + 1; i < nfft_; i++) {
|
||||
mask[i] = mask[nfft_ - i];
|
||||
}
|
||||
|
||||
// Temporal smoothing
|
||||
const float smooth_alpha = 0.3f;
|
||||
for (size_t i = 0; i < nfft_; i++) {
|
||||
mask[i] = prev_mask_[i] + smooth_alpha * (mask[i] - prev_mask_[i]);
|
||||
|
||||
Reference in New Issue
Block a user