11 KiB
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-23, после 22z): канон = структурная цепь 48k/4096 с RT_LAWAFFINE=7.4,1.85 (TOTAL 1.931; bridge 1.594 — гейт не пройден). ГЛАВНЫЙ ОТКРЫТЫЙ ВОПРОС — семантика входов
bands[]детектора: доказанно НЕ поточечная функция от (am,res^α) [22x], не форма-постобработка [22w], не спрединг IDFT→окно→DFT [22z]. Живая кривая редукции R=1/mask захвачена (слот 0x5407f8, dualtrace.py), но применённый фильтр ≠ её поточечной копии — механизм живёт ДО кривой (twin-шаблон/скалярный драйв). Журнал: NOTES_LEVEL 22s–22z; карта метода: handoff/BLOCKMAP_529fe0.md. ЭТОТ ФАЙЛ ЧИТАЙ ПЕРВЫМ.
Золотое правило (обязательно)
- Цель — bit-exact реверс кода, НЕ эмпирическая подгонка кривых. Каждый параметр должен иметь источник (decomp адрес / live-таблица), а не быть подогнанным числом. Если берёшь эмпирику — явно пометь и занеси в «осталось».
- Источник истины — декомпиляция (
decomp_funs.txt,decomp_funs2.txt,handoff/nls_dasm/*.dis) и live-снимки (/tmp/snap_rt.bin). Обновлять заметки при любом новом декоде. - Команды через
rtk(токен-фильтр), включая цепочки&&.
Сборка и тесты (канон)
# собрать библиотеку + 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_*:
# 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-21, P4)
ДВА канона в dsp/framed_model.cpp:
- 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)
- СТРУКТУРНАЯ цепь 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)
- Семантика входов
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; (б) синхронная трасса буферов в аудио-колбеке. - dual-таблица по q (22x): cut@центра константен при любом q, Δcut скайрта ≈ линейно по −ln res с b≈2.25 — геометрия twin-шаблона на сетке 0.25 Гц.
- FFT-conv: последовательность вызовов декодирована (BLOCKMAP/22z), тело 0x1802a24c0 (AVX2) и complex-op шаги — не расшифрованы.
- Бит-экзактный exp2 (0x26b820); бит-точная DSP-FFT (P3); стерео M8 (P5) — отложены.
- Источник констант 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— полный decompFUN_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).
Чистая работа
- Не коммитить:
*.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 метрику держать честной (тримнутая длина).