157 lines
11 KiB
Markdown
157 lines
11 KiB
Markdown
# 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).
|
||
|
||
---
|
||
|
||
## Статус (24mm14+, 2026-08-29) — ЕДИНСТВЕННЫЙ ИСТОЧНИК TOTAL
|
||
|
||
**Канон (bridge, `framed_test` 44.1k): TOTAL 1.594 dB** — честная 24-bit trimmed (`scripts/baseline_bridge.json`). **VLAW канон (структурный `render48k` 48k/4096, `RT_VLAW=1 RT_SYN=1 RT_NOWARP=1 RT_NOIIR3=1 RT_IIR12=0 RT_EQ=1`): TOTAL 0.341 dB** (dual 0.193/0.438, res 0.284, comb 0.81, t1k 0.36) — лучше bridge на `1.25`, max `1.17` (`t1kq_1200`). Guard: `python3 scripts/corpus.py --compare scripts/baseline_bridge.json --tol 0.25` + `corpus_structural --vs-bridge`. Детали — `handoff/NOTES_LEVEL_INDEX.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 решено**: `RT_VLAW+EQ` TOTAL 0.341 (канон `f40f41e`), per-fc `800/1200` ещё нужны (`0.341` vs `0.443` без них).
|
||
- **Буфер 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 <proj> soothe_x64 -process soothe_mem.bin
|
||
-noanalysis -postScript <X>.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). |