T7: hardware MIDI keyboard route qua UnifiedMidiRouter (3 nguon 1 router)
This commit is contained in:
@@ -817,27 +817,32 @@ const scaledVel=Math.min(127,Math.max(1,Math.round(rawVel)));if(cmd===0x9&&rawVe
|
||||
// đây chỉ keybed ảo gọi __ensureMasteringRouting).
|
||||
try{if(window.__ensureMasteringRouting)window.__ensureMasteringRouting();}catch(er){}// Route MIDI input to ALL armed tracks on their dedicated channels
|
||||
// Do NOT use raw MIDI hardware channel (msg.data[0] & 0x0F)
|
||||
if(window.SonicSF){var allTracks=activeTracksRef.current||[];var arSubs=subTabsRef&&subTabsRef.current?subTabsRef.current.filter(function(s){return s.type==='PIANO_ROLL'&&s.isArmed;}):[];var armedTracks=allTracks.filter(function(t){return t.isArmed;});// Piano Roll arming has priority: route to each armed sub-tab's parent track
|
||||
if(window.SonicSF){var allTracks=activeTracksRef.current||[];var arSubs=subTabsRef&&subTabsRef.current?subTabsRef.current.filter(function(s){return s.type==='PIANO_ROLL'&&s.isArmed;}):[];var armedTracks=allTracks.filter(function(t){return t.isArmed;});// T7: UnifiedMidiRouter gom targets, dispatch 1 lan sau 2 vong.
|
||||
var hwRouter=_getMidiRouter();var hwTargets=[];// Piano Roll arming has priority: route to each armed sub-tab's parent track
|
||||
if(arSubs.length>0){arSubs.forEach(function(as){var asTrk=allTracks.find(function(t){return t.id===as.trackId;});var asCh=asTrk?assignTrackMidiChannel(asTrk,allTracks):0;var asProg=as.instrumentProgram;var asSe=as.synth_engine;if(window.triggerMidiVuActivity){window.triggerMidiVuActivity(as.trackId,scaledVel);}// Giữ VU theo trường độ: tăng counter note đang giữ
|
||||
// (tick giữ peak cho tới khi note-off)
|
||||
try{heldMidiNotesRef.current[as.trackId]=(heldMidiNotesRef.current[as.trackId]||0)+1;}catch(err){}if(isStandaloneSf()&&isSfTrackEngine(asSe)&&!shouldRouteCarla(asSe)){if(!_routeNoteOn(asTrk&&asTrk.id,_makeCtx(asCh,asProg,asSe,null),pitch,scaledVel/127,60000,'HARDWARE_KEYBOARD')){window.SonicSF.playNote(pitch,scaledVel,60000,undefined,asProg,null,asCh,asSe);}}else{window.SonicSF.playNote(pitch,scaledVel,60000,undefined,asProg,null,asCh,asSe);}// MIDI Keyboard → Carla bridge (piano roll sub-tab ARM):
|
||||
try{heldMidiNotesRef.current[as.trackId]=(heldMidiNotesRef.current[as.trackId]||0)+1;}catch(err){}if(hwRouter&&asTrk&&asTrk.id){hwTargets.push({trackId:asTrk.id,ch:asCh,engine:new window.TrackInstrument(asTrk.id,_makeCtx(asCh,asProg,asSe,null))});}else if(isStandaloneSf()&&isSfTrackEngine(asSe)&&!shouldRouteCarla(asSe)){if(!_routeNoteOn(asTrk&&asTrk.id,_makeCtx(asCh,asProg,asSe,null),pitch,scaledVel/127,60000,'HARDWARE_KEYBOARD')){window.SonicSF.playNote(pitch,scaledVel,60000,undefined,asProg,null,asCh,asSe);}}else{window.SonicSF.playNote(pitch,scaledVel,60000,undefined,asProg,null,asCh,asSe);}// MIDI Keyboard → Carla bridge (piano roll sub-tab ARM):
|
||||
// track VSTi của sub-tab phát VSTi realtime giống keybed.
|
||||
if(window.SonicCarlaMidi&&window.SonicCarlaMidi.shouldRoute(asSe,true)){try{window.SonicCarlaMidi.noteOn(asCh,pitch,scaledVel);}catch(e){}}});}// Route to ALL armed tracks (not just the first one)
|
||||
armedTracks.forEach(function(at){var atCh=assignTrackMidiChannel(at,allTracks);var atProg=at.instrumentProgram;var atSe=at.synth_engine;var atDest=activeTrackNodesRef.current[at.id]?.gainNode||null;if(window.triggerMidiVuActivity){window.triggerMidiVuActivity(at.id,scaledVel);}// Giữ VU theo trường độ: tăng counter note đang giữ
|
||||
try{heldMidiNotesRef.current[at.id]=(heldMidiNotesRef.current[at.id]||0)+1;}catch(err){}if(isStandaloneSf()&&isSfTrackEngine(atSe)&&!shouldRouteCarla(atSe)){if(!_routeNoteOn(at&&at.id,_makeCtx(atCh,atProg,atSe,atDest),pitch,scaledVel/127,60000,'HARDWARE_KEYBOARD')){window.SonicSF.playNote(pitch,scaledVel,60000,undefined,atProg,atDest,atCh,atSe);}}else{window.SonicSF.playNote(pitch,scaledVel,60000,undefined,atProg,atDest,atCh,atSe);}// MIDI Keyboard → Carla bridge (track VSTi + ARM + Carla
|
||||
try{heldMidiNotesRef.current[at.id]=(heldMidiNotesRef.current[at.id]||0)+1;}catch(err){}if(hwRouter&&at&&at.id){hwTargets.push({trackId:at.id,ch:atCh,engine:new window.TrackInstrument(at.id,_makeCtx(atCh,atProg,atSe,atDest))});}else if(isStandaloneSf()&&isSfTrackEngine(atSe)&&!shouldRouteCarla(atSe)){if(!_routeNoteOn(at&&at.id,_makeCtx(atCh,atProg,atSe,atDest),pitch,scaledVel/127,60000,'HARDWARE_KEYBOARD')){window.SonicSF.playNote(pitch,scaledVel,60000,undefined,atProg,atDest,atCh,atSe);}}else{window.SonicSF.playNote(pitch,scaledVel,60000,undefined,atProg,atDest,atCh,atSe);}// MIDI Keyboard → Carla bridge (track VSTi + ARM + Carla
|
||||
// local): phát VSTi realtime — giống hệt keybed ảo. Trước
|
||||
// đây chỉ keybed gọi SonicCarlaMidi; keyboard hardware bị
|
||||
// bỏ sót → track VSTi không kêu khi bấm đàn thật.
|
||||
if(window.SonicCarlaMidi&&window.SonicCarlaMidi.shouldRoute(atSe,at.isArmed)){try{window.SonicCarlaMidi.noteOn(atCh,pitch,scaledVel);}catch(e){}}});}}else if(cmd===0x8||cmd===0x9&&rawVel===0){activeMidiPitchesRef.current.delete(pitch);setActiveMidiPitches(new Set(activeMidiPitchesRef.current));const current=lastMidiNoteRef.current;if(current&¤t.pitch===pitch){const lenSec=(performance.now()-current.startTime)/1000;lastMidiNoteRef.current={...current,length:lenSec};setLastMidiNote(prev=>prev&&prev.pitch===pitch?{...prev,length:lenSec,time:Date.now()}:prev);}// Stop the note on ALL tracks (not just armed) to prevent stuck notes
|
||||
if(window.SonicCarlaMidi&&window.SonicCarlaMidi.shouldRoute(atSe,at.isArmed)){try{window.SonicCarlaMidi.noteOn(atCh,pitch,scaledVel);}catch(e){}}});// T7: dispatch 1 lan qua router - keybed/scheduler/hardware
|
||||
// chung 1 voice tracker (chong stuck note khi doi engine).
|
||||
if(hwRouter&&hwTargets.length){hwRouter.handleHardwareKeyboardMessage(msg.data,hwTargets,[]);}}}else if(cmd===0x8||cmd===0x9&&rawVel===0){activeMidiPitchesRef.current.delete(pitch);setActiveMidiPitches(new Set(activeMidiPitchesRef.current));const current=lastMidiNoteRef.current;if(current&¤t.pitch===pitch){const lenSec=(performance.now()-current.startTime)/1000;lastMidiNoteRef.current={...current,length:lenSec};setLastMidiNote(prev=>prev&&prev.pitch===pitch?{...prev,length:lenSec,time:Date.now()}:prev);}// Stop the note on ALL tracks (not just armed) to prevent stuck notes
|
||||
// when ARM is toggled off while a key is held
|
||||
if(window.SonicSF&&window.SonicSF.stopNote){var stopTracks=activeTracksRef.current||[];stopTracks.forEach(function(st){// Only stop channels that actually carry this track's notes —
|
||||
if(window.SonicSF&&window.SonicSF.stopNote){var stopTracks=activeTracksRef.current||[];var hwRouterOff=_getMidiRouter();var hwStopTargets=[];stopTracks.forEach(function(st){// Only stop channels that actually carry this track's notes —
|
||||
// an index-based fallback could hit another track's dedicated
|
||||
// channel and kill its sound.
|
||||
if(!st.synth_engine&&st.midiChannel===undefined)return;var stCh=assignTrackMidiChannel(st,stopTracks);if(isStandaloneSf())_routeNoteOff(st.id,{ch:stCh},pitch,'HARDWARE_KEYBOARD');window.SonicSF.stopNote(stCh,pitch);// MIDI Keyboard → Carla bridge: note-off khi thả phím — tránh
|
||||
if(!st.synth_engine&&st.midiChannel===undefined)return;var stCh=assignTrackMidiChannel(st,stopTracks);if(hwRouterOff&&st.id){hwStopTargets.push({trackId:st.id,ch:stCh});}else if(isStandaloneSf()){_routeNoteOff(st.id,{ch:stCh},pitch,'HARDWARE_KEYBOARD');}window.SonicSF.stopNote(stCh,pitch);// MIDI Keyboard → Carla bridge: note-off khi thả phím — tránh
|
||||
// kẹt âm VSTi (giống keybed ảo).
|
||||
if(window.SonicCarlaMidi&&window.SonicCarlaMidi.shouldRoute(st.synth_engine,st.isArmed)){try{window.SonicCarlaMidi.noteOff(stCh,pitch);}catch(e){}}// Giảm counter note đang giữ — hết note → VU được phép decay/tắt
|
||||
// (tick sẽ thấy counter = 0 và không còn giữ peak nữa)
|
||||
try{if(heldMidiNotesRef.current[st.id]!==undefined){heldMidiNotesRef.current[st.id]=Math.max(0,heldMidiNotesRef.current[st.id]-1);if(heldMidiNotesRef.current[st.id]===0){delete heldMidiNotesRef.current[st.id];}}}catch(err){}});}}// ── Sustain (CC64), Modulation (CC1), Pitch Bend ──
|
||||
try{if(heldMidiNotesRef.current[st.id]!==undefined){heldMidiNotesRef.current[st.id]=Math.max(0,heldMidiNotesRef.current[st.id]-1);if(heldMidiNotesRef.current[st.id]===0){delete heldMidiNotesRef.current[st.id];}}}catch(err){}});// T7: note-off dispatch qua router - engine voice giu tu note-on;
|
||||
// SonicSF.stopNote o tren van giu belt-and-suspenders.
|
||||
if(hwRouterOff&&hwStopTargets.length){hwRouterOff.handleHardwareKeyboardMessage(msg.data,[],hwStopTargets);}}}// ── Sustain (CC64), Modulation (CC1), Pitch Bend ──
|
||||
const midiCh=msg.data[0]&0x0F;if(cmd===0xB){// Controller Change: forward to ALL armed tracks' dedicated channels
|
||||
const cc=msg.data[1];const val=msg.data[2];if(window.SonicSF&&window.SonicSF.controllerChange){var ccTracks=activeTracksRef.current||[];var hasArmed=ccTracks.some(function(t){return t.isArmed;});if(hasArmed){ccTracks.forEach(function(ct){if(!ct.isArmed)return;var ctCh=assignTrackMidiChannel(ct,ccTracks);window.SonicSF.controllerChange(ctCh,cc,val);});}else{window.SonicSF.controllerChange(midiCh,cc,val);}}}else if(cmd===0xE){// Pitch Bend: forward to ALL armed tracks' dedicated channels
|
||||
const lsb=msg.data[1];const msb=msg.data[2];const bendVal=msb<<7|lsb;if(window.SonicSF&&window.SonicSF.pitchBend){var pbTracks=activeTracksRef.current||[];var hasArmedPB=pbTracks.some(function(t){return t.isArmed;});if(hasArmedPB){pbTracks.forEach(function(pt){if(!pt.isArmed)return;var ptCh=assignTrackMidiChannel(pt,pbTracks);window.SonicSF.pitchBend(ptCh,bendVal);});}else{window.SonicSF.pitchBend(midiCh,bendVal);}}}// Forward to active MIDI recorders
|
||||
|
||||
Reference in New Issue
Block a user