Files
soothe2-re/AGENTS.md
T

14 KiB
Raw Permalink 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.

Текущая фаза (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 24j24kk2; карта метода: 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 (токен-фильтр), включая цепочки &&.

Сборка и тесты (канон)

# собрать библиотеку + 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:

  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 = (1C) · res_k^rp(Q)                  rp(Q) = 0.0275·Q^0.2159
LUT  = monotone cubic (FritschCarlson) через joint-fit узлы (al_* + B.11 anchors)
  1. СТРУКТУРНАЯ цепь FUN_180529fe0 (process_band_structural, внутренняя сетка 48000/4096 через dsp/build/render48k, NOTES_LEVEL:820-840 + апдейты 20j21c):
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 22s22z)

  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=<f> (+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 <rpp> [cap] [outdir] мягкий STOP-снаппер: слоты FIR/scratch/bands/R + скалярный банк + t_snap; НЕ убивает reaper; RENDER_FILE из rpp (не удалять чужие рефы!)
scripts/campaign.py <base> <fc> <q> <sens> <in_prefix> <drives> <out> ячейка параметризации: клоны rpp+рефы (~8 мин)
scripts/disasm_func.py <VA> [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 24bb24kk2).

Чистая работа

  • Не коммитить: *.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 метрику держать честной (тримнутая длина).