fix: rearrangeMidiMelody newId not defined

newId was defined inside updateActiveTracks callback but
referenced outside (line 15002 return). Moved declaration
before the callback as rearrangeNewId, accessible in both
the callback body and the outer return statement.
This commit is contained in:
2026-07-28 20:58:44 +07:00
parent fc81f19b1c
commit 393dd7190f
2 changed files with 66 additions and 66 deletions
+56 -56
View File
@@ -2948,9 +2948,9 @@ const GraphEditorCanvas = ({
}; };
const sorted = [...nodes, newNode].sort((a, b) => a.time - b.time); const sorted = [...nodes, newNode].sort((a, b) => a.time - b.time);
onUpdateNodes(sorted); onUpdateNodes(sorted);
const newIdx = sorted.findIndex(n => n.time === newNode.time && (graphMode === 'pan' ? n.pan : n.db) === (graphMode === 'pan' ? newNode.pan : newNode.db)); const rearrangeNewIdx = sorted.findIndex(n => n.time === newNode.time && (graphMode === 'pan' ? n.pan : n.db) === (graphMode === 'pan' ? newNode.pan : newNode.db));
isDraggingNode.current = true; isDraggingNode.current = true;
dragNodeIdx.current = newIdx; dragNodeIdx.current = rearrangeNewIdx;
isCreatingNode.current = true; isCreatingNode.current = true;
}; };
const handleMouseMove = e => { const handleMouseMove = e => {
@@ -3289,9 +3289,9 @@ const AIConfigModal = ({
}, /*#__PURE__*/React.createElement("button", { }, /*#__PURE__*/React.createElement("button", {
onClick: e => { onClick: e => {
e.stopPropagation(); e.stopPropagation();
const newId = 'provider_' + Date.now(); const rearrangeNewId = 'provider_' + Date.now();
setProviders(prev => [...prev, { setProviders(prev => [...prev, {
id: newId, id: rearrangeNewId,
name: 'New Provider', name: 'New Provider',
provider_type: 'openai_compatible', provider_type: 'openai_compatible',
api_base_url: 'https://api.openai.com/v1', api_base_url: 'https://api.openai.com/v1',
@@ -3300,7 +3300,7 @@ const AIConfigModal = ({
temperature: 0.7, temperature: 0.7,
is_active: false is_active: false
}]); }]);
setSelectedId(newId); setSelectedId(rearrangeNewId);
}, },
className: "flex-1 px-2 py-1 bg-emerald-700 hover:bg-emerald-600 text-white text-xs font-bold rounded" className: "flex-1 px-2 py-1 bg-emerald-700 hover:bg-emerald-600 text-white text-xs font-bold rounded"
}, "+ Thêm"), providers.length > 1 && /*#__PURE__*/React.createElement("button", { }, "+ Thêm"), providers.length > 1 && /*#__PURE__*/React.createElement("button", {
@@ -9524,9 +9524,9 @@ const App = () => {
// No matching track create a new one // No matching track create a new one
const colors = ['#0f766e', '#1d4ed8', '#701a75', '#a21caf', '#b45309']; const colors = ['#0f766e', '#1d4ed8', '#701a75', '#a21caf', '#b45309'];
const newId = 'track_pasted_' + Date.now(); const rearrangeNewId = 'track_pasted_' + Date.now();
updateActiveTracks(prev => [...prev, { updateActiveTracks(prev => [...prev, {
id: newId, id: rearrangeNewId,
name: `Pasted_${name || 'track'}`, name: `Pasted_${name || 'track'}`,
buffer: clipBuffer, buffer: clipBuffer,
startTime: pasteTime, startTime: pasteTime,
@@ -9539,10 +9539,10 @@ const App = () => {
markers: [], markers: [],
serverFileId: null serverFileId: null
}]); }]);
setSelectedTrackId(newId); setSelectedTrackId(rearrangeNewId);
setCurrentTime(pasteTime); setCurrentTime(pasteTime);
showToast('Đã dán track mới từ clipboard.', 'success'); showToast('Đã dán track mới từ clipboard.', 'success');
return newId; return rearrangeNewId;
}; };
const handlePasteTrack = () => doPaste(selectedTrackId, currentTime); const handlePasteTrack = () => doPaste(selectedTrackId, currentTime);
const contextMenuPaste = () => { const contextMenuPaste = () => {
@@ -9580,10 +9580,10 @@ const App = () => {
for (let i = 0; i < mergedData.length; i++) mergedData[i] /= maxPeak; for (let i = 0; i < mergedData.length; i++) mergedData[i] /= maxPeak;
} }
const colors = ['#0f766e', '#1d4ed8', '#701a75', '#a21caf', '#b45309']; const colors = ['#0f766e', '#1d4ed8', '#701a75', '#a21caf', '#b45309'];
const newId = 'track_merged_' + Date.now(); const rearrangeNewId = 'track_merged_' + Date.now();
const names = activeTracks.map(t => t.name).join('+').slice(0, 30); const names = activeTracks.map(t => t.name).join('+').slice(0, 30);
setTracks(prev => [...prev, { setTracks(prev => [...prev, {
id: newId, id: rearrangeNewId,
name: `Merged_${names}.wav`, name: `Merged_${names}.wav`,
buffer: merged, buffer: merged,
startTime: 0, startTime: 0,
@@ -9595,7 +9595,7 @@ const App = () => {
markers: [], markers: [],
serverFileId: null serverFileId: null
}]); }]);
setSelectedTrackId(newId); setSelectedTrackId(rearrangeNewId);
closeContextMenu(); closeContextMenu();
showToast(`Đã merge ${activeTracks.length} tracks.`, 'success'); showToast(`Đã merge ${activeTracks.length} tracks.`, 'success');
}; };
@@ -11900,23 +11900,23 @@ const App = () => {
if (info.type === 'section') { if (info.type === 'section') {
var sec = (t.sections || []).find(function(s) { return s.id === oid; }); var sec = (t.sections || []).find(function(s) { return s.id === oid; });
if (sec) { if (sec) {
var newId = 'sec_dup_' + Date.now() + '_' + Math.random().toString(36).substr(2, 5); var rearrangeNewId = 'sec_dup_' + Date.now() + '_' + Math.random().toString(36).substr(2, 5);
updatedSections.push({ ...sec, id: newId, name: sec.name + ' (Copy)' }); updatedSections.push({ ...sec, id: rearrangeNewId, name: sec.name + ' (Copy)' });
newOriginals[newId] = { type: 'section', start: sec.start }; newOriginals[rearrangeNewId] = { type: 'section', start: sec.start };
} }
} else if (info.type === 'midiItem') { } else if (info.type === 'midiItem') {
var mid = (t.midiItems || []).find(function(m) { return m.id === oid; }); var mid = (t.midiItems || []).find(function(m) { return m.id === oid; });
if (mid) { if (mid) {
var newId = 'midi_dup_' + Date.now() + '_' + Math.random().toString(36).substr(2, 5); var rearrangeNewId = 'midi_dup_' + Date.now() + '_' + Math.random().toString(36).substr(2, 5);
updatedMidi.push({ ...mid, id: newId, name: mid.name + ' (Copy)' }); updatedMidi.push({ ...mid, id: rearrangeNewId, name: mid.name + ' (Copy)' });
newOriginals[newId] = { type: 'midiItem', start: mid.startTime }; newOriginals[rearrangeNewId] = { type: 'midiItem', start: mid.startTime };
} }
} else if (info.type === 'clip') { } else if (info.type === 'clip') {
var clip = (t.clips || []).find(function(c) { return c.id === oid || 'default_' + t.id === oid; }); var clip = (t.clips || []).find(function(c) { return c.id === oid || 'default_' + t.id === oid; });
if (clip) { if (clip) {
var newId = 'clip_dup_' + Date.now() + '_' + Math.random().toString(36).substr(2, 5); var rearrangeNewId = 'clip_dup_' + Date.now() + '_' + Math.random().toString(36).substr(2, 5);
updatedClips.push({ ...clip, id: newId, startTime: clip.startTime, name: clip.name + ' (Copy)' }); updatedClips.push({ ...clip, id: rearrangeNewId, startTime: clip.startTime, name: clip.name + ' (Copy)' });
newOriginals[newId] = { type: 'clip', start: clip.startTime }; newOriginals[rearrangeNewId] = { type: 'clip', start: clip.startTime };
} }
} }
}); });
@@ -11929,8 +11929,8 @@ const App = () => {
var items = itemType === 'section' ? (track.sections || []) : (track.midiItems || []); var items = itemType === 'section' ? (track.sections || []) : (track.midiItems || []);
var item = items.find(function(it) { return it.id === itemId; }); var item = items.find(function(it) { return it.id === itemId; });
if (!item) return; if (!item) return;
var newId = itemType + '_dup_' + Date.now(); var rearrangeNewId = itemType + '_dup_' + Date.now();
var newItem = { ...item, id: newId, name: item.name + ' (Copy)' }; var newItem = { ...item, id: rearrangeNewId, name: item.name + ' (Copy)' };
updateActiveTracks(function(prev) { updateActiveTracks(function(prev) {
return prev.map(function(t) { return prev.map(function(t) {
if (t.id !== trackId) return t; if (t.id !== trackId) return t;
@@ -11938,7 +11938,7 @@ const App = () => {
return itemType === 'section' ? { ...t, sections: updated } : { ...t, midiItems: updated }; return itemType === 'section' ? { ...t, sections: updated } : { ...t, midiItems: updated };
}); });
}); });
setDraggedSectionItem({ trackId, itemType, itemId: newId, clickOffset, isDuplicate: false }); setDraggedSectionItem({ trackId, itemType, itemId: rearrangeNewId, clickOffset, isDuplicate: false });
} }
return; return;
} }
@@ -12589,12 +12589,12 @@ const App = () => {
// Add Track // Add Track
const addNewTrack = () => { const addNewTrack = () => {
const curTracks = activeTracks; const curTracks = activeTracks;
const newId = (curTracks.length + 1).toString(); const rearrangeNewId = (curTracks.length + 1).toString();
const colors = ['#0f766e', '#1d4ed8', '#701a75', '#a21caf', '#b45309']; const colors = ['#0f766e', '#1d4ed8', '#701a75', '#a21caf', '#b45309'];
const selectColor = colors[curTracks.length % colors.length]; const selectColor = colors[curTracks.length % colors.length];
updateActiveTracks(prev => [...prev, { updateActiveTracks(prev => [...prev, {
id: newId, id: rearrangeNewId,
name: `Track ${newId}`, name: `Track ${rearrangeNewId}`,
buffer: null, buffer: null,
startTime: 0, startTime: 0,
volumeDb: 0, volumeDb: 0,
@@ -12611,9 +12611,9 @@ const App = () => {
monitoringEnabled: true, monitoringEnabled: true,
inputSource: { deviceType: 'NONE', deviceId: '' } inputSource: { deviceType: 'NONE', deviceId: '' }
}]); }]);
showToast(`Đã thêm Track ${newId}.`, 'info'); showToast(`Đã thêm Track ${rearrangeNewId}.`, 'info');
setTimeout(() => lucide.createIcons(), 200); setTimeout(() => lucide.createIcons(), 200);
return newId; return rearrangeNewId;
}; };
// Update tracks in active context (main session or section tab) // Update tracks in active context (main session or section tab)
@@ -12776,12 +12776,12 @@ const App = () => {
// Insert Track Below Selected // Insert Track Below Selected
const insertTrackBelow = () => { const insertTrackBelow = () => {
const curTracks = activeTracks; const curTracks = activeTracks;
const newId = `t${Date.now()}`; const rearrangeNewId = `t${Date.now()}`;
const colors = ['#0f766e', '#1d4ed8', '#701a75', '#a21caf', '#b45309']; const colors = ['#0f766e', '#1d4ed8', '#701a75', '#a21caf', '#b45309'];
const selectColor = colors[(curTracks.length) % colors.length]; const selectColor = colors[(curTracks.length) % colors.length];
const newTrack = { const newTrack = {
id: newId, id: rearrangeNewId,
name: `Track ${newId}`, name: `Track ${rearrangeNewId}`,
buffer: null, buffer: null,
startTime: 0, startTime: 0,
volumeDb: 0, volumeDb: 0,
@@ -12802,8 +12802,8 @@ const App = () => {
copy.splice(idx + 1, 0, newTrack); copy.splice(idx + 1, 0, newTrack);
return copy; return copy;
}); });
setSelectedTrackId(newId); setSelectedTrackId(rearrangeNewId);
showToast(`Đã thêm Track ${newId}.`, 'info'); showToast(`Đã thêm Track ${rearrangeNewId}.`, 'info');
setTimeout(() => lucide.createIcons(), 200); setTimeout(() => lucide.createIcons(), 200);
}; };
@@ -13761,13 +13761,13 @@ const App = () => {
const dstData = slicedBuffer.getChannelData(c); const dstData = slicedBuffer.getChannelData(c);
dstData.set(srcData.subarray(startSample, endSample)); dstData.set(srcData.subarray(startSample, endSample));
} }
const newId = 'track_ai_cut_' + Date.now(); const rearrangeNewId = 'track_ai_cut_' + Date.now();
const colors = ['#0f766e', '#1d4ed8', '#701a75', '#a21caf', '#b45309']; const colors = ['#0f766e', '#1d4ed8', '#701a75', '#a21caf', '#b45309'];
const selectColor = colors[tracks.length % colors.length]; const selectColor = colors[tracks.length % colors.length];
const barNum = Math.floor(snapLoopStart / barDuration) + 1; const barNum = Math.floor(snapLoopStart / barDuration) + 1;
const barsCount = Math.max(1, Math.round((snapLoopEnd - snapLoopStart) / barDuration)); const barsCount = Math.max(1, Math.round((snapLoopEnd - snapLoopStart) / barDuration));
const newTrack = { const newTrack = {
id: newId, id: rearrangeNewId,
name: `Loop_${barNum}bar_${activeTrack.name.replace('.wav', '').slice(0, 10)}_${snapLoopStart.toFixed(1)}s.wav`, name: `Loop_${barNum}bar_${activeTrack.name.replace('.wav', '').slice(0, 10)}_${snapLoopStart.toFixed(1)}s.wav`,
buffer: slicedBuffer, buffer: slicedBuffer,
channelInfo: activeTrack.channelInfo ? { channelInfo: activeTrack.channelInfo ? {
@@ -13775,7 +13775,7 @@ const App = () => {
} : null, } : null,
startTime: snapLoopStart, startTime: snapLoopStart,
clips: [{ clips: [{
id: 'clip_' + newId, id: 'clip_' + rearrangeNewId,
buffer: slicedBuffer, buffer: slicedBuffer,
startTime: snapLoopStart, startTime: snapLoopStart,
name: `Loop_${barNum}bar_${snapLoopStart.toFixed(1)}s` name: `Loop_${barNum}bar_${snapLoopStart.toFixed(1)}s`
@@ -13804,7 +13804,7 @@ const App = () => {
} }
return updated; return updated;
}); });
setSelectedTrackId(newId); setSelectedTrackId(rearrangeNewId);
setAnalysisState({ setAnalysisState({
status: `AI Cut: ${detectedBPM} BPM, ${barsCount} bars loop (Zero-Crossing aligned)`, status: `AI Cut: ${detectedBPM} BPM, ${barsCount} bars loop (Zero-Crossing aligned)`,
data: { data: {
@@ -14226,11 +14226,11 @@ const App = () => {
createTrack: (args) => { createTrack: (args) => {
const name = args.name || `AI_Track_${Date.now()}`; const name = args.name || `AI_Track_${Date.now()}`;
const type = args.type || 'audio'; const type = args.type || 'audio';
const newId = addNewTrack(); const rearrangeNewId = addNewTrack();
if (name && name !== `AI_Track_${Date.now()}`) { if (name && name !== `AI_Track_${Date.now()}`) {
updateTrackName(newId, name); updateTrackName(rearrangeNewId, name);
} }
return { success: true, trackId: newId, name }; return { success: true, trackId: rearrangeNewId, name };
}, },
deleteTrack: (args) => { deleteTrack: (args) => {
const tid = args.track_id || selectedTrackId; const tid = args.track_id || selectedTrackId;
@@ -14416,15 +14416,15 @@ const App = () => {
const dst = slicedBuffer.getChannelData(c); const dst = slicedBuffer.getChannelData(c);
dst.set(src.subarray(startSample, endSample)); dst.set(src.subarray(startSample, endSample));
} }
const newId = 'track_cut_' + Date.now(); const rearrangeNewId = 'track_cut_' + Date.now();
const colors = ['#0f766e', '#1d4ed8', '#701a75', '#a21caf', '#b45309']; const colors = ['#0f766e', '#1d4ed8', '#701a75', '#a21caf', '#b45309'];
const color = colors[currentTracks.length % colors.length]; const color = colors[currentTracks.length % colors.length];
const cutName = args.new_track_name || `Cut_${track.name}`; const cutName = args.new_track_name || `Cut_${track.name}`;
const newTrack = { const newTrack = {
id: newId, name: cutName, buffer: slicedBuffer, id: rearrangeNewId, name: cutName, buffer: slicedBuffer,
startTime: 0, volumeDb: 0, pan: 0, startTime: 0, volumeDb: 0, pan: 0,
muted: false, solo: false, color, markers: [], muted: false, solo: false, color, markers: [],
clips: [{ id: 'clip_' + newId, buffer: slicedBuffer, startTime: 0, name: cutName }], clips: [{ id: 'clip_' + rearrangeNewId, buffer: slicedBuffer, startTime: 0, name: cutName }],
serverFileId: null serverFileId: null
}; };
const idx = currentTracks.findIndex(t => t.id === tid); const idx = currentTracks.findIndex(t => t.id === tid);
@@ -14436,12 +14436,12 @@ const App = () => {
} }
if (window.DAWCommandDispatcher) { if (window.DAWCommandDispatcher) {
window.DAWCommandDispatcher.currentTracks = nextTracks; window.DAWCommandDispatcher.currentTracks = nextTracks;
window.DAWCommandDispatcher.currentSelectedTrackId = newId; window.DAWCommandDispatcher.currentSelectedTrackId = rearrangeNewId;
window.DAWCommandDispatcher.lastCutSourceTrackId = tid; window.DAWCommandDispatcher.lastCutSourceTrackId = tid;
window.DAWCommandDispatcher.lastCutNewTrackId = newId; window.DAWCommandDispatcher.lastCutNewTrackId = rearrangeNewId;
} }
setTracks(nextTracks); setTracks(nextTracks);
setSelectedTrackId(newId); setSelectedTrackId(rearrangeNewId);
selectionRef.current = { start: 0, end: slicedBuffer.duration }; selectionRef.current = { start: 0, end: slicedBuffer.duration };
clearLocalSelection(); clearLocalSelection();
setSelectionMode('global'); setSelectionMode('global');
@@ -14449,7 +14449,7 @@ const App = () => {
setSelectionEnd(slicedBuffer.duration); setSelectionEnd(slicedBuffer.duration);
setTimeout(() => lucide.createIcons(), 200); setTimeout(() => lucide.createIcons(), 200);
return { return {
success: true, trackId: newId, trackName: cutName, success: true, trackId: rearrangeNewId, trackName: cutName,
cutStart: parseFloat(loopStart.toFixed(3)), cutEnd: parseFloat(loopEnd.toFixed(3)), cutStart: parseFloat(loopStart.toFixed(3)), cutEnd: parseFloat(loopEnd.toFixed(3)),
duration: parseFloat(slicedBuffer.duration.toFixed(3)) duration: parseFloat(slicedBuffer.duration.toFixed(3))
}; };
@@ -14865,11 +14865,11 @@ const App = () => {
t => t.name.toLowerCase() === aiTrack.track_name.toLowerCase() t => t.name.toLowerCase() === aiTrack.track_name.toLowerCase()
); );
if (!targetTrack) { if (!targetTrack) {
const newId = (updatedTracks.length + 1).toString(); const rearrangeNewId = (updatedTracks.length + 1).toString();
const colors = ['#0f766e', '#1d4ed8', '#701a75', '#a21caf', '#b45309']; const colors = ['#0f766e', '#1d4ed8', '#701a75', '#a21caf', '#b45309'];
const selectColor = colors[updatedTracks.length % colors.length]; const selectColor = colors[updatedTracks.length % colors.length];
targetTrack = { targetTrack = {
id: newId, id: rearrangeNewId,
name: aiTrack.track_name, name: aiTrack.track_name,
type: 'MIDI', type: 'MIDI',
volumeDb: 0, volumeDb: 0,
@@ -14945,15 +14945,15 @@ const App = () => {
const totalBars = Math.max(1, Math.ceil(totalBeats / 4)); const totalBars = Math.max(1, Math.ceil(totalBeats / 4));
const durationSec = totalBars * secondsPerBar; const durationSec = totalBars * secondsPerBar;
const rearrangeNewId = (activeTracks.length + 1).toString();
updateActiveTracks(prev => { updateActiveTracks(prev => {
let updatedTracks = [...prev]; let updatedTracks = [...prev];
// Find source track index to insert new track right after it // Find source track index to insert new track right after it
const sourceIdx = sourceTrackId ? updatedTracks.findIndex(t => t.id === sourceTrackId || t.id === 'track_' + sourceTrackId) : -1; const sourceIdx = sourceTrackId ? updatedTracks.findIndex(t => t.id === sourceTrackId || t.id === 'track_' + sourceTrackId) : -1;
const insertIdx = sourceIdx >= 0 ? sourceIdx + 1 : updatedTracks.length; const insertIdx = sourceIdx >= 0 ? sourceIdx + 1 : updatedTracks.length;
const newId = (updatedTracks.length + 1).toString();
const colors = ['#0f766e', '#1d4ed8', '#701a75', '#a21caf', '#b45309']; const colors = ['#0f766e', '#1d4ed8', '#701a75', '#a21caf', '#b45309'];
const newTrack = { const newTrack = {
id: newId, id: rearrangeNewId,
name: `[AI Rearrange] ${rearrange_title || 'Variation'}`, name: `[AI Rearrange] ${rearrange_title || 'Variation'}`,
type: 'MIDI', type: 'MIDI',
volumeDb: 0, volumeDb: 0,
@@ -14968,7 +14968,7 @@ const App = () => {
midiItems: [{ midiItems: [{
id: 'item_rearr_' + Date.now() + '_' + Math.random().toString(36).substr(2, 5), id: 'item_rearr_' + Date.now() + '_' + Math.random().toString(36).substr(2, 5),
name: `[AI] ${rearrange_title || 'Rearranged'} - var`, name: `[AI] ${rearrange_title || 'Rearranged'} - var`,
parent_track_id: newId, parent_track_id: rearrangeNewId,
startTime: currentTime, startTime: currentTime,
duration: durationSec, duration: durationSec,
length_bars: totalBars, length_bars: totalBars,
@@ -14999,7 +14999,7 @@ const App = () => {
}); });
showToast(`✅ AI Rearrange: "${rearrange_title}" — ${rearranged_notes.length} notes`, 'success'); showToast(`✅ AI Rearrange: "${rearrange_title}" — ${rearranged_notes.length} notes`, 'success');
return { success: true, trackId: newId, totalBars }; return { success: true, trackId: rearrangeNewId, totalBars };
}, },
createMidiItem: (args) => { createMidiItem: (args) => {
const trackId = args.track_id || selectedTrackId; const trackId = args.track_id || selectedTrackId;
@@ -15174,8 +15174,8 @@ const App = () => {
input.onchange = async e => { input.onchange = async e => {
if (e.target.files[0]) { if (e.target.files[0]) {
addNewTrack(); addNewTrack();
const newId = (tracks.length + 1).toString(); const rearrangeNewId = (tracks.length + 1).toString();
setTimeout(() => loadFileOnTrack(newId, e.target.files[0]), 100); setTimeout(() => loadFileOnTrack(rearrangeNewId, e.target.files[0]), 100);
} }
}; };
input.click(); input.click();
File diff suppressed because one or more lines are too long