Files
soothe2-re/roadmap.md
T

124 lines
12 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.
# Roadmap: bit-exact реверс DSP-ядра oeksound soothe2 (v1.1.2)
## Цель
Воспроизвести DSP-путь soothe2 в виде **собираемого standalone C++** с **побайтово идентичным**
выходом (bit-exact) на верификационных свипах, с пониманием логики и подписанными функциями.
## Результат
`re-tools/dsp/``*.cpp/*.h` (классы DSP, подписаны), `CMakeLists.txt`, `harness.cpp`
(WAV16 → рендер → WAV24), `dsp_notes.md` (карта функция↔смысл, константы, LUT),
`verify_bit_exact.py` (прогон всех свипов, побайтовое сравнение).
## Задел (уже есть)
- Ghidra-проект `ghidra-proj/soothe2.rep` + скрипты `Dump*.java`/`ImportRtti*.java`/`Diag.java`.
- RTTI иерархия DSP: `SpectralProcessor<float,7,1>`, `Soothe2ModuleBase<float,1>`,
`Soothe2Module<float,1>`, `FilterGraph<float,6,0x400>`, `FilterGraphGrid<float>`,
`DigitalFilter<float,0xBA,1>`, `IIRFilterExtended<float,1>`, `AudioProcessingModule<float,1>`
(`rtti_dsp.json`, `rtti_full.json`).
- Декомпиляция vtable-слотов DSP-классов (`decomp_dsp.txt`, `decomp_vtables.txt`,
`decomp_candidates.txt`) — 6634 строки C, 127 неразрешённых `FUN_*`, ~30 констант `DAT_1824c*`.
- Поведенческая модель `sim_v5.py` (RMSE ≈ 0.3dB): base_red, W(f)=6.02·min(1,sens/12)·H,
H=1/√(1+(Qeff·A)²), Qeff=1.54·q^1.33, sat(level), Q_notch=qn·(1g)+1, per-frame env, WOLA-маска.
- LUT: depthcurve (207 float @0x1826170e8, `0.302+0.698·sin(π/2·x)^0.94`, r²=0.99999).
- Рендер-свипы в `/home/m/soothe-bt/` (506 wav + 609 rpp) — эталон для bit-exact.
- BFS-замыкание call-graph от сидов: `fun_map.txt` (2035 функций), `decomp_funs.txt` (1640 декомпилировано,
312K), `consts.txt` (11602 констант) — после фикса `getInstructions()` в `DumpFuns.java`.
## Контракт из manual (`soothe2_ManualFAQ.pdf`, v1.0.0)
| # | Факт | Следствие для DSP |
|---|---|---|
| M1 | Soft/Hard: выбор режима меняет всё; depth 3.0 в soft ≠ hard (стр.7). Soft менее level-dependent | mode = глобальный препроцессор детектора (перемасштаб глубины/масштаба) |
| M2 | Depth — референтный dB (−18..18), реальная глубина до 60dB (стр.8) | вход depthcurve-LUT; clip 60dB = `red.clip(0,60)` в sim |
| M3 | Sharpness: выше = глубже и уже (стр.8) | Q_notch растёт с sharp; подтверждает `Q≈qn·(1g)` |
| M4 | Selectivity: выше = только сильные резонансы; 0 = «everything must go» (стр.9) | selectivity = отбор/порог пиков, число нотчей НЕ ограничивает |
| M5 | Attack/Release: референтные константы, **реальные времена частотно-зависимы**, атака быстрее на ВЧ (стр.11) | Env НЕ один one-pole; нужен частотный масштаб времени — замер τ(f) + код |
| M6 | Oversample = «расчёт reduction-фильтра в более высоком спектральном разрешении» (стр.11) | это интерполяция детекторной сетки → фильтра, НЕ up/downsample аудио |
| M7 | Resolution = «частота обновления детекции и фильтра» (стр.11), eco/high/ultra | период пересчёта коэффициентов фильтра |
| M8 | Stereo: link 100% = сумма каналов для анализа + общий фикс; 0% = dual mono; balance глоб+per-band; L/R vs M/S | детектор на sum; коррекция симметрична/раздельна |
| M9 | Trim: «регулирует ТОЛЬКО wet»; Delta = xwet; Mix 0..100% (стр.14) | порядок: detect→notch→trim→mix/delta/bypass |
| M10 | Банды: 2 cut + 4 general; general: peak/shelf/reject/tilt (стр.17-19) | `FilterGraph<float,6,0x400>`, `DigitalFilter` мультитипный |
| M11 | Кривая = «inverse EQ / side-chain EQ», сумма band-кривых = белая кривая (стр.17) | `red(f)=base+ΣW_i·H_i` подтверждён |
| M12 | Sidechain: детект по второму входу; Input trim — скрытый предусилитель анализа (стр.26) | analysis имеет отдельный вход/гейн — граф с 2 входами |
## Топология пайплайна (Приложение A, стр.30 — OCR `pipeline_ocr.txt`)
```
main inputs ──┐
sidechain ────┤ (sidechain enabled?)
input trim ──► analysis (детекция; depth/sharpness/selectivity; EQ curves из per-band balances)
stereo apply + balance (channel link + global balance)
ms encode? ──► processing (нотч-синтез в M/S) ──► ms decode?
mix ──► bypass? ──► output
```
- **mid/side ручка**: обработка в M/S-области (`ms encode?`/`ms decode?`) — стерео-путь подтверждён диаграммой.
- GUI/visualisation (depth/sharpness/selectivity, EQ curves, per-band balances) — побочная ветвь, в DSP-ядро не входит (кроме параметров).
## Фазы
### Фаза 0 — Снятие диаграммы пайплайна (сделано)
0.1. OCR стр.30 (`tesseract`, PNG в `/tmp/opencode/manual/p30_s4.png`) → `pipeline_ocr.txt`. ✅
### Фаза A — Полный статический RE (Ghidra headless)
- A.1. Декомпилировать все 127 `FUN_*` из vtable-слотов 8 DSP-классов → полный `processBlock`-путь.
- A.2. Извлечь float-константы `DAT_1824c*` + все LUT-таблицы в `.data` (поиск массивов float).
- A.3. **Идентифицировать FFT** (twiddle/бит-реверс/радикс) и окно (формула `sin²` vs LUT) — ключ bit-exact.
- A.4. Найти частотно-зависимые attack/release (M5): функции масштабирования времени по частоте.
- A.5. Найти oversample/resolution-путь (M6/M7): интерполяция сетки, период обновления.
- A.6. Сопоставить топологию с диаграммой (0.1) и stereo/link/balance (M8).
### Статус фазы A (~40%)
- **A.2 константы — готово**: `consts.txt` (11602 из инструкций BFS-замыкания, 2670 в DSP-диапазоне
0x1824c00000x182700000) из повторного прогона `DumpFuns.java`. Точная double/f32-интерпретация —
`consts_double.txt` (чтение PE напрямую, `.data` vs `.rdata` через RVA).
- **A.3 ОКНО — найден**: `FUN_1805356f0` генерирует **Hann** `w(i)=0.5·(1cos(2πi/N))`
(double 2π @0x1824c4e00/4248, 1.0 @4da0/4140, 0.5 @4c90/4050; хвост через `cos`, чётные пары через
SIMD `divpd`+`thunk_FUN_181a114e0(=cos)`). Размер N: `FUN_18052e130`
`N = 2^floor(log2(sr/44100))·N0` (44100 @0x1824c45ec, 2.0 @41e8). **Нормализация окна** в
`FUN_18052df60`: сумма по окну → `scale=1/(mean/N)`, потом `/= (fsize @+0x1ac)`.
- **A.3 FFT — НАЙДЕН (свой)**: Vorbis-планировщик `FUN_181384180` — не тот (это декодер).
Настоящий DSP-FFT: `FUN_180008140` = init FFT-spec (`N=1<<log2`, масштаб `DAT_181c5cd10(=1.0)/N`
для inverse, ветки float/double/complex), строит twiddle/bitrev через `FUN_18003a2a0`
(radix-2/3/5 для малых N), `FUN_18003f1a0`+`FUN_18003f600` и `FUN_18003b6c0` (N≥2^18: бит-реверсовая
пермутация с XOR-маской знака `DAT_181c5e4e0`). Внешних lib (kissfft/fftw/MKL) нет.
Xrefs на init только из диспетчерской таблицы `182615ef0` (+ .pdata) — вызов косвенный.
- **Диспетчерские таблицы (PACE/ModuleDecryptor)**: все DSP-примитивы вызываются через
`thunk_FUN_181ba94b0@0x180001850` → слот из таблиц `PTR_FUN_1826159c8/5a88/6408...` по глобальному
индексу `DAT_1826159a0`. 36 таблиц, 245 уникальных функций-целей (`dispatch_targets.txt`).
Примеры ядер: `FUN_1800025e0` = double-вектор add (развёртка по 16), `FUN_18003fa20` =
комплексное умножение a[i]·b[i] (фрейм-пар, 425б). Для bit-exact нужен порядок double-операций.
- **Константы детектора**: `10^((dB)/20)` через `expf((30·X90)·0.115129255)`,
`0.115129255=1/(20·log10e)`, `6.907755=ln1000`, `0.707`/`0.51`/`0.54`/`0.001`,
маппинг резонанса `(x0.707)·0.5+1` в `FUN_1805316e0`.
### Фаза B — Реконструкция C++ (bit-exact)
- B.1. Классы 1:1: `Soothe2FilterGraph::processBlock`, `FilterGraphGrid`, `DigitalFilter`,
`SpectralProcessor` (STFT), `AudioProcessingModule`, `IIRFilterExtended`, env-модуль с
частотным масштабом (M5), интерполятор oversample (M6), периодичность resolution (M7).
- B.2. Точный порядок FP-операций float32, без перестановок; буферный фрейминг независимо от блока хоста.
- B.3. Имена по смыслу + подписи, сверяемые с моделью sim_v5 (base_red, W, Qeff, sat, Q_notch).
- B.4. Модули по manual: mode (M1), input trim/sidechain (M12), trim/delta/mix/bypass-порядок (M9),
stereo/link/balance + ms encode/decode (M8).
### Фаза C — Сборка и bit-exact-верификация
- C.1. `libsoothe2_dsp.so` + CLI-харнесс (WAV16→рендер→WAV24, как Reaper).
- C.2. Критерий: каждый свип (`trk_*`, `wf_*`, `qmap`, `sens`, `lvl`, `neut`, `al`, `psh`,
`dual`, `pair`, `chirp`, `burst`, `tj`) — **побайтовая идентичность** int24 PCM с рендерами.
- C.3. Итеративный цикл diff → локализация блока → фикс → повтор.
## Риски
- **FFT bit-exact**: свой планировщик есть только у Vorbis-декодера; DSP-STFT-FFT ещё не найден (A.3) —
если свой radix-2 — воспроизводим напрямую; главный нерешённый риск фазы A.
- **Хост-зависимость**: уточнить точный размер буфера/фрейма (рендеры при разных RENDER_RANGE должны давать одинаковые байты).
- **Stereo**: все текущие свипы mono; для бит-exact графа M8 нужны стерео-рендеры (link/balance/ms).
## Открытые вопросы
1. Где реальный DSP-STFT FFT (не Vorbis/не внешний lib)? Искать большие функции с butterfly/стадиями
в 18052*/18053* или через трассировку вызовов от `processBlock` спектрального процессора.
2. Окна/oversample детали — из декомпиляции (A.6) или требуется доп. замеры.
3. Стерео-верификация (M8) — приоритет mono-путь или сразу стерео-граф.