fix: realtime velocity with updatedNotes + ruler restart without onStop

This commit is contained in:
2026-07-26 11:28:47 +07:00
parent 7ede9bbf72
commit d3a3adca8a
2 changed files with 49 additions and 34 deletions
+46 -31
View File
@@ -5424,12 +5424,13 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
const currentNote = notes[cursorNoteIdx];
const currentVal = ccMode === 'pan' ? ((currentNote.pan || 0) / 2.0 + 0.5) : (currentNote.velocity !== undefined ? currentNote.velocity : 0.8);
if (Math.abs(currentVal - val) > 0.001) {
setNotes(prev => prev.map((n, i) => {
const updatedNotes = notes.map((n, i) => {
if (i !== cursorNoteIdx) return n;
if (ccMode === 'pan') return { ...n, pan: (val - 0.5) * 2.0 };
return { ...n, velocity: val };
}));
if (isPlaying && onRescheduleMidi) onRescheduleMidi();
});
setNotes(updatedNotes);
if (isPlaying && onRescheduleMidi) onRescheduleMidi(updatedNotes);
}
ccDragRef.current = { active: true, lastBeat: beat, selectedMode: true, lastPainted: [cursorNoteIdx] };
} else {
@@ -5444,11 +5445,13 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
if (noteIdx !== -1) {
const currentVal = ccMode === 'pan' ? ((notes[noteIdx].pan || 0) / 2.0 + 0.5) : (notes[noteIdx].velocity !== undefined ? notes[noteIdx].velocity : 0.8);
if (Math.abs(currentVal - val) > 0.001) {
setNotes(prev => prev.map((n, i) => {
const updatedNotes = notes.map((n, i) => {
if (i !== noteIdx) return n;
if (ccMode === 'pan') return { ...n, pan: (val - 0.5) * 2.0 };
return { ...n, velocity: val };
}));
});
setNotes(updatedNotes);
if (isPlaying && onRescheduleMidi) onRescheduleMidi(updatedNotes);
}
}
};
@@ -5474,12 +5477,13 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
if (cursorNote && selectedNoteIds.includes(cursorNote.id) && !painted.includes(cursorNoteIdx)) {
const currentVal = ccMode === 'pan' ? ((cursorNote.pan || 0) / 2.0 + 0.5) : (cursorNote.velocity !== undefined ? cursorNote.velocity : 0.8);
if (Math.abs(currentVal - val) > 0.001) {
setNotes(prev => prev.map((n, i) => {
const updatedNotes = notes.map((n, i) => {
if (i !== cursorNoteIdx) return n;
if (ccMode === 'pan') return { ...n, pan: (val - 0.5) * 2.0 };
return { ...n, velocity: val };
}));
if (isPlaying && onRescheduleMidi) onRescheduleMidi();
});
setNotes(updatedNotes);
if (isPlaying && onRescheduleMidi) onRescheduleMidi(updatedNotes);
}
drag.lastPainted = [...painted, cursorNoteIdx];
}
@@ -5491,12 +5495,13 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
if (candidateIdx !== -1 && !painted.includes(candidateIdx)) {
const currentVal = ccMode === 'pan' ? ((notes[candidateIdx].pan || 0) / 2.0 + 0.5) : (notes[candidateIdx].velocity !== undefined ? notes[candidateIdx].velocity : 0.8);
if (Math.abs(currentVal - val) > 0.001) {
setNotes(prev => prev.map((n, i) => {
const updatedNotes = notes.map((n, i) => {
if (i !== candidateIdx) return n;
if (ccMode === 'pan') return { ...n, pan: (val - 0.5) * 2.0 };
return { ...n, velocity: val };
}));
if (isPlaying && onRescheduleMidi) onRescheduleMidi();
});
setNotes(updatedNotes);
if (isPlaying && onRescheduleMidi) onRescheduleMidi(updatedNotes);
}
drag.lastPainted = [...painted, candidateIdx];
}
@@ -5855,11 +5860,21 @@ const beatSec = 60.0 / (parseInt(bpm) || 120);
if (clickTime >= 0) {
setSubTabs(prev => prev.map(s => s.id === st.id ? { ...s, currentTime: clickTime } : s));
if (isPlaying) {
onStop();
setSubTabs(prev => prev.map(s => s.id === st.id ? { ...s, currentTime: clickTime } : s));
setTimeout(() => {
setSubTabs(prev => prev.map(s => s.id === st.id ? { ...s, currentTime: clickTime } : s));
onPlayPause();
}, 30);
stopAllPlayback();
const sub = subTabs.find(s2 => s2.id === st.id);
if (sub) {
const ctx = getAudioContext();
startOffsetTimeRef.current = clickTime;
startAudioTimeRef.current = ctx.currentTime;
startBufferOffsetRef.current = clickTime * (sub.speed || 1.0);
schedulePianoRollMidi(sub, clickTime);
startSubTabPlayback(sub, clickTime);
setSubTabs(prev => prev.map(s => s.id === st.id ? { ...s, currentTime: clickTime, isPlaying: true } : s));
animationFrameIdRef.current = requestAnimationFrame(updatePlayhead);
}
}, 20);
}
}
if (e.ctrlKey || e.metaKey) {
@@ -10027,10 +10042,10 @@ const App = () => {
});
}
};
const schedulePianoRollMidi = (st, offsetSeconds) => {
const schedulePianoRollMidi = (st, offsetSeconds, notesOverride) => {
if (st.type !== 'PIANO_ROLL') return;
const context = getAudioContext();
const midiNotes = st.notes || [];
const midiNotes = notesOverride || st.notes || [];
const bpmVal = parseInt(bpm) || 120;
const secondsPerBeat = 60.0 / bpmVal;
const startWallTime = context.currentTime;
@@ -15814,20 +15829,20 @@ const App = () => {
onMidiInputSelect: handleMidiInputSelect,
activeMidiPitches: activeMidiPitches,
onInstrumentSelect: (trackId) => { openInstrumentSelector(trackId); },
onRescheduleMidi: () => {
const playingSub = subTabs.find(s => s.id === activeTab && s.type === 'PIANO_ROLL' && s.isPlaying);
if (playingSub) {
const offset = playingSub.currentTime || 0;
window.SonicSF.stopAll();
setTimeout(() => {
const ctx = getAudioContext();
startOffsetTimeRef.current = offset;
startAudioTimeRef.current = ctx.currentTime;
startBufferOffsetRef.current = offset * (playingSub.speed || 1.0);
schedulePianoRollMidi(playingSub, offset);
}, 20);
}
}
onRescheduleMidi: (updatedNotes) => {
const playingSub = subTabs.find(s => s.id === activeTab && s.type === 'PIANO_ROLL' && s.isPlaying);
if (playingSub) {
const offset = playingSub.currentTime || 0;
window.SonicSF.stopAll();
setTimeout(() => {
const ctx = getAudioContext();
startOffsetTimeRef.current = offset;
startAudioTimeRef.current = ctx.currentTime;
startBufferOffsetRef.current = offset * (playingSub.speed || 1.0);
schedulePianoRollMidi(playingSub, offset, updatedNotes);
}, 20);
}
}
});
}
const subTrack = tracks.find(t => t.id === st.trackId);