Files

54 KiB
Raw Permalink Blame History

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..nbands1 по массиву @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 A–D.

ДОПОЛНЕНИЕ 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 с клампом [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%).

ДОПОЛНЕНИЕ 24mm2: ПОЛНАЯ РЕЗОЛЮВСЯ ВСЕХ 10 ЯДЕР + ИСПРАВЛЕНИЯ DATAFLOW

Инструмент: статический резолв цепочки стаб→таблица→L2→IAT-слот по soothe_mem.bin (без live). Стаб = movsxd rax,[idx@1826159a0]; lea r10,[tbl]; jmp [r10+rax*8], idx=4, L2=mov rax,[slot]; jmp rax.

Таблица резолва (исправляет 24jj!)

стаб таблица runtime опознание по константам
140950 182617448 18026b820 exp2/exp DOUBLE (ln2, log2e, 1021.5, 2^27)
140980 182617488 18027c120 logf FLOAT (ряд −½,+⅓,−¼,+⅕,−⅙; ln2 hi/lo; 2^32)
1409b0 1826174c8 18028d1e0 powf/log+exp DOUBLE (ряд log + магия expf вместе)
1409e0 182617508 180296c80 ✓ expf FLOAT — ДЕКОДИРОВАН ПОЛНОСТЬЮ (ниже)
140a40 182617588 1802dc0e0 ✓ exp-вариант FLOAT c hi/lo сплитами
140aa0 182617608 18030fee0 sincos DOUBLE (1/6,1/120,1/5040; π hi/lo)
140ad0 182617648 180323f20 ✓ кусочно-табличная DOUBLE (сетка Δ=0.00541521)
140b00 182617688 180367980 pow/exp DOUBLE (1023/1022, магия 1.5·2^20)
140b30 1826176c8 1803831c0 кусочно-табличная FLOAT (π/2, π/4, сетка 184.665!)
140b60 182617708 1803a06a0 ✓ DIVIDE FLOAT B/A (rcp+квантование+vpermps-таблицы+полином невязки)

ИСПРАВЛЕНИЕ 24jj: «140b30/140b60 → общий 1803a06a0» — НЕВЕРНО. FIR-секция вызывает 140b30 = 1803831c0 (табличная кривая), divide только в шаге 9c.

ДИСПЕТЧЕР float/double

Каждый call-site имеет ПАРУ стабов через call [181bab008]; test eax,eax; jne: float-стаб (eax==0) / double-стаб. Дескрипторы type_info СТАТИЧЕСКИ идентичны (оба →182650db8) ⇒ eax=0 ⇒ double-ядра мертвы на нашем пути; рендеры идут по float. Double-тела не транскрибируем (отмечено на будущее M8).

expf 180296c80 — полная формула (горячий цикл, FMA-точно)

n   = fma(log2e_hi=1.4427, x, MAGIC=12582912.0)     ; округление до int
k   = n  MAGIC
r   = (x  0.693146·k)  1.42861e-06·k               ; ln2 hi/lo
p   = (((0.00829172·r + 0.0418735)·r + 0.166674)·r + 0.499994)·r + 1)·r + 1
out = bits( (k<<23) + bits(p) )                      ; vpaddd сборка
guard: |x|>87.3365 → slow-path; head/tail через vmaskmovps+popcnt-маски

Коэф. минимаксные — транскрибировать КАК ЕСТЬ.

DIVIDE 1803a06a0 — структура (90%)

A=[rcx], B=[rdx], dst=[r8]; r9d=n
q0 = rcp(A); q0 += 2^23-magic (округление); q = q0 & 0xfff00000  ; 12 бит
e  = (q>>23); idx = q>>20 → vpermps tbl@1821269c0 (127±ε) и @182126a00
err = 1  q·A
полином невязки {0.207515, 0.241687, 0.288535, 0.360671, ..., 0.240264, 0.0555119}
сборка через магию 1.5·2^20 + vpslld 20
результат ≈ B/A с точностью ~0.5 ulp

Таблицы коррекций сдамплены (per-mantissa-top-bits).

