Files
soothe2-re/handoff/SESSION_HANDOFF.md
T

138 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SESSION HANDOFF — soothe2 detector reverse → bit-exact render
Prepared: 2026-08-18 (checkpoint end-of-session: commits c8f97e4 + 60bf3a2 pushed). Start: READ THIS FIRST.
## 1. Objective (unchanged since session 1)
Transcribe the decoded soothe2 detector ("twins" 0x180535880/0x180536f90, 2nd-order resonator) into
C++ and reach **bit-exact render parity** with the Reaper reference wavs in `/home/m/soothe-bt/*.wav`
(checking dB/magnitude parity first, then byte-diff).
Path A (bit-exact) chosen. Phase 0,1,2 done. Phase 3,4 advanced. Phase 5 (render diff) is next.
## 2. PROOF OF STATE — run this first (5 min)
Everything below must reproduce. If `twin_check` fails, the transcription moved stale.
```bash
cd /home/m/re-tools/dsp && cmake --build build && ./build/twin_check
# expect:
# max rel err = 1.268e-05, PASS = yes (float-parity)
# max sweep rel err = 1.233e-05, SWEEP PASS = yes, exit 0
```
`build/soothe2_dsp.so` and `build/twin_check` are current. CMakeLists already has `twin.cpp` + `twin_check` executable.
## 3. TRANSCRIPTION STATE (summary — details in NOTES_TWIN.md)
- `dsp/twin.hpp` + `dsp/twin.cpp` = twin kernel FUN_180535880:
- build_twin_coeff (FUN_180533ec0 double pipeline → cvtpd2ps floats)
- generator formula (confirmed): `fVar1=sqrtf(param_5)`; `w0=max(2.0,freq)·2π/fs_total`;
`p=(sin(w0)·0.5)/Q`; `A=[1+dVar5, dVar2, 1dVar5]`, `B=[1+param_4, dVar2, 1param_4]`,
`dVar2=cos(w0)·−2.0` (DAT_1824c46b0=2.0).
- cplx_div_exact (rcpps+Newton: `ref=r0·(2den·r0)`, NaN-guard cmpeqps+movmskps, numerator B·conj(A))
- cplx_mul_exact (vfmaddsub213ps form `re=fma(br,ar,bi·ai)`, `im=fma(br,ai,bi·ar)`)
- twin_apply: conj(z1) mirroring 0x1800018b0, z2=z1·z1, out=2·B/A
- **OPEN phase question (byte-exactness)**: conjugate shaping — (-α+π/2) vs (-α) axis. Magnitudes match
either way; final proof needed via phase of a single-bin run before claiming byte-exactness.
## 4. GRID + CALLER (Phase 3 — details in NOTES_TWIN.md §Phase 3)
- Caller FUN_180536300 (decomp 6218, `caller_536300.dis`), scratch ≥52·N complex bytes:
+0..8N A-accum, +8N..16N B-accum, +16N..24N z-powers, +24N..32N rotor-in (filled 1.0),
+32N..36N phase ramp lVar1, +36N..44N rotor-out z1, +44N..52N lVar3(1.0)/lVar4(0.0)
- `0x18052da00(lVar1, scale=2π/(os·sr), N)` = ramp fill; `0x18052dbc0(param_2, lVar4, N)` cplx-interleave
→ out slots get (cos,sin) = e^{+iθ}.
- **Grid law**: `os=*(int*)(cfg+0x240080)=4` (mov DWORD PTR [rbx+0x240080],0x4 @0x18052ce3e),
`sr=*(float*)(cfg+0x24)=44100.0` → generator `fs_total=os·sr=176400`; per-cell phase `2π/176400`;
cell k ↔ freq k/os Hz (0.25 Hz steps). Phase-1 FS=44100 was a valid normalization (res depends on f/fc).
- twin always = FUN_180535880 (type-info compare equal); sibling FUN_180536f90 dead.
- case8: numBands `+0x814`=1, `+0x103`=1; `param_5=10^(sens_dB/20)`, `gain=sqrtf(param_5)=10^(sens_dB/40)`
→ fit gain=4.132 means stored `sens_dB@+0x101 ≈ 24.65`; freq=[band+0x804]=1000.0, Q=[band+0x80c].
## 5. LEVEL-WEIGHT FORMULA (Phase 4 — DECODED, NEGATIVE RESULT — NOTES_LEVEL.md §UPDATE 2026-08-18)
Exact formula from decomp 22330 (FUN_180530d30):
- `base=(2000/(sr·0.5))·iVar5/(bin+1)`, iVar5=NFFT/2+1
- `w8=powf(base,0.25)`
- `v=[0x540880]·0.25·w8·fVar12` (fVar12=4.0 if offline flag [0x5408b8], else 1.0)
- `q=1/(1+v/([0x540880]·4))` (2nd pair 0x540884: q2=1/(1+v2/[0x540884]))
- `dVar1=(sr/[0x1a0])·[0x1ac]·0.001`
- `w=0.1^(1/(max(q·v,floor)·dVar1))`; bufs: 0x5406b8=w, 0x5406c8=1w (and 0x5406d8/6e8 w/ 0x540884)
- consts: c3d3c=0.25, c4334=4.0, c3d8c=0.5, c45b4=2000.0, c3f70=0.1 f32, c3e30=0.001 f64, c3f70=0.1
- **Numerically**: w(500)=w(1000)=w(2000)≈0 (1e-20..1e-0.07), complements≈1 → but the weights are STILL
APPLIED (as 1w ≈ 1) by FUN_180529fe0 (`0x5407c8[band] += 0x5406c8·res_upper + 0x5406e8·res_lower`,
thunk 003c40, kernel 0x1800752e0 = vfmadd213pd) — the form is weight·resonance, not dead code.
- **TILT analysis (2026-08-18, checkpoint NEGATIVE result)**: warp `0x5406a8 = 0.87·x/(1+x/K)`,
`K=exp(2.0723267)≈7.942`, `x=f/2000`, applied by FUN_180529fe0 as `mask *= 0x5406a8` (float, thunk 008700)
BEFORE the FFT-conv. warp: 500→0.211, 1000→0.409, 2000→0.773 (lin ratio 2000/500=3.67).
**BUT warp ≠ empirical tilt (ratio 1.27)**: `C(dB2000)=depth·warp(2000)·LUT_max = 0.864·0.772·0.667=0.445`,
yet red2000=15.2 dB needs `C=0.826` ⇒ warp alone CANNOT produce deep-2000 (dual_b1q). Empirical tilt is the
envelope of the BLEND term (0x5407c8 += weights·res + freq-axis 0x540698) + FFT-conv shaping, NOT warp —
simple tilt→warp substitution in model_lut.py is INVALID. Nothing else decoded yet closes dual_b1q.
- **FUN_180563ce0 decoded (2026-08-18)**: INIT of per-bin IIR level-trackers (0x156=342 bins, order=3.0f
0x40400000, coeff A/B from 0x24c4780/4790, strided fill; third pass +0xffd0 fills 0x40e00000=7.0f).
Not the update loop. Full disasm: `/tmp/opencode/f_563ce0.dis`.
- **Level-path map (2026-08-18, NOTES_LEVEL.md)**: 0x563440 (LUT curve +0x188, gamma, 6 band-slots, combine
→+0x2198, LUT pairs +0x98 at 0x3ff pts) + 0x56e3e0 twin-mask factory (N=1024, DOUBLE, LUT-ramp input) +
0x563ce0 IIR init. 0x563440 NOT in decomp_funs.txt (search via /tmp/opencode/f_563440.dis + level_notes.md).
- **DIAGNOSTIC BRIDGE DONE (2026-08-18) — model_fir.py**: реальная цепочка из FUN_180529fe0
воспроизводит 36 точек до rmse=0.236 dB БЕЗ эмпирического tilt:
`C(f) = g·LUT(log10(L0/res(f))) + w·warp(f)^a`, g=1.221, w=0.358, a=3.143.
- dual500-константа = res_band(500;fc=500)=0.117 Q-НЕЗАВИСИМ, не tilt;
- dual2000-глубина = АДДИТИВНЫЙ терм `w·warp^3.14` (на 1000 Гц вклад ≤0.021 — иначе t1k
рушится; на 2000 = 0.149) — это аккумулятор `0x5407c8 += weights·res + mask` (шаг 5),
НЕ мультипликация warp·LUT (та проваливается >10 dB);
- warp^~3.14 ≈ π — подозрение на кратный каскад (0x540698 freq-axis, ∏0x540688, двойной FFT);
- остаток 0.7 dB при Q=0.1 = форма LUT-колена 0.574, не закрывается per-bin → нужен FFT-уровень.
- **FFT-CONV FULLY MAPPED (2026-08-18, NOTES_LEVEL.md §2026-08-18c, /tmp/opencode/f_52b570.dis)**:
0x535a70 = dispatcher to base-CRT FFT (0x140a10/0x140a70); 0x540548/0x540550/0x540598 = FFT-plan
tables (plan 0x540530, built by 0x52dc30), NOT windows. Per-band loop 0x52b550-0x52b8b5:
mask→fwdFFT→invFFT→fill low/high (xmm13/xmm9 consts)→inv→cplx-op→fwd→`FIR *= 0x540658`→fill→inv→
`FIR[0]=1,FIR[1]=0``*=0x540888`→copy out.
**freq-axis 0x540698**: OFFLINE = constant scalar (NOT exp-formula — exp/rand = online dither).
**Window 0x540658**: only ONE direct ref in dump (read at 0x52b771), written only indirectly —
STATICALLY INVISIBLE → the only plausible source of warp^3.14/LUT-knee. Need runtime capture or
full-pipeline empirical closure.
## 6. PHASE 5 PLAN (updated 2026-08-18 — bridge done, tilt replaced, FFT mined out)
Decision (user): bridge FIRST. **DONE — bridge result above in §5.**
Status: step 2 DONE, step 3 PARTIAL (static analysis exhausted).
1. (15 min) Proof-of-state above; confirm twin + mdl files complete; repo at `60bf3a2`.
2. **Replace empirical tilt** in model_lut.py with `g·LUT(xv) + w·warp(f)^a`**DONE**, rmse 0.236 dB
reproduced, committed `c8f97e4`. Optional refinement fit (2 LUT-knots) reaches 0.167 but is overfit.
3. **Close the 0.7-dB gap**: FFT-conv loop mapped + freq-axis cleared (offline const) — **DONE/PARTIAL**,
committed `60bf3a2`. Remaining unknown = 0x540658 window content (static-invisible). Options:
(a) runtime capture of 0x540658, (b) skip and close empirically in full-pipeline step 5.
4. Runtime values: per-bin IIR level trackers (0x563ce0), 0x540880/884, `[0x1a0]/[0x1ac]`, cell count N.
5. Full pipeline + render diff vs `/home/m/soothe-bt/*.wav`: dB parity → byte parity.
NEXT SESSION START (recommendation): skip deeper FFT mining; go straight to step 5 full pipeline
(mask-chain already in model_lut.py B.12 at 0.236; freq-axis const; FFT-conv reduces to a per-bin
smoothing + 0x540658 shaping that can be fit/absorbed). Runtime capture of 0x540658 only if step 5
stalls on the Q=0.1 knee.
### STEP 5 STARTED (2026-08-18) — dB-parity harness DONE (commit f96bb42)
- `/home/m/re-tools/render_parity.py`: measures steady-state per-tone reduction DIRECTLY on the
reference wavs (Goertzel tone-amp over late steady window; handles 16/24-bit, mono/stereo).
NOTE: Goertzel must use the SEQUENTIAL update form (s2=s1;s1=s0;s0=v+cw*s1-s2) — the tuple-unpack
form is numerically unstable (overflows ~1500 steps).
- Validation: measured dual Q-scan == stored dataset (dual.wav is 4s mono 16-bit; renders 6s stereo 24-bit).
- **dB-PARITY RESULT (canonical B.12, 36 pts, real wavs): TOTAL rmse=0.268 dB**
(dual500 0.130, dual2000 0.387, t1kq 0.320, t1k 0.076).
residual structure: dual2000 -0.80@Q0.1..+0.36@Q10 (LUT-knee), t1kq +0.36..+0.26 (level region),
t1k ±0.1 (good). Refit (g,w,a)=(1.224,0.379,3.405)→0.264; +2 LUT-knots→0.203 (plateau).
- CONCLUSION: B.12 form plateau ~0.20-0.27 dB vs real renders; residual is structural (0x540658
FFT shaping + level-curve region), matches plan expectation. Re-measured-on-wav numbers differ
slightly from the stored model_lut.py dataset (t1kq ~+0.3 dB) — different steady-window method.
- Open: full PIPELINE frame-render (STFT + per-frame mask + time constants) is the remaining big
lift for byte-parity; dB-parity milestone achieved at 0.268 dB.
Candidates that may consume Phase 5 time: source of sens≈24.65 (host ×2 over XML 12.0 — not found in dump),
IAT\*0x181bab370 outside dump (non-blocking), final z¹ phase proof, the 0x563440 LUT curve (+0x188) values.
## 7. FILES LAYOUT
- `/home/m/re-tools/dsp/` — twin.{hpp,cpp}, twin_check.cpp, CMakeLists.txt, build/
- `/home/m/re-tools/model_lut.py` — model **B.12** (Q=xmlq, gain=10^(sens/20), depth 0.8639736175537109,
`C=g·LUT(xv)+w·warp^a`, g=1.221/w=0.358/a=3.143) — 0.236 dB bridge model; PCHIP LUT nodes frozen
- `/home/m/re-tools/model_fir.py` — bridge canonical source (rmse 0.236, committed b1066f3)
- `/home/m/re-tools/soothe_mem.bin` — memory dump, offset=VA0x180000000
- `/home/m/re-tools/decomp_funs.txt` — decomp: FUN_180536300 (6218), FUN_180530d30 (22330),
FUN_180533ec0 (123204), FUN_180529fe0
- `/home/m/re-tools/handoff/` — THIS DOC, NOTES_TWIN.md, NOTES_LEVEL.md, phase1/*.py, nls_dasm/*.dis
- `/home/m/soothe-bt/*.rpp` (decoder `/home/m/re-tools/dsp/...`; also `decode_rpp4.py` referenced) + `*.wav` refs