bench: official param bridge (setparam/dump_params.lua) + rpp_setparam format tool; 22c — XML params decorative, depth=+-18dB, trim=+-24dB, reduction curves measured

This commit is contained in:
2026-08-22 18:28:54 +03:00
parent 7fac8b2a4f
commit f5ef81667c
4 changed files with 176 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
#!/usr/bin/env python3
"""rpp_setparam.py — rewrite PARAM values inside a REAPER .rpp soothe2 state chunk.
!!! CAVEAT (NOTES_LEVEL 22c): the XML <PARAM> list is a decorative UI-restore copy,
NOT the VST3 state source. Editing values here does NOT change plugin audio behaviour
(plugin falls back to defaults on any length mismatch). For real param changes use
setparam.lua (TrackFX_SetParam bridge). This tool is kept for format surgery only.
Block layout (joined from N consecutive base64 lines):
[u32 A=len(rest)][u32 ver=1]['VC2!'][u32 B=len(xml)][xml][tail: JUCEPrivateData...]
Both length fields MUST be updated when xml size changes, otherwise the plugin
silently rejects the state and falls back to defaults.
Usage:
python3 scripts/rpp_setparam.py in.rpp out.rpp depth=1.0 release=0.5
"""
import re, base64, struct, sys
def find_block(lines):
idx = [i for i, ln in enumerate(lines) if re.fullmatch(r"[A-Za-z0-9+/=]{40,}", ln.strip())]
start = None
for i in idx:
if base64.b64decode(lines[i].strip())[:1] == b"\x95":
start = i; break
if start is None:
raise SystemExit("no state block found")
end = start
while end + 1 < len(lines) and re.fullmatch(r"[A-Za-z0-9+/=]{40,}", lines[end + 1].strip()):
end += 1
return start, end
def main():
inp, outp = sys.argv[1], sys.argv[2]
sets = dict(kv.split("=", 1) for kv in sys.argv[3:])
lines = open(inp).read().splitlines()
start, end = find_block(lines)
buf = b"".join(base64.b64decode(lines[k].strip()) for k in range(start, end + 1))
a, ver, magic, blen = struct.unpack_from("<II4sI", buf, 0)
i = buf.find(b"<?xml")
head, xml, tail = buf[:i], buf[i:i + blen], buf[i + blen:]
for k, v in sets.items():
pat = f'<PARAM id="{k}" value="'
j = xml.find(pat.encode())
assert j >= 0, f"param {k} not found"
v0 = j + len(pat)
e = xml.index(b'"/>', v0)
print(f" {k}: {xml[v0:e].decode()} -> {v}")
xml = xml[:v0] + v.encode() + xml[e:]
new_blen = len(xml)
new_buf = struct.pack("<II4sI", a - blen + new_blen, ver, magic, new_blen) + xml + tail
ind = re.match(r"\s*", lines[start]).group(0)
width = max(len(lines[k]) - len(ind) for k in range(start, end + 1))
enc = base64.b64encode(new_buf).decode("ascii")
wrapped = [ind + enc[j:j + width] for j in range(0, len(enc), width)]
lines[start:end + 1] = wrapped
open(outp, "w").write("\n".join(lines) + "\n")
print(f"wrote {outp} (block {end-start+1}->{len(wrapped)} lines, xml {blen}->{new_blen})")
if __name__ == "__main__":
main()