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:
@@ -1797,6 +1797,38 @@ function getAudioContext() {
|
||||
}
|
||||
window.BridgeAudioNode.init(audioCtx);
|
||||
window.NativeBridgeService.onAudio(function (l, r) { window.BridgeAudioNode.onAudio(l, r); });
|
||||
// A14: plugin MIDI output -> route notes to the selected track
|
||||
// (Scaler2/Instacomposer chords play the selected track's
|
||||
// instrument). Feedback guard: skip events whose source channel
|
||||
// is the selected track's own channel (would loop generator into
|
||||
// itself). command is the VST2 status high nibble (0x90 etc.).
|
||||
window.NativeBridgeService.onMidiOut(function (events) {
|
||||
if (!events || !events.length) return;
|
||||
var ref = window.__selectedTrackIdRef;
|
||||
var tId = (ref && ref.current) ? ref.current : '1';
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
var ev = events[i];
|
||||
var cmd;
|
||||
switch (ev.command) {
|
||||
case 0x90: cmd = ev.velocity > 0 ? 'NOTE_ON' : 'NOTE_OFF'; break;
|
||||
case 0x80: cmd = 'NOTE_OFF'; break;
|
||||
case 0xB0: cmd = 'CC'; break;
|
||||
case 0xC0: cmd = 'PROGRAM'; break;
|
||||
case 0xE0: cmd = 'PITCH_BEND'; break;
|
||||
default: continue;
|
||||
}
|
||||
if (window.SonicMidiRouter && window.SonicMidiRouter.isBridgeActive()) {
|
||||
var tCh = window.SonicMidiRouter.allocateChannel(tId, false);
|
||||
if (tCh === ev.channel) continue; // feedback guard
|
||||
window.SonicMidiRouter.pushEvent({
|
||||
cmd: cmd, channel: tId, pitch: ev.pitch,
|
||||
velocity: ev.velocity / 127, data2: ev.data2, data3: ev.data3,
|
||||
sampleOffset: ev.sample_offset || 0, live: true
|
||||
});
|
||||
}
|
||||
console.log('[Bridge] MIDI-out', cmd, 'ch', ev.channel, 'note', ev.pitch, 'vel', ev.velocity, '-> track', tId);
|
||||
}
|
||||
});
|
||||
if (window.AudioRoutingEngine) window.AudioRoutingEngine.connect(window.BridgeAudioNode, null, null);
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -18976,6 +19008,9 @@ const App = () => {
|
||||
selectedClipIdRef.current = selectedClipId;
|
||||
const selectedTrackIdRef = useRef(selectedTrackId);
|
||||
selectedTrackIdRef.current = selectedTrackId;
|
||||
// A14: plugin MIDI-out routing target — bootstrap handler (module scope)
|
||||
// reads the live selection through this window ref (avoid stale closure).
|
||||
window.__selectedTrackIdRef = selectedTrackIdRef;
|
||||
const handleDeleteTrackRef = useRef(() => {});
|
||||
const handleSplitTrackRef = useRef(() => {});
|
||||
const handleRecordClickRef = useRef(() => {});
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
activeInstrumentType: 'VST3',
|
||||
_audioCb: null,
|
||||
_statusCb: null,
|
||||
_midiOutCb: null,
|
||||
_tauri: function () { return window.__TAURI__; },
|
||||
|
||||
/** D10: UI subscribes to bridge connection changes. cb({connected}) or null to clear. */
|
||||
@@ -58,6 +59,12 @@
|
||||
if (!self.isBridgeConnected) self._reconnectIfNeeded();
|
||||
if (self._audioCb) self._audioCb(e.payload.l, e.payload.r);
|
||||
});
|
||||
// A14: plugin MIDI output (VstEvents -> SHM midiOutQueue -> pump).
|
||||
// Payload: array of {command, channel, pitch, velocity, data2,
|
||||
// data3, reserved, sample_offset}. JS routes notes to DAW tracks.
|
||||
window.__TAURI__.event.listen('bridge-midi-out', function (e) {
|
||||
if (self._midiOutCb) self._midiOutCb(e.payload);
|
||||
});
|
||||
window.__TAURI__.event.listen('bridge-down', function () {
|
||||
self._notifyStatus(false);
|
||||
if (window.SonicMidiRouter) window.SonicMidiRouter.setBridgeConnected(false);
|
||||
@@ -187,6 +194,13 @@
|
||||
*/
|
||||
onAudio: function (cb) {
|
||||
this._audioCb = cb;
|
||||
},
|
||||
|
||||
/** A14: register consumer of plugin MIDI output.
|
||||
* cb(events): array of {command, channel, pitch, velocity, data2,
|
||||
* data3, reserved, sample_offset} — route to DAW tracks. */
|
||||
onMidiOut: function (cb) {
|
||||
this._midiOutCb = cb;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user