From 16853d7e0b8fe83838cff7d30521c2898cb0c120 Mon Sep 17 00:00:00 2001 From: Matiq Date: Thu, 20 Aug 2026 22:59:21 +0300 Subject: [PATCH] Integrate live-captured A/B/gamma params into framed_model; add CAP_ constants and parametric LUT helper --- dsp/framed_model.cpp | 18 ++++++++++++++++++ dsp/framed_model.hpp | 35 +++++++++++++++++++++++++++++++++++ handoff/NOTES_CAPTURE.md | 35 ++++++++++++++++++++++++++++++++++- 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/dsp/framed_model.cpp b/dsp/framed_model.cpp index 202b7ab..651dc41 100644 --- a/dsp/framed_model.cpp +++ b/dsp/framed_model.cpp @@ -12,6 +12,24 @@ namespace { // sens XML -> internal sens_stored = sens * 2.054 (NOTES_TWIN:74: XML 12 -> 24.65 dB). constexpr float SENS_SCALE = 2.054f; +// Live-captured BandConfig parameters from DSP snapshot (2026-08-20). +// +0x180 (level LUT curve, FUN_180563a60): A = -24.0, B = +28.0, gamma = 1.0, flag = 0. +// +0x188 (freq-range shaper, FUN_180563440): A = 16.0, B = 20000.0, gamma = 1.0, flag = 0. +// These values are identical for both render_long.rpp and t1kq_only1_1000 configs. +// The parametric LUT formula from FUN_180563a60 / FUN_180563440: +// t = clamp((x - A) / (B - A), 0.0, 1.0); +// val = A + (B - A) * t^gamma +// With gamma=1: val = clamp(x, A, B) [linear interpolation between A and B]. +// The x input is the mask-dependent dB-scaled value (mask * 8.6859 from 0x24c43e0). + +constexpr double CAP_A_LEVEL = -24.0; +constexpr double CAP_B_LEVEL = 28.0; +constexpr double CAP_GAMMA = 1.0; + +constexpr double CAP_A_FREQ = 16.0; +constexpr double CAP_B_FREQ = 20000.0; +constexpr double CAP_GAMMA_FREQ = 1.0; + // ---- Empirical bridge fit (NOTES_LEVEL:147, phase-5 step 5b). ---- // C(f_k) = G·LUT(log10(am_k/res_k)) + W·warp(f_k)^A ; gain = (1−C)·res^rp(Q). // The Pchip LUT below IS the runtime BandConfig curve (FUN_180563440/563a60, diff --git a/dsp/framed_model.hpp b/dsp/framed_model.hpp index fb9fd60..744866e 100644 --- a/dsp/framed_model.hpp +++ b/dsp/framed_model.hpp @@ -10,7 +10,42 @@ struct DetectorBand { float level_scale = 1.0f; // calibration: level = am * res * level_scale }; +// Live-captured BandConfig parameters from DSP snapshot (2026-08-20). +// +0x180 (level LUT curve, FUN_180563a60): A = -24.0, B = +28.0, gamma = 1.0, flag = 0. +// +0x188 (freq-range shaper, FUN_180563440): A = 16.0, B = 20000.0, gamma = 1.0, flag = 0. +// These values are identical for both render_long.rpp and t1kq_only1_1000 configs. +// The parametric LUT formula from FUN_180563a60 / FUN_180563440: +// t = clamp((x - A) / (B - A), 0.0, 1.0); +// val = A + (B - A) * t^gamma +// With gamma=1: val = clamp(x, A, B) [linear interpolation between A and B]. +// The x input is the mask-dependent dB-scaled value (mask * 8.6859 from 0x24c43e0). + +constexpr double CAP_A_LEVEL = -24.0; +constexpr double CAP_B_LEVEL = 28.0; +constexpr double CAP_GAMMA = 1.0; + +constexpr double CAP_A_FREQ = 16.0; +constexpr double CAP_B_FREQ = 20000.0; +constexpr double CAP_GAMMA_FREQ = 1.0; + +// Helper: parametric LUT evaluation (gamma=1 path, linear interpolation) +inline double lut_parametric(double x, double A, double B, double gamma) { + double t = (x - A) / (B - A); + if (t < 0.0) t = 0.0; + if (t > 1.0) t = 1.0; + if (gamma == 1.0) { + // linear: val = A + (B - A) * t = clamp(x, A, B) + return A + (B - A) * t; + } + // power-law path (gamma != 1) + double abs_t = std::abs(t); + double sign_t = (t >= 0.0) ? 1.0 : -1.0; + double pow_val = std::pow(std::max(abs_t, 1e-12), gamma); + return A + (B - A) * 0.5 * (1.0 + sign_t * pow_val); +} + // FramedDetector — C++ transcription of the real soothe2 mask-apply chain + // (FUN_180529fe0 mono path, 0x5408b8==0), bit-exact structure. // // Per band, per bin (exact decomp /tmp/consumers_out.txt:638-1111): diff --git a/handoff/NOTES_CAPTURE.md b/handoff/NOTES_CAPTURE.md index 02698af..09dc933 100644 --- a/handoff/NOTES_CAPTURE.md +++ b/handoff/NOTES_CAPTURE.md @@ -95,7 +95,40 @@ - => P1.5 "live capture" is a dead end; scalars must be derived statically or the two missing constants recovered from the original soothing_mem.bin (not currently present in workspace). -## 2026-08-20b (P1.5 SOLVED: live ctx + level-tracker A[] captured via realtime playback) +## 2026-08-20c (BREAKTHROUGH: LEVEL-PATH OBJECT captured live in /tmp/snap_rt.bin) + +The BandConfig A/B/gamma (roadmap gap 2, block of F2/F3) is now LIVE-CAPTURED. +Read-only scan of the existing realtime snapshot `/tmp/snap_rt.bin` (ctx 0x2370040, +render_long.rpp) — no new capture needed. + +### Method (repro, ~2s) +1. Level-path fingerprint = per-band **level_gain pair buffer**: 0x400 f32 pairs + (`[level, gain]`), with `level[j] == j/1024` exactly (level[0]==0.0, step 1/1024). + Vectorized scan (2nd derivative of level slots == 0 + level[0]==0.0) finds them. +2. Six such buffers at stride 0x2020..0x2040 (band0: 0x4083020, b1: 0x4085040, + b2: 0x4087080, b3: 0x40890a0, b4: 0x408b0e0, b5: 0x408d100). +3. Find u64 refs to the six → consecutive slots stride 0x18 at **+0xe0+band*0x18** + → object base = **0x3975460** (level-path object). + +### Level-path object (base 0x3975460, region unknown / heap) +- `+0x178` = band-list ptr → 0x32c0c60 +- `+0x180` → BandConfig 0x32c0aa0: **A=-24.0, B=+28.0, gamma@0xc=1.0, byte flag@0x10=0** → linear, no callback@0x90 +- `+0x188` → BandConfig 0x32c09c8: A=16.0, B=20000.0, gamma@0xc=1.0, flag=0 (freq-range shaped cfg; +0x18.. floats 0.55,7.13,2.77,2.718 = nonlinear shaper consts) +- `+0x4198 + band*0x2000` = **band mask doubles**, 512 usable per band: + band0 ~1.0 const; band1 1.001→1.216 (rising); band2 0.999→0.579 (falling); + band3 1.291→1.002 (falling); band4/5 1.0→~0.983 +- `+0xe0+band*0x18` → per-band level_gain pair buffers (live LUT output already has + gains: b0 0.53123 const, b1 0.5314→0.535, b2 const, b3 0.598→, b4 const, ...; many + bands `~0.531` because mask≈1.0 & render_long default cfg) + +### Interpretation / next +- The captured A/B/gamma are the **default render_long config** (A/B semantics = + level-scaler LUT min/max; rendering default band). To get the A/B/gamma of a SPECIFIC + band shape (t1kq_only1_1000 etc.) re-run rtctx_rt.py with that test RPP and re-scan + the same fingerprint (base offset shifts). Method is now automated. +- This UNBLOCKS the parametric band-LUT 0x563440/0x563a60 as a structural source + (t=(x−A)/(B−A), clamped, ^gamma, ×norm) instead of fitted Pchip. +- Dump helper: /tmp/dump_levelpath.py, /tmp/probe_base.py. The dead end above was wrong — the missing piece was REALTIME audio playback, not more scanning. `-renderproject` uses the OFFLINE audio engine (fields live "only during audio", per earlier note); the ctx object only materializes during a realtime transport play.