fix: multitrack play select plays immediately in realtime
This commit is contained in:
+48
-6
@@ -5880,7 +5880,7 @@ const AIPresetModal = ({ isOpen, onClose }) => {
|
|||||||
}))) : null);
|
}))) : null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClose, onUpdateNotes, onSaveNotes, setSubTabs, onPlayPause, onStop, isPlaying, playPreviewNote, showToast, midiDevices, recordingState, recTempMidiNotes, onRecord, selectedMidiInputId, onMidiInputSelect, activeMidiPitches, onInstrumentSelect, onRescheduleMidi, onSeekPlayhead, snapValue, onSnapChange }) => {
|
const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClose, onUpdateNotes, onSaveNotes, setSubTabs, onPlayPause, onStop, isPlaying, playPreviewNote, showToast, midiDevices, recordingState, recTempMidiNotes, onRecord, selectedMidiInputId, onMidiInputSelect, activeMidiPitches, onInstrumentSelect, onRescheduleMidi, onSeekPlayhead, snapValue, onSnapChange, onRealtimePlay }) => {
|
||||||
const [activeRollTool, setActiveRollTool] = React.useState('select');
|
const [activeRollTool, setActiveRollTool] = React.useState('select');
|
||||||
const [renderTick, setRenderTick] = React.useState(0);
|
const [renderTick, setRenderTick] = React.useState(0);
|
||||||
const [ccMode, setCcMode] = React.useState('velocity');
|
const [ccMode, setCcMode] = React.useState('velocity');
|
||||||
@@ -7581,10 +7581,10 @@ const beatSec = 60.0 / (parseInt(bpm) || 120);
|
|||||||
els.push(React.createElement("button", {
|
els.push(React.createElement("button", {
|
||||||
key: m._trackId,
|
key: m._trackId,
|
||||||
onClick: function() {
|
onClick: function() {
|
||||||
setActivePlayTrackIds(function(prev) {
|
var prevList = activePlayTrackIds || [];
|
||||||
var list = prev || [];
|
var nextList = prevList.indexOf(m._trackId) !== -1 ? prevList.filter(function(id) { return id !== m._trackId; }) : prevList.concat([m._trackId]);
|
||||||
return list.indexOf(m._trackId) !== -1 ? list.filter(function(id) { return id !== m._trackId; }) : list.concat([m._trackId]);
|
setActivePlayTrackIds(nextList);
|
||||||
});
|
if (onRealtimePlay) onRealtimePlay(nextList);
|
||||||
},
|
},
|
||||||
className: "flex items-center justify-center h-[20px] border border-zinc-600 rounded-md cursor-pointer outline-none mx-1 my-[2px] " + (isActive ? 'bg-yellow-600 text-black font-bold' : (isPlayOn ? 'bg-red-700 text-white font-semibold' : 'bg-zinc-700 text-zinc-300 hover:bg-zinc-600'))
|
className: "flex items-center justify-center h-[20px] border border-zinc-600 rounded-md cursor-pointer outline-none mx-1 my-[2px] " + (isActive ? 'bg-yellow-600 text-black font-bold' : (isPlayOn ? 'bg-red-700 text-white font-semibold' : 'bg-zinc-700 text-zinc-300 hover:bg-zinc-600'))
|
||||||
}, React.createElement("span", {
|
}, React.createElement("span", {
|
||||||
@@ -13619,6 +13619,47 @@ const App = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
handlePlayPauseRef.current = handlePlayPause;
|
handlePlayPauseRef.current = handlePlayPause;
|
||||||
|
const handlePianoRollRealtimePlay = (trackIds) => {
|
||||||
|
const prSt = subTabs.find(s => s.id === activeTab && s.type === 'PIANO_ROLL');
|
||||||
|
if (!prSt) return;
|
||||||
|
var prLayers = [];
|
||||||
|
var ghostData = (window.SonicGhost && window.SonicGhost.extractGhostLayers) ? window.SonicGhost.extractGhostLayers(activeTracks, prSt.trackId, prSt.target_id, parseInt(bpm) || 120) : [];
|
||||||
|
(ghostData || []).forEach(function(layer) {
|
||||||
|
if (!trackIds || trackIds.indexOf(layer.track_id) === -1) return;
|
||||||
|
var ltrk = (activeTracks || []).find(function(t) { return t.id === layer.track_id; });
|
||||||
|
prLayers.push({
|
||||||
|
trackId: layer.track_id,
|
||||||
|
notes: layer.notes.map(function(n) { return { pitch: n.pitch, start_beat: n.relative_start_beat, duration_beats: n.duration_beats, velocity: n.velocity || 0.8 }; }),
|
||||||
|
instrumentProgram: ltrk ? ltrk.instrumentProgram : undefined,
|
||||||
|
instrumentName: ltrk ? ltrk.instrumentName : undefined,
|
||||||
|
synthEngine: ltrk ? ltrk.synth_engine : undefined
|
||||||
|
});
|
||||||
|
});
|
||||||
|
stopAllPlayback();
|
||||||
|
const prCtx = getAudioContext();
|
||||||
|
const prTNode = activeTrackNodesRef.current[prSt.trackId];
|
||||||
|
if (prTNode && prTNode.gainNode) {
|
||||||
|
prTNode.gainNode.gain.setValueAtTime(prTNode.gainNode.gain.value || 1, prCtx.currentTime);
|
||||||
|
prTNode.gainNode.gain.linearRampToValueAtTime(0.001, prCtx.currentTime + 0.04);
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
window.SonicSF.stopAll();
|
||||||
|
if (prTNode && prTNode.gainNode) {
|
||||||
|
const prTrackData = activeTracksRef.current ? activeTracksRef.current.find(t => t.id === prSt.trackId) : null;
|
||||||
|
const prVolDb = prTrackData ? (prTrackData.volumeDb ?? 0) : 0;
|
||||||
|
const prVolLinear = prVolDb <= -50 ? 0 : Math.pow(10, prVolDb / 20);
|
||||||
|
prTNode.gainNode.gain.setValueAtTime(0.001, prCtx.currentTime);
|
||||||
|
prTNode.gainNode.gain.linearRampToValueAtTime(prVolLinear || 0.8, prCtx.currentTime + 0.015);
|
||||||
|
}
|
||||||
|
const prOffset = prSt.currentTime || 0;
|
||||||
|
startOffsetTimeRef.current = prOffset;
|
||||||
|
startAudioTimeRef.current = prCtx.currentTime;
|
||||||
|
startBufferOffsetRef.current = prOffset * (prSt.speed || 1.0);
|
||||||
|
const playTab = Object.assign({}, prSt, { ghostPlayLayers: prLayers });
|
||||||
|
schedulePianoRollMidi(playTab, prOffset);
|
||||||
|
setSubTabs(prev => prev.map(s => s.id === prSt.id ? Object.assign({}, s, { ghostPlayLayers: prLayers, isPlaying: true, currentTime: prOffset }) : s));
|
||||||
|
}, 60);
|
||||||
|
};
|
||||||
const handlePause = () => {
|
const handlePause = () => {
|
||||||
if (isPlaying || subTabs.some(s => s.isPlaying)) stopAllPlayback();
|
if (isPlaying || subTabs.some(s => s.isPlaying)) stopAllPlayback();
|
||||||
};
|
};
|
||||||
@@ -20461,7 +20502,8 @@ const App = () => {
|
|||||||
selectedMidiInputId: selectedMidiInputId,
|
selectedMidiInputId: selectedMidiInputId,
|
||||||
onMidiInputSelect: handleMidiInputSelect,
|
onMidiInputSelect: handleMidiInputSelect,
|
||||||
activeMidiPitches: activeMidiPitches,
|
activeMidiPitches: activeMidiPitches,
|
||||||
onInstrumentSelect: (trackId) => { openInstrumentSelector(trackId); },
|
onInstrumentSelect: (trackId) => { openInstrumentSelector(trackId); },
|
||||||
|
onRealtimePlay: handlePianoRollRealtimePlay,
|
||||||
onRescheduleMidi: (updatedNotes) => {
|
onRescheduleMidi: (updatedNotes) => {
|
||||||
const playingSub = subTabs.find(s => s.id === activeTab && s.type === 'PIANO_ROLL' && s.isPlaying);
|
const playingSub = subTabs.find(s => s.id === activeTab && s.type === 'PIANO_ROLL' && s.isPlaying);
|
||||||
if (playingSub) {
|
if (playingSub) {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user