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:
@@ -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()
|
||||
Reference in New Issue
Block a user