Files
soothe2-re/AGENTS.md
T
Matiq cc52461903 P4: AGENTS.md — honest baseline state (log-domain LUT bridge, correct 24-bit metric)
Replaces stale exp2(am/res) chain description + wrong metrics with the actual
honest state: C=G*LUT(log10(am/res))+W*warp^A, gain=(1-C)*res^rp; dual<=0.72,
fc-scan<=0.59, corpus mean 0.77. Documents the 24-bit metric trap, negative
broadband test, and the remaining structural gaps (combine + FFT-conv, A/B/gamma).
2026-08-20 18:31:22 +03:00

6.4 KiB
Raw Blame History

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.

Золотое правило (обязательно)

  1. Цель — bit-exact реверс кода, НЕ эмпирическая подгонка кривых. Каждый параметр должен иметь источник (decomp адрес / live-таблица), а не быть подогнанным числом. Если берёшь эмпирику — явно пометь и занеси в «осталось».
  2. Источник истины — декомпиляция (decomp_funs.txt, decomp_funs2.txt, handoff/nls_dasm/*.dis) и live-снимки (/tmp/snap_rt.bin). Обновлять заметки при любом новом декоде.
  3. Команды через 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 — 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 = (1C) · res_k^rp(Q)                  rp(Q) = 0.0275·Q^0.2159
LUT  = monotone cubic (FritschCarlson) через 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 метрику держать честной (тримнутая длина).