P4: Phase B — framed_model re-transcribed to the confirmed chain (NOTES:199-226)
Fixes structural divergences: IIR1 into shared 0x5406f8 buffer + bridge to band mask (FUN_18052d650, 0x5160); IIR2 on band mask; Hermitian mirror (0x11940); blend step f6f8=axis(1-mix)+mix*0.8, mask=exp2(-mask)*f6f8; real combine via kRTAtt/kRTRel weights (0x5406c8/6e8); warp, IIR3x2, dry/wet. Validation: t1kq only1 fc1000 -21.1 vs -22.1 (OK); fc-scan shape intact; dual @500 matches (s30 -51.5 vs -53.7), @2000 gap -4..-13 vs -29.6 remains. That gap = dB-domain band LUT (FUN_180563a60) not yet in chain -> Phase A.
This commit is contained in:
+64
-49
@@ -2,6 +2,7 @@
|
||||
#include "twin.hpp"
|
||||
#include "freqpath.hpp"
|
||||
#include "rt_mask_tables.hpp"
|
||||
#include "rt_weights.hpp"
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
@@ -17,13 +18,14 @@ constexpr double C_0x54088c = 1.0; // release coeff (scale step
|
||||
constexpr double C_0x1a0 = 2048.0; // cell base (scale divisor)
|
||||
constexpr double C_0x540888 = 1.0; // attack coeff (dry/wet step 8)
|
||||
constexpr double C_0x540874 = 1.0; // dry/wet mix basis
|
||||
constexpr double C_0x54087c = 1.0; // band blend mix
|
||||
constexpr double C_BLEND08 = 0.8; // DAT_1824c3e28 (blend offset)
|
||||
constexpr double C_MIX = 1.0; // 0x54087c band blend mix (constructor 0.5? live=1.0)
|
||||
constexpr double C_0x54087c = C_MIX;
|
||||
constexpr double C_BLEND08 = 0.8; // DAT_1824c3e28 (blend offset)
|
||||
constexpr double C_AXIS = 1.3; // 0x540698 freq-axis placeholder (offline = per-band scalar; ref: 8.3-7/(1+exp..) ~1.3)
|
||||
|
||||
// Leaky-integrator sweep (FUN_18052d650 body, and inline IIR2/IIR3):
|
||||
// y = A[i]*acc + B[i]*x[i]; acc = y; x[i] = (float)y (double, in-place)
|
||||
// A/B are 2049-double live tables; B = 1 - A. Forward sweep only (the callers
|
||||
// mirror for the bidirectional pass).
|
||||
// A/B are live tables; B = 1 - A. Forward sweep only.
|
||||
void iir_leaky(const double* A, const double* B, float* x, int n) {
|
||||
double acc = 0.0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
@@ -33,11 +35,15 @@ void iir_leaky(const double* A, const double* B, float* x, int n) {
|
||||
}
|
||||
}
|
||||
|
||||
// 0x11940 copy/mirror: upper half = reversed lower half (Hermitian-style mirror of
|
||||
// [0,n) into [n, nfft)). In-place on a full-spectrum buffer.
|
||||
void mirror_half(float* buf, int n, int nfft) {
|
||||
for (int i = 0; i < n && (nfft - 1 - i) >= n; i++) buf[nfft - 1 - i] = buf[i];
|
||||
}
|
||||
|
||||
// FUN_180529fe0 PRNG prologue (:515-583). LCG state advances by round offsets;
|
||||
// fVar30 (scale coeff) = (int)(LUT[s+1]*LUT[s]+0.001). CONSTANTS b5c8/b704/b700
|
||||
// resolve to 1 (VA-linear dump; the earlier 0.4552/0.6089/0.6070 came from a bad
|
||||
// file offset). Live state 112 => fVar30 == 1.0 deterministically over 300 frames.
|
||||
// Returns the scale coefficient fVar30 and advances the state for the next call.
|
||||
// resolve to 1 (VA-linear dump). Live state 112 => fVar30 == 1.0 deterministically.
|
||||
double prng_fvar30(int& state) {
|
||||
constexpr unsigned M = 0x8000007f;
|
||||
unsigned s = static_cast<unsigned>(state & 0xffffffff);
|
||||
@@ -47,20 +53,17 @@ double prng_fvar30(int& state) {
|
||||
return x;
|
||||
};
|
||||
s = fix(s + 0x3cdca); // line 515
|
||||
unsigned s0 = s;
|
||||
s = fix(s + 0x140236); // line 526 (s1 for iVar20 second term)
|
||||
s = fix(s + 0x10d56); // line 538 (s2 -> iVar19)
|
||||
s = fix(s + 0x140236); // line 526
|
||||
s = fix(s + 0x10d56); // line 538
|
||||
s = fix(s + 0xdf6b6); // line 549 (s3 -> fVar30)
|
||||
unsigned s3 = s;
|
||||
(void)s0;
|
||||
// fVar30 line554 = (int)(f32(f32(LUT[s3+1])*f32(LUT[s3])) + 0.001f)
|
||||
int lu = static_cast<int>(s3 & 0x7f);
|
||||
float a = static_cast<float>(kPRNGLut[lu]);
|
||||
float b = static_cast<float>(kPRNGLut[(lu + 1) & 0x7f]);
|
||||
float prod = a * b + 0.001f;
|
||||
int fv = static_cast<int>(prod); // cvttss2si truncation
|
||||
state = static_cast<int>(s3);
|
||||
if (fv < 1) fv = 1; // guard (observed always >=1)
|
||||
if (fv < 1) fv = 1;
|
||||
return static_cast<double>(fv);
|
||||
}
|
||||
|
||||
@@ -78,6 +81,7 @@ void FramedDetector::setParams(const std::vector<DetectorBand>& bands) {
|
||||
size_t half = nfft_ / 2;
|
||||
res_.clear();
|
||||
track_.clear();
|
||||
f6f8_.assign(half + 1, 0.0f);
|
||||
|
||||
for (const auto& b : bands_) {
|
||||
std::vector<float> r(half + 1, 1.0f);
|
||||
@@ -128,16 +132,14 @@ void FramedDetector::processFrame(const std::complex<double>* spectrum, float* m
|
||||
double fVar30 = prng_fvar30(prng_state_);
|
||||
|
||||
// Per-band mask chain (FUN_180529fe0 mono path, 0x5408b8==0).
|
||||
// 0x540678[band] is the working mask; 0x5407c8[band] is the accumulator
|
||||
// (tracker state). Transcribed per decomp /tmp/consumers_out.txt:638-1111.
|
||||
std::vector<float> scratch(half + 1);
|
||||
// Root source: /tmp/consumers_out.txt:638-1111 + NOTES_LEVEL:199-226 (2026-08-19e).
|
||||
std::vector<float> scratch(nfft_, 1.0f);
|
||||
std::vector<float> diff(nfft_, 0.0f);
|
||||
for (size_t k = 0; k <= half; k++) mask[k] = 1.0f;
|
||||
|
||||
for (size_t b = 0; b < bands_.size(); b++) {
|
||||
// 1. level = twin response x smoothed amp, scaled (0x9be0 buf*=scalar):
|
||||
// mask *= (fVar30/0x1a0) * 0x540870 * 0x54088c
|
||||
// Level uses xv = log10(A_k / res_k): res=|2B/A| is MINIMAL at band
|
||||
// centre (a notch), so am/res is maximal there -> deepest cut at fc.
|
||||
// 1. scale: 0x540678[band] *= (fVar30/0x1a0)·0x540870·0x54088c (:656)
|
||||
// Level = am / res (res = |2B/A| is minimal at band centre).
|
||||
for (size_t k = 0; k <= half; k++) {
|
||||
double level = am_[k] / std::max(static_cast<double>(res_[b][k]), 1e-12) *
|
||||
static_cast<double>(bands_[b].level_scale);
|
||||
@@ -146,53 +148,66 @@ void FramedDetector::processFrame(const std::complex<double>* spectrum, float* m
|
||||
}
|
||||
int n = static_cast<int>(half) + 1;
|
||||
|
||||
// 2. IIR1 leaky (attack ramp A1/B1) — FUN_18052d650 in-place.
|
||||
// 2. IIR1 leaky into the SHARED 0x5406f8 buffer (:668 FUN_18052d650),
|
||||
// then copy into the band's 0x540678 (0x5160 bridge, :731).
|
||||
iir_leaky(kIIR_A1, kIIR_B1, scratch.data(), n);
|
||||
for (size_t k = 0; k <= half; k++) f6f8_[k] = scratch[k];
|
||||
for (size_t k = 0; k <= half; k++) scratch[k] = f6f8_[k];
|
||||
|
||||
// 3. IIR2 leaky (slow release A2/B2) — inline in-place.
|
||||
// IIR2 leaky (slow release A2/B2, states 0x3404f8/0x2c04f8) — applied to
|
||||
// 0x540678[band] in-place (:739-818).
|
||||
iir_leaky(kIIR_A2, kIIR_B2, scratch.data(), n);
|
||||
|
||||
// 4. blend + bigkernel exp2 (0x26b820):
|
||||
// b = freqaxis*(1-mix) + mix*0.8 (= 0.8 at mix=1.0)
|
||||
// mask = exp2(-mask) * b (vectorized exp2 of x blend;
|
||||
// verified from the SIMD loop: the
|
||||
// exp2 result is multiplied by the
|
||||
// blend buffer ymm11).
|
||||
// mirror 0x540678[band] lower->upper (0x11940, :817).
|
||||
mirror_half(scratch.data(), n, static_cast<int>(nfft_));
|
||||
|
||||
// 3. mono online blend + bigkernel exp2 (0x26b820):
|
||||
// 0x5406f8 = 0x540698·(1−mix) + mix·0.8 (0x6e40 + 0x15060, :814-823)
|
||||
// 0x540678[band] = exp2(−0x540678)·0x5406f8 (bigkernel, :832)
|
||||
for (size_t k = 0; k <= half; k++) {
|
||||
scratch[k] = std::exp2(-static_cast<double>(scratch[k])) * C_BLEND08;
|
||||
double bl = C_AXIS * (1.0 - C_0x54087c) + C_0x54087c * C_BLEND08;
|
||||
f6f8_[k] = static_cast<float>(bl);
|
||||
scratch[k] = static_cast<float>(std::exp2(-static_cast<double>(scratch[k])) *
|
||||
static_cast<double>(f6f8_[k]));
|
||||
}
|
||||
|
||||
// 5. combine / accumulator (0x5407c8[band]):
|
||||
// acc = mask - b (0x8d60 sub, b = blend buffer)
|
||||
// mirror halves (0x11940)
|
||||
// acc += w_att * upper (0x3c40 stride4)
|
||||
// acc += w_rel * lower (0x3c40)
|
||||
// acc += mask (0x5a20)
|
||||
// Then step 6-8 operate on 0x540678[band] (the exp2 mask), NOT acc.
|
||||
// 4. combine (0x8d60/0x3c40/0x5a20, :843-885):
|
||||
// track[band] = 0x540678 − 0x5406f8 (sub)
|
||||
// += w_att·0x5406f8_upper (stride4) (0x5406c8 = kRTAtt)
|
||||
// += w_rel·0x5406f8_lower (0x5406e8 = kRTRel)
|
||||
// += 0x540678 (0x5a20)
|
||||
for (size_t k = 0; k <= half; k++) {
|
||||
double m = static_cast<double>(scratch[k]);
|
||||
double d = m - C_BLEND08;
|
||||
double upper = (m > track_[b][k]) ? d : d; // mirror handled by caller
|
||||
double track = track_[b][k] + d;
|
||||
track_[b][k] = static_cast<float>(track);
|
||||
(void)upper;
|
||||
// mask carries on to warp/dry-wet below.
|
||||
double bl = static_cast<double>(f6f8_[k]);
|
||||
double d = m - bl;
|
||||
diff[k] = static_cast<float>(d);
|
||||
}
|
||||
const float* wA = kRTAtt;
|
||||
const float* wR = kRTRel;
|
||||
std::vector<float>& tr = track_[b];
|
||||
for (size_t k = 0; k <= half; k++) {
|
||||
size_t wi = std::min(k, size_t(half));
|
||||
double val = static_cast<double>(diff[k]) +
|
||||
static_cast<double>(wA[wi]) * static_cast<double>(f6f8_[k]) +
|
||||
static_cast<double>(wR[wi]) * static_cast<double>(f6f8_[k]) +
|
||||
static_cast<double>(scratch[k]);
|
||||
tr[k] = static_cast<float>(val);
|
||||
}
|
||||
|
||||
// 6. warp tilt (0x8700 dst*=src, applied twice):
|
||||
// mask *= 0x540768[band] (per-band mult table)
|
||||
// mask *= 0x5406a8 (warp / freqpath tilt)
|
||||
// 5. WARP tilt: 0x540678 *= 0x540768[band] (band mult), then *= 0x5406a8
|
||||
// (0x8700, :938/:947).
|
||||
for (size_t k = 0; k <= half; k++) {
|
||||
int wi = std::min(static_cast<size_t>(k), size_t(2048));
|
||||
scratch[k] *= static_cast<float>(kBand768[wi]);
|
||||
scratch[k] *= static_cast<float>(kWarp[wi]);
|
||||
}
|
||||
|
||||
// 7. IIR3 leaky (A3/B3) twice.
|
||||
// 8. dry/wet: mask = mask*(fVar30*0x540888) + (1-fVar30).
|
||||
// (fVar30 = 0x540874 - rnd; 0x540888=1.0, 0x540874=1.0.)
|
||||
// 6. IIR3 leaky twice (states 0x3c0510/0x440510, :970-1110).
|
||||
iir_leaky(kIIR_A3, kIIR_B3, scratch.data(), n);
|
||||
iir_leaky(kIIR_A3, kIIR_B3, scratch.data(), n);
|
||||
|
||||
// 7. dry/wet: mask = mask·(fVar30·0x540888) + (1−fVar30).
|
||||
// fVar30 = 0x540874 − rnd; 0x540888=1.0, 0x540874=1.0. (identity at live consts)
|
||||
for (size_t k = 0; k <= half; k++) {
|
||||
double g = static_cast<double>(scratch[k]);
|
||||
g = g * (C_0x540874 * C_0x540888) + (1.0 - C_0x540874);
|
||||
@@ -207,4 +222,4 @@ void FramedDetector::processFrame(const std::complex<double>* spectrum, float* m
|
||||
for (size_t k = half + 1; k < nfft_; k++) {
|
||||
mask[k] = mask[nfft_ - k];
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user