ИСПРАВЛЕНИЯ DATAFLOW (по fn529fe0.dis, адреса call-sites)

  1. Шаг 14 порядок ОБРАТЕН к BLOCKMAP 24ii: сначала bigkernel exp IN-PLACE на bands_curve (52ae0e), ПОТОМ bands_curve += (1.0) (52ae40, конст. 1824c4680 через th2270).
  2. Шаг 9b точно: vec6f8 += [ctx+54087c] · 0.8 (xmm10=0.8@1824c3e28, множитель виден в asm: mulss xmm6,xmm10 после movss xmm6,[54087c]).
  3. Шаг 9a: vec698 *= (xmm12=1.0 [54087c]) ⇒ zero-fill при дефолтах ✓.
  4. Шаг 10 combine dc40: аргументы rcx=ACC_i(таблица указателей @0x5407c8, НЕ дампилась rendersnap2!), rdx=bands_curve_i(@678+i), r8=vec6f8(@6f8), семантика dst=r8: vec6f8 = bands_curve_i ACC_i. ACC-слот надо ДОБАВИТЬ в SLOTS rendersnap2 (0x5407c8).
  5. Шаги 15/16 подтверждены: th2000/th1c40 array-mul; затем rbx=[5406a8] (kWarp) — array-mul на bands_curve.
  6. Эпилог: скалярная часть из decomp (consumers_out 100-143): mix-веса, fVar17 = [540874] expf(DAT_1824c4704=-ln1000) → bands += f17·[540888].

Call-site карта больших ядер (fn529fe0)

52a63a/52a641: 140980(logf-float)/1409b0  — pre-combine #1
52ab84/52ab8b: 140b60(divide)/140950      — шаг 9c
52acd?       : (шаги 1012 мелкие ILT)
52ae0e/52ae15: 1409e0(expf)/140ad0        — шаг 14 нелинейность
52b32c/52b336: 1409e0(expf)/140ad0        — шаг 17 (повтор)
52b3a0/52b3aa: 140a40(exp-var)/140b00     — пост-17
52b716/52b71d: 140b30(кривая-float)/140aa0 — FIR-секция

ДОПОЛНЕНИЕ 24mm5: ПОЛНАЯ КАРТА ТРАКТА — буферы каждого шага; design = conv-тело 22z

Полоса-цикл (float-путь), трасса регистров 52a580–52b3cd

пре:    [678i] *= скаляры (s888-цепь, xmm7·[540870]·[54088c])
        LOG#1 (140980!) на [678i]           ; 52a63a — В ЛОГ-ДОМЕН заранее
        combine 52d650([678i],[6f8])
шаг 9a: vec698@698 *= (1[54087c])          ; zero
шаг 9b: vec6f8@6f8 += [54087c]·0.8
шаг 9c: DIVIDE dst=[678i]: A=arg(rcx)=[678i], B=arg(rdx)=[6f8]
        ⇒ [678i] = vec6f8 / bands_curve     ; in-place
шаг 10: dc40: rcx=ACC_i(@7c8+i!), rdx=[678i], r8=[6f8]
        ⇒ vec6f8 = bands_curve  ACC_i      ; ACC — таблица указателей 7c8
шаг 11: fma ATT(@6c8)/REL(@6e8) — пары вызовов 1fa0/1940
шаг 12: COPY 1b80/1d60 c [678i]
шаг 13: зеркало 9a/9b + оп 1eb0(cbe0)([678i],[6f8])
шаг 14: EXP#1 (1409e0=expf) на [678i]; затем += (1)
шаг 15: array-mul: X[rsp+0x40] *= [678i]    ; НЕ bands*=track!
шаг 16: [678i] *= kWarp@[5406a8]
        LOG#2 (140980) на [678i]            ; 52aefd — возврат в лог!
        IIR4 ×2 бидир                       ; ~52af0952b2b6, СПЕКТРАЛЬНОЕ
                                            ; СМЕШЕНИЕ В ЛОГ-ДОМЕНЕ
        скаляры xmm14(0.7)/xmm15(0.5)-класс
шаг 17: EXP#2 (1409e0) на [678i]; += scalar; exp-var 140a40 финал
        → bands_final @678i

FIR-секция (52b3cd52b94a)

bands_final *= s888, *= [540888]; += xmm7 (скаляр с expf(ln1000)=0.001)
DESIGN: call 535a70(rcx=scratch@628, rdx=bands)
  535a70 = диспетчер СО СВОПОМ аргументов → ILT 140a10/140a70 →
  → РЕЗОЛВ: float=1802a24c0 (!!!), double=1802fa420
  ⚡ ЭТО ТЕЛО FFT-CONV ИЗ ОТКРЫТОГО ВОПРОСА 22z («conv_float_a24c0.dis»,
    184K AVX2). Дизайн детектора == недекодированный conv. Пазл склеен.
дальше: copy th2210; complex-op th2180/th1bb0 с твидл-буферами
        548/550/598; знак 1 (52d920); EXP 140b30(=1803831c0);
        окно 52d990(WINfreq); pair-scalar 1880/1ca0; *= wet[540888];
        финал df0(FIR, track_i)

Где γ=1.760561

