Files
SonicForgeStudio/native_bridge/src/SharedMemoryIPC.cpp
T

126 lines
4.2 KiB
C++

// native_bridge/src/SharedMemoryIPC.cpp
#include "SharedMemoryIPC.h"
#include <cstring>
#include <string>
// ── Platform shared-memory helpers (used by main.cpp on Windows and by the
// self-check test on POSIX). The DAW (Rust) creates the mapping; the bridge
// opens it. Layout must match the Rust struct (see src-tauri/src/shm.rs).
#ifdef _WIN32
#include <windows.h>
struct ShmHandle {
HANDLE map = nullptr;
void* view = nullptr;
};
ShmHandle* shm_open(const char* name, size_t size) {
ShmHandle* h = new ShmHandle();
h->map = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, name);
if (!h->map) { delete h; return nullptr; }
h->view = MapViewOfFile(h->map, FILE_MAP_ALL_ACCESS, 0, 0, size);
if (!h->view) { CloseHandle(h->map); delete h; return nullptr; }
return h;
}
// Creates the mapping (used by tests/self-check; the DAW normally owns it).
ShmHandle* shm_create(const char* name, size_t size) {
ShmHandle* h = new ShmHandle();
int wlen = MultiByteToWideChar(CP_UTF8, 0, name, -1, nullptr, 0);
std::wstring wname(wlen, L'\0');
MultiByteToWideChar(CP_UTF8, 0, name, -1, &wname[0], wlen);
h->map = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0,
size, wname.c_str());
if (!h->map) { delete h; return nullptr; }
h->view = MapViewOfFile(h->map, FILE_MAP_ALL_ACCESS, 0, 0, size);
if (!h->view) { CloseHandle(h->map); delete h; return nullptr; }
return h;
}
void shm_close(ShmHandle* h) {
if (!h) return;
if (h->view) UnmapViewOfFile(h->view);
if (h->map) CloseHandle(h->map);
delete h;
}
#else
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
struct ShmHandle {
int fd = -1;
void* view = nullptr;
std::string name;
};
ShmHandle* shm_open(const char* name) {
size_t sz = sizeof(SharedAudioBufferIPC);
int fd = ::shm_open(name, O_CREAT | O_RDWR, 0666);
if (fd < 0) return nullptr;
if (ftruncate(fd, (off_t)sz) != 0) { ::close(fd); return nullptr; }
void* view = mmap(nullptr, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (view == MAP_FAILED) { ::close(fd); return nullptr; }
ShmHandle* h = new ShmHandle();
h->fd = fd;
h->view = view;
h->name = name;
return h;
}
void shm_close(ShmHandle* h) {
if (!h) return;
if (h->view) munmap(h->view, sizeof(SharedAudioBufferIPC));
if (h->fd >= 0) ::close(h->fd);
shm_unlink(h->name.c_str());
delete h;
}
#endif
ShmHandle* shm_open_default() { return shm_open("SonicForge_DAW_IPC"); }
SharedAudioBufferIPC* shm_ptr(ShmHandle* h) {
return h ? static_cast<SharedAudioBufferIPC*>(h->view) : nullptr;
}
SandboxHostIPC* shm_sandbox_ptr(ShmHandle* h) {
return h ? static_cast<SandboxHostIPC*>(h->view) : nullptr;
}
bool shm_write_midi(ShmHandle* h, uint8_t cmd, uint8_t channel, uint8_t pitch,
uint8_t velocity, uint32_t sampleOffset, uint8_t data2, uint8_t data3) {
SharedAudioBufferIPC* ipc = shm_ptr(h);
if (!ipc) return false;
// Ring overwrite guard: keep at most queue capacity pending events.
if (ipc->midiQueueCount >= 64) return false;
uint32_t i = ipc->midiQueueCount++;
SharedAudioBufferIPC::MidiEventIPC& e = ipc->midiQueue[i];
e.command = cmd;
e.channel = channel;
e.pitch = pitch;
e.velocity = velocity;
e.data2 = data2;
e.data3 = data3;
e.sampleOffset = sampleOffset;
return true;
}
bool shm_write_control(ShmHandle* h, uint32_t type, uint32_t arg0, uint32_t arg1,
uint32_t channel, const char* path) {
SharedAudioBufferIPC* ipc = shm_ptr(h);
if (!ipc) return false;
if (ipc->controlQueueCount >= 8) return false;
uint32_t i = ipc->controlQueueCount++;
SharedAudioBufferIPC::ControlEventIPC& c = ipc->controlQueue[i];
c.type = type;
c.arg0 = arg0;
c.channel = channel;
std::memset(c.arg2, 0, sizeof(c.arg2));
if (path && type == 2 /*LOAD*/) {
c.arg1 = (uint32_t)std::strlen(path); // path length in arg1
if (c.arg1 < sizeof(c.arg2)) std::memcpy(c.arg2, path, c.arg1);
} else {
c.arg1 = arg1; // TRANSPORT playhead / OPEN_GUI hwnd etc.
}
return true;
}