Phase 1: import .vstpreset in offline render (loadSerializedState)
daw_vst_bridge --render now applies a VST3 preset when job has 'preset' (base64 of a .vstpreset file). Parse the SDK binary chunk format with PresetFile (vst3sdk), rewrap component/controller state into the bridge blob [4B BE compLen][comp][4B BE ctrlLen][ctrl] and apply via loadSerializedState before rendering. SF2/SFZ ignore preset (warning). Bad base64/magic/chunks fail the job with rc 1 and no partial clip. Tests: golden Nexus .vstpreset fixture; VST3 with/without preset, bad preset -> rc 1, non-VST3 preset ignored. 20/20 pass.
This commit is contained in:
@@ -90,6 +90,56 @@ def main():
|
||||
check("bad plugin_path -> rc 2", rc == 2, f"rc={rc}")
|
||||
check("bad render removes partial out", not os.path.exists(out), "no clip left behind")
|
||||
|
||||
# 5. VST3 render (Nexus) - baseline without preset
|
||||
NEXUS = r"C:\Program Files\Common Files\VST3\Nexus.vst3"
|
||||
GOLDEN = os.path.abspath(os.path.join(os.path.dirname(__file__), "golden", "nexus_default.vstpreset"))
|
||||
if os.path.exists(NEXUS) and os.path.exists(GOLDEN):
|
||||
import base64
|
||||
with open(GOLDEN, "rb") as f:
|
||||
preset_b64 = base64.b64encode(f.read()).decode("ascii")
|
||||
|
||||
job = os.path.join(td, "vst3.json"); out = os.path.join(td, "vst3.wav")
|
||||
rc, log = run_render(make_job(0, NEXUS, td), out)
|
||||
if rc == 0 and os.path.exists(out):
|
||||
frames, rms = read_wav(out)
|
||||
check("VST3 render exit 0", rc == 0, log.strip().splitlines()[-1:] or "")
|
||||
check("VST3 exact duration", frames == TOTAL, f"{frames} == {TOTAL}")
|
||||
check("VST3 non-silent", rms > 0.001, f"rms={rms:.5f}")
|
||||
else:
|
||||
check("VST3 render exit 0", False, f"rc={rc} {log[-400:]}")
|
||||
|
||||
# 6. VST3 render WITH .vstpreset - same default state, must still
|
||||
# render (proves the parse + loadSerializedState path runs).
|
||||
job = os.path.join(td, "vst3p.json"); out = os.path.join(td, "vst3p.wav")
|
||||
jobdict = make_job(0, NEXUS, td); jobdict["preset"] = preset_b64
|
||||
rc, log = run_render(jobdict, out)
|
||||
if rc == 0 and os.path.exists(out):
|
||||
frames, rms = read_wav(out)
|
||||
check("VST3+preset exit 0", rc == 0, log.strip().splitlines()[-1:] or "")
|
||||
check("VST3+preset exact duration", frames == TOTAL, f"{frames} == {TOTAL}")
|
||||
check("VST3+preset non-silent", rms > 0.001, f"rms={rms:.5f}")
|
||||
check("VST3+preset applied (log)", "preset imported" in log, "log has preset imported")
|
||||
else:
|
||||
check("VST3+preset exit 0", False, f"rc={rc} {log[-400:]}")
|
||||
|
||||
# 7. Corrupt preset (not base64) -> rc 1, no partial clip
|
||||
job = os.path.join(td, "vst3bad.json"); out = os.path.join(td, "vst3bad.wav")
|
||||
jobdict = make_job(0, NEXUS, td); jobdict["preset"] = "!!!not-base64!!!"
|
||||
rc, log = run_render(jobdict, out)
|
||||
check("VST3 bad preset -> rc 1", rc == 1, f"rc={rc}")
|
||||
check("bad preset removes partial out", not os.path.exists(out), "no clip left behind")
|
||||
|
||||
# 8. Non-VST3 with preset: ignored (warning), still renders fine
|
||||
job = os.path.join(td, "sf2p.json"); out = os.path.join(td, "sf2p.wav")
|
||||
jobdict = make_job(2, SF2, td); jobdict["preset"] = preset_b64
|
||||
rc, log = run_render(jobdict, out)
|
||||
if rc == 0 and os.path.exists(out):
|
||||
frames, rms = read_wav(out)
|
||||
check("SF2+preset exit 0 (ignored)", rc == 0, log.strip().splitlines()[-1:] or "")
|
||||
check("SF2+preset non-silent", rms > 0.001, f"rms={rms:.5f}")
|
||||
else:
|
||||
check("SF2+preset exit 0 (ignored)", False, f"rc={rc} {log[-400:]}")
|
||||
|
||||
failed = [n for n, ok, _ in results if not ok]
|
||||
print()
|
||||
print(f"{len(results) - len(failed)}/{len(results)} passed")
|
||||
|
||||
Reference in New Issue
Block a user