24k: application law EXACT — cutA=1.8345*cutV+0.1615dB (rms 0.0025dB, 8 drive levels); x1.805 = exponent product 0.984x1.8345; single instance confirmed; R-slots static; probe-multitone method

This commit is contained in:
2026-08-24 18:02:28 +03:00
parent 6629e8bbf2
commit cc8ba34577
3 changed files with 222 additions and 4 deletions
+69
View File
@@ -2804,3 +2804,72 @@ Our application: mask × audio via complex multiply (WITH 1/N from IFFT)
3. Проверить hannfall-мультипликацию: fit exp(0.984·log(bands))·w против
захваченного fir_im≠0 (фаза!) — complex ops A-D дают мнимость.
4. Починить wav-path баг rendersnap2 (проверяет rpp.wav вместо RENDER_FILE).
## ============ UPDATE 2026-08-24k (24k): ЗАКОН ПРИМЕНЕНИЯ НАЙДЕН ТОЧНО — A = 1.019·V^1.8345; «×1.805» = ПРОИЗВЕДЕНИЕ ЭКСПОНЕНТ 0.984×1.8345 ============
### Инструменты раунда (все рабочие, закоммичены)
- `scripts/rendersnap2.py` v3: мягкий снаппер (не убивает reaper), t_snap в npz,
слоты {540668 FIR, 540678 bands, 540688, 540788 R, 5407f8 R} + скалярный банк
0x540860..c0. OUT = argv[3] (иначе каталог перезаписывается!).
- `scripts/hunt2.py`: полный чанковый перебор ВСЕХ ctx-кандидатов в рендере.
РЕЗУЛЬТАТ: инстанс ОДИН (0x2370040) — GUI/DSP-пара (24c) НЕ ПОДТВЕРЖДЕНА,
гипотеза закрыта.
- Зондовый мультитон: 2 главных тона (= амплитуды dual.wav 0.4248) + зонды
−30 дБ на фикс. сетке; Гёрцель по рефу даёт применённый отклик на всех
зондовых частотах при том же адаптивном состоянии детектора.
### Ключевые отрицательные результаты (не возвращаться)
- [ctx+0x540888] и весь банк 0x540874..88c = 1.000000 весь рендер; 0x540870 =
440.955. Скаляров-множителей в применении НЕТ.
- R-слоты 0x540788/0x5407f8 ИДЕНТИЧНЫ во всех проектах (r43=4.0285/3.9807) —
статические twin-шаблоны; с формой V НЕ коррелируют (rms 0.47).
- Слот 0x540678 = спектр кадра (HF→0), не кривая маски; 0x540688 = большие
значения (~183) — сырые аккумуляторы.
- Свип для Y/X-отношения непригоден (энергия только на гребне) — только
мультитон/мультиуровень.
- Динамическое выравнивание V(t)↔g(t) на рампе НЕ сходится (инерция детектора
+ STOP-семплирование) — пары брать только из стационарных прогонов.
- Каталоги снапов перезаписываются друг другом — всегда отдельный argv[3].
### ГЛАВНЫЙ ЗАКОН (8 уровней драйва −0..−30 дБ, q=0.5, fc=500)
Стационарная пара (V = устоявшийся видимый FIR@540668 «most-common complete
state», A = применённый отклик по Гёрцелю рефа):
```
cutA[дБ] = 1.8345 · cutV[дБ] + 0.1615 дБ (@500 Гц, центр нотча)
rms = 0.0025 дБ (!), max 0.005 дБ — 8 точек, cutV от 1.0 до 5.55 дБ
```
На скирте (@2000): та же форма, γ≈1.812, offset≈0.18, rms 0.087 дБ.
В линейном домене: A ≈ 1.019 · V^1.8345.
Погрешность выбора V (медиана most-common вместо истинного кадра) ~0.05-0.1 дБ
на скирте объяснима; закон устойчив по всем уровням.
### РАЗГАДКА «×1.805» (23e/24i окончательно закрыты)
```
0.984 × 1.8345 = 1.80515
```
23e эмпирическая константа «свёртка ×1.805» — это ПРОИЗВЕДЕНИЕ экспонент:
видимый кернел строится как exp(0.984·log(bands)) (23d ✓), а ПРИМЕНЯЕМЫЙ
kerнел = bands^1.805 (в эквиваленте). Никакой свёртки/OLA/скаляра нет:
применение = побиновный комплекс-multiply (th_b3c0 ✓ 24e) на кернел
A = 1.019·V^1.8345. Старые phase*.npz (m43=0.588) — init-кернелы, всё что
строилось на них — артефакты.
### Двойные аттракторы видимого буфера
V_steady@43 = 0.524±0.002 ∀q (0.1..10); редкие флэши D@43=0.315 ∀q;
ln(D)/ln(V)=1.85 ≈ γ ⇒ флэш = применяемый кернел A, пойманный в буфере
(перестройка каждый кадр: rebuild→A→consume→запись V-стадии).
### Что осталось до транскрипции применения
1. Формула V(content,params): ширина провала vs q, глубина vs drive/sens,
позиция vs fc. Зондовая методика + rn_q*/rn_lv* каталоги = данные уже есть.
2. Источник 1.8345 в коде: искать вторую экспоненту в ops A-D / bigkernel
140b30 (exp2-кернел?) — кандидат: двойное применение стадии exp или
exp(0.984·log)²·коррекция окна (0.984·2=1.968≠1.805 — нет; искать точно).
3. RT_FIRCONV=3: маска = 1.019·M^1.8345, где M = выход нашей detector-цепи,
после того как M приведён к форме V (единичный passband, провалы у контента).
4. Корпусный гейт --vs-bridge после каждого шага.
### Контрольные числа уровня −0 дБ (dual-эквивалент)
V43=0.5279 → cutV=5.550 дБ; cutA=10.34 дБ (реф 10.32 ✓); cutA@2000=11.85 (реф
11.82 ✓). Уровневая серия: см. /tmp/opencode/{lv*,rn_lv*}, pairs в
level_pairs.npz.
+136
View File
@@ -0,0 +1,136 @@
#!/usr/bin/env python3
"""hunt2.py — enumerate ALL soothe2 module instances during offline render.
Chunk-correct full-heap scan (rendersnap-style) collecting EVERY ctx candidate
(vtable 0x1824AC210 or m48 marker), not just the first. Per candidate: sens,
fir43/fir171 (via ctx+0x540668 ptr), scalar bank snapshot. Goal: find the
GUI/DSP pair (24c/24j): visible instance holds shallow kernel while audio is
processed by another instance with the deep one.
"""
import hashlib
import os
import signal
import struct
import subprocess
import sys
import time
import numpy as np
VT = struct.pack('<Q', 0x1824AC210)
M48 = struct.pack('<I', 0x473b8000)
def find_host():
import glob
for p in glob.glob('/proc/[0-9]*'):
pid = int(os.path.basename(p))
try:
cmd = open(f'/proc/{pid}/cmdline', 'rb').read().replace(b'\0', b' ').decode('utf8', 'replace')
maps = open(f'/proc/{pid}/maps').read()
except Exception:
continue
if 'soothe2' in maps and 'reaper' not in cmd:
return pid
return None
def main():
rpp = sys.argv[1] if len(sys.argv) > 1 else '/tmp/opencode/multi.rpp'
subprocess.run("pkill -9 -x reaper; pkill -9 -f '[y]abridge'; "
"rm -rf /run/user/1000/yabridge-soothe2_x64-*; sleep 1", shell=True)
proc = subprocess.Popen(['/usr/bin/reaper', '-nosplash', '-ignoreerrors',
'-renderproject', rpp],
stdout=open('/dev/null', 'w'), stderr=subprocess.STDOUT)
t0 = time.time()
host = None
while time.time() - t0 < 30 and not host:
host = find_host()
time.sleep(0.001)
if not host:
print('NO HOST')
return 1
fd = os.open(f'/proc/{host}/mem', os.O_RDONLY)
def rd(a, n):
try:
return os.pread(fd, n, a)
except OSError:
return None
def scan_all():
found = {}
for line in open(f'/proc/{host}/maps'):
parts = line.split()
if 'rw' not in parts[1]:
continue
lo, hi = (int(x, 16) for x in parts[0].split('-'))
CH = 16 * 1024 * 1024
a = lo
while a < hi:
d = rd(a, min(CH + 4096, hi - a))
if not d:
break
for pat, off in ((VT, 0), (M48, -0x24)):
j = d.find(pat)
while j >= 0:
cand = a + j + off
if cand not in found:
sb = rd(cand + 0x540870, 4)
if sb and struct.unpack('<f', sb)[0] > 100:
found[cand] = True
j = d.find(pat, j + 1)
a += CH
return list(found)
known = {}
rounds = 0
while time.time() - t0 < 25:
rounds += 1
try:
os.kill(host, signal.SIGSTOP)
except ProcessLookupError:
break
try:
cands = scan_all()
new = [c for c in cands if c not in known]
for c in new:
known[c] = rounds
pb = rd(c + 0x540668, 8)
m43 = m171 = -1
if pb:
p = struct.unpack('<Q', pb)[0]
if p > 0x10000:
fb = rd(p, 2049 * 8)
if fb:
arr = np.frombuffer(fb[:2049 * 8], dtype='<f4')
mag = np.hypot(arr[0::2], arr[1::2])
m43, m171 = float(mag[43]), float(mag[171])
sb = rd(c + 0x540888, 4)
s888 = struct.unpack('<f', sb)[0] if sb else -1
print('NEW ctx %#x @r%d t=%.2f fir43=%.4f fir171=%.4f s888=%.4f'
% (c, rounds, time.time() - t0, m43, m171, s888), flush=True)
# status of known ones every round
for c in known:
pb = rd(c + 0x540668, 8)
if pb:
p = struct.unpack('<Q', pb)[0]
if p > 0x10000:
fb = rd(p, 2049 * 8)
if fb:
arr = np.frombuffer(fb[:2049 * 8], dtype='<f4')
mag = np.hypot(arr[0::2], arr[1::2])
print(' st ctx %#x t=%.2f fir43=%.4f' % (c, time.time() - t0, mag[43]), flush=True)
finally:
try:
os.kill(host, signal.SIGCONT)
except ProcessLookupError:
pass
time.sleep(0.05)
print('total instances: %d' % len(known))
proc.kill()
return 0
if __name__ == '__main__':
sys.exit(main())
+17 -4
View File
@@ -18,7 +18,7 @@ import time
import numpy as np
SLOTS = [0x540668]
SLOTS = [0x540668, 0x540678, 0x540688, 0x540788, 0x5407f8]
NARR = 8194
SCAL_OFF = 0x540860
SCAL_N = 24 # floats -> 0x540860..0x5408c0
@@ -42,6 +42,8 @@ def find_host():
def main():
rpp = sys.argv[1] if len(sys.argv) > 1 else '/home/m/soothe-bt/dual_b1q_0.5.rpp'
cap = int(sys.argv[2]) if len(sys.argv) > 2 else 200
global OUT
OUT = sys.argv[3] if len(sys.argv) > 3 else OUT
os.makedirs(OUT, exist_ok=True)
subprocess.run("pkill -9 -x reaper; pkill -9 -f '[y]abridge'; "
"rm -rf /run/user/1000/yabridge-soothe2_x64-*; sleep 1", shell=True)
@@ -148,9 +150,20 @@ def main():
arr = np.frombuffer(fb[:2049 * 8], dtype='<f4')
mag = np.hypot(arr[0::2], arr[1::2])
sv = np.frombuffer(scal, dtype='<f4')
np.savez_compressed(f'{OUT}/ph{saved:03d}.npz',
fir_re=arr[0::2].copy(), fir_im=arr[1::2].copy(),
scal=sv.copy())
store = {'fir_re': arr[0::2].copy(), 'fir_im': arr[1::2].copy(),
'scal': sv.copy()}
for off in SLOTS[1:]:
q = rd(ctx + off, 8)
if not q:
continue
ptr = struct.unpack('<Q', q)[0]
if ptr < 0x10000:
continue
ab = rd(ptr, NARR * 4)
if ab:
store[hex(off)] = np.frombuffer(ab, dtype='<f4').astype(np.float32)
np.savez_compressed(f'{OUT}/ph{saved:03d}.npz', t_snap=time.time() - t0,
**store)
print('PH%03d t=%.2f fir43=%.4f fir171=%.4f | s888=%.6f s88c=%.6f s874=%.6f s87c=%.6f s870=%.3f' %
(saved, time.time() - t0, mag[43], mag[171],
sv[10], sv[11], sv[5], sv[7], sv[4]), flush=True)