- Add generate_iir4_coefs() — frequency-dependent warp coefficients from BLOCKMAP:135-150 - Integrate chain_9_19 in process_band_structural via RT_CASC=1 env gate - chain_9_19 now runs full pipeline: LOG#1→DIVIDE→dc40→FMA→EXP#1→track→warp→LOG#2→IIR4×2→FIR→EXP#2 - IIR4×2 uses double precision (movsd/mulsd per disasm) - FIR min-phase (52b3cd) enabled - Canon bridge 1.594 unchanged when RT_CASC=0 - Requires live-dump or ph*.npz capture for input format calibration
soothe2-re
Обратный инжиниринг DSP-ядра oeksound soothe2 (VST3, Windows x64) → проверяемая реконструкция на C++ с bit-exact целью.
Цель — понять, как именно плагин считает подавление резонансов (уровневый детектор,
маска, фильтр), и воспроизвести это дословно. Текущий активный канон — C++
FramedDetector (dsp/framed_model.cpp): real mask-apply цепь с live-таблицами.
Канонные команды и метрика — в AGENTS.md.
Статус (24mm14+, 2026-08-29) — ЕДИНСТВЕННЫЙ ИСТОЧНИК TOTAL
Новый канон (структурный render48k 48k/4096 VLAW+EQ, 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, max 1.17 t1kq_1200). Старый bridge (framed_test 44.1k) 1.594 dB (scripts/baseline_bridge.json) — превзойдён на 1.25. Guard: python3 scripts/corpus_structural.py --out /tmp/v.json (канон 0.341) + python3 scripts/corpus.py --compare scripts/baseline_bridge.json --tol 0.25 (bridge). Следующий шаг — 2. k-маппинг twin/am (handoff/BLOCKMAP_529fe0.md:22v FilterGraph до детектора) для снятия per-fc (800/1200). Детали — 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+EQTOTAL 0.341 (канонf40f41e), per-fc800/1200ещё нужны (0.341vs0.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)
- Применение = побиновный multiply на вещественную маску; «×1.805» =
0.984×1.8345(экспоненты стадий). - Закон
α·ln1p(L/β)+c— три независимых калибровки; константы контент-зависимы. - Слой STFT без синтез-окна (
RT_SYN=1);WIN_WINDOW0.5→0.8 за 2049 сэмплов. - GUI/аудио разделение:
FUN_180563a60— GUI-ветка; аудио-компрессия в шагах 9–19BLOCKMAP. - Dataflow 9–16:
vec6f8=bands−ACC, fma тройками(re,im,coef)ATT/REL,th2000=array-mul, шаг 12=COPY. - Детекторный каскад
180529c60(vt+0x28):|z| → Haar [0.25,0.5,0.25]×2 → peak/sin → w=1/inner → blend 5407a8. - RFFT до df0 бит-точна (
th1a90/th2180+buf548scale 2^-12,24mm90.0065 dB).
# Сборка и канонные команды (см. 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)
- Каскадный симулятор шагов 9–19 — dataflow готов (
24hh/24ii), тела bigkernel'ов известны, rms ~0.42 на угаданных формах → оп-за-оп транскрипция +sc_*датасеты. - k-маппинг фронтенда (twin/am,
k=0.403 ∀q≥2,24x). - Δ-правило вторых пиков из 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 | Runbook: сборка, метрика, env-флаги, tooling hazard |
| BITEXACT_PLAN.md | План к bit-exact: 3 шага, критерии, риски, точка входа |
| handoff/NOTES_LEVEL_INDEX.md | Оглавление журнала по датам/темам → NOTES_LEVEL.md / archive/ |
| handoff/NOTES_LEVEL.md | Живой журнал (голова 24mm5+; хвост → archive/) |
| handoff/BLOCKMAP_529fe0.md | Карта метода FUN_180529fe0 (актуальна) |
| handoff/nls_dasm/ | 134 дизассембла декомпа |
| roadmap.md | Журнал B-фаз (свёрнут, детали → archive) |
| handoff/NOTES_TWIN.md | Twin краткая справка (детали → dsp/twin.cpp) |
| handoff/NOTES_CAPTURE.md | Registry heartbeat, live-таблицы (сжато) |
| 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, см. выше)
# 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].
Как всё это воспроизвести
- Достать бинарь: установить soothe2 (Windows VST3) под yabridge, запустить
dump_soothe.py→soothe_mem.bin(или взять.vst3, выдернуть секции). - Декомпиляция:
analyzeHeadless <proj> soothe_x64 -process soothe_mem.bin -noanalysis -postScript <X>.java(image_base=0, блокram=[0x180000000,…], адреса = RVA; смещение в файле = VA−0x180000000). - Рендеры:
sweep.pyгенерит.rpp,reaper -renderprojectвыдаёт.wav. - Анализ:
render_parity.py/framed_render.pyсравнивают модель с реальными рендерами (steady-state tone-замер, тримнутая метрика).
Чего не хватает / следующие шаги (bit-exact) → BITEXACT_PLAN.md
- Каскадный симулятор шагов 9–19 (приоритет №1) — см.
BITEXACT_PLAN.md:1. - k-маппинг фронтенда twin/am (приоритет №2).
- Δ-правило вторых пиков (приоритет №3).