FIX: sửa PIANO ROLL TAB khi vẽ draw note midi phải play các note được vẽ

This commit is contained in:
2026-07-30 11:38:36 +07:00
parent eb61015cff
commit 0c1a27ef2c
2 changed files with 55 additions and 14 deletions
+41 -3
View File
@@ -5137,6 +5137,8 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
notesRef.current = notes; notesRef.current = notes;
React.useEffect(() => { if (!draggedNoteRef.current) setNotes(st.notes || []); }, [st.notes]); React.useEffect(() => { if (!draggedNoteRef.current) setNotes(st.notes || []); }, [st.notes]);
const brushVelocityRef = React.useRef(0.8); const brushVelocityRef = React.useRef(0.8);
const previewPitchRef = React.useRef(null);
const previewNodesRef = React.useRef(null);
const [selectedNoteIds, setSelectedNoteIds] = React.useState([]); const [selectedNoteIds, setSelectedNoteIds] = React.useState([]);
const [loopStartBeat, setLoopStartBeat] = React.useState(null); const [loopStartBeat, setLoopStartBeat] = React.useState(null);
const [loopEndBeat, setLoopEndBeat] = React.useState(null); const [loopEndBeat, setLoopEndBeat] = React.useState(null);
@@ -5718,12 +5720,21 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
noteStartBeats: [start], noteStartBeats: [start],
lastDrawnPitch: snapToScaleRef.current ? snapPitchToScale(pitch, selectedScaleRef.current) : pitch lastDrawnPitch: snapToScaleRef.current ? snapPitchToScale(pitch, selectedScaleRef.current) : pitch
}); });
// Play the note with SoundFont // Play the note with SoundFont - stop previous preview first
if (window.SonicSF) { if (previewNodesRef.current) {
try { previewNodesRef.current.osc.stop(); } catch(e) {}
try { previewNodesRef.current.osc.disconnect(); } catch(e) {}
try { previewNodesRef.current.gain.disconnect(); } catch(e) {}
previewNodesRef.current = null;
}
if (window.SonicSF && window.SonicSF._playNoteFallback) {
const ctx = getAudioContext(); const ctx = getAudioContext();
var dwTrk = activeTracks.find(function(t) { return t.id === st.trackId; }); var dwTrk = activeTracks.find(function(t) { return t.id === st.trackId; });
var dwCh = window.SonicPianoRoll ? window.SonicPianoRoll.getTrackMidiChannel(dwTrk, activeTracks) : (dwTrk ? dwTrk.midiChannel : 0); var dwCh = window.SonicPianoRoll ? window.SonicPianoRoll.getTrackMidiChannel(dwTrk, activeTracks) : (dwTrk ? dwTrk.midiChannel : 0);
window.SonicSF.playNote(pitch, 0.8, 300, ctx.currentTime, dwTrk ? dwTrk.instrumentProgram : undefined, null, dwCh, dwTrk ? dwTrk.synth_engine : undefined); var dwPitch = snapToScaleRef.current ? snapPitchToScale(pitch, selectedScaleRef.current) : pitch;
var dwDurMs = Math.max(100, Math.round(initialDur * (60 / bpm) * 1000));
var dwNodes = window.SonicSF._playNoteFallback(dwPitch, Math.round(brushVelocityRef.current * 127), dwDurMs, ctx.currentTime, dwTrk ? dwTrk.instrumentProgram : undefined, null, dwCh, dwTrk ? dwTrk.synth_engine : undefined);
if (dwNodes) previewNodesRef.current = dwNodes;
} }
} }
}; };
@@ -5809,6 +5820,29 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
const pitchChanged = snappedPitch !== lastPitch; const pitchChanged = snappedPitch !== lastPitch;
const noteBeats = draggedNote.noteStartBeats || []; const noteBeats = draggedNote.noteStartBeats || [];
const defaultDur = getSnapDuration(snapVal); const defaultDur = getSnapDuration(snapVal);
function stopPreviewNote() {
var pn = previewNodesRef.current;
if (pn) {
try { pn.osc.stop(); } catch(e) {}
try { pn.osc.disconnect(); } catch(e) {}
try { pn.gain.disconnect(); } catch(e) {}
previewNodesRef.current = null;
}
}
function playDrawPreview(p, durMs) {
stopPreviewNote();
if (window.SonicSF && window.SonicSF._playNoteFallback) {
var pvCtx = getAudioContext();
var pvTrk = activeTracks.find(function(t) { return t.id === st.trackId; });
var pvCh = window.SonicPianoRoll ? window.SonicPianoRoll.getTrackMidiChannel(pvTrk, activeTracks) : (pvTrk ? pvTrk.midiChannel : 0);
var pvVel = Math.round(brushVelocityRef.current * 127);
var pvNodes = window.SonicSF._playNoteFallback(p, pvVel, durMs, pvCtx.currentTime, pvTrk ? pvTrk.instrumentProgram : undefined, null, pvCh, pvTrk ? pvTrk.synth_engine : undefined);
if (pvNodes) previewNodesRef.current = pvNodes;
previewPitchRef.current = p;
}
}
if (pitchChanged) { if (pitchChanged) {
const brushIds = draggedNote.brushIds || []; const brushIds = draggedNote.brushIds || [];
if (brushIds.length > 0 && noteBeats.length > 0) { if (brushIds.length > 0 && noteBeats.length > 0) {
@@ -5833,6 +5867,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
draggedNote.brushIds = [...brushIds, newNote.id]; draggedNote.brushIds = [...brushIds, newNote.id];
draggedNote.lastDrawnPitch = snappedPitch; draggedNote.lastDrawnPitch = snappedPitch;
draggedNote.noteStartBeats = [...noteBeats, beat]; draggedNote.noteStartBeats = [...noteBeats, beat];
playDrawPreview(snappedPitch, Math.max(100, Math.round(defaultDur * (60 / bpm) * 1000)));
} else { } else {
const brushIds = draggedNote.brushIds || []; const brushIds = draggedNote.brushIds || [];
const lastBrushId = brushIds.length > 0 ? brushIds[brushIds.length - 1] : draggedNote.drawNoteId; const lastBrushId = brushIds.length > 0 ? brushIds[brushIds.length - 1] : draggedNote.drawNoteId;
@@ -5843,6 +5878,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
if (n.id !== lastBrushId) return n; if (n.id !== lastBrushId) return n;
return { ...n, duration_beats: extDur }; return { ...n, duration_beats: extDur };
})); }));
playDrawPreview(snappedPitch, Math.max(100, Math.round(extDur * (60 / bpm) * 1000)));
} }
} }
const container = gridScrollRef.current; const container = gridScrollRef.current;
@@ -5961,6 +5997,8 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
clearInterval(brushAutoScrollRef.current.id); clearInterval(brushAutoScrollRef.current.id);
brushAutoScrollRef.current = null; brushAutoScrollRef.current = null;
} }
stopPreviewNote();
previewPitchRef.current = null;
}; };
const handleContextMenu = (e) => { const handleContextMenu = (e) => {
File diff suppressed because one or more lines are too long