mask = bands_final^γ точно ⇒ γ возникает между scratch=log(bands_final) и финальной маской: либо ВНУТРИ design 1802a24c0 (масштаб на выходе), либо в комплекс-op цепочке 52b64452b716 перед EXP 140b30. Обе точки локализованы до ~десятка инструкций — декод следующего раунда.

Исправление понимания слотов

  • 688 = exp(628) тривиально: 628 — копия лога bands_final (design), 688 — сами bands_final (или их exp-копия). «track» — имя рендерснапа.
  • 678 ПОСЛЕ цикла = bands_final; применённая маска перезаписывает поверх (финальный combine) — поэтому захваченный 678 матчит аудио.

ДОПОЛНЕНИЕ 24mm6: ПЕРЕД EXP В FIR — УМНОЖЕНИЕ НА 2.0 (не −1!); гипотеза γ=2·k_design

Точная последовательность 52b60c–52b720 (проверено, без пропусков)

rcx=[540628](scratch), rdx=[r15](источник design — уточнить r15!)
call 535a70 → swap → 1802a24c0(scratch ← DESIGN(src))
th2210: FIR(@540668) ← scratch (copy, edx=0)
opB: th2180(FIR, buf548|550, buf598)          ; complex pass
FIR[n]=0
FIR[1 .. n/2] *= xmm13 = 2.0 @1824c41e0       ; 52d920, БЫЛО «−1» в 24l — НЕВЕРНО
FIR[n/2+1 .. n-1] *= xmm9 (=0)                ; 52db50
opC: th1a90(FIR, buf548|550, buf598)          ; complex pass
EXP in-place 140b30 (float) / 140aa0 (double)

xmm13/xmm9 не перезаписываются между 52b3d6 и использованием (проверено).

Гипотеза источника γ

Если opB/opC сохраняют пропорциональность (упаковка real-FFT), то mask = exp(2 · scratch) ⇒ γ = 2·k, где k — масштаб выхода design 1802a24c0 относительно ln(bands): k = 1.760561/2 = 0.8802805. Альтернатива: k=1, а opB/opC суммарно дают множитель 0.88028.

Открытые микровопросы (следующий раунд, всё локализовано)

  1. Что такое [r15] на входе design (bands_final@678 или иной буфер)?
  2. Семантика opB/opC (th2180/th1bb0/th1a90/th19d0 + твидлы 548/550/598) — вероятно упаковка/развёртка real-FFT.
  3. Масштаб выхода design: декод хвоста 1802a24c0 (файл уже есть: nls_dasm/conv_float_a24c0.dis, 184K).
  4. Согласование с identity-фазой захватов (гонка финального combine).

ДОПОЛНЕНИЕ 24mm7: design выход = точный ln(bands_final); γ создаётся после design

Численный тест (multi6/ph034, identity-фаза)

scr@628  ln(cur@678): max|r| = 9.0e-08 (float32 eps) на 1013 бинах
⇒ k_design = 1 (в момент захвата)

Оговорка: станционарность делает «свежий» и «сталый» scratch неразличимы; но факт (scr, cur)=(лог, значение) одной пары твёрд.

Следствие для γ

γ=1.760561 ≠ 2 ⇒ множитель НЕ только «×2 перед EXP». Источники: (a) opB/opC не взаимно сокращаются (не чистая упаковка real-FFT); (b) пост-exp шаги: окно 52d990 (варьируется по позиции — нарушил бы степенной закон, значит действует на верхнюю половину/после), pair-scalar th1880/th1ca0, финальный combine df0(FIR, track_i), где track=exp(scr)=bands_final. Комбинации дающие γ из {1,2}: 1+2x=1.760561 ⇒ x=0.3802805; либо лог-доменное смешение track^a·FIR^b c a+2b=1.760561.

Статус декода design 1802a24c0

AVX-512 (zmm, masked {k3}/{k4}), 3822 строки objdump — трансформ-класс. Для замыкания γ его полный декод МОЖНО НЕ НУЖЕН: достаточно семантики opB/opC + df0 (десятки инструкций в fn529fe0.dis).

ДОПОЛНЕНИЕ 24mm8 (финал захода): opB/opC/df0 резолвлены

opB: 180002180→180004ca80(f)/18001d160(d)   ; дескриптор-оп (тег [obj]==6)
opC: 180001a90→18001a0c0(f)/180018400(d)
df0: 18000df0→18000b3c0 ; f70→18000e360     ; финальный combine

Все четыре микровопроса 24mm6 закрыты или локализованы до тел-обёрток. Следующий раунд: семантика 4ca80/1a0c0 (кандидаты источника γ=2k−масштаба), затем полный numpy-конвейер.

