# 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`. > **Текущая фаза (2026-08-25, после 24kk2):** ПРИМЕНЕНИЕ ДЕКОДИРОВАНО ФОРМУЛАМИ: > аудио = побиновное умножение кадра на вещественную маску `10^(−cut_D/20)`, > `cut_D = α·ln1p(lvl_raw/β)+c` (+Δ у вторых пиков). Калибровки (rms ≤0.016 дБ): > dual(q0.5,s12,2 тона)=3.2193/0.4927/+0.54; fc1000(1 тон,q0.5)=1.6151/0.3645/+0.48; > fc500(1 тон)=1.1530/0.4038/+0.33. lvl_raw — НАШ фронтенд (float-parity ✓). > Слой STFT = БЕЗ синтез-окна (`RT_SYN=1`). **dual-корпус 0.193 max 0.438** > (канон 3.264); канон TOTAL 2.286 нетронут. ГЕЙТ СМЕНЫ КАНОНА = BIT EXACT > (решение пользователя: все параметры прослежены до декомпа + шумовой пол корпуса). > > Ключевые факты: q НЕ влияет на закон (доказано 24kk); sens линейно через > lvl_raw; далёкий контент не влияет — смешение шаблонно-локальное (24ll); > аудио = exp(deepest-scratch)+const; буфер FIR@540668 = мин.-фазовое > представление (exp(s−iH(s))) — не для транскрипции. Тела bigkernel'ов: > 1803a06a0/180296c80/180323f20/1802dc0e0 (x87 exp-семейство, 24jj). > > ОСТАТОК: каскадный симулятор шагов 9–19 по dataflow (24hh/24ii) → > параметризация α(контент)/fc через campaign.py (датасеты готовы) → > Δ-правило из pre-combine → полный корпус. Журнал: NOTES_LEVEL 24j–24kk2; > карта метода: handoff/BLOCKMAP_529fe0.md. ЭТОТ ФАЙЛ ЧИТАЙ ПЕРВЫМ. ## Золотое правило (обязательно) 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 (bridge, 44.1k) + render48k (структурная цепь, 48k/4096) cmake -S dsp -B dsp/build cmake --build dsp/build --target framed_test render48k # bridge-рендер (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) # структурный рендер (внутренняя сетка 48000/4096: resample -> FUN_180529fe0 chain -> resample) ./dsp/build/render48k /home/m/soothe-bt/tone1kq.wav /tmp/o48.wav 1000,0.99999785,12 # корпусные прогонки (62 случая, честная 24-bit метрика) python3 scripts/corpus.py # bridge + guard --compare python3 scripts/corpus_structural.py # структурная цепь python3 scripts/corpus_structural.py --vs-bridge scripts/baseline_bridge.json # отдельные модули (bit-exact черные проверки) cmake --build dsp/build --target twin_check tables_check fftconv_check vlog_check leveltrack_check levelpath_check fn529fe0_check exp2_check ./dsp/build/twin_check # float-parity twin-резонатора ``` > **TOOLING HAZARD**: cmake пропускает пересборку при изменении исходника в ту же секунду — > параметрические свипы молча гоняют STALE бинарь. Протокол: `touch` исходника перед сборкой + > проверять свежесть mtime бинаря (пример: /tmp/sweep_fresh.py паттерн в NOTES_LEVEL:21a). ### Метрика (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_.wav` (рефы), `comb.wav`/`comb_ref.wav` (мультиполосный). ## Текущее состояние (2026-08-21, P4) **ДВА канона в `dsp/framed_model.cpp`:** 1. **BRIDGE** (эмпирическая погона, путь framed_test 44.1k, NOTES:147): ``` 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) ``` 2. **СТРУКТУРНАЯ цепь FUN_180529fe0** (`process_band_structural`, внутренняя сетка 48000/4096 через `dsp/build/render48k`, NOTES_LEVEL:820-840 + апдейты 20j–21c): ``` scale → LUT level-domain (t^γ·MULT, γ=0.344 decomp / MULT=4.2 placeholder) → IIR1 → IIR2 → mirror → blend(0.8)/exp2(−lvl) → combine(acc-update, без консюмера) → dual-warp(kBand768·kWarp·res^rp) → IIR3 bidirectional ×2 → dry/wet(identity) ``` - **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. - **Честные результаты**: bridge корпус mean 1.594 (comb 10.15 сломан); структурная цепь: comb **6.12** и res **0.44** — лучше bridge; t1kq 0.77 / t1k 2.11 / al 0.99 / dual 3.26 — хуже. Полная таблица: BITEXACT_PLAN §0 / NOTES_LEVEL:21c. - **ГЛАВНЫЙ ОТКРЫТЫЙ РАЗРЫВ**: насыщение кривой редукции — реальная упирается в C_max≈0.70, exp2(−lvl) не ограничен (dual@500: константный −6.7 dB при всех q). Лечится Шагом 7 (live-захват A/B/γ) или статическим hunt'ом clamp'а в level-пути. Слепая подкрутка γ/MULT исчерпана (свип 21c). - **21d — закон редукции найден, канон НЕ сменён**: эффективное ослабление аффинно в dB(lvl) (маска ≈ 0.8·lvl^−0.354; al-свееп ±0.13 dB). Scalar-семейство (X0,S,floor, CMAX) не закрывает тон+шум одновременно → res/dual регресс у любой точки; ищем контент-зависимый механизм. Инструментарий RT_DUMP_BIN / RT_DUMP_ALL в коде (opt-in). ### Открытые пробелы (после 22z; детали — NOTES_LEVEL 22s–22z) 1. **Семантика входов `bands[]` в FUN_180529fe0** — главный вопрос. Отвергнуто: lvl=f(am,res^α) с единым законом [22x, теорема], форма-постобработка маски [22w], спрединг IDFT→окно→DFT [22z]. Живой захват: кривая редукции R=1/mask @слот 0x5407f8 (пик следует за fc полосы), acc/f6f8 нули в стационаре. Пути: (а) декод тел conv 0x1802a24c0 + complex-op шагов с буферами 0x540548/550/598; (б) синхронная трасса буферов в аудио-колбеке. 2. dual-таблица по q (22x): cut@центра константен при любом q, Δcut скайрта ≈ линейно по −ln res с b≈2.25 — геометрия twin-шаблона на сетке 0.25 Гц. 3. FFT-conv: последовательность вызовов декодирована (BLOCKMAP/22z), тело 0x1802a24c0 (AVX2) и complex-op шаги — не расшифрованы. 4. Бит-экзактный exp2 (0x26b820); бит-точная DSP-FFT (P3); стерео M8 (P5) — отложены. 5. Источник констант RT_LAWAFFINE A/S в декомпе не найден (помечено EMPIRICAL). ## Структура ключевых файлов - `dsp/framed_model.{cpp,hpp}` — C++ порт mask-apply цепи: bridge-канон + структурная `process_band_structural` (ГЛАВНЫЙ активный файл). - `dsp/render48k.cpp` — пайплайн внутренней сетки 48000/4096 (resample → структурная цепь → resample). - `dsp/framed_test.cpp` — CLI bridge-рендер входа (метрика см. выше). - `scripts/corpus.py` — корпусный харнесс bridge + guard `--compare baseline_bridge.json`. - `scripts/corpus_structural.py` — тот же корпус через render48k + режим `--vs-bridge`. - `dsp/{twin,levelpath,freqpath,fftconv,vlog,leveltrack,fn529fe0}.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). - `handoff/BLOCKMAP_529fe0.md` — полная блок-карта FUN_180529fe0 по raw asm (22v). - `scripts/lawfit22r.py` — офлайн реплей-сим пайплайна (~2 c корпус), фиты законов. - `scripts/resalpha.py` — сбор трактов + теорема об отсутствии α (22x). - `scripts/dualtrace.py` + `play_loop.lua` — живой захват ctx при realtime-playback (22y). ## Env-флаги экспериментов (24j–24kk2) | флаг | действие | |------|----------| | `RT_VLAW=1` | закон применённой стадии: mask=10^(−(α·ln1p(lvl/β)+c)/20) | | `RT_SYN=1` | STFT БЕЗ синтез-окна (найденный слой плагина) | | `RT_WIN=0/1/2` | окно анализа: sym-hann / periodic / rect | | `RT_NOWARP=1` | отключить warp-модуляцию маски | | `RT_NOIIR3=1` | отключить IIR3 ×2 | | `RT_IIR12=0` | отключить частотные IIR1/2 (КРИТИЧНО с RT_VLAW — иначе размывают дипы) | | `RT_DUMP_BIN=` (+`RT_DUMP_FRAME=N`) | дамп тракта бина N: am/res/lvl_raw/band_level/prewarp/w | | `RT_VDBG=1` | stderr-печать vlaw-вычислений | Полный набор dual-решения: `RT_VLAW=1 RT_SYN=1 RT_NOWARP=1 RT_NOIIR3=1 RT_IIR12=0`. ## Инструменты сессии 24j–24kk2 | скрипт | назначение | |--------|-----------| | `scripts/rendersnap2.py [cap] [outdir]` | мягкий STOP-снаппер: слоты FIR/scratch/bands/R + скалярный банк + t_snap; НЕ убивает reaper; RENDER_FILE из rpp (не удалять чужие рефы!) | | `scripts/campaign.py ` | ячейка параметризации: клоны rpp+рефы (~8 мин) | | `scripts/disasm_func.py [len]` | capstone-дизасм с инлайн-резолвом RIP-констант | | `scripts/iat_name.py` | рантайм-резолв импортов bigkernel'ов через PE-экспорты (SIGSTOP!) | | `scripts/probe_states.py` / `probe_mem.py` / `dump_dispatch.py` | живые state-заголовки / память / таблицы диспатча | | `scripts/hunt2.py` | перебор всех ctx-инстансов | | `scripts/scan_pairs.py`, `scan_lutsub.py` | диагностика памяти по сигнатурам float-пар | Датасеты кампании: `/tmp/opencode/sc_{q,sens,qmap,k,f,d}*` + `tract_*` + `{level_pairs,f_series,q_series,k_series}.pkl/.npz` (см. NOTES 24bb–24kk2). ## Чистая работа - Не коммитить: `*.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 метрику держать честной (тримнутая длина).