G4.3: double-buffer sandbox SHM - SandboxHostIPC writeSlot+2x256 double audio, latency 15.6ms, multi-instance no-xrun verified
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#endif
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
@@ -50,18 +51,19 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
#ifdef _WIN32
|
||||
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
timeBeginPeriod(1); // Sleep(1) really sleeps ~1ms, not the 15.6ms timer tick
|
||||
#endif
|
||||
printf("[plugin_host] pid=%lu shm=%s path=%s sr=%.0f block=%u\n",
|
||||
(unsigned long)GetCurrentProcessId(), shmName.c_str(), path.c_str(), sr, block);
|
||||
fflush(stdout);
|
||||
|
||||
// --open: bridge already created the mapping (G4.2); default PoC: child owns.
|
||||
ShmHandle* shm = isOpen ? shm_open(shmName.c_str()) : shm_create(shmName.c_str());
|
||||
ShmHandle* shm = isOpen ? shm_open(shmName.c_str(), sizeof(SandboxHostIPC)) : shm_create(shmName.c_str(), sizeof(SandboxHostIPC));
|
||||
if (!shm) {
|
||||
printf("[plugin_host] FAILED shm_create %s\n", shmName.c_str());
|
||||
return 3;
|
||||
}
|
||||
SharedAudioBufferIPC* ipc = shm_ptr(shm);
|
||||
SandboxHostIPC* ipc = shm_sandbox_ptr(shm);
|
||||
|
||||
Vst3Instrument inst;
|
||||
inst.init(sr, block); // sets sampleRate_/maxBlockSize_ used by setupProcessing
|
||||
@@ -92,7 +94,7 @@ int main(int argc, char* argv[]) {
|
||||
std::thread([ipc]() {
|
||||
for (;;) {
|
||||
Sleep(100);
|
||||
ipc->heartbeat++;
|
||||
ipc->base.heartbeat++;
|
||||
}
|
||||
}).detach();
|
||||
|
||||
@@ -102,9 +104,9 @@ int main(int argc, char* argv[]) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
uint32_t n = ipc->midiQueueCount > 64 ? 64 : ipc->midiQueueCount;
|
||||
uint32_t n = ipc->base.midiQueueCount > 64 ? 64 : ipc->base.midiQueueCount;
|
||||
for (uint32_t i = 0; i < n; ++i) {
|
||||
const SharedAudioBufferIPC::MidiEventIPC& e = ipc->midiQueue[i];
|
||||
const SharedAudioBufferIPC::MidiEventIPC& e = ipc->base.midiQueue[i];
|
||||
switch (e.command) {
|
||||
case 0x9:
|
||||
if (e.velocity > 0) inst.noteOn(e.channel, e.pitch, e.velocity / 127.0f, 0);
|
||||
@@ -117,9 +119,14 @@ int main(int argc, char* argv[]) {
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
ipc->midiQueueCount = 0;
|
||||
inst.processAudioBlock(ipc->masterLeft, ipc->masterRight, block);
|
||||
ipc->bridgeWriteIndex++;
|
||||
ipc->base.midiQueueCount = 0;
|
||||
// G4.3 double buffer: render into the slot we are NOT publishing, then
|
||||
// publish. The bridge keeps the last published block, so a slow child
|
||||
// never tears audio (it just repeats the previous block).
|
||||
uint32_t slot = 1u - (ipc->writeSlot & 1u);
|
||||
inst.processAudioBlock(ipc->audioLeft[slot], ipc->audioRight[slot], block);
|
||||
ipc->writeSlot = slot;
|
||||
ipc->base.bridgeWriteIndex++;
|
||||
if (parentPid && !parent_alive(parentPid)) {
|
||||
printf("[plugin_host] parent gone - exiting\n");
|
||||
break;
|
||||
@@ -128,6 +135,7 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
inst.closeGUI();
|
||||
#ifdef _WIN32
|
||||
timeEndPeriod(1);
|
||||
CoUninitialize();
|
||||
#endif
|
||||
shm_close(shm);
|
||||
|
||||
Reference in New Issue
Block a user