100 lines
6.8 KiB
Markdown
100 lines
6.8 KiB
Markdown
# AGENTS.md — guide for AI agents working in this repo
|
||
|
||
Bit-exact реверс DSP-ядра oeksound soothe2 (VST3) → транскрипция на C++18 в `dsp/`.
|
||
Полное журналирование — в `handoff/NOTES_LEVEL.md`, `handoff/NOTES_TWIN.md`,
|
||
`handoff/NOTES_CAPTURE.md`, `roadmap.md`.
|
||
|
||
> **Текущая фаза: bit-exact НЕ достигнут** — мы на dB-параллели (полный корпус mean 1.594
|
||
> dB, comb 10 dB). Путь к байтам — в `BITEXACT_PLAN.md` (8 шагов, порядок и критерии).
|
||
> ЭТОТ ФАЙЛ ЧИТАЙ ПЕРВЫМ. Bridge-модель — запасной канон; структурная цепочка
|
||
> FUN_180529fe0 (Шаг 1-2 плана) — целевая.
|
||
|
||
## Золотое правило (обязательно)
|
||
1. **Цель — bit-exact реверс кода**, НЕ эмпирическая подгонка кривых. Каждый параметр
|
||
должен иметь источник (decomp адрес / live-таблица), а не быть подогнанным числом.
|
||
Если берёшь эмпирику — явно пометь и занеси в «осталось».
|
||
2. Источник истины — **декомпиляция** (`decomp_funs.txt`, `decomp_funs2.txt`,
|
||
`handoff/nls_dasm/*.dis`) и **live-снимки** (`/tmp/snap_rt.bin`). Обновлять заметки
|
||
при любом новом декоде.
|
||
3. Команды через `rtk` (токен-фильтр), включая цепочки `&&`.
|
||
|
||
## Сборка и тесты (канон)
|
||
```bash
|
||
# собрать библиотеку + framed_test
|
||
cmake -S dsp -B dsp/build
|
||
cmake --build dsp/build --target framed_test
|
||
|
||
# рендер через каркас (N=2048, hop=512, SR 44100, sqrt-Hann OLA)
|
||
# формат полосы: fc,q,sens,level_scale (одна полоса в comma-форме)
|
||
./dsp/build/framed_test /home/m/soothe-bt/tone1kq.wav /tmp/o.wav 678.7611083984375,0.99999785,12,600
|
||
# многополосный: через отдельные аргументы fc q sens scale (см. framed_test.cpp)
|
||
|
||
# отдельные модули (bit-exact черные проверки)
|
||
cmake --build dsp/build --target twin_check tables_check fftconv_check vlog_check leveltrack_check levelpath_check
|
||
./dsp/build/twin_check # float-parity twin-резонатора
|
||
```
|
||
|
||
### Метрика (tone-cmp, Goertzel stead-state)
|
||
Сравнивать **тримкнутый** выход (длина = длина входа) с референсом `*_ref.wav` / `t1kq_b1f_*`:
|
||
```python
|
||
# ref: t1kq_b1f_678.7611083984375.wav (или t1kq_b1f_1000.wav и т.д. по fc полосы)
|
||
# вход: tone1kq.wav (тон 1000 Гц)
|
||
import wave, numpy as np
|
||
def load(p):
|
||
w=wave.open(p,'rb'); n=w.getnframes(); d=w.readframes(n)
|
||
return np.frombuffer(d,dtype=np.int16).astype(np.float64).reshape(-1,w.getnchannels()).mean(1)/32768
|
||
def ta(x,f,sr=44100):
|
||
x=x[-int(0.75*sr):]; t=np.arange(len(x))/sr; w=2*np.pi*f
|
||
return np.hypot(2*np.sum(x*np.cos(w*t))/len(x), 2*np.sum(x*np.sin(w*t))/len(x))
|
||
def db(a): return 20*np.log10(max(a,1e-9))
|
||
inp=load('/home/m/soothe-bt/tone1kq.wav')
|
||
out=load('/tmp/o.wav')
|
||
ref=load('/home/m/soothe-bt/t1kq_b1f_678.7611083984375.wav') # fc полосы = 678.76
|
||
err = db(ta(out,1000)/ta(ref,1000)) # err в dB, цель <0.1
|
||
```
|
||
Тестовый корпус (`/home/m/soothe-bt/`, вне git): `tone1kq.wav`(вход),
|
||
`t1kq_b1f_<fc>.wav` (рефы), `comb.wav`/`comb_ref.wav` (мультиполосный).
|
||
|
||
## Текущее состояние (2026-08-20, P4)
|
||
|
||
**Реализованная модель в `dsp/framed_model.cpp`** — BRIDGE-канон (NOTES:147, honest):
|
||
```
|
||
am_k: smoothed amp (2|X|/wsum, att~11ms/trel~80ms)
|
||
xv = log10(am_k / res_k) res_k = |2B/A| twin (min@band centre)
|
||
C = G·LUT(xv) + W·warp(f_k)^A G/W/A = 0.9963/0.3335/0.9807 (fit)
|
||
gain_k = (1−C) · res_k^rp(Q) rp(Q) = 0.0275·Q^0.2159
|
||
LUT = monotone cubic (Fritsch–Carlson) через joint-fit узлы (al_* + B.11 anchors)
|
||
```
|
||
- **METRIC CRITICAL**: рефы 24-bit НЕЛЬЗЯ читать 16-bit кодеком (даёт phantom −53 dB);
|
||
`render_parity.load` (sw handling) + окно 3.5s — канон. dual honest ref = −10.2 dB FLAT.
|
||
- **Broadband-hypothesis ОПРОВЕРГНУТА** (NOTES:2026-08-20s): редукция per-bin (tone-бины
|
||
режутся, пустые bin ~1.0);
|
||
- **Честные результаты (24-bit метрика, окно 3.5s, trimmed)**: dual (band fc=500,
|
||
q-sweep) err ≤0.72; t1kq fc-scan (only1 800..1200) err ≤0.59; al_* lv3-12 err ≤0.43;
|
||
полный корпус mean|err| 0.77, max 2.12 (t1k_b1f loud +2.1, al lv18/24 low-level −1.8).
|
||
- Эмпирика (G/W/A/rp/LUT-узлы) ЯВНО помечена в коде и NOTES; структурные лэкеры ниже.
|
||
|
||
### Открытые bit-exact/структурные пробелы (см. NOTES_LEVEL.md)
|
||
1. `combine/аккумулятор 0x5407c8` (аддитивные веса 0x5406c8/6e8) + `FFT-conv 0x535a70`
|
||
(сглаживание маски) — НЕ замкнуты в цепь; структурно могут закрыть t1k_b1f/al хвосты.
|
||
2. BandConfig `ctx+0x188` A/B/γ (параметрический LUT 0x563a60) — не live-захвачен;
|
||
писатели = JUCE param plumbing (статически исчерпаны).
|
||
3. PRNG-пролог (LCG+LUT → fVar30) — залочен (fVar30=1 при live state 112), dry/wet rnd импорт.
|
||
4. Бит-экзактный exp2 (0x26b820) вместо std::exp2; SR-mismatch 48000/4096 vs 44100/2048.
|
||
|
||
## Структура ключевых файлов
|
||
- `dsp/framed_model.{cpp,hpp}` — C++ порт mask-apply цепи (ГЛАВНЫЙ активный файл).
|
||
- `dsp/framed_test.cpp` — CLI рендер входа (3010 метрика см. выше).
|
||
- `dsp/{twin,levelpath,freqpath,fftconv,vlog,leveltrack}.cpp` — расшифрованные модули.
|
||
- `dsp/rt_mask_tables.{hpp,cpp}`, `rt_weights.{hpp,cpp}` — live-таблицы.
|
||
- `handoff/NOTES_LEVEL.md` — полный журнал уровня/маски (самый актуальный).
|
||
- `handoff/nls_dasm/` — 134 дизассембла декомпа.
|
||
- `/tmp/consumers_out.txt` — полный decomp `FUN_180529fe0` (уникален, вне git).
|
||
- `/tmp/snap_rt.bin` — live-снимок (ctx 0x2370040, SR 48000).
|
||
|
||
## Чистая работа
|
||
- Не коммитить: `*.bin`(дампы 112М), `*.wav/rpp`, `*.log`, `dsp/build/`, `ghidra-proj/`,
|
||
`dl/lib/bin/include/`, `regions*/`. См. `.gitignore`.
|
||
- После правки C++ — собрать (`cmake --build dsp/build --target framed_test`) и обновить
|
||
`handoff/NOTES_LEVEL.md`. Fasta метрику держать честной (тримнутая длина).
|