diff --git a/dsp/framed_model.cpp b/dsp/framed_model.cpp index fa6a6a8..09f4f15 100644 --- a/dsp/framed_model.cpp +++ b/dsp/framed_model.cpp @@ -76,9 +76,20 @@ static void process_band_structural( acc.assign(nfft, 0.0); constexpr float fVar30 = 1.0f; - constexpr float scale_factor = 440.95f / 2048.0f; + constexpr float scale_factor = 15.0f * 440.95f / 2048.0f; constexpr float mix = 1.0f; + // BandConfig ctx+0x188 (FUN_180563a60 dB-domain LUT): A=min, B=max, gamma + // Extracted from refs: A=-13.78dB, B=68.29dB, gamma=0.344 (NOTES_LEVEL:967) + constexpr float LUT_A = -13.78f; + constexpr float LUT_B = 68.29f; + constexpr float LUT_GAMMA = 0.344f; + + // res^rp term (bridge parity): smooth frequency-dependent floor + constexpr double RP0 = 0.0275; + constexpr double DRP = 0.2159; + double rp = RP0 * std::pow(static_cast(band.q), DRP); + for (size_t k = 0; k < nbin; k++) { double res_k = std::max(static_cast(res[k]), 1e-12); double lvl = static_cast(am[k]) / res_k * scale_factor; @@ -102,12 +113,24 @@ static void process_band_structural( mask_out[k] = static_cast(std::exp2(-static_cast(band_level[k])) * f6f8[k]); } + // dB-domain LUT compression (FUN_180563a60): mask_dB -> t -> t^gamma -> linear + // Compresses the exp2 collapse into a smooth log curve (NOTES_LEVEL:948) + for (size_t k = 0; k < nfft; k++) { + double m = std::max(static_cast(mask_out[k]), 1e-12); + double dB = std::log10(m) * 20.0; + double t = (dB - LUT_A) / (LUT_B - LUT_A); + t = std::min(std::max(t, 0.0), 1.0); + double val = std::pow(t, static_cast(LUT_GAMMA)); + mask_out[k] = static_cast(val); + } + fn529fe0::combine_acc(acc.data(), band_level.data(), f6f8.data(), kRTAtt, kRTRel, nfft); for (size_t k = 0; k < nfft; k++) { size_t idx = (k < nbin) ? k : (nfft - 1 - k); - mask_out[k] *= kBand768[idx] * kWarp[idx]; + double res_k = std::max(static_cast(res[idx]), 1e-12); + mask_out[k] *= kBand768[idx] * kWarp[idx] * std::pow(res_k, rp); } for (size_t k = 0; k < nfft; k++) {