Files
soothe2-re/handoff/BLOCKMAP_529fe0.md
T

539 lines
37 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# BLOCK MAP: FUN_180529fe0 (полная разметка по raw asm, 22v)
Источник: `handoff/nls_dasm/f529fe0_full.dis` (soothe_mem.bin, база 0x180000000,
диапазон 529c6052ba00; старый f529fe0.dis был ОБРЕЗАН на 52a813).
Регистры: r13 = индекс полосы, r12 = state-ptr ctx+0x440518, esi/r8d = nbin,
rbx = nbands ([rsp+0x30]), rdi = ctx. Флаг 0x5408b8 выбирает float/double
вариант thunk-операций (семантика пар идентична).
## Исправление адресации (главное)
«Скалярные» буферы NOTES 21b — МАССИВЫ пер-полосных векторов (шаг 16 байт):
- bands[i] = [ctx+0x540678+i·16] — кривые полос
- acc[i] = [ctx+0x5407c8+i·16] — ПЕР-ПОЛОСНЫЙ аккумулятор combine
- track[i] = [ctx+0x540768+i·16] — трек основного цикла
## Thunk-таблица (ILT-стаб 180001xxx -> jmp [table + idx*8], idx @1826159a0)
Резолв при live idx=4; семантика из тел + NOTES 21b:
| стаб float | стаб double | impl | op |
|---|---|---|---|
| 0x180001f10 | 0x180001c70 | dc40 / **8d60** | dst = B A (sub) |
| 0x180001fa0 | 0x180001940 | ee20→487a0 / **3c40** | fma att/rel половин |
| 0x180001d60 | —(встречен в 1b80-паре?) | — / **5a20** | dst += B (add) |
| 0x180001970 | — | **3f40** | sub (float) |
| 0x1800019a0 | — | **4200** | mul scalar? (делегирует 181a63fe0) |
| 0x180001a00 | — | **4720** | mul |
| 0x180001a60 | — | **5160** | sub DOUBLE |
| 0x180001850 | — | **25e0** | add DOUBLE |
| 0x180002000 | 0x180001c40 | ? | axpy-класс (band ⊕ track) |
| 0x180002060 | 0x180002120 | 10860/11940 | transform со скаляром xmm3 |
| 0x180002270 | 0x1800022a0 | 14c40/15060 | transform со скаляром xmm0/xmm1 |
| 0x180002030 | 0x180001d30 | ? | transform float/double |
| in-place кернелы | | 140950/140980/1409b0/1409e0/140a40/140ad0/140b00/140b60 | bigkernel-семейство (exp2/mask) |
## Карта блоков
### Пролог
- `52a03a52a396`: PRNG-пролог. LCG state @ctx+0x2404e0, шаги +0x3cdca,
+0x140236, +0x10d56, +0xdf6b6, +0xa8c5e, +0x72916; LUT ptr @ctx+0x5408b0;
константы 262b704/262b5c8(int)/262b700(int)/24c3c58. Результат: индексы
iVar7/iVar8 ([rsp+0x130]/счётчики) и стартовая позиция цикла.
Live-поведение залочено раньше (fVar30=1).
- `52a397`: r14 = &bands[0].
### Pre-combine #1 (52a39752a421)
- `52dbc0(f6f8_data, bands[0], nbin)` — copy bands[0] → f6f8.
- цикл i=1..nbands−1 по массиву @0x540688 (= &bands[1]!): transform(f6f8, bands[i])
через 20f0(float)/1850(double=25e0 ADD). ⇒ **f6f8 = Σ_{i≥1} bands[i]** (или min/max
— точный op 20f0 не залочен, кандидат ADD по double-паре!).
### Нормировка + mix-вес (52a42152a458)
- `52d920(f6f8, xmm11/[rsp+0x148](int), nbin)` — f6f8 /= K.
- `xmm7 = powf([ctx+0x2c], xmm13)` — mix^p.
### Pre-combine #2 (52a45e52a4f6) по всем полосам
- band[i] *= (xmm11 xmm7) [thunk 2030/1d30]
- f6f8 ⊕= ... с весом xmm7 [thunk 1fd0/2150]
⇒ взвешенное смешение кривых полос ДО основного цикла.
### Основной цикл по полосам (52a4fb..52b3c7, тело с 52a580)
На каждую полосу i (r13):
1. `scale` (52a58352a5c4): s = xmm11·[0x540870]; если флаг 0x5408b8:
s ← exp(PRNG)-ветка; затем ·[0x54088c]. Читается track_i (@0x540768[i]) в [rsp+0x40].
2. `transform(bands[i], s)` (52a5cc52a607): bands[i] *= s [2030/1d30].
3. флаг-оп (52a60852a645): transform(bands[i], bands[i]) через 140980/1409b0
(bigkernel, вероятно exp2-кернел) — только при флаге.
4. `52d650(state@0x440518, f6f8, bands[i], nbin)` (52a64652a658) — БИДИР-IIR #1:
band → f6f8 (double, коэф down@0x440528/up@0x4c0528, acc@0x540528, reset внутри).
5. Инлайн БИДИР-IIR #2 (52a65d52a85a, только при флаге; иначе прыжок на 6):
вход f6f8 → выход bands[i] (тот же state 0x440518, reset отдельно).
6. `transform(f6f8 ⊕ bands[i])` (52a85b52a896) [1970/1a60 = 3f40 SUB float /
5160 SUB double]: f6f8 = bands[i]? (аргументы rcx=f6f8, rdx=band).
7. **БИДИР-IIR #3** (52a89752aa6e, инлайн): state base 0x3404f8
(down@0x2404f8, up@0x2c04f8, acc@0x3404f8), длина из поля ctx+0x2404e8,
IN-PLACE по bands[i]. Reset каждый вызов.
8. `op(bands[i], скаляр xmm9=0?)` (52aa6e52aaaf) [2060/2120].
9. Ветка флага==0 (52aabc52ab90):
- op(vec@0x540698, f6f8, scalar=(конст1 [0x54087c])) [1a00/1be0 = mul]
- op(f6f8, scalar=[0x54087c]·xmm10) [2270/22a0]
- bigkernel `140b60/140950(bands[i], f6f8, bands[i], nbin)`
10. **COMBINE (52ab9052abd7)**: acc_i = [0x5407c8+i·16];
`op(rcx=acc_i, rdx=bands[i], r8=f6f8, r9=nbin)` [1f10→dc40 float-SUB /
1c70→8d60 double-SUB]: **f6f8 = bands[i] acc_i** ✓ NOTES 21b.
11. Половины f6f8 + fma (52abd752ad04):
- rbp = f6f8 + nbin (верхняя половина); op(f6f8_low?, ...) [2060/2120, scalar 0]
- op(rcx=f6f8_upper, rdx=vec@0x5406c8, r8=acc_i) [1fa0/1940 = **3c40 fma**]
- op(rcx=f6f8_lower, rdx=vec@0x5406e8, r8=acc_i) [1fa0/1940]
⇒ fma с коэф-массивами 0x5406c8 (upper/att) и 0x5406e8 (lower/rel) ✓.
12. `acc_i += bands[i]` (52acf452ad03) [1b80→6840 / 1d60→**5a20** add] ✓.
13. Ветка флага!=0 (52ad0452ae57): повтор п.9 с теми же адресами
(0x540698, f6f8-blend, bigkernel 1409e0/140ad0).
14. `op(bands[i], скаляры 0x1824c4680 / xmm13)` (52ae5852ae56 хвост).
15. `bands[i] ⊕= track_i [rsp+0x40]` (52ae7452ae8a) [2000/1c40].
16. `op(vec@0x5406a8, bands[i])` (52ae8f52aecа) [2000/1c40].
17. флаг → bigkernel in-place 140980/1409b0 (52aecb52af08).
18. **БИДИР-IIR #4 ×2** (52af0952b2af и повтор 52b0de52b2af):
state base 0x440510 (down@0x340510, up@0x3c0510, acc@0x440510),
длина ctx+0x340500, in-place bands[i]. ДВА прохода подряд (каждый с reset).
19. Финальные scale/op полосы (52b2af52b3af):
- скаляр `[ctx+0x1c+i·4] · xmm14` → transform [2030/1d30]
- bigkernel in-place 1409e0/140ad0 (при флаге) ИЛИ
op(scalar=xmm12/xmm8) [2270/22a0] + `140a40/140b00(band,band,scalar)`
20. Инкремент i (52b3af–52b3c7), выход при i ≥ nbands.
### Эпилог (52b3cd52b935)
- GUI-snapshot блок (флаг 0x2404bc): копии векторов @0x540728 ← bands[i]
(совпадает с consumers_out.txt:144-183).
- Остаток до 52b935: восстановить при транскрипции (вероятно dry/wet + mirror).
## Состояния бидир-IIR (4 базы, лейаут {down,+0x80000 up,+0x80010/+0x100010 acc})
| # | база | downCoef | upCoef | acc | длина |
|---|------|----------|--------|-----|-------|
| 12 (52d650+инлайн) | 0x440518 | +0x10 | +0x80010 | +0x100010 | nbin |
| 3 | 0x2c04f8-группа | 0x2404f8 | 0x2c04f8 | 0x3404f8 | поле ctx+0x2404e8 |
| 4 ×2 | 0x340510/0x3c0510 | 0x340510 | 0x3c0510 | 0x440510 | поле ctx+0x340500 |
## Открытые вопросы к транскрипции
1. Точный op thunk 20f0/1850 в pre-combine #1 (ADD — кандидат).
2. Аргументный порядок 2000/1c40 (axpy) и 2060/2120.
3. Семантика bigkernel-семейства 1409xx/140axx/140bxx (какой где: exp2(-x),
exp2(-x)·blend, mirror?).
4. Что пишется в track_i @0x540768[i] (writer вне метода — искать отдельной охотой;
кандидат FUN_18052e9b0).
5. Эпилог 52b4eb52b935.
## ДОПОЛНЕНИЕ 22v: декод генератора коэффициентов
### FUN_180530b60 (апдейт параметров, size=462)
- fVar2 = powf([ctx+0x540878], K1); fVar3 = powf([ctx+0x54087c], K2)
(оба live = 0.5 — параметры attack/release-класса);
- лог-интерполяция констант → [ctx+0x540894] и [ctx+0x540898] (тау-скаляры);
- вызовы генератора на все три состояния:
- 180533340(ctx+0x2404e8, tau=0x540894-ветка, C=DAT_1824c459c, sr, ...)
- 180533340(ctx+0x340500, tau=[0x540894], ...)
- 180533340(ctx+0x440518, tau=[0x540898], ..., mult=DAT_1824c4564)
### FUN_180533340(state, tau, C, sr, p, mult) — ГЕНЕРАТОР КОЭФ. БИДИР-IIR
```
sr' = sr · DAT_1824c3d8c
acc = 0; downCoef[0] = 1.0 (int-пара {0, 0x3ff00000} @+0x10)
n = state[0]; fc_norm = (C/sr')·n
for i in 1..n-1:
g = (i <= fc_norm) ? fc_norm/i : powf(fc_norm/i, p) # частотный варп!
c = 1/(g·tau/mult + 1)
up[i] = exp(c·g·tau/state[2] · DAT_1824c46b8)
down[i] = 1 up[i]
```
ЛЕЙАУТ СОСТОЯНИЯ СОШЁССЯ: downCoef[] @base+0x10, upCoef[] @base+0x80010
(pdVar6[0x10000] = +0x80000 байт), acc — скаляр в хвосте. Это ЧАСТОТНО-
ЗАВИСИМОЕ сглаживание маски: сила растёт к низким бинам (1/i) с питч-законом
выше кросса. Вот где «размазывание» нотча в реале — НЕ плоский IIR, который
мы отвергли офлайн (22u), а пер-биновый варп!
### Статус сбора (решение: без коммитов до первой валидации)
Незакоммичено: f529fe0_full.dis, BLOCKMAP_529fe0.md, thunk-резолвер,
правки NOTES_LEVEL (22v будет добавлена при транскрипции). Следующий шаг —
транскрипция process_frame_faithful по этой карте.
## ДОПОЛНЕНИЕ 23b: резолв ILT + декод FIR-цикла (52b55052b8bb)
### Резолвер
`scripts/ilt_resolve.py`: стаб = `mov eax,[rip+idx]; lea r10,[rip+tbl]; jmp [r10+rax*8]`;
live idx=4 у всех; таблицы @0x1826xxxx. Полная таблица «стаб→impl»:
| стаб | impl | роль (уточн.) |
|---|---|---|
| 0x180002210 | 0x136e0 | copy scratch→FIR? (валидатор → 39de0/3a040/3a220) |
| 0x180002180 | 0x125e0 | complex-op A/C float (воркер 3a4a0; r9 НЕ передаётся ⇒ длина из объекта) |
| 0x180001bb0 | 0x6a40 | complex-op A/C double |
| 0x180001a90 | 0x5560 | complex-op B/D float — ЧИСТЫЙ FMA (fma=28, mul/add=0!) |
| 0x1800019d0 | 0x4340 | complex-op B/D double |
| 0x180001880 | 0x2c60 | paired-scalar op 1 (флаг-ветка) |
| 0x180001ca0 | 0x9380 | paired-scalar op 2 |
| 0x180001df0 | 0xb3c0 | final op float |
| 0x180001f70 | 0xe360 | final op double |
| 0x180140a10 | 0x141400→[1826181d8]=**0x1802a24c0** | дизайн float |
| 0x180140a70 | 0x141580→[1826183c8]=**0x1802fa420** | дизайн double |
| 2030/1d30 | ffe0 / 9be0 | scalar-transform |
| 2270/22a0 | 14c40 / 15060 | scalar-transform-2 |
| 2000/1c40 | fb60 / 8700 | axpy-класс |
| остальное | dc40,8d60,5a20,4720,4200,3f40,5160,25e0,ee20,3c40 | как в BLOCKMAP ✓ |
### Дизайн-тело 0x1802a24c0 (float, вход=rcx bands[i], выход=rdx scratch@0x540628)
Функция входа 0..0x675 (~1.6КБ), далее сиблинги. Алгоритм = **ВЕКТОРНЫЙ LOG2**
(range reduction бит-трюком с 0.6666667, полином Хорнера на YMM-константах
0.5, 0.3333656, 0.2500466, 0.198225, 0.1646246, 0.1696488, 0.1517721,
реконструкция ×ln2=0.6931472; константы @FN+0x1cdfac0..d20). Маскированный
хвост через vmaskmovps/popcnt-таблицы (@0x181F8xxxx). ИТОГ: **scratch = log(bands[i])**.
Диспетчер 535a70 делает swap аргументов (rcx↔rdx) перед прыжком!
### Структура FIR-цикла (полностью залочена)
На полосу: 2×scalar-transform(bands[i], xmm8·[540888] при флаге 540890==0, иначе
xmm8; затем xmm12xmm8) [ср. decomp 184-185: A=[0x540874]expf(K), wet=[0x540888]]
→ DESIGN=log(bands[i])→scratch → copy(scratch→FIR@0x540668) [2210]
→ opA(FIR,buf548,buf598) [2180/1bb0] → FIR[n]=0 (n=0x540534=4096!)
→ 52d920(&FIR[1], xmm13, n/21) деление; 52db50(&FIR[2049], xmm9, n/21)
→ opB [1a90/19d0] → bigkernel in-place 140b30/140aa0 (n/2+1)
→ opC [2180/1bb0] → FIR[n]=0 → 52d990(FIR, WIN_freq+n/2, n/2) УМНОЖЕНИЕ на
**падающую половину Hann** (WIN_freq=wperiodicHann4096: w[1024]=0.5,w[2048]=1.0!)
→ 52db50(&FIR[2048], xmm9, n/2) → opD [1a90/19d0] → FIR[0]=1.0, FIR[1]=0
→ флаг-ветка: парно-скалярные 1880/ca0 → dry/wet scale ×[0x540888] над **2n флоатов**
→ final(df0/f70) с сохранённым track_i ([rsp+0x138][i]).
### Живые буферы (firtrace.py по s1/s2 + свежие захваты dual_b1q_0.5)
- 0x540658 WIN_freq = периодический Hann(4096), пик 1.0 @bin2048 (НЕ рамп 0.5→0.8!)
- 0x540758 freqaxis = линейный, шаг ≈11.713 Гц (≈48000/4096=11.71875, лёгкое
занижение — похоже на накопительную ошибку f32 при построении суммой)
- 0x540598 = SIMD-маски: 8×1.0 / 8×0.0 периодом 16 флоатов, ровно 1024 шт
(YMM lane-select для комплексных кернелов)
- 0x540550 NULL (float-путь активен, флаг 0x5408b8=0); 0x540628 scratch нулевой
между колбеками; 0x540668 FIR = комплексная единица (1,0)×2049 бинов МЕЖДУ
колбеками — кернел потребляется и сбрасывается внутри колбека
- 0x5406f8 хранит аудио-масштабный сигнал (~±0.1) между колбеками — overlap/STFT
буфер conv-движка (не «нулевой acc»!)
- 0x540788 vs 0x5407f8 различаются (max 1.108; @171: 1.751 vs 1.409) — две РАЗНЫЕ
кривые; ни одна не достигает нужных 3.89×@171 (11.82 дБ) ⇒ применённый фильтр
≠ поточечная копия любой из живых кривых (подтверждение разрыва 22y)
## ДОПОЛНЕНИЕ 24l: точный декод FIR-цикла по дизасму (52b550–52b8bb) + константы
Инструмент: scripts/disasm.py (capstone, base 0x180000000 над soothe_mem.bin).
ILT-резолв bigkernel-стабов даёт impl в 141100..141940 — все они IAT-thunk
массивы (`mov rax,[rip+..]; jmp rax`) вне дампа ⇒ тела за импортами; НО
последовательность и КОНСТАНТЫ цикла видны полностью:
### Пошагово (float-ветка, флаг 0x540890==0):
```
52b5a3: xmm6 = xmm8 · [ctx+0x540888]
52b5bf: th2030(bands[i], xmm6, n) ; bands *= 1.0·s888 (xmm8=double 1.0!)
52b5f6: th2270(bands[i], xmm7, n) ; scalar-transform-2
52b62f: 535a70(scratch@540628, bands[i], n/2+1) ; DESIGN: swap→scratch=log(bands)
52b644: th2210(rcx=scratch, rdx=0, r8=FIR, r9=n/2+1) ; копия (+упаковка?)
52b696: FIR[n]=0 ; float-индекс n=4096
52b69e: 52d920(&FIR[1], xmm13=-1.0, n/2-1) ; РАЗДЕЛЕНИЕ НА −1 ⇒ ИНВЕРСИЯ ЗНАКА бинов 1..n/2!
52b6ab: 52db50(&FIR[n/2+1], xmm9=0, n/2-1) ; ОБНУЛЕНИЕ верхней половины до exp!
52b6e1: opB = th1a90(FIR, buf548, mask598, n/2-1) ; FMA-complex (twiddle!)
52b716: BIGKERNEL 140b30(FIR, FIR, n/2+1) ; EXP in-place (тело за IAT)
52b74b: opC = th2180(FIR, buf548, mask598, n/2-1)
52b76d: FIR[n]=0
52b77c: 52d990(FIR, WINfreq+n/2, n/2) ; окно: th2000-класс (FMA axpy!)
52b78c: 52db50(&FIR[n/2], xmm9=0, n/2) ; верхняя половина ×0 снова
52b7ba: opD = th1a90(...)
52b7d4: FIR[0]=1.0f; FIR[1]=0
если флаг f890!=0:
52b803: th1880(FIR, {xmm10,xmm9}, n) ; парно-скалярный с (−1|0.8, 0)
52b81f: th1ca0(FIR, {xmm12,xmm9}, n) ; парно-скалярный с (1.0, 0)
52b857: th2030(FIR, s888, 2n) ; ×wet (=1 live)
52b893: final df0(FIR, track_i, n)
```
### Константы (статические значения из дампа):
| reg | адрес | значение | роль |
|-----|-------|----------|------|
| xmm8 | 1824c4140 (double) | 1.0 | множитель шага 1 = NO-OP при s888=1 |
| xmm13 | 1824c46a0 (double) | 1.0 | делитель бинов 1..n/2 (ИНВЕРСИЯ!) |
| xmm9 | xorps | 0.0 | обнуление верхних половин |
| xmm10 | 1824c4680 / 1824c3e28 | 1.0 / **0.8** | парный скаляр (0.8 активен в цикле) |
| xmm12 | 1824c3ea4 | 1.0 | парный скаляр 2 |
| xmm14 | 1824c4674 | 0.7 | (использование вне FIR) |
| xmm15 | 1824c4670 | 0.5 | (использование вне FIR) |
| xmm7 | вычисл. | sens·[540870]-цепочка | аргумент th2270 |
### СЛЕДСТВИЯ (меняют понимание построения кернела):
1. Перед EXP: бины 1..n/2 = log(bands) ⇒ после exp = **1/bands** (обратная
величина!), бины выше = exp(0)=1. Экспонента применяется НЕ к спектру маски
напрямую — вокруг неё twiddle-FMA стадии (ops B/C/D = радиальные проходы
FFT-класса над упакованным вещественным спектром; buf548 = cos/sin таблица,
mask598 = lane-select).
2. «×0.984» из 23d НЕ найден как константа цикла — либо внутри exp-IAT-обёртки,
либо следствие нормировки twiddle-стадий. Требуется численная репликация
пайплайна против живых захватов (rendersnap2 ph*.npz содержат готовые пары).
3. Шаг 1 и шаг ×s888 — no-op при дефолтных параметрах (s888=1, live 24j).
4. 52d920/52d990/52db50 = тонкие обёртки: 920→th2030/1d30 (scalar-op),
990→th2000/1c40 (axpy!), db50→то же. «УМНОЖЕНИЕ на окно» реализовано
axpy-кернелом, «деление» — scalar-op.
5. Ops A–D работают над дескрипторными векторами (проверка тега [obj]==6 в
4ca80; ошибка 0xfffffff3 при несоответствии).
### Динамика (попытки перехвата; окружение)
- realtime-playback НЕ тикает DSP (нет аудио-девайса; треды спят в futex);
кривые 22y = результат инициализации при загрузке проекта
- `-renderproject`: полный цикл init+render+exit хоста занимает ~0.8 c
(host@1.2s, workers@1.4s, wav@1.6s, exit@2.0s); обработка идёт в окне ~0.5 c
- INT3-ptrace: SEIZE+TRACECLONE обязательны до CONT (иначе untraced thread
ловит SIGTRAP и убивает процесс — подтверждено); DR-брейкпоинты: DR0@user+0x380,
но POKEUSER DR7 даёт EIO. Скрипты: fntrace*.py, fnhw.py, fnall.py, firstop.py,
firtrace.py, hotips.py (см. scripts/)
- Вывод: FUN_180529fe0 и 52d650/536300/52e260 НЕ ловятся в рендер-окне —
маск-цепь выполняется при ЗАГРУЗКЕ/изменении параметров, стационарный рендер
использует закэшированный кернел; либо трассировать надо момент инициализации
- Выход плагина НЕдетерминирован: md5 двух свободных рендеров различен при
одинаковом rms (PRNG-дизеринг из LCG-прологов) — метрика только спектральная!
## ДОПОЛНЕНИЕ 24t: ТОЧНЫЕ СЕМАНТИКИ СКАЛЯР-ОПОВ + опознание 563a60
Инструмент: scripts/disasm_func.py (полный дизасм функции с резолвом
RIP-констант инлайн).
### Тела скаляр-трансформов (float-ветки):
| стаб/impl | семантика | спец-случаи |
|---|---|---|
| th2030→ffe0 | dst[i] *= scalar | scalar==1 → скип; ==0 → zero-fill |
| th2270→14c40 | dst[i] += scalar | scalar==0 → скип |
Оба: скалярный хвост + AVX2 основной цикл (vmulps/vaddps ymm). Двойные
ветки (1d30/22a0) аналогичны на sd/pd.
### FUN_180563a60 = init-time ПОСТРОИТЕЛЬ таблицы (не per-bin!)
- Один caller: 1805636c2 (init-семейство).
- Константы пролога: xmm11=8.68589 (20/ln10 — ln⇒дБ!), xmm12=1/1024,
xmm14=0.5, xmm10=2, xmm9=1, xmm6=1; вызов IAT 181a14cd0 (log-класс)
над double из [obj+0x4198], ×8.68589 → дБ, запись пар во вектор
([obj+0xe0], рост через realloc 56c640).
- Вывод: строит дБ-доменную таблицу парами при param-rebuild — согласуется
с «LUT» ролью. Хвост с вирт. вызовом [rax+0x10] не декодирован.
### Алгебра T1: обе формы фитуют серию драйва (8 точек недоопределены)
- softplus α·ln1p(L/β)+c: rms 0.016 (α=3.2193 β=0.4927 c=0.542)
- LUT-форма t=((dBA)/(BA))^γ·M: rms 0.029 (A=36.2 B=20.0 γ=2.097 M=10.49)
Различить только декомпом тракта am/res→scratch или бОльшим числом точек.
### Открытые микровопросы
1. Значение xmm7 на входе th2270 в FIR-цикле (52b5f6): трассировка от
52a583; если mix^p=1 → «bands+=1» противоречит провалам ⇒ xmm7 иной
либо порядок аргументов иной.
2. Раскладка объекта-вектора (тег 6) для ops AD.
## ДОПОЛНЕНИЕ 24u: WIN_WINDOW движка — кусочное окно аудио-пути
Таблица WIN_WINDOW[8193] (dsp/tables_data.hpp, live-захват):
- [0]=0.500000, плавный подъём до [2048]=0.800000, затем СКАЧОК до 1.0
и единица до конца ([2049..8192]).
- Длина перехода = РОВНО 2049 сэмплов = число бинов кернела (4096-сетка)!
- Формула перехода не каноническая (ханн/синус/степенные не сошлись,
maxdiff ≥0.09); для репликации достаточно встраивания таблицы как есть.
- Структура намекает: блок аудио 8192 сэмплов ({16384,8192} из cfg движка),
первые 2049 позиций получают взвешивание 0.5..0.8 (область «кернельного
взаимодействия»?), остальное прозрачно; 0.8 подозрительно = blend.
Проверка употребления — в resize fe00 / audio-клее (следующий раунд).
### Движок dc30: карта инициализаторов (24u)
ctor 18052dc30 вызывает: 5335c0 (×2 — до/после валидатора), 534550 (×5 —
регистрация конфиг-итемов, аргументы edx из стека [rsp+0x30..0x4c] =
цепочка {2,4096},{16384,8192},{2,257}), затем ILT-стабы 2240/1c10.
Следующий шаг декода: тела 534550/5335c0 + употребление WIN_WINDOW
(по xref на таблицу или указатель из объекта).
## ДОПОЛНЕНИЕ 24w-3: ЖИВЫЕ КОНСТАНТЫ ГЕНЕРАТОРА 533340 (параметры частотных IIR)
Из scalar-bank (rendersnap2 v4+) на дефолтных параметрах multi:
```
p (экспонента) = [ctx+0x54087c] = 1.000000
tau1 = [ctx+0x540894] = 1200.000122
tau2 = [ctx+0x540898] = 180.000015
mult (стадия-3) = DAT_1824c4564 = 360
C_hz = DAT_1824c459c = 1000
константы 530b60 : 0.7, 2, 800→(×2)=1600, 1200, 15, 9, 180, 0.01,
[540898]=180*p+xmm6 (формула видна в дизасме)
```
Формула тела подтверждена дизасмом: g=min(fc_norm/i,(fc_norm/i)^p);
c=1/(1+g*tau/mult); up=exp(...); down=1-up.
Эксперимент: одноразовый bidir с этими коэф. НЕ двигает центр кривой
⇒ q-зависимость катов не через эти IIR напрямую; тракт между main-loop
и scratch содержит ещё этапы (ops AD / steps 919 BLOCKMAP).
## ДОПОЛНЕНИЕ 24z: FUN_180563a60 ДЕКОДИРОВАН ПОЛНОСТЬЮ — ЭТО ДЕТЕКТОРНАЯ LUT-ФОРМА!
Постройка (на каждый банд, 1024 точки, вход double[+0x4198+i·8],
выход пары-floats в вектор [+0xe0], stride вектора 0x18):
```
dB = log(input) · 8.68589
idx = i / 1024 → store[2j]
t = (dB A) / (B A) ; A=[sub+0], B=[sub+4] (sub=obj@[rcx+0x180])
t = clamp(t, 0, 1)
если γ(=[sub+0xc]) ≠ 1:
если [sub+0x10]==0: out = t^γ (классика)
иначе : out = sign(2t1)·|2t1|^γ + 1 (симметричный режим!)
else: out = t
out *= 0.5 → store[2j+1]
```
Виртуальная альтернатива: [sub+0x90]!=0 → вызов [sub vtbl+0x10](A,B,dB)
с клампом [0,1].
⇒ ЭТО ТА САМАЯ ФОРМА, ЧТО ДАЛА ФИТ cut=LUT(A,B,γ,M)! Стадия компрессии
уровня найдена материально: A/B/γ живут в объекте [band+0x180],
заполняются сеттерами. Осталось: снять их live-значения для наших конфигов
(расширить scalar-dump на [ctx+0x180]-объект) и найти потребителя таблицы
(интерполятор dB→out) в аудио-тракте.
## ДОПОЛНЕНИЕ 24cc: точная формула коэф. 533340 (дизасм+live)
[state+8] = n = 2049 (∀ трёх состояний; live probe_states.py).
```
fc_norm = (X/(sr·0.5))·n ; X=xmm2 (C_hz=1000 или tau — уточнить)
g(i) = min(fc_norm/i, (fc_norm/i)^p) ; p=[ctx+0x54087c]=1 @defaults
c = 1/(1 + g/mult) ; mult=360 (стадия-3)
arg = |c| · g / n ← НАСЫЩАЮЩАЯ форма (пол g→mult/n)
up[i] = exp(arg · (2π)) ; down[i]=1up[i]
```
При дефолтах down ∈ [0.003..0.19] — очень мягкие сглаживатели; эффект
только каскадом в полной цепочке шагов 9–19.
Осталось уточнить: роль xmm13 (множитель перед c), знак/конст экспоненты,
соответствие X=C_hz-vs-tau.
## ДОПОЛНЕНИЕ 24ff: семантика шага 11 (fma att/rel) — тройки (re,im,coef)
Цепочка вызова: ee20 → 487a0 → 1065c0; воркер получает r10=n/2·12 байт
⇒ элементы по 12 байт = (dst_re f32, dst_im f32, coef f32).
Call-site (52ac7052acd4):
```
шаг 11a: fma(rcx=f6f8_upper, rdx=ATT@[5406c8], r8=ACC_i, r9=n/2)
шаг 11b: fma(rcx=f6f8_lower, rdx=REL@[5406e8], r8=ACC_i, r9=n/2)
```
⇒ семантика: f6f8[k] += coef[k]·ACC_i[k] (комплексный axpy с пер-биновым
скаляром), верхняя половина спектра — с ATTACK коэф., нижняя — с RELEASE.
ACC_i персистентен между кадрами ⇒ утечный интегратор: стационар
ACC = input/(1coef); усиление 1/(1att): @43=2.57 @85=2.93 @171=3.42.
Коэф. массивы СТАТИЧНЫ (∀ конфигов бит-в-бит — проверено dual/qmap/sens18).
Гипотеза: резонансное усиление ACC объясняет k>1 аномалии уровней
(q2: impl/ours=2.48 ≈ A(85)); точная алгебра подачи ACC в кривую — в
остатке шагов 13–19.
## ДОПОЛНЕНИЕ 24gg: шаг 12 — ЭТО КОПИЯ (исправление BLOCKMAP)
th1b80→6840→1a5a0→181a646c0 = ЧИСТЫЙ MEMCPY (vmovdqu без арифметики).
«acc_i += bands[i]» из старого BLOCKMAP — НЕВЕРНО; реально копия
(направление/роли rbx/rbp уточнить трассировкой регистров через цикл —
аргументы на 52acf8: rcx=rbx, rdx=rbp, r8=n; значения rbx/rbp меняются
через 52ac98 [0x5406e8] и др. — нужен полный dataflow-проход шагов 9–19).
Следствие: если acc_i не накапливается сложением, «резонансная» гипотеза
24ff требует пересмотра — возможно ACC обновляется через fma шага 11
(ACC входит как источник), а шаг 12 синхронизирует массивы.
### Статус декода шагов 9–19 (24ff+24gg)
- шаг 11: f6f8[k] += att/rel_coef[k]·ACC_i[k] ✓ (тройки re,im,coef)
- шаг 12: COPY (не add!) ✓ исправлено
- шаги 1316: th2270-add ветка с xmm6=xmm12[54087c]; bigkernel 140950;
axpy 2000/1c40 с vec@540778 — тела не декодированы
- полный dataflow-проход = задача следующего раунда (связная, ~сессия)
## ДОПОЛНЕНИЕ 24hh: DATAFLOW шагов 9–12 (точный, из дизасма)
```
шаг 9a: vec698 *= (xmm12 [54087c]) ; th1a00=MUL; при 11=0 → ZERO
шаг 9b: vec6f8 += 0.8 ; xmm10=0.8 ([1824c3e28]); th2270=ADD
шаг 9c: bigkernel 140b60(vec6f8, bands_curve_i, vec6f8)
шаг 10: vec6f8 = bands_curve_i ACC_i ; dc40: out[r8]=rdxr10 ✓COMBINE
шаг 11: f6f8_upper += ATT[k]·ACC_i[k] ; тройки re/im/coef
f6f8_lower += REL[k]·ACC_i[k]
шаг 12: COPY(...) ; направление уточнить
```
Регистры: rbx↔vec698/6f8/acc_i, rbp↔bands_curve/[5406e8], r14=vec6f8.
Картина: строится КОРРЕКЦИОННАЯ кривая (bands−ACC), модулированная
att/rel-огибающими ACC — адаптивная петля редукции.
Остаток прохода: шаги 13–19 + эпилог + связь с FIR-секцией (52b3cd+).
## ДОПОЛНЕНИЕ 24ii: семантики шагов 13–16 + ИСПРАВЛЕНИЕ th2000
th2000/fb60 (и 1c40/8700) = ПОЭЛЕМЕНТНОЕ УМНОЖЕНИЕ МАССИВОВ
(dst[k] *= src[k]) — НЕ axpy! Исправляет интерпретации:
```
шаг 13 (флаг≠0): зеркало шага 9 (vec698*=..., vec6f8+=0.8·..., bigkernel)
шаг 14: bands_curve += (1.0) ; константа [1824c4680]=1 через th2270!
затем bigkernel 1409e0/140ad0 IN-PLACE на bands_curve
шаг 15: bands_curve *= track_i ; th2000 array-multiply
шаг 16: bands_curve *= kWarp@[5406a8] ; th2000 array-multiply
шаг 17(флаг): bigkernel in-place ещё раз
```
Картинка: кривая центрируется (−1), проходит нелинейность (bigkernel,
вероятно exp/abs — тела за IAT), модулируется track и warp.
Против log-входа design'а значение после этих шагов должно быть >0.
### Bigkernel-тела за ВЛОЖЕННЫМ диспатчем
Таблицы стабов содержат смесь IAT-слотов и внутренних адресов (напр.
table[7]=140a00), но внутренние ведут к call runtime-helper + НОВЫЙ
ILT-стаб с собственной idx-ячейкой (паковка/протектор). Статическое
разворачивание обрывается. Тела bigkernel'ов (exp/abs-нелинейность шага
14/17) остаются за пакером — при необходимости снимаются дампом памяти
ВОКРУГ вызова в рантайме (STOP + чтение таблиц после инициализации).
## ДОПОЛНЕНИЕ 24jj: ТЕЛА BIGKERNEL'ОВ НАЙДЕНЫ (рантайм-резолв IAT)
iat_name.py v2 (SIGSTOP + двойной deref + PE-экспорты) резолвит:
```
стаб 140b30/140b60 → runtime 1803a06a0 (общий для float/double!)
стаб 1409e0 → runtime 180296c80
стаб 140ad0 → runtime 180323f20
стаб 140a40 → runtime 1802dc0e0
```
Все — НАСТОЯЩИЕ функции внутри дампа (не импорты!): большие стек-фреймы,
x87 FNU-контроль, AVX2 полиномы, ДВЕ x87-трансцендентные инструкции
(fyl2x/f2xm1 класс = 2^x/exp семейство). Полный декод математики каждого —
отдельная сессия; вход/выход уже известны из контекста вызовов
(in-place над n/2+1 элементами FIR-буфера).
## ДОПОЛНЕНИЕ 24jj2: R@540788 — БАНДПАС-ФОРМА, НЕ совпадающая с нашим twin!
Сравнение (multi6, band1=500/q0.5/s12):
```
бин R@540788 наш_res R/наш
43 0.802 0.117 6.84
85 1.086 0.374 2.91
171 1.517 0.839 1.81
342 3.521 1.401 2.51 ← ПИК ~3.5-4 кГц!
512 2.910 1.673 1.74
684 1.829 1.811 1.01
1024 1.146 1.931 0.59
1536 0.689 1.988 0.35
```
Наш twin res растёт монотонно от fc; R@788 — БАНДПАС с пиком ~bin300-342
(~3.5-4 кГц) и СПАДОМ к Найквисту. Форма напоминает кривую равной
громкости / слухового взвешивания!
R@5407f8 = единичная нормировка (все 1.0000 в этом прогоне).
### ГИПОТЕЗА (проверяемая):
Детекторный уровень = am · ВЕС(f) / res(f), где ВЕС — кривая типа
равной громкости (R@788?). Тест: X=am·R/res против катов multi6 —
НЕ сошлось лобово (X@43=1.44 макс при мин кате) ⇒ взвешивание входит
иначе (до/после res-деления, или в log-домене).
### Ценность
Объясняет ВСЕ аномалии дальних бинов разом: наши дальние res слишком
велики (нет спада), их lvl занижен, каты недобираются. Формула ВЕСА —
ключ к кросс-конфиг параметризации.
## ДОПОЛНЕНИЕ 24kk3: слот [ctx+0x540668] ПОЛИМОРФНЫЙ!
Прямой проб во время рендера: [ctx+0x540668] содержит
`3fdbcd8940000000` = ДВА FLOAT (~0.434, 2.0), НЕ указатель!
(пробник probe_668.py; EIO на части чтений — слот мигрирует).
### Следствия:
1. rendersnap2 пропускает слот 668 (ptr<0x10000 или мусорный ptr) ⇒
во ВСЕХ новых захватах (sc_multi4b, sc_tt*, sc_q*, ...) НЕТ FIR-массивов.
2. Старые захваты rendersnap.py v1 ИМЕЛИ валидный FIR-указатель в эти
моменты (ловили фазу обработки). Данные старых phase*.npz про FIR —
валидны для своих моментов, но смешивать с новыми нельзя.
3. Все «FIR mag» анализы через этот слот зависят от ТОГО, в какой фазе
слот был пойман: указатель-на-буфер vs скаляры vs сброс.
4. Значения скаляров (~0.43, 2.0) — кандидаты: att/rel? dry/wet? g-компоненты?
### Статус
Канонический путь чтения ПРИМЕНЁННОЙ маски: слот [ctx+0x540678] (кривая
банды) — он стабилен и МАТЧИТ АУДИО в deep-фазах (±5%).