- AGENTS.md: canonical build/test commands, honest trimmed tone metric, current bit-exact state (mask-apply chain), open gaps (PRNG/FFT-conv/exp2/SR-mismatch). - README.md: status moved to P4 (C++ FramedDetector canon, framed_test), historical B.1..B.15 numerical model demoted to <details>; structure/doc table updated. - roadmap.md: P4 phase marked progress, P4.1/P4.2/P4.3 milestones, top status refresh. - summary.md: marked historical (behavioral v4). - SESSION_HANDOFF.md: fixed stale "NOT DECODED" (now decoded), copy note done. - Removed empty tmp_spec.txt/giant3.txt and untracked .log/__pycache__ clutter.
5.9 KiB
5.9 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.
Золотое правило (обязательно)
- Цель — bit-exact реверс кода, НЕ эмпирическая подгонка кривых. Каждый параметр должен иметь источник (decomp адрес / live-таблица), а не быть подогнанным числом. Если берёшь эмпирику — явно пометь и занеси в «осталось».
- Источник истины — декомпиляция (
decomp_funs.txt,decomp_funs2.txt,handoff/nls_dasm/*.dis) и live-снимки (/tmp/snap_rt.bin). Обновлять заметки при любом новом декоде. - Команды через
rtk(токен-фильтр), включая цепочки&&.
Сборка и тесты (канон)
# собрать библиотеку + 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_*:
# 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 (mask-apply цепь
FUN_180529fe0, mono-path 0x5408b8==0):
level=am*res*level_scale -> scale(0x540870*0x54088c/0x1a0)
-> IIR1 leaky(A1/B1) -> IIR2(A2/B2) -> mask=exp2(-mask)*blend (bigkernel 0x26b820)
-> combine/acc(0x5407c8) -> warp(mask*=0x540768, *=warp) -> IIR3(A3/B3)x2
-> dry/wet(mask*(fVar30*0x540888)+(1-fVar30)) -> [FFT-conv]
- bigkernel 0x26b820 = векторизованный exp2 (log2e=1.4424, floor −708.9, N-таблицы);
семантика залочена:
mask = exp2(-level) * blend, blend=0.8 при mix=1.0. - Level-tracker = би-направленный leaky-IIR
y=A[i]*acc+B[i]*x, B=1−A (НЕ per-bin независимый трекер). - Live-таблицы в
dsp/rt_mask_tables.{hpp,cpp}: kIIR_A1/B1..A3/B3 (2049 doubles), kWarp (8193), kBand768, kPRNGLut.dsp/rt_weights.{hpp,cpp}= acc коды весов. - Результаты: t1kq err −0.43 dB (scale=600); comb per-tone err ≤6.4 dB.
Открытые bit-exact пробелы (см. NOTES_LEVEL.md)
- PRNG-пролог (LCG+LUT → fVar30), per-frame рандомизация scale/dry-wet.
- FFT-conv (0x535a70) сглаживание маски перед FIR.
- Бит-экзактный exp2 (0x26b820) вместо std::exp2.
- combine/аккумулятор 0x5407c8 точная обратная связь.
- SR-mismatch: внутренний DSP SR=48000/N=4096 (спейс 11.713 Гц) против хоста 44100/2048; twin per-bin IIR статически невидим (FUN_180535880 tail-call).
Структура ключевых файлов
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— полный decompFUN_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 метрику держать честной (тримнутая длина).