feat(bridge): add --render offline CLI (Phase 0 of pedalboard replacement)

daw_vst_bridge --render <job.json> --out <clip.wav> renders MIDI notes
through the same instrument engines as realtime (SF2/SFZ/VST3/VST2) to a
16-bit stereo WAV, headless, no SHM. Mirrors plugins.py/vst_engine.py
note semantics (velocity int(vel*127), bank CC0 + program at t=0, beatSec
60/max(30,bpm), totalNeeded max(1024,endSample), no tail). Chunk clamped
to 256 to match VST3 host prepared buffers. Uses vendored sheredom json.h
(gated on HAVE_VST3SDK); rc: 0 ok, 1 arg/job error, 2 load fail, 3 crash.
Partial output removed on failure. Verified: SF2, SFZ, Nexus VST3 render
non-silent at exact duration; 9/9 tests pass.
This commit is contained in:
2026-08-17 08:04:25 +07:00
parent 4111995a5c
commit 0cca84c5f9
6 changed files with 426 additions and 0 deletions
+15
View File
@@ -5,6 +5,7 @@
#include "SharedMemoryIPC.h"
#include "NativeInstrumentEngine.h"
#include "StateStore.h"
#include "RenderJob.h"
#ifdef _WIN32
#include <windows.h>
@@ -599,6 +600,20 @@ int main(int argc, char* argv[]) {
#endif
// --render <job.json> --out <clip.wav>: one-shot offline render, no SHM/loop.
std::string renderJob, renderOut;
for (int i = 1; i < argc; ++i) {
if (std::strcmp(argv[i], "--render") == 0 && i + 1 < argc) renderJob = argv[i + 1];
else if (std::strcmp(argv[i], "--out") == 0 && i + 1 < argc) renderOut = argv[i + 1];
}
if (!renderJob.empty()) {
if (renderOut.empty()) {
std::cerr << "[RenderJob] --render requires --out <clip.wav>" << std::endl;
return 1;
}
return run_render_job(renderJob, renderOut);
}
// 1. Shared memory name: argv --shm <name> | env SF_SHM_NAME | default
std::string shmName = "SonicForge_DAW_IPC";
for (int i = 1; i + 1 < argc; ++i) {