- Инфраструктура: RTTI-дампы (rtti_dsp/full.json), декомпиляции DSP-классов (decomp_*.txt), Ghidra-скрипты (Dump*.java, ImportRtti*.java, Diag.java), depthcurve/curve_fits LUT. - Поведенческая модель sim_v5.py + sim.py (RMSE ~0.3dB), утилиты (measure, tt_sweep, patchparam, sweep, harness_*, verify_sim). - summary.md + roadmap.md (контракт из manual M1-M12, топология пайплайна из OCR, фазы A-C). - pipeline_ocr.txt: OCR диаграммы Appendix A (mid/side ручка, trim/mix/bypass порядок).
8.6 KiB
8.6 KiB
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·(1−g)+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.
Контракт из 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·(1−g) |
| 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 = x−wet; 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).
Фаза 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: если FFTW — нужна та же сборка; свой radix-2 — воспроизводим напрямую (A.3).
- Хост-зависимость: уточнить точный размер буфера/фрейма (рендеры при разных RENDER_RANGE должны давать одинаковые байты).
- Stereo: все текущие свипы mono; для бит-exact графа M8 нужны стерео-рендеры (link/balance/ms).
Открытые вопросы
- Окна/oversample детали — из декомпиляции (A.6) или требуется доп. замеры.
- Стерео-верификация (M8) — приоритет mono-путь или сразу стерео-граф.