feat: native host bridge integration — C++ bridge, Rust SHM, JS routing, build scripts, docs
- native_bridge/: InstrumentEngineManager multi-channel, sample-accurate, CC/program/pitchbend, transport, Vst3Instrument stub (HAVE_VST3SDK) - src-tauri: shm.rs, bridge spawn + audio pump + health monitor, open_vst_gui, externalBin, commands - app: UnifiedMidiRouter, NativeBridgeService, bridgeAudioNode, audioRoutingEngine, Plugin Manager UI, Bridge/WASM indicator, set_position sync - build: 3 ps1 (force-added, build/ ignored), verify_bundle --check-bridge, CI workflow - docs: TASKS.md, TEST_NOTES.md (Windows verify checklist), install/report updates
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
// native_bridge/tests/shm_selfcheck.cpp
|
||||
// Self-check for SharedMemoryIPC helpers (assert-based, no framework).
|
||||
// POSIX path runs on Linux/macOS; Win32 path guarded (runs on Windows build).
|
||||
#include "../include/SharedMemoryIPC.h"
|
||||
#include "../src/SharedMemoryIPC.cpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
int main() {
|
||||
// Use a test-only name to avoid clashing with a live DAW bridge.
|
||||
ShmHandle* h = shm_open("SonicForge_SelfCheck_IPC");
|
||||
assert(h != nullptr);
|
||||
|
||||
SharedAudioBufferIPC* ipc = shm_ptr(h);
|
||||
assert(ipc != nullptr);
|
||||
// Reset state (POSIX shm may survive an aborted previous run).
|
||||
std::memset(ipc, 0, sizeof(SharedAudioBufferIPC));
|
||||
|
||||
// 1. MIDI event write + read back (A12: data2/data3 for CC/program/pitch bend)
|
||||
assert(shm_write_midi(h, 0x9, 2, 60, 100, 37));
|
||||
assert(ipc->midiQueueCount == 1);
|
||||
assert(ipc->midiQueue[0].command == 0x9);
|
||||
assert(ipc->midiQueue[0].channel == 2);
|
||||
assert(ipc->midiQueue[0].pitch == 60);
|
||||
assert(ipc->midiQueue[0].velocity == 100);
|
||||
assert(ipc->midiQueue[0].sampleOffset == 37);
|
||||
assert(ipc->midiQueue[0].data2 == 0 && ipc->midiQueue[0].data3 == 0);
|
||||
assert(shm_write_midi(h, 0xB, 3, 64, 0, 0, 127)); // CC64 sustain = 127
|
||||
assert(shm_write_midi(h, 0xE, 3, 0, 0, 0, 0x00, 0x40)); // pitch bend MSB
|
||||
assert(ipc->midiQueue[1].data2 == 127);
|
||||
assert(ipc->midiQueue[2].data3 == 0x40);
|
||||
assert(ipc->midiQueueCount == 3);
|
||||
|
||||
// 2. Control event with path + channel (A10)
|
||||
assert(shm_write_control(h, 2, 1 /*SOUNDFONT_SF2_SF3*/, 0, 4, "C:\\sf\\SGM.sf2"));
|
||||
assert(ipc->controlQueueCount == 1);
|
||||
assert(ipc->controlQueue[0].type == 2);
|
||||
assert(ipc->controlQueue[0].arg0 == 1);
|
||||
assert(ipc->controlQueue[0].channel == 4);
|
||||
assert(std::strcmp(ipc->controlQueue[0].arg2, "C:\\sf\\SGM.sf2") == 0);
|
||||
// TRANSPORT (A13): STOP with playhead arg
|
||||
assert(shm_write_control(h, 3, 0, 44100, 0, ""));
|
||||
assert(ipc->controlQueue[1].type == 3 && ipc->controlQueue[1].arg0 == 0
|
||||
&& ipc->controlQueue[1].arg1 == 44100);
|
||||
|
||||
// 3. Queue capacity guard
|
||||
for (int i = 0; i < 70; ++i) shm_write_midi(h, 0x8, 0, 40, 0, 0);
|
||||
assert(ipc->midiQueueCount == 64); // capped, not overflowed
|
||||
|
||||
// 4. Audio block round-trip
|
||||
for (uint32_t i = 0; i < AUDIO_BLOCK_SIZE; ++i) ipc->masterLeft[i] = (float)i;
|
||||
ipc->bridgeWriteIndex++;
|
||||
ipc->blockTimestamp = 123456;
|
||||
assert(ipc->masterLeft[255] == 255.0f);
|
||||
assert(ipc->bridgeWriteIndex == 1);
|
||||
assert(ipc->blockTimestamp == 123456);
|
||||
|
||||
// 5. Layout stability — MUST match Rust src-tauri/src/shm.rs
|
||||
assert(sizeof(SharedAudioBufferIPC::MidiEventIPC) == 12);
|
||||
assert(sizeof(SharedAudioBufferIPC::ControlEventIPC) == 1040);
|
||||
|
||||
std::printf("SHM self-check OK (sizeof struct = %zu bytes)\n", sizeof(SharedAudioBufferIPC));
|
||||
shm_close(h);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user