From 9abecb60d5a79a76543d0efd31b8bf64f7d3a9b9 Mon Sep 17 00:00:00 2001 From: Matiq Date: Tue, 18 Aug 2026 12:29:07 +0300 Subject: [PATCH] =?UTF-8?q?README:=20=D1=87=D0=B5=D0=BB=D0=BE=D0=B2=D0=B5?= =?UTF-8?q?=D1=87=D0=B5=D1=81=D0=BA=D0=BE=D0=B5=20=D0=BE=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82?= =?UTF-8?q?=D0=B0,=20=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D1=83=D1=80?= =?UTF-8?q?=D0=B0=20=D1=80=D0=B5=D0=BF=D0=BE,=20=D1=81=D1=82=D0=B0=D1=82?= =?UTF-8?q?=D1=83=D1=81=20B.10=20=D0=B8=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 145 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d26d24..15f0456 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,147 @@ # soothe2-re -Reverse engineering of oeksound soothe2 VST3 DSP core → bit-exact buildable C++ \ No newline at end of file +Обратный инжиниринг DSP-ядра **oeksound soothe2** (VST3, Windows x64) → проверяемая +численная модель и реконструкция на C++. + +Цель — разобраться, как именно плагин считает подавление резонансов, и воспроизвести +его поведение (в идеале бит-точно, но пока — с точностью ~0.1 dB на формах полос). + +--- + +## Статус (B.10, август 2026) + +**Детектор расшифрован структурно и проверен численно на двух независимых наборах +измерений (31 точка, совместный фит rmse = 0.109 dB).** + +- **Freq-path (форма полосы)** — близнец `FUN_180535880`/`FUN_180536f90` (резонатор + 2-го порядка). Коэффициенты case8 (mode=1 исполняется как case8!): + `w0=2π·fc/fs; p=(sin(w0)·0.5)/Q; A=[p·gain+1, −2cos(w0), 1−p·gain]; + B=[p/gain+1, −2cos(w0), 1−p/gain]; res(f)=|2·B/A|(f)`. +- **Level-path (глубина)** — per-band маска `= depth·tilt(f)·D0·(L0/res(f))^p`, + где `tilt(f)=1−w(f)` — per-bin спектральный вес из `FUN_180530d30` + (`w[i] = log10(1/exp(...·exp(2000/f_bin))...)`), `L0` — уровень входа, `p≈0.085`. +- **Ключевые факты**: + - `gain ≈ 10^(sens/20)` (sens=12 → gain≈4.1); + - частотная селективность — НЕ notch самой маски, а резонанс в знаменателе: + врез глубже там, где `L0/res` больше (на центре полосы); + - «парадокс dual_b1q» (red@2000 > red@500 при низком Q) решён: это частотный + наклон `tilt(f)` (растёт с частотой), а не ширина резонанса; + - warp-ось `0x540748` = сигмоида `8.3 − 7/(1+exp((x·20000−120)·(−0.01)))`, + а НЕ `f/(f+K)`, как ошибочно предполагалось раньше. + +Подробная история, гипотезы и все промежуточные находки — в [`roadmap.md`](roadmap.md). + +--- + +## Структура репозитория + +``` +re-tools/ +├── README.md ← вы здесь +├── roadmap.md ← журнал всех результатов/гипотез (B.1…B.10) +├── model_dual.py ← КАНОНИЧЕСКАЯ верифицированная модель (B.10) +│ +├── dsp/ ← реконструкция DSP-пайплайна на C++17 +│ ├── rotor_kernel.hpp ← бит-точное ядро ротора (близнец детектора) +│ ├── spectral.cpp/.hpp ← WOLA/STFT-обработчик +│ ├── detect.cpp/.hpp ← детектор резонансов +│ ├── filter.cpp/.hpp ← биквад-фильтры +│ ├── fft*.cpp, twiddle_*.cpp/hpp, phase_table.* ← FFT-планы/твилдлы +│ ├── ms.hpp ← encode/decode mid/side +│ ├── cody_waite.hpp ← быстрый exp/log (Cody–Waite) +│ ├── soothe_constants.hpp ← константы из дампа +│ ├── harness.cpp ← CLI: input.wav → output.wav (24-bit) +│ └── CMakeLists.txt +│ +├── *.java ← Ghidra-скрипты (analyzeHeadless, пост-скрипты) +│ ├── ListFuns / DumpFuns / DumpList ← списки функций/декомпиляция +│ ├── DumpVtables / DumpDsp / DumpCandidates +│ ├── ImportRtti, SearchRefs, Diag ← RTTI/перекрёстные ссылки +│ └── ... +│ +├── ghidra-proj/ ← Ghidra-проект (soothe2.gpr/.rep), вне git +├── soothe_mem.bin ← дамп памяти плагина (frida), вне git +├── regions/, regions_* ← регионы памяти из дампа +├── phase_table_1024.f64/.json← таблица фаз (FFT) +│ +├── Измерение и фиты полосы: +│ ├── measure.py ← анализ WAV: глубина вреза, attack/release тау +│ ├── probe.py ← спектральный анализ тонов +│ ├── bandshape.py ← эмпирическая форма полосы из рендеров +│ ├── fit_bandshape.py ← фит формы полосы +│ ├── fit_curves.py ← фит кривых (глубина/частота) +│ ├── fit_maskaxis.py ← brute-force подбор формулы маски (B.7/B.8) +│ ├── model_dual.py ← ВЕРИФИКАЦИЯ модели (dual_b1q + t1kq) +│ └── notch.py ← расчёт/проверка notch +│ +│ ── Поведенческие симуляторы: +│ ├── sim.py, sim_v5.py ← STFT-детектор (эволюция гипотез о архитектуре) +│ └── verify_sim.py +│ +│ ── Инструменты REAPER-рендеров: +│ ├── sweep.py ← генерит .rpp с изменением параметров плагина +│ ├── run_sweep.py, tt_sweep.py, run_verif*.py +│ ├── patchparam.py ← патчит PARAM в base64-блоке состояния +│ └── addfx.lua ← добавление soothe2 в проект +│ +│ ── Живая трассировка (yabridge-host + Frida): +│ ├── dump_soothe.py ← дамп всей памяти плагина → soothe_mem.bin +│ ├── rtall.py / rtscan.py / rtsig.py / rttbl.py / rtver.py +│ ├── rtone.py / rtsig.py / rtwin.py / rtdeep*.py / rtdump*.py +│ └── probe.py, procdump.py, ghidra_diag.py, mkbase.py +│ +├── *.txt / *.log ← декомпиляции, лямбли-дампы, xrefs (архив) +├── summary.md, notes_giant_fft.md +└── curve_fits.npz, depthcurve.npy, consts*.txt +``` + +### Тестовый корпус `/home/m/soothe-bt/` (вне git) + +~600 рендеров REAPER (`.rpp` + `.wav`), сгенерированы скриптами выше. Ключевые наборы: + +| Префикс | Что измеряет | +|---------|-------------| +| `burst500_b1` | основной эталон: burst 500 Гц, band1 fc=500 mode=1 sens=12 depth=0.864 | +| `dual_b1q_*` | 2 тона (500+2000), q полосы 0.1…10 → **парадокс red2000>red500** | +| `t1kq_only1_*`| 1 тон 1 кГц, fc-скан → форма полосы (rmse 0.047) | +| `t1k_b1f_*`, `t1kq_b1f_*` | fc-сканы, другие q/сенс | +| `tone1k`, `tone1kq`, `dual`, `n5_b1q_*`, `b2*`, `al_*` | уровни/частоты/сенсы | + +Входы: `dual.wav` (500+2000 Гц, −7.1 dBFS), `tone1k.wav` (0 dBFS), `tone1kq.wav` (−18 dBFS). + +--- + +## Модель (B.10) в двух строках + +```python +red(f) = -20*log10(1 - C(f)) +C(f) = depth * tilt(f) * D0 * (L0 / res(f))**p +# res(f) = |2B/A|(f; fc, Q, gain) — case8, tilt(f) = 1 - w(f) — веса 0x530d30 +# p ≈ 0.085, gain ≈ 10**(sens/20), tilt ratio(2000/500) ≈ 1.27 +``` + +Проверить: `python3 model_dual.py` (31 точка, rmse 0.109 dB). + +--- + +## Как всё это воспроизвести + +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. **Анализ**: `measure.py fx.wav dry.wav --fc 500` → глубина/тау; + `bandshape.py` → форма полосы; `model_dual.py` → верификация модели. + +--- + +## Чего не хватает / следующие шаги + +- Бит-точная сверка рендера: собрать `dsp/harness.cpp`, прогнать `burst500_b1.wav` + и сверить байт-в-байт (сейчас модель — численная, а не побайтовая). +- Семантика IAT-хелперов `0x181a14xxx` (exp/log/pow) и AVX-ядер (`FUN_18001a5a0` + и др.) — целевые адреса вне дампа. +- Точная функция LUT `level→mask` (кривая `param_1+0x188`) вместо аппроксимации `^p`. +- Полный конвейер WOLA/oversample (offline 3×) и sidechain/стерео-путь.