diff --git a/rttbl.py b/rttbl.py new file mode 100644 index 0000000..7e7f509 --- /dev/null +++ b/rttbl.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 +import subprocess, os, glob, sys, time, struct, math + +RPP = "/home/m/soothe-bt/render_short.rpp" +OUT = "/home/m/soothe-bt/out_rt.wav" +proc = subprocess.Popen(['reaper', '-nosplash', '-renderproject', RPP], + stdout=open('/tmp/rttbl.log', 'w'), stderr=subprocess.STDOUT) +print('reaper', proc.pid, flush=True) + +def find_hosts(): + out = [] + for p in glob.glob('/proc/[0-9]*'): + try: + pid = int(os.path.basename(p)) + m = open(f'/proc/{pid}/maps').read() + c = open(f'/proc/{pid}/cmdline', 'rb').read().decode('utf8', 'replace') + if 'soothe2' in m and 'yabridge-host.exe' in c: + out.append(pid) + except Exception: + pass + return out + +def out_growth(): + try: + return os.path.getsize(OUT) + except Exception: + return 0 + +t0 = time.time() +hosts = None +base_sz = out_growth() +while time.time() - t0 < 60: + hosts = find_hosts() + if hosts: + break + time.sleep(0.2) +print('hosts:', hosts, flush=True) +grew = 0 +while time.time() - t0 < 120: + s = out_growth() + if s > base_sz: + grew = s; break + if proc.poll() is not None: + print('reaper exited early', flush=True); break + time.sleep(0.3) +print('out:', grew, flush=True) +if not hosts or grew == 0: + proc.kill(); sys.exit('fail') +time.sleep(0.5) + +step = 2 * math.pi / 2048 +def qsin(k): + # sin(k*step) search tolerance 1e-6 (we only need anchor match) + return math.sin(k * step) + +for pid in hosts: + mem = os.open(f'/proc/{pid}/mem', os.O_RDONLY) + tables = [] + maps = open(f'/proc/{pid}/maps').read() + for line in maps.splitlines(): + p = line.split() + lo, hi = (int(x, 16) for x in p[0].split('-')) + if 'r' not in p[1]: + continue + if lo < 0x180000000 or lo >= 0x183000000: + try: + d = os.pread(mem, hi - lo, lo) + except Exception: + continue + if len(d) < 16: + continue + q = len(d) // 8 + qw = struct.unpack('<%dQ' % q, memoryview(d)[:q * 8]) + for o in range(0, q - 4): + if qw[o] != 0: + continue + # candidate anchor: qw[o]==0.0 and qw[o+1] approx sin(step), qw[o+2] approx sin(2step) + v1 = struct.unpack(' base_sz: + grew = s; break + if proc.poll() is not None: + print('reaper exited early', flush=True); break + time.sleep(0.3) +print('out:', grew, flush=True) +if not hosts or grew == 0: + proc.kill(); sys.exit('fail') +time.sleep(0.5) + +N_POW2 = {2048, 4096} +UPS = {2,4,8,16} + +for pid in hosts: + mem = os.open(f'/proc/{pid}/mem', os.O_RDONLY) + found = [] + maps = open(f'/proc/{pid}/maps').read() + for line in maps.splitlines(): + p = line.split() + lo, hi = (int(x, 16) for x in p[0].split('-')) + if 'r' not in p[1]: + continue + if lo < 0x180000000 or lo >= 0x183000000: + try: + d = os.pread(mem, hi - lo, lo) + except Exception: + continue + if len(d) < 0x1ac + 8: + continue + for o in range(0, len(d) - (0x1ac + 8), 8): + n0 = struct.unpack_from(' 1e-9 and k <= 4: + ok = False + break + if ok: + best = o + break + if best is not None: + tgt = a + best * 8 + print(' table start ~', hex(tgt), 'collecting 1024 doubles', flush=True) + vals = [struct.unpack('