From ddf2ac2050b514cc9f8cffe8b0eacdd6fa547e6e Mon Sep 17 00:00:00 2001 From: Matiq Date: Thu, 20 Aug 2026 16:14:50 +0300 Subject: [PATCH] P4: lock PRNG prologue + correct constants (DAT_*=1); scale via prng_fvar30 CRITICAL fix: soothe_mem.bin is VA-linear (offset=RVA). DAT_18262b5c8/b704/b700 are INT 1 (cvtdq2ps -> 1.0), NOT the 0.4552/0.6089/0.6070 read earlier via a bad section offset. Transcribed FUN_180529fe0 PRNG prologue into prng_fvar30(): fVar30=(int)(LUT[s+1]*LUT[s]+0.001). At live state 112 this is deterministically 1.0 over 300 frames, so scale level *= (1/2048)*440.95 is not randomized in practice. Scale coefficient now computed structurally; t1kq unchanged -0.43 dB. --- dsp/framed_model.cpp | 37 ++++++++++++++++++++++++++++++++++++- dsp/framed_model.hpp | 5 +++++ handoff/NOTES_LEVEL.md | 21 +++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/dsp/framed_model.cpp b/dsp/framed_model.cpp index d5d8f9f..8b55f6f 100644 --- a/dsp/framed_model.cpp +++ b/dsp/framed_model.cpp @@ -33,6 +33,37 @@ void iir_leaky(const double* A, const double* B, float* x, int n) { } } +// 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. +double prng_fvar30(int& state) { + constexpr unsigned M = 0x8000007f; + unsigned s = static_cast(state & 0xffffffff); + auto fix = [](unsigned x) { + x &= M; + if (x & 0x80000000u) x = ((x - 1) | 0xffffff80u) + 1; + 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 + 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(s3 & 0x7f); + float a = static_cast(kPRNGLut[lu]); + float b = static_cast(kPRNGLut[(lu + 1) & 0x7f]); + float prod = a * b + 0.001f; + int fv = static_cast(prod); // cvttss2si truncation + state = static_cast(s3); + if (fv < 1) fv = 1; // guard (observed always >=1) + return static_cast(fv); +} + } // namespace FramedDetector::FramedDetector(size_t nfft, float sample_rate) @@ -93,6 +124,9 @@ void FramedDetector::processFrame(const std::complex* spectrum, float* m am_[k] = static_cast(am); } + // PRNG prologue: advance state once per frame; fVar30 -> scale coefficient. + 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. @@ -105,7 +139,8 @@ void FramedDetector::processFrame(const std::complex* spectrum, float* m for (size_t k = 0; k <= half; k++) { double level = am_[k] * static_cast(res_[b][k]) * static_cast(bands_[b].level_scale); - scratch[k] = static_cast(level * C_0x540870 * C_0x54088c / C_0x1a0); + scratch[k] = static_cast(level * (fVar30 / C_0x1a0) * + C_0x540870 * C_0x54088c); } int n = static_cast(half) + 1; diff --git a/dsp/framed_model.hpp b/dsp/framed_model.hpp index b6511c3..efdf01e 100644 --- a/dsp/framed_model.hpp +++ b/dsp/framed_model.hpp @@ -23,6 +23,10 @@ struct DetectorBand { // 7. IIR3 leaky: twice with A3/B3 // 8. dry/wet: mask = mask*(fVar30*0x540888) + (1-fVar30) // final = min over bands. +// PRNG (FUN_180529fe0 prologue :515-583): LCG state 0x2404e0 advances by round +// offsets; fVar30 (scale coeff) = (int)(LUT[s+1]*LUT[s]+0.001), DAT_18262b5c8/ +// b704/b700 == 1 (VA-linear dump; earlier 0.4552/0.6089/0.6070 was a bad offset). +// At live state 112 this yields fVar30 == 1.0 deterministically over many frames. class FramedDetector { public: FramedDetector(size_t nfft, float sample_rate); @@ -36,6 +40,7 @@ private: size_t nfft_; float sample_rate_; double wsum_; + int prng_state_ = 112; // 0x2404e0 (live snapshot value; advances per frame) std::vector bands_; std::vector> res_; // per band, per bin |2B/A| diff --git a/handoff/NOTES_LEVEL.md b/handoff/NOTES_LEVEL.md index f3a53c5..29c8dc7 100644 --- a/handoff/NOTES_LEVEL.md +++ b/handoff/NOTES_LEVEL.md @@ -884,3 +884,24 @@ exact LCG sequence per frame. scale already calibrated (t1kq -0.43 dB). 4. combine/accumulator (0x5407c8) exact feedback (1500Hz comb err +6.4 dB) 5. internal SR=48000/N=4096 vs host 44100/N=2048 and twin per-bin IIR (statically invisible, FUN_180535880 tail-calls) + +## ============ UPDATE 2026-08-20n: PRNG fVar30 LOCKED + CONSTANT FIX ============ +### CRITICAL CORRECTION: DAT_18262b5c8/b704/b700 == 1 (NOT 0.4552/0.6089/0.6070) +soothe_mem.bin is a VA-linear dump: file offset = RVA = VA - 0x180000000. +Earlier 0.4552/0.6089/0.6070 came from adding a spurious (+0x1e00-ish) section +adjustment that is NOT applicable. Verified at raw=RVA=0x262b5c8/b704/b700: +bytes 01 00 00 00 => int 1. Code does cvtdq2ps => (float)1 = 1.0. All three = 1. +Verified constants at raw=RVA: 0x24c3c58=0.001, 0x24c3e28=0.8, 0x24c4674=-0.7, +0x24c4670=-0.5 (match NOTES). + +### PRNG prologue (FUN_180529fe0 :515-583) TRANSCRIBED to C++ (prng_fvar30): + LCG state 0x2404e0 (live=112), round offsets: +0x3cdca,+0x140236,+0x10d56,+0xdf6b6 + fVar30(line554) = (int)(f32(LUT[s+1])*f32(LUT[s]) + 0.001f) [b5c8=b704=1] + => at live state 112, fVar30 == 1.0 deterministically over 300 frames. + => scale step: level *= (fVar30/0x1a0)*0x540870*0x54088c = /2048*440.95*1.0. + scale is NOT effectively randomized for this LUT/state. + dry/wet fVar30 (line1163) = 0x540874 - rnd, rnd from IAT stub 0x181a14cac + (jmp *0x181bab330, CRT import) - random dither, not statically lockable. + +### framed_model.cpp: scale coeff now computed via prng_fvar30() (prng_state_=112), + not a hardcoded constant. t1kq still -0.43 dB at level_scale=600 (unchanged).