A14: MIDI-out từ plugin (VST2/VST3) → SHM → Rust emit → DAW track
- Vst2Instrument: audioMaster callback thu VstEvents, push SHM midiOutQueue
- Vst3Instrument: IEventList output bus (kAudioMasterWantMidi) — check
- SharedMemoryIPC.h: midiOutQueue[64] + midiOutCount (offset 27556/28324, sizeof 28328)
- shm.rs: MidiEventIPC Serialize, drain_midi_out() emit 'bridge-midi-out'
- lib.rs: pump emit midi-out events
- nativeBridgeService.js: onMidiOut API
- app.jsx: route MIDI-out về selected track qua SonicMidiRouter (feedback guard)
- TASKS.md: A14 ✅
This commit is contained in:
@@ -120,6 +120,7 @@ static std::mutex g_guiMutex;
|
||||
static std::map<uint32_t, void*> g_guiWindows; // channel -> HWND (keep window alive)
|
||||
static std::map<HWND, uint32_t> g_hwndToCh; // HWND -> channel (WM_DESTROY cleanup)
|
||||
static ChannelWorker* g_uiWorker = nullptr;
|
||||
static SharedAudioBufferIPC* g_shmIPC = nullptr; // A14: midi-out hook writes SHM
|
||||
// VST2 (DUNE 3) thread contract: entry + init dispatcher + processReplacing
|
||||
// must share ONE thread. processReplacing runs on the audio (main) thread,
|
||||
// so VST2 loads (LoadLibrary + VSTPluginMain + init dispatcher) are deferred
|
||||
@@ -852,6 +853,7 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
auto* shmIPC = (SharedAudioBufferIPC*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(SharedAudioBufferIPC));
|
||||
if (!shmIPC) { CloseHandle(hMapFile); return 1; }
|
||||
g_shmIPC = shmIPC; // A14: midi-out hook (audio thread) writes SHM via this
|
||||
// VSTi crackle fix: 8-slot audio ring (see SharedMemoryIPC.h). Must be set
|
||||
// on Windows too — ringMask stays 0 otherwise and the ring collapses to
|
||||
// 1 slot (slot = writeIndex & 0), dropping whole blocks on any jank.
|
||||
@@ -903,6 +905,26 @@ int main(int argc, char* argv[]) {
|
||||
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
});
|
||||
});
|
||||
// A14: plugin MIDI output sink. audioMaster(kAudioMasterProcessEvents)
|
||||
// (VstEvents from Scaler2/Instacomposer/...) -> SHM midiOutQueue,
|
||||
// drained by the Tauri pump to `bridge-midi-out`, JS routes notes to
|
||||
// DAW tracks. Append-only, no mutex — same pattern as midiQueue (audio
|
||||
// thread writes, pump reads+resets). Cap 64; drop when full.
|
||||
Vst2Instrument::setMidiOutHook([](uint8_t cmd, uint8_t ch, uint8_t d1,
|
||||
uint8_t d2, uint32_t deltaFrames) {
|
||||
if (!g_shmIPC) return;
|
||||
if (g_shmIPC->midiOutCount >= 64) return;
|
||||
auto& ev = g_shmIPC->midiOutQueue[g_shmIPC->midiOutCount++];
|
||||
ev.command = cmd;
|
||||
ev.channel = ch;
|
||||
ev.pitch = d1;
|
||||
ev.velocity = d2;
|
||||
ev.data2 = 0;
|
||||
ev.data3 = 0;
|
||||
ev.reserved[0] = 0;
|
||||
ev.reserved[1] = 0;
|
||||
ev.sampleOffset = deltaFrames;
|
||||
});
|
||||
// B9: native editor windows per channel — keep alive (HWND outlives the job).
|
||||
// Registry la global (g_guiWindows) — WM_DESTROY cleanup can tu VstWindowProc.
|
||||
// B8: sample rate from the DAW (Rust spawns us with SF_SAMPLE_RATE).
|
||||
|
||||
Reference in New Issue
Block a user