fix: realtime velocity with updatedNotes + ruler restart without onStop
This commit is contained in:
+46
-31
@@ -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);
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user