ДОПОЛНЕНИЕ 24mm9: opB/opC = RFFT-близнецы; df0 = complex-mul; цепь валидирована 0.0065 дБ

Слой вызовов FIR-секции (уточнение поверх 24l/24mm6)

обёртки: th2180 impl=125e0, th1a90 impl=5560 — только перестановка аргументов:
         воркер получает (rcx=data, rdx=data, r8=ПЛАН, r9=WORK), ин-плейс.
ПЛАН = [ctx+540548] (buf548!): tag=6 [+0], log2n=12 [+4], flag [+8]=0,
       scale_flag=1 [+0xc], scale=2^-12 [+0x10], workbytes=16384 [+0x18].
WORK = [ctx+540598] — рабочая область FFT (заметение «lane-mask» из 23b).
th2180 → воркер 4ca80(f)/1d160(d): INVERSE real-RFFT (голова: X[0]±X[Nyq]).
th1a90 → воркер 1a0c0(f)/18400(d): FORWARD real-RFFT (хвост: пакинг Nyq).
тела: импортные близнецы 181b853e0(inv)/181b81b80(fwd); константы только
      ±0.707107; масштабов нет. ffe0 = ×scale pass (skip при scale∈{0,1}).
copy th2210 → 136e0 → 4d900(src,dst,n): pack re=v, im=0 (vunpcklps+zero).
df0 18000b3c0: ПОЭЛЕМЕНТНОЕ КОМПЛЕКСНОЕ УМНОЖЕНИЕ dst=[rdx]=arg2:
      track_i := track_i ⊗ FIR (vfmaddsub213ps; f70/b560 — double версия).
EXP 140b30 → 1803831c0: полиномиальная комплексная exp (без таблиц значений):
      magic 12582912 (=2^23·1.5), guard 87.33654, редукция 184.665≈128/ln2,
      коэф. {0.01604,1.541667(=37/24), 3.166e-05, 1.008329, 1.65777e-06,
      0.01932, 0.00134, 0.00541687, 10000, 4.19179}; AVX-512+FMA.
      Численно = поточечный комплексный exp (flat-exp проигрывает 8 дБ).

Полная последовательность (52b60c–52b893, все шаги, без пропусков)

design 535a70(scratch@628 ← ln(bands_i))          ; 52b62f, своп аргументов
copy 2210(scratch → FIR, 2049 пар (re,im=0))      ; 52b644
FIR[4096]=0                                       ; 52b685 Найквост ДО фолда
inv-RFFT opA                                      ; 52b672 th2180
fold: float[1..2047]*=2.0 (xmm13@1824c41e0)       ; 52d920
      float[2049..4095]=0                         ; 52db50
fwd-RFFT opB                                      ; 52b6e1 th1a90
EXP in-place, аргумент×q (q≈0.80, источник ОТКРЫТ); 52b716
inv-RFFT opC                                      ; 52b74b th2180
FIR[4096]=0                                       ; 52b76d
float[0..2047]*=WINfreq[2048..4095]               ; 52d990 (падающий Hann)
float[2048..4095]=0                               ; 52db50
fwd-RFFT opD                                      ; 52b7ba th1a90
FIR[0]=1.0f; FIR[1]=0                             ; 52b7cd
(flag f890≠0: pair-scalars 1880/ca0 — live мертво)
th2030(FIR, wet=s888, 2n float)                   ; 52b857, s888=1 no-op
df0(FIR, track_i, n): track_i := track_i ⊗ FIR    ; 52b893

Смысл: классическое минимально-фазовое ядро через кепстр (IDFT лога → фолдинг ×2 причинной части + усечение → exp → обратный ход).

Валидация и γ

mask_sim = trk·|F(q)|: 60 ультрачистых кадров, ВСЕ 2049 бина: rms мед 0.0065 дБ / p90 0.0075 / max 0.035 при q=0.80 (порог 0.05 ✓). γ = 1 + s_F(q), s_F = наклон log|F| по log trk в нотче: q=0.8 ⇒ γ_pred=1.7516 (точный 1.760561). Открыто: место q в асме (внутренность 1803831c0); unicorn не эмулирует FMA ⇒ нужен статдекод ядра или live-захват входа EXP. Дизасмы: /tmp/opencode/cascade/{wrapA_125e0,wrapB_5560,opB_4ca80,opC_1a0c0, df0_b3c0,h_ffe0,h_136e0*,imp_b8*3e0_full,bk_1803831c0}.dis (*copy: python3 scripts/disasm_func.py 1800136e0 — ВАЖНО: полный VA, короткая форма «125e0» даёт пустой файл!).