# soothe2-re Обратный инжиниринг DSP-ядра **oeksound soothe2** (VST3, Windows x64) → проверяемая реконструкция на C++ с **bit-exact** целью. Цель — понять, как именно плагин считает подавление резонансов (уровневый детектор, маска, фильтр), и воспроизвести это дословно. Текущий активный канон — C++ `FramedDetector` (`dsp/framed_model.cpp`): real mask-apply цепь с live-таблицами. Канонные команды и метрика — в [`AGENTS.md`](AGENTS.md). --- ## Статус (2026-09-02, chain919) — ЕДИНСТВЕННЫЙ ИСТОЧНИК TOTAL **Bridge (`framed_test` 44.1k): TOTAL 1.594 dB** (`scripts/baseline_bridge.json`, guard `--tol 0.25`). **Структурный `render48k` 48k/4096 L/R (`RT_VLAW=1 RT_SYN=1 RT_NOWARP=1 RT_NOIIR3=1 RT_IIR12=0`): TOTAL 2.689 dB** (dual 2.04, t1k 5.43, max `6.8`). Исторический канон `0.341` (24mm14, `f40f41e`) недостижим на текущем `HEAD` (L/R `e343b0a` + chain gated `RT_CASC=0`); требует перекалибровки `per-fc`/`EQ`. Guard: `python3 scripts/corpus_structural.py` + `python3 scripts/corpus.py --compare scripts/baseline_bridge.json --tol 0.25`. Chain 9–19 интегрирован (`RT_CASC=1` gated, IIR4 double + FIR min-phase) но некалиброван (`31.6` при включении, блокер — входной формат level vs cut). Следующий шаг — калибровка chain по live-dump/`ph*.npz` (BLOCKMAP:285). Детали — `handoff/NOTES_LEVEL_INDEX.md`, `.opencode/plans/chain919.md`. **Цель — bit-exact** (гейт = все параметры до декомпа + корпус в шумовой пол). Декомп ~95%, `handoff/nls_dasm/` ~140 `.dis`. **Применение декодировано**: ``` mask(b) = 10^(−cut_D(b)/20) ← вещественная, per-bin multiply cut_D(b) = α·ln(1+lvl_raw EQ(b)/β)+c [+Δ content-aware, lvl EQ before detector] lvl_raw = am/res·scale · W_eq(fc,q,sens) (W=10^(sens·H·0.3/12/20), H=1/√(1+(1.54q^1.33·A)²)) слой = STFT БЕЗ синтез-окна (RT_SYN=1), EQ до детектора (pipeline_ocr) ``` Калибровки: α/β/c контент-зависимы (dual `3.22/0.49/0.54 Δ6.92` rms 0.016), q не влияет (`24kk`), sens линейно, `fc`-геом через `W_eq` (`24mm14` `R bandpass`), `dual q1.0` misclass пофикшено `has_second_peak+maxlvl>2` (`dsp/framed_model.cpp:331`), `t1k_500` `4.5/0.35` + `comb 0.05/5.0`. - **dual+EQ**: исторический `0.341` (канон `f40f41e`) сейчас `2.689` на L/R `e343b0a` — регресс из-за смены M/S→L/R + chain gated; per-fc `800/1200` и EQ требуют перекалибровки. - **Буфер FIR@540668** — `exp(scratch)` напрямую (`24s`), мин.-фазовое `exp(s−iH(s))`. - **Bigkernels** IAT: `1803a06a0 / 180296c80 / 180323f20 / 1802dc0e0` (`handoff/BLOCKMAP_529fe0.md:540`). ### Главное за 2026-08-24…28 (24j–24mm14) 1. **Применение = побиновный multiply** на вещественную маску; «×1.805» = `0.984×1.8345` (экспоненты стадий). 2. **Закон `α·ln1p(L/β)+c`** — три независимых калибровки; константы контент-зависимы. 3. **Слой STFT без синтез-окна** (`RT_SYN=1`); `WIN_WINDOW` 0.5→0.8 за 2049 сэмплов. 4. **GUI/аудио разделение**: `FUN_180563a60` — GUI-ветка; аудио-компрессия в шагах 9–19 `BLOCKMAP`. 5. **Dataflow 9–16**: `vec6f8=bands−ACC`, fma тройками `(re,im,coef)` ATT/REL, `th2000`=array-mul, шаг 12=COPY. 6. **Детекторный каскад `180529c60` (vt+0x28)**: `|z| → Haar [0.25,0.5,0.25]×2 → peak/sin → w=1/inner → blend 5407a8`. 7. **RFFT до df0 бит-точна** (`th1a90/th2180` + `buf548` scale 2^-12, `24mm9` 0.0065 dB). ```bash # Сборка и канонные команды (см. AGENTS.md — runbook): cmake -S dsp -B dsp/build && cmake --build dsp/build --target framed_test render48k ./dsp/build/render48k /home/m/soothe-bt/tone1kq.wav /tmp/o48.wav 1000,0.99999785,12 python3 scripts/corpus.py --compare scripts/baseline_bridge.json --tol 0.25 python3 scripts/corpus_structural.py --vs-bridge scripts/baseline_bridge.json ``` ### Открытые bit-exact пробелы (приоритет → `BITEXACT_PLAN.md`) 1. **Каскадный симулятор шагов 9–19** — dataflow готов (`24hh/24ii`), тела bigkernel'ов известны, rms ~0.42 на угаданных формах → оп-за-оп транскрипция + `sc_*` датасеты. 2. **k-маппинг фронтенда** (twin/am, `k=0.403 ∀q≥2`, `24x`). 3. **Δ-правило вторых пиков** из pre-combine. > Исторический блок B.1…B.15 (`framed_render.py`, Pchip, `res_power`) — см. `handoff/archive/NOTES_LEVEL_2026-08-18_2026-08-23.md` и `roadmap.md`; не канон. --- ## Структура репозитория ``` re-tools/ ├── README.md ← вы здесь (ЕДИНСТВЕННЫЙ источник TOTAL) ├── AGENTS.md ← runbook: сборка, метрика, env-флаги, tooling hazard ├── BITEXACT_PLAN.md ← план к bit-exact (3 шага, критерии, риски) ├── roadmap.md ← журнал B-фаз (B.1…B.15, свёрнут; детали → archive) ├── dsp/ ← реконструкция DSP-пайплайна на C++17 │ ├── framed_model{.cpp,.hpp} ← ГЛАВНЫЙ: mask-apply цепь (канон) │ ├── framed_test.cpp ← CLI bridge-рендер (N=2048, SR 44100) │ ├── render48k.cpp ← структурная цепь 48k/4096 (resample → chain → resample) │ ├── rt_mask_tables{.hpp,.cpp}, rt_weights{.hpp,.cpp} ← live-таблицы (IIR A/B, warp) │ ├── twin{.hpp,.cpp} ← twin FUN_180535880 (float-parity) │ ├── levelpath/freqpath/fftconv/vlog/leveltrack/fn529fe0 ← расшифрованные модули │ ├── fft*.cpp, twiddle_*.cpp/hpp, phase_table.*, cody_waite.hpp │ └── CMakeLists.txt ├── handoff/ │ ├── NOTES_LEVEL.md ← живой журнал (голова 24mm5+; хвост → archive/) │ ├── NOTES_LEVEL_INDEX.md ← оглавление журнала по датам/темам │ ├── BLOCKMAP_529fe0.md ← карта метода FUN_180529fe0 (актуальна) │ ├── NOTES_TWIN.md ← twin краткая справка (детали → dsp/twin.cpp) │ ├── NOTES_CAPTURE.md ← registry heartbeat, live-таблицы (сжато) │ ├── archive/ ← история: NOTES_LEVEL_2026-08-18_2026-08-23.md, │ │ SESSION_HANDOFF_2026-08-18.md, summary_v4.md │ └── nls_dasm/ ← 134 дизассембла (f_563440, f_563a60, f529fe0, twin, fft) ├── scripts/ │ ├── corpus.py / corpus_structural.py ← харнессы (guard --compare) │ ├── rendersnap2.py, campaign.py, disasm_func.py, iat_name.py ← инструменты 24j+ │ └── lawfit22r.py, resalpha.py, cascade_sim.py, wine_*trace.py ├── *.java ← Ghidra-скрипты (DumpFuns, ImportRtti …) ├── soothe_mem.bin ← дамп памяти (вне git, VA−0x180000000) ├── rwin_{A0,A1,B0,C0}.npy, r_freqaxis.npy ← живые таблицы (48k) └── framed_render.py, model_*.py, sim.py ← исторические B-модели (не канон) ``` ## Документация | Документ | Содержание | |---|---| | [AGENTS.md](AGENTS.md) | **Runbook**: сборка, метрика, env-флаги, tooling hazard | | [BITEXACT_PLAN.md](BITEXACT_PLAN.md) | **План к bit-exact**: 3 шага, критерии, риски, точка входа | | [handoff/NOTES_LEVEL_INDEX.md](handoff/NOTES_LEVEL_INDEX.md) | **Оглавление журнала** по датам/темам → `NOTES_LEVEL.md` / `archive/` | | [handoff/NOTES_LEVEL.md](handoff/NOTES_LEVEL.md) | Живой журнал (голова 24mm5+; хвост → `archive/`) | | [handoff/BLOCKMAP_529fe0.md](handoff/BLOCKMAP_529fe0.md) | Карта метода FUN_180529fe0 (актуальна) | | [handoff/nls_dasm/](handoff/nls_dasm/) | 134 дизассембла декомпа | | [roadmap.md](roadmap.md) | Журнал B-фаз (свёрнут, детали → archive) | | [handoff/NOTES_TWIN.md](handoff/NOTES_TWIN.md) | Twin краткая справка (детали → `dsp/twin.cpp`) | | [handoff/NOTES_CAPTURE.md](handoff/NOTES_CAPTURE.md) | Registry heartbeat, live-таблицы (сжато) | | [handoff/archive/](handoff/archive/) | История: `NOTES_LEVEL_2026-08-18_2026-08-23.md`, `SESSION_HANDOFF_…`, `summary_v4.md` | ### Тестовый корпус `/home/m/soothe-bt/` (вне git) ~600 рендеров REAPER (`.rpp` + `.wav`). Ключевые наборы: | Префикс | Что измеряет | |---------|-------------| | `dual_b1q_*` | 2 тона (500+2000), q 0.1…10 → **парадокс red2000>red500** (решён: аддитивный warp) | | `al_*` | уровневой свип (fc=1000) → прямое измерение LUT-кривой | | `t1kq_*`, `t1k_*` | 1 тон, fc-скан, уровни −18/0 dBFS → форма полосы | | `burst500_b1` | основной эталон: burst 500 Гц, band1 fc=500 mode=1 sens=12 | | `tone1k`, `tone1kq`, `dual` | входные тоны (0 / −18 / −7.1 dBFS) | --- ## Историческая численная модель (B-фазы; канон теперь — C++ FramedDetector, см. выше) ```python # per-frame, per-bin (framed_render.py — исторический канон B.15) xv = log10(A_k / res_k) # A_k = 2|X_k|/wsum (twin-env), res = |2B/A| case8 C = G * LUT(xv) + W * warp(f_k)**A # additive mask (НЕ мультипликация warp·LUT) gain = max(1 - C, eps) * res_k**rp # rp = rp0 * Q**drp (res_power) ``` - LUT — Pchip, узлы из joint-фита (dual+al_*) **или** свободные 8 узлов (B.15 → mean 0.027); - warp — эмпирический `0.87·7.942·x/(7.942+x)`, x=f/2000 (аппроксимация runtime-вычисления FUN_180563440); - rp(Q)=0.0275·Q^0.2159 (Q-dep rp, B.14); - B.15: G/W/A/rp0/drp = 0.9752/0.3394/1.0222/0.0254/0.2231; LUT KX=[−0.8..1.0]. --- ## Как всё это воспроизвести 1. **Достать бинарь**: установить soothe2 (Windows VST3) под yabridge, запустить `dump_soothe.py` → `soothe_mem.bin` (или взять `.vst3`, выдернуть секции). 2. **Декомпиляция**: `analyzeHeadless soothe_x64 -process soothe_mem.bin -noanalysis -postScript .java` (image_base=0, блок `ram`=[0x180000000,…], адреса = RVA; смещение в файле = VA−0x180000000). 3. **Рендеры**: `sweep.py` генерит `.rpp`, `reaper -renderproject` выдаёт `.wav`. 4. **Анализ**: `render_parity.py` / `framed_render.py` сравнивают модель с реальными рендерами (steady-state tone-замер, тримнутая метрика). --- ## Чего не хватает / следующие шаги (bit-exact) → `BITEXACT_PLAN.md` 1. **Каскадный симулятор шагов 9–19** (приоритет №1) — см. `BITEXACT_PLAN.md:1`. 2. **k-маппинг фронтенда** twin/am (приоритет №2). 3. **Δ-правило вторых пиков** (приоритет №3).