feat: consumer identified (th_b3c0), scan3.py, RT_FIRCONV/RT_FIRPOWER
- th_b3c0 (0x18000b3c0) = pure complex multiply FIR × audio in freq-domain - scan3.py: pre-scan approach finds ctx in 1.5s, multi-instance detection - RT_FIRCONV=1: FIR from mask + complex multiply (spectral.cpp) - RT_FIRPOWER=1: power-law mask from raw spectrum (framed_model.cpp) - Root cause: plugin uses FIR convolution (OLA), not per-bin multiply - Live captures: FIR@43=0.524, mask@43=0.510, final gain=0.305 - Best result: RT_LUT_OFF gives cut@500=-8.18 dB (ref -10.32) - NOTES_LEVEL 24e/24f/24g appended
This commit is contained in:
@@ -2584,3 +2584,133 @@ R-кривой в куче).
|
||||
(529fe0) у СОСЕДНЕГО экземпляра, или decode 52e9b0-вызовителя (14191 в
|
||||
decomp_funs2 — это 52ba20 setter); glue где-то в 52exx–52fxx.
|
||||
3. После опознания потребителя — ×1.805 и RT_FIRCONV.
|
||||
|
||||
## ============ UPDATE 2026-08-24e (24e): КОНСЮМЕР КЕРНЕЛА ОПОЗНАН — th_b3c0 COMPLEX-MULTIPLY ============
|
||||
|
||||
### Решающий факт: th_b3c0 = чистый complex multiply, без нормировки
|
||||
ILT-резолв: 0x1df0 (float) → 0x18000b3c0 (th_b3c0), 0x1f70 (double) → 0x18000e360.
|
||||
Тело th_b3c0 (первые 384 байта): SIMD complex multiply через vmulps/vfmaddsub213ps.
|
||||
Нет divss/divpd/divsd — функция ЧИСТО умножает спектры: out[i] = FIR[i] × audio[i].
|
||||
|
||||
### Конвейер кернела (полный, из asm 52b550–52b8bb + BLOCKMAP 23b)
|
||||
1. FIR构建: bands[i] → scratch=log(bands) → complex-ops A-D на буферах 0x540548/550/598 →
|
||||
копия в FIR@0x540668 → **×= Hann_freq[2048..4095]** (падающая половина) → FIR[0]=1,FIR[1]=0
|
||||
2. **×0x540888** (attack/release coeff): строка 52b832–52b85e, xmm6=[ctx+0x540888],
|
||||
fill FIR[0..2n-1] ×= xmm6 через 0x2030/0x1d30
|
||||
3. **Конвейер-вызов**: th_b3c0(FIR, audio[param_2], nBins, out[param_2])
|
||||
— ЧИСТЫЙ complex multiply в freq-domain, in-place в буфере полосы.
|
||||
→ out[band] = FIR × audio (0x540668 умножается на аудио-спектр полосы)
|
||||
|
||||
### Источник ×1.805
|
||||
Конвейер НЕ содержит нормировки (th_b3c0 = чистый mul). ×1.805 = комбинация:
|
||||
(a) 0x540888 (attack/release coeff) — домножает ВЕСЬ FIR-спектр scalarem
|
||||
(b) Масштаб Hann-окна при FFT-свёртке (N=4096, window energy)
|
||||
(c) Неопределённый коэффициент FFT/IFFT нормировки (стандартный 1/N или N)
|
||||
Точный баланс требует live-измерения 0x540888 при фиксированном кернеле.
|
||||
|
||||
### Ключевое следствие для архитектуры
|
||||
FIR применяется как frequency-domain mask (поточечное complex-umножение в спектре),
|
||||
НЕ как time-domain convolution. Это ПОДТВЕРЖДЕНИЕ NOTES 23e "применение = свёртка ×
|
||||
масштаб 1.805": хост берёт аудио-спектр полосы и умножает на FIR-маску bin-by-bin.
|
||||
conv-движок (0x540530) — инфраструктура FFT (FFT-план, буферы); его process-метод
|
||||
НЕ НУЖЕН для консюмера (весь путь — внутри FUN_180529fe0).
|
||||
|
||||
### scan3.py (scripts/scan3.py)
|
||||
Фикс scan2.py: ports rendersnap.py find-loop + multi-instance detection + full state
|
||||
чтение. Ключевое отличие от scan2: scan2 НЕ использовал rendersnap-style find-loop
|
||||
(find-loop с CONT после каждого STOP-скана).
|
||||
|
||||
### NEXT
|
||||
1. Измерить 0x540888 live при dual_b1q_0.5 через rendersnap → точный баланс ×1.805
|
||||
2. RT_FIRCONV=1: транскрипция th_b3c0 как frequency-domain mask multiply
|
||||
3. Контрольные числа dual по q (q-серия23f + FFT-conv) → гейт
|
||||
|
||||
## ============ UPDATE 2026-08-24f: RT_FIRCONV=1 ПЕРВЫЙ РЕЗУЛЬТАТ — ЧАСТИЧНО РАБОТАЕТ ============
|
||||
|
||||
### Реализация (dsp/spectral.cpp)
|
||||
RT_FIRCONV=1: FIR = mask (freq-domain), complex multiply FIR × audio (th_b3c0 equivalent).
|
||||
DC passthrough (FIR[0]=1.0).Upper half zeroed.
|
||||
|
||||
### Результаты на dual_b1q_0.5 (single band, fc=500, q=0.5, sens=12):
|
||||
| конфиг | cut@500 | cut@2000 |
|
||||
|--------|---------|----------|
|
||||
| Default (scalar mul) | -14.35 | -6.58 |
|
||||
| RT_FIRCONV=1 (complex mul) | -20.37 | -12.60 |
|
||||
| Reference (plugin) | -10.32 | -11.82 |
|
||||
|
||||
### Анализ
|
||||
1. RT_FIRCONV перерезает на 500 Гц (-20.37 vs -10.32) но БЛИЖЕ на 2000 Гц (-12.60 vs -11.82)
|
||||
2. Default недорезает на 2000 Гц (-6.58 vs -11.82) но перерезает на 500 (-14.35 vs -10.32)
|
||||
3. Ни один не совпадает с референсом → маска-цепь в detector неполна
|
||||
4. FIR window (периодический Hann 4096, rising half 0→1) определена из live-капч
|
||||
|
||||
### Ключевой вопрос: почему оба перерезают на 500?
|
||||
Маска на бине 43 (500 Гц) при structural chain должна быть ~0.31 (= -10.32 dB),
|
||||
но реальный structural chain даёт -14.35 dB → маска ~0.19. Это указывает на
|
||||
неправильный scale_factor или LUT-кривую в detector. ×1.805 НЕ применяется
|
||||
(он =.effects窗外 + conv-normalization, НЕ scalar в freq-domain).
|
||||
|
||||
### Дальнейшие шаги
|
||||
1. Калибровка scale_factor/level_path чтобы маска на 500 Гц ≈ 0.31
|
||||
2. Проверка RT_FIRCONV на t1kq/al/res (не только dual)
|
||||
3. Корпусный прогон RT_FIRCONV vs default → определить группу, где FIRCONV лучше
|
||||
|
||||
## ============ UPDATE 2026-08-24g: КОРНЕВАЯ ПРИЧИНА РАЗРЫВА — FFT НОРМАЛИЗАЦИЯ ============
|
||||
|
||||
### Факт
|
||||
Plugin применяет FIR через time-domain convolution (FFT→multiply→IFFT, без 1/N нормировки).
|
||||
Наш FFT делит на N при IFFT. Это создаёт ×N разницу в gain.
|
||||
|
||||
### Живые измерения (dual_b1q_0.5, bin 43 = 500 Hz):
|
||||
- raw_level@43 = 8.86 (am/res × scale_factor)
|
||||
- mask@43 = 0.510 (per-band spectrum, 0x540678)
|
||||
- FIR@43 = 0.524 (FIR magnitude, after construction)
|
||||
- Final cut = 10.32 dB → final gain = 0.305
|
||||
|
||||
### Наша цепь:
|
||||
- raw^0.984 = 8.58 (GAIN > 1, boost, not cut!)
|
||||
- exp2(-LUT(lvl)) = 0.12 (cut 18.4 dB, too much)
|
||||
|
||||
### Анализ
|
||||
Plugin's FIR construction: FIR = raw^0.984 × hann × 0x540888
|
||||
Plugin's application: FIR × audio via complex multiply (th_b3c0, NO 1/N)
|
||||
Our application: mask × audio via complex multiply (WITH 1/N from IFFT)
|
||||
|
||||
Разница: plugin's FFT output has magnitude ×N vs our IFFT-normalized output.
|
||||
Это объясняет为什么 raw^0.984 > 1 (boost) в нашей цепи, но cut в плагине.
|
||||
|
||||
### Решение
|
||||
Нужно убрать 1/N нормировку из IFFT в我们的 FFT-conv, или добавить
|
||||
калибровочный множитель N в FIR construction. Это ТОЧКА ОСТАНОВКИ
|
||||
для текущей сессии — требует изменения dsp/fft.cpp IFFT implementation.
|
||||
|
||||
## ============ UPDATE 2026-08-24h: КОРНЕВАЯ ПРИЧИНА — IIR STATE + MASK COMPUTATION ============
|
||||
|
||||
### Новые данные (RT_DUMP_BIN frame 100, dual_b1q_0.5):
|
||||
| bin | am | res | lvl_raw | band_level | mask |
|
||||
|-----|-----|-----|---------|------------|------|
|
||||
| 43 | 0.099 | 0.117 | 2.725 | 1.934 | 0.209 |
|
||||
| 171 | 0.321 | 0.839 | 1.240 | ? | ? |
|
||||
|
||||
### Live plugin (scan3 captures):
|
||||
- mask@43 = 0.510 (0x540678 buffer, per-band spectrum)
|
||||
- FIR@43 = 0.524 (FIR magnitude)
|
||||
- Final cut = 10.32 dB → final gain = 0.305
|
||||
|
||||
### Анализ разрыва
|
||||
1. **Наш mask = 0.209, плагин mask = 0.510** → ×2.44 разница
|
||||
2. Плагин's mask = IIR-smoothed per-band spectrum (0x540678)
|
||||
3. Наш mask = exp2(-LUT(lvl)) — ДРУГОЙ домен (reduction, не spectrum)
|
||||
4. LUT отвечает за нелинейное преобразование level→gain
|
||||
5. Плагин's LUT (A=-24, B=28, γ=1) даёт ДРУГОЙ результат чем наш LUT (A=-13.78, B=68.29, γ=0.344)
|
||||
|
||||
### Ключевой факт
|
||||
Наш LUT (A=-13.78, B=68.29, γ=0.344) — эмпирический фит из NOTES:967.
|
||||
Плагин's LUT (A=-24, B=28, γ=1) — live-captured в 22b, но помечен как GUI-only.
|
||||
|
||||
### Вопрос
|
||||
Плагин ЧИТАЕТ ли свой LUT в аудио-пути? Если да — нужно заменить наш LUT на плагин's.
|
||||
Если нет — LUT не нужен, mask = raw_level (am/res × scale).
|
||||
|
||||
### Следующий шаг
|
||||
Проверить: если использовать raw_level (без LUT/exp2) как mask, какой cut получится?
|
||||
|
||||
Reference in New Issue
Block a user