G4.3: double-buffer sandbox SHM - SandboxHostIPC writeSlot+2x256 double audio, latency 15.6ms, multi-instance no-xrun verified
This commit is contained in:
@@ -57,12 +57,12 @@ bool SandboxVst3Host::spawnChild() {
|
||||
shm_ = nullptr;
|
||||
ipc_ = nullptr;
|
||||
}
|
||||
shm_ = shm_create(shmName_.c_str());
|
||||
shm_ = shm_create(shmName_.c_str(), sizeof(SandboxHostIPC));
|
||||
if (!shm_) {
|
||||
std::cerr << "[SandboxVst3Host] shm_create failed ch=" << channel_ << std::endl;
|
||||
return false;
|
||||
}
|
||||
ipc_ = shm_ptr(shm_);
|
||||
ipc_ = shm_sandbox_ptr(shm_);
|
||||
|
||||
// plugin_host.exe sits next to daw_vst_bridge.exe (same dir, install/).
|
||||
char exePath[MAX_PATH] = {};
|
||||
@@ -96,7 +96,7 @@ bool SandboxVst3Host::spawnChild() {
|
||||
#endif
|
||||
|
||||
// Wait for the child heartbeat (Nexus load can take 30s+).
|
||||
uint32_t hb = ipc_->heartbeat;
|
||||
uint32_t hb = ipc_->base.heartbeat;
|
||||
auto t0 = std::chrono::steady_clock::now();
|
||||
while (std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::steady_clock::now() - t0).count() < 60) {
|
||||
@@ -104,7 +104,7 @@ bool SandboxVst3Host::spawnChild() {
|
||||
std::cerr << "[SandboxVst3Host] child exited during load ch=" << channel_ << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (ipc_->heartbeat != hb) {
|
||||
if (ipc_->base.heartbeat != hb) {
|
||||
alive_.store(true);
|
||||
return true;
|
||||
}
|
||||
@@ -125,7 +125,8 @@ void SandboxVst3Host::watchdogLoop() {
|
||||
continue;
|
||||
}
|
||||
alive_.store(false);
|
||||
std::cerr << "[SandboxVst3Host] child died ch=" << channel_ << " — respawning" << std::endl;
|
||||
DWORD ec = 0; GetExitCodeProcess(childProc_, &ec);
|
||||
std::cerr << "[SandboxVst3Host] child died ch=" << channel_ << " rc=" << ec << " — respawning" << std::endl;
|
||||
++fails;
|
||||
if (fails >= 3) {
|
||||
std::cerr << "[SandboxVst3Host] ch=" << channel_
|
||||
@@ -180,11 +181,12 @@ void SandboxVst3Host::processAudioBlock(float* outputL, float* outputR, uint32_t
|
||||
std::memset(outputR, 0, numSamples * sizeof(float));
|
||||
return;
|
||||
}
|
||||
// The child renders the latest full block into masterLeft/Right
|
||||
// continuously. Copy a stable snapshot (G4.3 replaces this with a ring
|
||||
// buffer for sample-accurate, lock-free realtime handoff).
|
||||
// G4.3: the child publishes the slot it finished rendering (writeSlot).
|
||||
// Copy that block. A stale slot means the child is still working on the
|
||||
// other one — we repeat the previous block instead of tearing.
|
||||
uint32_t slot = ipc_->writeSlot & 1u;
|
||||
for (uint32_t i = 0; i < numSamples; ++i) {
|
||||
outputL[i] = ipc_->masterLeft[i];
|
||||
outputR[i] = ipc_->masterRight[i];
|
||||
outputL[i] = ipc_->audioLeft[slot][i];
|
||||
outputR[i] = ipc_->audioRight[slot][i];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user