fix: piano roll record via ARM + INPUT routes to piano roll tab
This commit is contained in:
+54
-4
@@ -4548,7 +4548,6 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
|
||||
const [snapVal, setSnapVal] = React.useState('1/16');
|
||||
const [ccMode, setCcMode] = React.useState('velocity');
|
||||
const [rollZoom, setRollZoom] = React.useState(60); // local horizontal zoom factor
|
||||
const [isArmed, setIsArmed] = React.useState(false);
|
||||
const [aiBarStart, setAiBarStart] = React.useState(0);
|
||||
const [aiBarEnd, setAiBarEnd] = React.useState(4);
|
||||
|
||||
@@ -5598,8 +5597,8 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, onClose, onUpdateNot
|
||||
key: v,
|
||||
value: v
|
||||
}, v)))), /*#__PURE__*/React.createElement("button", {
|
||||
onClick: () => setIsArmed(!isArmed),
|
||||
className: `px-2 py-1 rounded text-xs font-bold ${isArmed ? 'bg-red-600 text-white' : 'bg-zinc-800 text-zinc-400'}`
|
||||
onClick: () => setSubTabs(prev => prev.map(s => s.id === st.id ? { ...s, isArmed: !s.isArmed } : s)),
|
||||
className: `px-2 py-1 rounded text-xs font-bold ${st.isArmed ? 'bg-red-600 text-white' : 'bg-zinc-800 text-zinc-400'}`
|
||||
}, "ARM"), /*#__PURE__*/React.createElement("select", {
|
||||
value: selectedMidiInputId || '',
|
||||
onChange: e => onMidiInputSelect(e.target.value),
|
||||
@@ -6313,6 +6312,7 @@ const App = () => {
|
||||
|
||||
const activeMIDIRecordersRef = useRef({});
|
||||
const activeAudioRecordersRef = useRef({});
|
||||
const pianoRollRecorderRef = useRef(null);
|
||||
const recordingPCMDataRef = useRef({});
|
||||
const recordingStartTimeRef = useRef(0);
|
||||
const recordingSyncRef = useRef(null);
|
||||
@@ -9775,6 +9775,24 @@ const App = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if piano roll tab is active and armed
|
||||
const activePianoRoll = subTabs.find(s => s.id === activeTab && s.type === 'PIANO_ROLL' && s.isArmed);
|
||||
if (activePianoRoll && selectedMidiInputId) {
|
||||
setRecordingState('COUNT_IN');
|
||||
const secondsPerBeat = 60.0 / (parseInt(bpm) || 120);
|
||||
const countInDuration = secondsPerBeat * 4;
|
||||
const audioCtx = getAudioContext();
|
||||
const now = audioCtx.currentTime;
|
||||
showToast('Metronome Count-in: 4... 3... 2... 1... (MIDI Piano Roll)', 'info');
|
||||
for (let i = 0; i < 4; i++) {
|
||||
playMetronomeClick(now + i * secondsPerBeat, i === 0);
|
||||
}
|
||||
setTimeout(() => {
|
||||
startPianoRollRecording(activePianoRoll);
|
||||
}, countInDuration * 1000);
|
||||
return;
|
||||
}
|
||||
|
||||
const armed = activeTracks.filter(t => t.isArmed && t.inputSource?.deviceType && t.inputSource.deviceType !== 'NONE');
|
||||
if (armed.length === 0) {
|
||||
showToast('Vui lòng Arm (R) ít nhất một track và chọn cổng Input để ghi âm.', 'warning');
|
||||
@@ -9798,6 +9816,22 @@ const App = () => {
|
||||
}, countInDuration * 1000);
|
||||
};
|
||||
|
||||
const startPianoRollRecording = (tab) => {
|
||||
const context = getAudioContext();
|
||||
const secondsPerBeat = 60.0 / (parseInt(bpm) || 120);
|
||||
const startTime = currentTime;
|
||||
const midiRec = new ClientMIDIRecorder(context, parseInt(bpm) || 120, 4);
|
||||
midiRec.tempTabId = tab.id;
|
||||
pianoRollRecorderRef.current = midiRec;
|
||||
activeMIDIRecordersRef.current['piano_roll'] = midiRec;
|
||||
if (selectedMidiInputId) midiRec.setSelectedMidiInputId(selectedMidiInputId);
|
||||
setRecordingState('RECORDING');
|
||||
setRecTempMidiNotes([]);
|
||||
startTrackPlayback(startTime);
|
||||
setIsPlaying(true);
|
||||
showToast('Recording MIDI to Piano Roll...', 'info');
|
||||
};
|
||||
|
||||
const startRecordingTake = async (armedTracks) => {
|
||||
const context = getAudioContext();
|
||||
if (context.state === 'suspended') {
|
||||
@@ -9986,7 +10020,23 @@ const App = () => {
|
||||
const midiRec = midiRecorders[trackId];
|
||||
const recordedNotes = midiRec.stop();
|
||||
|
||||
if (midiRec.tempMidiItemId) {
|
||||
if (midiRec.tempTabId) {
|
||||
const recordedNotes = midiRec.stop();
|
||||
if (recordedNotes.length > 0) {
|
||||
const newNotes = recordedNotes.map((n, i) => ({
|
||||
id: 'rec_' + Date.now() + '_' + i,
|
||||
pitch: n.pitch,
|
||||
start_beat: Math.max(0, n.start_beat || 0),
|
||||
duration_beats: Math.max(0.125, n.duration_beats || 0.25),
|
||||
velocity: Math.min(1, (n.velocity || 0.8)),
|
||||
pan: 0.0
|
||||
}));
|
||||
setSubTabs(prev => prev.map(s => s.id === midiRec.tempTabId ? { ...s, notes: [...(s.notes || []), ...newNotes], isDirty: true } : s));
|
||||
setCanvasRedrawCount(n => n + 1);
|
||||
showToast(`Đã ghi ${recordedNotes.length} notes vào Piano Roll.`, 'success');
|
||||
}
|
||||
hasRecordedAnything = true;
|
||||
} else if (midiRec.tempMidiItemId) {
|
||||
const recCurrentTimeSec = Math.max(0, context.currentTime - midiRec.recStartAudioTime - midiRec.latencyCompSec);
|
||||
const recElapsedBeats = recCurrentTimeSec / (60.0 / midiRec.bpm);
|
||||
const totalDurationBeats = Math.max(4.0, recordedNotes.length > 0 ? Math.max(recElapsedBeats, ...recordedNotes.map(n => n.start_beat + n.duration_beats)) : recElapsedBeats);
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user