diff --git a/findctx.py b/findctx.py new file mode 100644 index 0000000..24cb4b7 --- /dev/null +++ b/findctx.py @@ -0,0 +1,33 @@ +import struct +data=open('/tmp/snap_all.bin','rb').read() +i=0; regs=[] +while i+16<=len(data): + lo,sz,=struct.unpack_from(' 1.0 (saturates; idx1024=0.68, idx2048=0.8)** — the FFT-conv window (0x540658) | +| [02] | 8193 | 0x29f2280 | 0 -> ~0.01 (levels/curve) | +| [03] | 8193 | 0x29fa300 | **0.596 -> 0.126** = matches known rwin_C0 | +| [04] | 8193 | 0x2a02340 | **0.404 -> 0.874** = 1-[03] complement | +| [05] | 8193 | 0x2a0a3c0 | 0.0435 -> ~0 (weight, small) | +| [06] | 8193 | 0x2a12400 | 0.9565 -> ~1.0 (1-[05]) | +| [07] | 8193 | 0x2aca740 | zeros + small negatives | +| [0d] | 2049 | 0x2cd0fc0 | **freq-axis 0..23988.3 Hz, spacing 11.713 = 48000/4096** → internal SR=48000 | +| [0e] | 8193 | 0x2cd9000 | 2.017 -> 0 (LUT/knee?) | +| [0f] | 16384 | 0x2ce9080 | same as [0e] doubled | +| [10] | 16384 | 0x2cf90c0 | 1.2914 -> 0 | +| [12] | 16384 | 0x2a62540 | 11.29.. (scattering) | +| [14]/[15] | 8193 | .. | first-fire IR? 0,0.022,0.104,0.084,0.018,0 | +| [17] | 32768 | 0x2d29140 | 0.9999 -> ~1 (ramp) | +| [19] | 32768 | 0x2d69200 | 1.2915 -> 1.0 | +| others | 32768/65536 | .. | ones / ramps (FFT plans, mirrors) | + +- Key numeric check: registry[03] head 0.5960761, idx1024 0.168, idx2048 0.1257 — + byte-identical to earlier GUI rwin_C0 (0.596 -> 0.126). Confirms registry IS the + authoritative per-bin weight source; tables are stable across sessions/SR. +- **FREQ-AXIS uses internal SR=48000 regardless of project 44100** (spacing 11.713). + This reconciles "rwin tables at 48k" even when rendering 44.1k projects. + +## Files saved (handoff/) +- `rtwin_freq_44100.npy` — WIN_freq (8193 f32): 0.5 -> 1.0 (this is live 0x540658 window) +- `rtfreqaxis_48000_internal.npy` — freq-axis (2048 f32, 0..23988.3, spacing 11.713) +- `rtwa_596.npy` — [03] 0.596->0.126 +- `rtwb_404.npy` — [04] 0.404->0.874 +- `rtwc_043.npy` — [05] +- `rtwd_956.npy` — [06] +- Full raw snapshot: /tmp/snap_all.bin (318MB, entries {lo,sz,bytes}), registry.txt list. + +## Method notes (repro) +- rtsnap_fast.py: spawn reaper render_long, find host (soothe2 in maps, not reaper), + sleep 6s (tables built), pread ALL readable maps chunked 8MB -> snap_all.bin. +- pread of large anon regions can EIO -> MUST chunk (8MB); whole-region pread loses data. +- Scan ~0.1s for 318MB once chunked; far cheaper than object-base scan. +- Earlier vptr-based (rtobj/rtdump2/rtall) and 44100-marker scans all failed because + the DSP object has NO static vptr match in a fresh render (host dies / fields live + only during audio) and ctor field +0x24 != 44100 live. The registry run is the + reliable beacon. + +## Remaining (for twin IIR attack/release per-bin) +- twin state A/B (342 double per-bin IIR states) still not uniquely located live; + short renders keep them ~0. They are NOT the registry tables. +- Next: render_long + capture at t=10-20s into sustain, then locate the per-bin + attack/release smoothing coefficients (0x540888/88c set, converted via ln(10)/20) + inside the arena near registry. diff --git a/handoff/rtfreqaxis_44100.npy b/handoff/rtfreqaxis_44100.npy new file mode 100644 index 0000000..8eb3804 Binary files /dev/null and b/handoff/rtfreqaxis_44100.npy differ diff --git a/handoff/rtfreqaxis_48000_internal.npy b/handoff/rtfreqaxis_48000_internal.npy new file mode 100644 index 0000000..8eb3804 Binary files /dev/null and b/handoff/rtfreqaxis_48000_internal.npy differ diff --git a/handoff/rtwa_596.npy b/handoff/rtwa_596.npy new file mode 100644 index 0000000..02b7082 Binary files /dev/null and b/handoff/rtwa_596.npy differ diff --git a/handoff/rtwb_404.npy b/handoff/rtwb_404.npy new file mode 100644 index 0000000..fc67e74 Binary files /dev/null and b/handoff/rtwb_404.npy differ diff --git a/handoff/rtwc_043.npy b/handoff/rtwc_043.npy new file mode 100644 index 0000000..349613a Binary files /dev/null and b/handoff/rtwc_043.npy differ diff --git a/handoff/rtwd_956.npy b/handoff/rtwd_956.npy new file mode 100644 index 0000000..f453369 Binary files /dev/null and b/handoff/rtwd_956.npy differ diff --git a/handoff/rtwin_44100.npy b/handoff/rtwin_44100.npy new file mode 100644 index 0000000..6c1df9c Binary files /dev/null and b/handoff/rtwin_44100.npy differ diff --git a/handoff/rtwin_freq_44100.npy b/handoff/rtwin_freq_44100.npy new file mode 100644 index 0000000..6c1df9c Binary files /dev/null and b/handoff/rtwin_freq_44100.npy differ diff --git a/rtchunk.py b/rtchunk.py new file mode 100644 index 0000000..b6ceae0 --- /dev/null +++ b/rtchunk.py @@ -0,0 +1,50 @@ +import subprocess, os, glob, time, struct +def mem_open(pid): return os.open(f'/proc/{pid}/mem', os.O_RDONLY) +def find_host(proc, wait=120): + t0=time.time() + while time.time()-t0/dev/null; pkill -9 -f '[y]abridge' 2>/dev/null; sleep 1") +proc=subprocess.Popen(['/usr/bin/reaper','-nosplash','-ignoreerrors','-renderproject','/home/m/soothe-bt/dual300.rpp'], + stdout=open('/dev/null','w'),stderr=subprocess.STDOUT) +host=find_host(proc); print('host',host) +time.sleep(4) +fd=mem_open(host) +SIG=struct.pack(' 1 else '/home/m/soothe-bt/dual300.rpp' -BEACON = 0x182615608 # VA of phase_table_1024 (static .data) +BEACON = np.uint64(0x182615608) -def vst_base(pid): - lo = None - for line in open(f'/proc/{pid}/maps').read().splitlines(): - if 'soothe2' not in line: - continue - a = int(line.split()[0].split('-')[0], 16) - lo = a if lo is None else min(lo, a) - return lo +def get_maps(pid): + try: + return open(f'/proc/{pid}/maps').read() + except Exception: + return '' def readable_regions(pid): out = [] - for line in open(f'/proc/{pid}/maps').read().splitlines(): + for line in get_maps(pid).splitlines(): p = line.split()[0] lo, hi = int(p.split('-')[0], 16), int(p.split('-')[1], 16) - if 'vst3' in line: - continue # skip module itself out.append((lo, hi)) return out @@ -35,17 +31,28 @@ def find_beacon(pid): return [] res = [] for lo, hi in readable_regions(pid): - sz = (hi - lo) & ~7 + sz = hi - lo if sz <= 0 or sz > 0x200000000: continue - try: - buf = os.pread(mem, sz, lo) - except Exception: + if sz < 65536: continue - arr = np.frombuffer(buf, dtype=' 64: + break + if len(res) > 64: + break os.close(mem) return res @@ -57,26 +64,42 @@ def main(): host = None while time.time() - t0 < 60: for p in glob.glob('/proc/[0-9]*'): - try: - maps = open(f'/proc/{p}/maps').read() - except Exception: - continue - if 'soothe2' not in maps: - continue - host = int(os.path.basename(p)) - break + pid = int(os.path.basename(p)) + if 'soothe2' in (get_maps(pid) or ''): + host = pid + break if host: break - time.sleep(0.05) - print(f'host={host}') + time.sleep(0.01) + print(f'host={host}', flush=True) if not host: - proc.kill() + proc.wait(timeout=10) return - base = vst_base(host) - # allow module load: plugin init first mem = os.open(f'/proc/{host}/mem', os.O_RDONLY) t1 = time.time() - while time.time() - t1 < 50: + regs = [] + for line in get_maps(host).splitlines(): + p = line.split()[0] + lo, hi = int(p.split('-')[0], 16), int(p.split('-')[1], 16) + if 'vst3' in line or 'reaper' in line or 'soothe2' in line and 'rw' not in line.split()[1][:2]: + continue + if 'rw' not in line.split()[1][:2]: + continue + if hi - lo > 0x10000000: + continue + regs.append((lo, hi)) + print(f'{len(regs)} rw regions to capture', flush=True) + with open('/tmp/host_rw.bin', 'wb') as f: + for lo, hi in regs: + try: + buf = os.pread(mem, hi - lo, lo) + f.write(lo.to_bytes(8, 'little')) + f.write((hi - lo).to_bytes(8, 'little')) + f.write(buf) + except Exception: + pass + print(f'captured {os.path.getsize("/tmp/host_rw.bin")} bytes', flush=True) + while time.time() - t1 < 30: hits = find_beacon(host) ctxs = set() for p in hits: @@ -96,7 +119,7 @@ def main(): blk = os.pread(mem, 0x8000, ctx + 0x540000) open(f'/tmp/ctx_{ctx:x}_win.bin', 'wb').write(blk) break - time.sleep(0.2) + time.sleep(0.05) os.close(mem) try: proc.wait(timeout=5) diff --git a/rtsnap_fast.py b/rtsnap_fast.py new file mode 100644 index 0000000..31b5a97 --- /dev/null +++ b/rtsnap_fast.py @@ -0,0 +1,44 @@ +import subprocess, os, glob, time, struct, sys +def mem_open(pid): return os.open(f'/proc/{pid}/mem', os.O_RDONLY) +def find_hosts(): + hosts=[] + 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: + hosts.append(pid) + return hosts +os.system("pkill -9 -x reaper 2>/dev/null; pkill -9 -f '[y]abridge' 2>/dev/null; sleep 1") +proc=subprocess.Popen(['/usr/bin/reaper','-nosplash','-ignoreerrors','-renderproject','/home/m/soothe-bt/render_long.rpp'], + stdout=open('/dev/null','w'),stderr=subprocess.STDOUT) +# wait for host +t0=time.time(); host=None +while time.time()-t0<60 and not host: + hs=find_hosts() + host=hs[0] if hs else None + time.sleep(0.2) +print('host',host, flush=True) +time.sleep(6) # let render warm up, tables built +fd=mem_open(host) +out=open('/tmp/snap_all.bin','wb') +idx=open('/tmp/snap_all.idx','wb') +t0=time.time(); nreg=0; nbytes=0 +for line in open(f'/proc/{host}/maps').read().splitlines(): + p=line.split(); lo,hi=(int(x,16) for x in p[0].split('-')) + if 'r' not in p[1]: continue + a=lo + while a