fix: MIDI record + key highlight on MIDI key press

This commit is contained in:
2026-07-25 18:55:31 +07:00
parent c3edda5c81
commit da760dbb86
2 changed files with 30 additions and 19 deletions
+25 -14
View File
@@ -4543,7 +4543,7 @@ const AIPresetModal = ({ isOpen, onClose }) => {
}, "Đóng"))));
};
const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNotes, onSaveNotes, setSubTabs, onPlayPause, onStop, isPlaying, playPreviewNote, showToast, midiDevices, recordingState, recTempMidiNotes, onRecord, selectedMidiInputId, onMidiInputSelect }) => {
const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNotes, onSaveNotes, setSubTabs, onPlayPause, onStop, isPlaying, playPreviewNote, showToast, midiDevices, recordingState, recTempMidiNotes, onRecord, selectedMidiInputId, onMidiInputSelect, activeMidiPitches }) => {
const [activeRollTool, setActiveRollTool] = React.useState('select');
const [snapVal, setSnapVal] = React.useState('1/16');
const [ccMode, setCcMode] = React.useState('velocity');
@@ -5381,7 +5381,7 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
/*#__PURE__*/React.createElement("div", {
key: pitch,
style: { height: `${NoteHeight}px` },
className: `w-[60px] shrink-0 border-b border-zinc-800 text-[9px] font-bold flex items-center justify-end pr-2 transition cursor-pointer ${isBlack ? 'bg-zinc-950 text-slate-500 border-zinc-900 hover:bg-zinc-800' : 'bg-white text-zinc-800 border-r border-zinc-400 hover:bg-amber-100'}`,
className: `w-[60px] shrink-0 border-b border-zinc-800 text-[9px] font-bold flex items-center justify-end pr-2 transition cursor-pointer ${activeMidiPitches && activeMidiPitches.has(pitch) ? 'bg-emerald-500 text-white border-emerald-400' : isBlack ? 'bg-zinc-950 text-slate-500 border-zinc-900 hover:bg-zinc-800' : 'bg-white text-zinc-800 border-r border-zinc-400 hover:bg-amber-100'}`,
onMouseDown: (e) => {
e.stopPropagation();
keybedMouseDownRef.current = true;
@@ -6279,13 +6279,21 @@ const App = () => {
input.onmidimessage = msg => {
console.log(`[DevLog] [Raw MIDI] Received from "${input.name}" (ID: ${input.id}) - Data:`, Array.from(msg.data));
if (msg.data.length < 3) return;
const cmd = msg.data[0] >> 4;
const pitch = msg.data[1];
const velocity = msg.data[2];
if (cmd === 0x9 && velocity > 0) {
lastMidiNoteRef.current = { pitch, velocity, startTime: performance.now(), length: 0 };
setLastMidiNote({ pitch, velocity, length: 0, time: Date.now() });
} else if (cmd === 0x8 || (cmd === 0x9 && velocity === 0)) {
const cmd = msg.data[0] >> 4;
const pitch = msg.data[1];
const velocity = msg.data[2];
if (cmd === 0x9 && velocity > 0) {
lastMidiNoteRef.current = { pitch, velocity, startTime: performance.now(), length: 0 };
setLastMidiNote({ pitch, velocity, length: 0, time: Date.now() });
activeMidiPitchesRef.current.add(pitch);
setActiveMidiPitches(new Set(activeMidiPitchesRef.current));
const activeTabInfo = subTabs.find(s => s.id === activeTab && s.type === 'PIANO_ROLL' && s.isArmed);
if (activeTabInfo && window.SonicSF) {
try { window.SonicSF.playNote(pitch, velocity, 500, undefined, activeTabInfo.instrumentProgram, null); } catch (e) {}
}
} else if (cmd === 0x8 || (cmd === 0x9 && velocity === 0)) {
activeMidiPitchesRef.current.delete(pitch);
setActiveMidiPitches(new Set(activeMidiPitchesRef.current));
const current = lastMidiNoteRef.current;
if (current && current.pitch === pitch) {
const lenSec = (performance.now() - current.startTime) / 1000;
@@ -6329,6 +6337,8 @@ const App = () => {
const activeMIDIRecordersRef = useRef({});
const activeAudioRecordersRef = useRef({});
const pianoRollRecorderRef = useRef(null);
const activeMidiPitchesRef = useRef(new Set());
const [activeMidiPitches, setActiveMidiPitches] = useState(new Set());
const recordingPCMDataRef = useRef({});
const recordingStartTimeRef = useRef(0);
const recordingSyncRef = useRef(null);
@@ -15420,11 +15430,12 @@ const App = () => {
playPreviewNote: playMidiPreviewNote,
showToast: showToast,
midiDevices: midiDevices,
recordingState: recordingState,
onRecord: handleRecordClick,
selectedMidiInputId: selectedMidiInputId,
onMidiInputSelect: handleMidiInputSelect
});
recordingState: recordingState,
onRecord: handleRecordClick,
selectedMidiInputId: selectedMidiInputId,
onMidiInputSelect: handleMidiInputSelect,
activeMidiPitches: activeMidiPitches
});
}
const subTrack = tracks.find(t => t.id === st.trackId);
const vTrack = subTrack ? {
File diff suppressed because one or more lines are too long