118 lines
4.0 KiB
Python
118 lines
4.0 KiB
Python
#!/usr/bin/env python3
|
|
import subprocess, os, glob, sys, time, struct
|
|
|
|
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/rtwin.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)
|
|
|
|
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('<I', d, o + 0x19c)[0]
|
|
n1 = struct.unpack_from('<I', d, o + 0x1a0)[0]
|
|
u = struct.unpack_from('<I', d, o + 0x1ac)[0]
|
|
if n0 in N_POW2 and n1 == n0 and u in UPS:
|
|
w = struct.unpack_from('<f', d, o + 0x1a4)[0]
|
|
if 0.1 < w < 5.0:
|
|
found.append((lo + o))
|
|
print('PID', pid, 'SP objects:', [hex(a) for a in found], flush=True)
|
|
# dump a generous window around each object; hunt for a sin-quarter table
|
|
for a in found:
|
|
try:
|
|
big = os.pread(mem, 0x400000, a)
|
|
except Exception:
|
|
continue
|
|
db = struct.unpack('<%dQ' % (len(big) // 8), big)
|
|
# sin table starts with 0.0 then sin(2*pi/N)... find 513 consecutive doubles matching
|
|
import math
|
|
N = 2048
|
|
step = 2 * math.pi / N
|
|
best = None
|
|
for o in range(0, len(db) - 520):
|
|
# candidate: db[o]==0 and db[o+1]~sin(step), monotonic up to pi/2
|
|
if db[o] != 0:
|
|
continue
|
|
# convert qwords to doubles for compare window
|
|
ok = True
|
|
for k in range(1, 8):
|
|
v0 = struct.unpack('<d', struct.pack('<Q', db[o + k]))[0]
|
|
e = math.sin(k * step)
|
|
if abs(v0 - e) > 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('<d', struct.pack('<Q', db[best + k]))[0] for k in range(1024)]
|
|
with open('twiddle_2048_ref.f64', 'wb') as f:
|
|
for v in vals:
|
|
f.write(struct.pack('<d', v))
|
|
print(' first:', ' '.join('%.9g' % v for v in vals[:6]), flush=True)
|
|
print(' at 256 (pi/2):', vals[256], flush=True)
|
|
print(' saved twiddle_2048_ref.f64', flush=True)
|
|
os.close(mem)
|
|
proc.kill()
|
|
print('done', flush=True) |