#!/usr/bin/env python3 """Batch soothes2 RPP render runner with hang protection. Usage: run_sweep.py [--src burst500.wav] [--dur 2.0] [--outdir ...] grid.json: { "name": "verif", "base": "/home/m/soothe-bt/render_rt.rpp", "data": [ {"rpp":"d05", "wav":"d05.wav", "params":{"depth":"0.5!"}}, ... ] } Each data row renders base template with src substituted and params applied, then runs reaper -renderproject with a per-render timeout and kills on hang. """ import json, sys, os, time, subprocess, signal, argparse sys.path.insert(0, '/home/m/re-tools') from mkbase import patch_tt from tt_sweep import TPL as _x # noqa REAPER = '/usr/bin/reaper' SRC = '/home/m/soothe-bt/burst500p.wav' DUR = 2.0 OUTDIR = '/home/m/soothe-bt' def render(rpp, timeout=150): proc = subprocess.Popen([REAPER, '-nosplash', '-renderproject', rpp], stdout=open('/tmp/render.log','w'), stderr=subprocess.STDOUT) try: return proc.wait(timeout=timeout) except subprocess.TimeoutExpired: for sig in (signal.SIGTERM, signal.SIGKILL): try: proc.send_signal(sig); proc.wait(timeout=5) except Exception: pass print(f' !! HANG killed {rpp}') return 'hang' def pkill_sos(): os.system("pkill -9 -x reaper 2>/dev/null; pkill -9 -f '[y]abridge' 2>/dev/null") def main(): ap = argparse.ArgumentParser() ap.add_argument('grid') ap.add_argument('--src', default=SRC) ap.add_argument('--dur', type=float, default=DUR) ap.add_argument('--outdir', default=OUTDIR) a = ap.parse_args() g = json.load(open(a.grid)) pkill_sos(); time.sleep(1) miss = 0 for row in g['data']: rpp = os.path.join(a.outdir, row['rpp'] + '.rpp') wav = os.path.join(a.outdir, row['wav']) if not os.path.exists(wav): patch_tt(g['base'], a.src, rpp, wav, dur=a.dur) # now patch params on top os.system(f"python3 /home/m/re-tools/tt_sweep.py {rpp} {rpp}.tmp {wav} " + ' '.join(f'{k}={v.rstrip("!")}' for k, v in row['params'].items())) os.rename(rpp + '.tmp', rpp) rc = render(rpp) print(f"{row['rpp']}: render rc={rc}") miss += 1 if os.path.exists(wav) else 0 else: print(f"{row['rpp']}: already exists") print(f"done. rendered {miss} fresh.") if __name__ == '__main__': main()