fix: giải quyết các lỗi về xuất track, tải cấu hình AI, tràn dropdown, click hủy chọn và làm mới bảng DSP Tools

This commit is contained in:
2026-07-22 18:08:23 +07:00
parent 6b7872c636
commit a8b484bd15
3 changed files with 191 additions and 20 deletions
+97 -10
View File
@@ -549,6 +549,17 @@ const WaveformLane = ({
speed: track.speed || 1.0 speed: track.speed || 1.0
}] : []; }] : [];
// Check if Ctrl+Click to exit selection
if (e.ctrlKey && selectionMode) {
e.preventDefault();
e.stopPropagation();
if (onClearLocalSelection) onClearLocalSelection();
if (onSetSelectionMode) onSetSelectionMode(null);
if (onSetSelectionStart) onSetSelectionStart(null);
if (onSetSelectionEnd) onSetSelectionEnd(null);
return;
}
// 1. Shift+Click (TOP PRIORITY): Range selection on track waveform // 1. Shift+Click (TOP PRIORITY): Range selection on track waveform
if (e.shiftKey) { if (e.shiftKey) {
e.preventDefault(); e.preventDefault();
@@ -3192,6 +3203,45 @@ const App = () => {
const [subTabs, setSubTabs] = useState([]); // [{id, label, trackId, startTime, endTime, buffer, effects, currentTime, selectionStart, selectionEnd, isPlaying}, ...] const [subTabs, setSubTabs] = useState([]); // [{id, label, trackId, startTime, endTime, buffer, effects, currentTime, selectionStart, selectionEnd, isPlaying}, ...]
const [selectionCleared, setSelectionCleared] = useState(false); // LOOP_EDITOR_2.md §4.2 const [selectionCleared, setSelectionCleared] = useState(false); // LOOP_EDITOR_2.md §4.2
const dspSelectionStats = useMemo(() => {
const track = tracks.find(t => t.id === selectedTrackId);
if (!track) return null;
const numChannels = track.buffer ? (track.buffer.numberOfChannels || 1) : 0;
if (selLeft === null || selRight === null || selRight <= selLeft || !track.buffer) {
return {
trackName: track.name,
channels: numChannels,
timeRange: 'Chưa chọn vùng',
peakVolume: 'N/A'
};
}
const buffer = track.buffer;
const sampleRate = buffer.sampleRate;
const startSample = Math.max(0, Math.min(buffer.length - 1, Math.floor(selLeft * sampleRate)));
const endSample = Math.max(0, Math.min(buffer.length, Math.floor(selRight * sampleRate)));
let maxVal = 0;
for (let c = 0; c < numChannels; c++) {
const data = buffer.getChannelData(c);
for (let i = startSample; i < endSample; i++) {
const val = Math.abs(data[i]);
if (val > maxVal) maxVal = val;
}
}
let peakDb = 'N/A';
if (maxVal > 0) {
const db = 20 * Math.log10(maxVal);
peakDb = db.toFixed(2) + ' dB';
} else {
peakDb = '-∞ dB';
}
return {
trackName: track.name,
channels: numChannels,
timeRange: `${selLeft.toFixed(2)}s - ${selRight.toFixed(2)}s (${(selRight - selLeft).toFixed(2)}s)`,
peakVolume: peakDb
};
}, [tracks, selectedTrackId, selLeft, selRight]);
// Temp Edit Tab (LOOP_EDITOR_2.md §1.2 Sub Tab) // Temp Edit Tab (LOOP_EDITOR_2.md §1.2 Sub Tab)
const [tempTabActive, setTempTabActive] = useState(false); const [tempTabActive, setTempTabActive] = useState(false);
const [tempTabBuffer, setTempTabBuffer] = useState(null); const [tempTabBuffer, setTempTabBuffer] = useState(null);
@@ -3306,6 +3356,14 @@ const App = () => {
if (data && data.preferences) loadPrefs(data.preferences); if (data && data.preferences) loadPrefs(data.preferences);
else { const cached = localStorage.getItem('sonic_preferences'); if (cached) loadPrefs(JSON.parse(cached)); } else { const cached = localStorage.getItem('sonic_preferences'); if (cached) loadPrefs(JSON.parse(cached)); }
} catch (e) { const cached = localStorage.getItem('sonic_preferences'); if (cached) loadPrefs(JSON.parse(cached)); } } catch (e) { const cached = localStorage.getItem('sonic_preferences'); if (cached) loadPrefs(JSON.parse(cached)); }
try {
const data = await window.SonicAPI.getAIConfigs();
if (data && data.providers) {
setAiProviders(data.providers);
const active = data.providers.find(p => p.is_active) || data.providers[0];
if (active) setSelectedProviderId(active.id);
}
} catch (e) {}
})(); })();
} }
}; };
@@ -7139,6 +7197,8 @@ const App = () => {
if (window.DAWCommandDispatcher) { if (window.DAWCommandDispatcher) {
window.DAWCommandDispatcher.currentSelectedTrackId = selectedTrackId; window.DAWCommandDispatcher.currentSelectedTrackId = selectedTrackId;
window.DAWCommandDispatcher.currentTracks = tracks; window.DAWCommandDispatcher.currentTracks = tracks;
window.DAWCommandDispatcher.lastCutSourceTrackId = null;
window.DAWCommandDispatcher.lastCutNewTrackId = null;
} }
setAiProcessing(true); setAiProcessing(true);
setAiActionLog(prev => [...prev, { type: 'status', text: ` ⏳ Đang gửi prompt đến AI...`, time: Date.now() }]); setAiActionLog(prev => [...prev, { type: 'status', text: ` ⏳ Đang gửi prompt đến AI...`, time: Date.now() }]);
@@ -7570,6 +7630,8 @@ const App = () => {
if (window.DAWCommandDispatcher) { if (window.DAWCommandDispatcher) {
window.DAWCommandDispatcher.currentTracks = nextTracks; window.DAWCommandDispatcher.currentTracks = nextTracks;
window.DAWCommandDispatcher.currentSelectedTrackId = newId; window.DAWCommandDispatcher.currentSelectedTrackId = newId;
window.DAWCommandDispatcher.lastCutSourceTrackId = tid;
window.DAWCommandDispatcher.lastCutNewTrackId = newId;
} }
setTracks(nextTracks); setTracks(nextTracks);
setSelectedTrackId(newId); setSelectedTrackId(newId);
@@ -7643,8 +7705,16 @@ const App = () => {
return { success: true, time: parseFloat(time.toFixed(3)) }; return { success: true, time: parseFloat(time.toFixed(3)) };
}, },
exportAudio: async (args) => { exportAudio: async (args) => {
const tid = args.track_id || selectedTrackId; const currentTracks = window.DAWCommandDispatcher?.currentTracks || tracks;
const track = tid && tracks.find(t => t.id === tid); const currentSelTrackId = window.DAWCommandDispatcher?.currentSelectedTrackId || selectedTrackId;
let tid = args.track_id;
if (tid && window.DAWCommandDispatcher?.lastCutSourceTrackId &&
(String(tid) === String(window.DAWCommandDispatcher.lastCutSourceTrackId) ||
'track_' + tid === String(window.DAWCommandDispatcher.lastCutSourceTrackId))) {
tid = window.DAWCommandDispatcher.lastCutNewTrackId;
}
if (!tid) tid = currentSelTrackId;
const track = tid && currentTracks.find(t => t.id === String(tid) || t.id === 'track_' + tid);
if (!track) return { success: false, error: 'No track found' }; if (!track) return { success: false, error: 'No track found' };
const clips = track.clips && track.clips.length > 0 ? track.clips : (track.buffer ? [{ id: 'default_' + track.id, buffer: track.buffer, startTime: track.startTime || 0, name: track.name }] : []); const clips = track.clips && track.clips.length > 0 ? track.clips : (track.buffer ? [{ id: 'default_' + track.id, buffer: track.buffer, startTime: track.startTime || 0, name: track.name }] : []);
if (clips.length === 0) return { success: false, error: 'Track has no audio clips' }; if (clips.length === 0) return { success: false, error: 'Track has no audio clips' };
@@ -7773,7 +7843,13 @@ const App = () => {
fadeIn: (args) => { fadeIn: (args) => {
const currentTracks = window.DAWCommandDispatcher?.currentTracks || tracks; const currentTracks = window.DAWCommandDispatcher?.currentTracks || tracks;
const currentSelTrackId = window.DAWCommandDispatcher?.currentSelectedTrackId || selectedTrackId; const currentSelTrackId = window.DAWCommandDispatcher?.currentSelectedTrackId || selectedTrackId;
const trackIdRaw = args.track_id || currentSelTrackId; let trackIdRaw = args.track_id;
if (trackIdRaw && window.DAWCommandDispatcher?.lastCutSourceTrackId &&
(String(trackIdRaw) === String(window.DAWCommandDispatcher.lastCutSourceTrackId) ||
'track_' + trackIdRaw === String(window.DAWCommandDispatcher.lastCutSourceTrackId))) {
trackIdRaw = window.DAWCommandDispatcher.lastCutNewTrackId;
}
if (!trackIdRaw) trackIdRaw = currentSelTrackId;
const track = currentTracks.find(t => t.id === String(trackIdRaw) || t.id === 'track_' + trackIdRaw); const track = currentTracks.find(t => t.id === String(trackIdRaw) || t.id === 'track_' + trackIdRaw);
if (!track) return { success: false, error: `Track ${trackIdRaw} not found` }; if (!track) return { success: false, error: `Track ${trackIdRaw} not found` };
const clips = track.clips && track.clips.length > 0 ? track.clips : (track.buffer ? [{ id: 'default_' + track.id, buffer: track.buffer, startTime: track.startTime || 0, name: track.name }] : []); const clips = track.clips && track.clips.length > 0 ? track.clips : (track.buffer ? [{ id: 'default_' + track.id, buffer: track.buffer, startTime: track.startTime || 0, name: track.name }] : []);
@@ -7833,7 +7909,13 @@ const App = () => {
fadeOut: (args) => { fadeOut: (args) => {
const currentTracks = window.DAWCommandDispatcher?.currentTracks || tracks; const currentTracks = window.DAWCommandDispatcher?.currentTracks || tracks;
const currentSelTrackId = window.DAWCommandDispatcher?.currentSelectedTrackId || selectedTrackId; const currentSelTrackId = window.DAWCommandDispatcher?.currentSelectedTrackId || selectedTrackId;
const trackIdRaw = args.track_id || currentSelTrackId; let trackIdRaw = args.track_id;
if (trackIdRaw && window.DAWCommandDispatcher?.lastCutSourceTrackId &&
(String(trackIdRaw) === String(window.DAWCommandDispatcher.lastCutSourceTrackId) ||
'track_' + trackIdRaw === String(window.DAWCommandDispatcher.lastCutSourceTrackId))) {
trackIdRaw = window.DAWCommandDispatcher.lastCutNewTrackId;
}
if (!trackIdRaw) trackIdRaw = currentSelTrackId;
const track = currentTracks.find(t => t.id === String(trackIdRaw) || t.id === 'track_' + trackIdRaw); const track = currentTracks.find(t => t.id === String(trackIdRaw) || t.id === 'track_' + trackIdRaw);
if (!track) return { success: false, error: `Track ${trackIdRaw} not found` }; if (!track) return { success: false, error: `Track ${trackIdRaw} not found` };
const clips = track.clips && track.clips.length > 0 ? track.clips : (track.buffer ? [{ id: 'default_' + track.id, buffer: track.buffer, startTime: track.startTime || 0, name: track.name }] : []); const clips = track.clips && track.clips.length > 0 ? track.clips : (track.buffer ? [{ id: 'default_' + track.id, buffer: track.buffer, startTime: track.startTime || 0, name: track.name }] : []);
@@ -8131,7 +8213,7 @@ const App = () => {
icon: 'settings', icon: 'settings',
action: () => setAiConfigModalOpen(true) action: () => setAiConfigModalOpen(true)
}, { }, {
label: 'Python DSP Tools Panel', label: 'DSP Tools Panel',
icon: 'wrench', icon: 'wrench',
action: () => openPanel('python_tools') action: () => openPanel('python_tools')
}] }]
@@ -8790,7 +8872,7 @@ const App = () => {
"data-lucide": "x", "data-lucide": "x",
className: "w-3 h-3" className: "w-3 h-3"
}))))), /*#__PURE__*/React.createElement("div", { }))))), /*#__PURE__*/React.createElement("div", {
className: "flex items-center gap-1.5 shrink-0" className: "flex items-center gap-1.5 w-full min-w-0 pb-1"
}, /*#__PURE__*/React.createElement("span", { }, /*#__PURE__*/React.createElement("span", {
className: "inline-flex items-center shrink-0" className: "inline-flex items-center shrink-0"
}, /*#__PURE__*/React.createElement("i", { }, /*#__PURE__*/React.createElement("i", {
@@ -8799,7 +8881,7 @@ const App = () => {
})), /*#__PURE__*/React.createElement("select", { })), /*#__PURE__*/React.createElement("select", {
value: selectedProviderId, value: selectedProviderId,
onChange: e => setSelectedProviderId(e.target.value), onChange: e => setSelectedProviderId(e.target.value),
className: "flex-1 bg-[#141414] text-zinc-200 border border-zinc-700 rounded px-1 py-0.5 text-xs font-mono focus:outline-none focus:border-purple-600" className: "flex-1 min-w-0 max-w-full bg-[#141414] text-zinc-200 border border-zinc-700 rounded px-1 py-0.5 text-xs font-mono focus:outline-none focus:border-purple-600 truncate"
}, aiProviders.length === 0 ? /*#__PURE__*/React.createElement("option", { }, aiProviders.length === 0 ? /*#__PURE__*/React.createElement("option", {
value: "" value: ""
}, "Chưa có provider") : aiProviders.map(p => /*#__PURE__*/React.createElement("option", { }, "Chưa có provider") : aiProviders.map(p => /*#__PURE__*/React.createElement("option", {
@@ -8917,7 +8999,7 @@ const App = () => {
}, /*#__PURE__*/React.createElement("i", { }, /*#__PURE__*/React.createElement("i", {
"data-lucide": "wrench", "data-lucide": "wrench",
className: "w-3.5 h-3.5 text-amber-400" className: "w-3.5 h-3.5 text-amber-400"
})), " Python DSP Tools"), /*#__PURE__*/React.createElement("button", { })), " DSP Tools"), /*#__PURE__*/React.createElement("button", {
onClick: () => closePanel('python_tools'), onClick: () => closePanel('python_tools'),
className: "text-zinc-600 hover:text-zinc-300" className: "text-zinc-600 hover:text-zinc-300"
}, /*#__PURE__*/React.createElement("span", { }, /*#__PURE__*/React.createElement("span", {
@@ -8926,8 +9008,13 @@ const App = () => {
"data-lucide": "x", "data-lucide": "x",
className: "w-3 h-3" className: "w-3 h-3"
})))), /*#__PURE__*/React.createElement("div", { })))), /*#__PURE__*/React.createElement("div", {
className: "p-1 bg-[#141414] rounded border border-zinc-800 text-xs font-mono text-zinc-400" className: "p-1.5 bg-[#141414] rounded border border-zinc-800 text-[10px] font-mono text-zinc-400 space-y-0.5 leading-relaxed"
}, "// Non-AI Audio Processing Tools"), /*#__PURE__*/React.createElement("div", { }, dspSelectionStats ? [
/*#__PURE__*/React.createElement("div", { key: "track" }, `Track: ${dspSelectionStats.trackName}`),
/*#__PURE__*/React.createElement("div", { key: "range" }, `Range: ${dspSelectionStats.timeRange}`),
/*#__PURE__*/React.createElement("div", { key: "ch" }, `Channels: ${dspSelectionStats.channels}`),
/*#__PURE__*/React.createElement("div", { key: "peak" }, `Peak Vol: ${dspSelectionStats.peakVolume}`)
] : "Chưa chọn track"), /*#__PURE__*/React.createElement("div", {
className: "grid grid-cols-2 gap-1 text-xs" className: "grid grid-cols-2 gap-1 text-xs"
}, /*#__PURE__*/React.createElement("button", { }, /*#__PURE__*/React.createElement("button", {
onClick: () => runPythonTool('normalize'), onClick: () => runPythonTool('normalize'),
+94 -10
View File
@@ -549,6 +549,17 @@ const WaveformLane = ({
speed: track.speed || 1.0 speed: track.speed || 1.0
}] : []; }] : [];
// Check if Ctrl+Click to exit selection
if (e.ctrlKey && selectionMode) {
e.preventDefault();
e.stopPropagation();
if (onClearLocalSelection) onClearLocalSelection();
if (onSetSelectionMode) onSetSelectionMode(null);
if (onSetSelectionStart) onSetSelectionStart(null);
if (onSetSelectionEnd) onSetSelectionEnd(null);
return;
}
// 1. Shift+Click (TOP PRIORITY): Range selection on track waveform // 1. Shift+Click (TOP PRIORITY): Range selection on track waveform
if (e.shiftKey) { if (e.shiftKey) {
e.preventDefault(); e.preventDefault();
@@ -3235,6 +3246,45 @@ const App = () => {
const [subTabs, setSubTabs] = useState([]); // [{id, label, trackId, startTime, endTime, buffer, effects, currentTime, selectionStart, selectionEnd, isPlaying}, ...] const [subTabs, setSubTabs] = useState([]); // [{id, label, trackId, startTime, endTime, buffer, effects, currentTime, selectionStart, selectionEnd, isPlaying}, ...]
const [selectionCleared, setSelectionCleared] = useState(false); // LOOP_EDITOR_2.md §4.2 const [selectionCleared, setSelectionCleared] = useState(false); // LOOP_EDITOR_2.md §4.2
const dspSelectionStats = useMemo(() => {
const track = tracks.find(t => t.id === selectedTrackId);
if (!track) return null;
const numChannels = track.buffer ? track.buffer.numberOfChannels || 1 : 0;
if (selLeft === null || selRight === null || selRight <= selLeft || !track.buffer) {
return {
trackName: track.name,
channels: numChannels,
timeRange: 'Chưa chọn vùng',
peakVolume: 'N/A'
};
}
const buffer = track.buffer;
const sampleRate = buffer.sampleRate;
const startSample = Math.max(0, Math.min(buffer.length - 1, Math.floor(selLeft * sampleRate)));
const endSample = Math.max(0, Math.min(buffer.length, Math.floor(selRight * sampleRate)));
let maxVal = 0;
for (let c = 0; c < numChannels; c++) {
const data = buffer.getChannelData(c);
for (let i = startSample; i < endSample; i++) {
const val = Math.abs(data[i]);
if (val > maxVal) maxVal = val;
}
}
let peakDb = 'N/A';
if (maxVal > 0) {
const db = 20 * Math.log10(maxVal);
peakDb = db.toFixed(2) + ' dB';
} else {
peakDb = '-∞ dB';
}
return {
trackName: track.name,
channels: numChannels,
timeRange: `${selLeft.toFixed(2)}s - ${selRight.toFixed(2)}s (${(selRight - selLeft).toFixed(2)}s)`,
peakVolume: peakDb
};
}, [tracks, selectedTrackId, selLeft, selRight]);
// ── Temp Edit Tab (LOOP_EDITOR_2.md §1.2 Sub Tab) ── // ── Temp Edit Tab (LOOP_EDITOR_2.md §1.2 Sub Tab) ──
const [tempTabActive, setTempTabActive] = useState(false); const [tempTabActive, setTempTabActive] = useState(false);
const [tempTabBuffer, setTempTabBuffer] = useState(null); const [tempTabBuffer, setTempTabBuffer] = useState(null);
@@ -3356,6 +3406,14 @@ const App = () => {
const cached = localStorage.getItem('sonic_preferences'); const cached = localStorage.getItem('sonic_preferences');
if (cached) loadPrefs(JSON.parse(cached)); if (cached) loadPrefs(JSON.parse(cached));
} }
try {
const data = await window.SonicAPI.getAIConfigs();
if (data && data.providers) {
setAiProviders(data.providers);
const active = data.providers.find(p => p.is_active) || data.providers[0];
if (active) setSelectedProviderId(active.id);
}
} catch (e) {}
})(); })();
} }
}; };
@@ -7277,6 +7335,8 @@ const App = () => {
if (window.DAWCommandDispatcher) { if (window.DAWCommandDispatcher) {
window.DAWCommandDispatcher.currentSelectedTrackId = selectedTrackId; window.DAWCommandDispatcher.currentSelectedTrackId = selectedTrackId;
window.DAWCommandDispatcher.currentTracks = tracks; window.DAWCommandDispatcher.currentTracks = tracks;
window.DAWCommandDispatcher.lastCutSourceTrackId = null;
window.DAWCommandDispatcher.lastCutNewTrackId = null;
} }
setAiProcessing(true); setAiProcessing(true);
setAiActionLog(prev => [...prev, { setAiActionLog(prev => [...prev, {
@@ -7861,6 +7921,8 @@ const App = () => {
if (window.DAWCommandDispatcher) { if (window.DAWCommandDispatcher) {
window.DAWCommandDispatcher.currentTracks = nextTracks; window.DAWCommandDispatcher.currentTracks = nextTracks;
window.DAWCommandDispatcher.currentSelectedTrackId = newId; window.DAWCommandDispatcher.currentSelectedTrackId = newId;
window.DAWCommandDispatcher.lastCutSourceTrackId = tid;
window.DAWCommandDispatcher.lastCutNewTrackId = newId;
} }
setTracks(nextTracks); setTracks(nextTracks);
setSelectedTrackId(newId); setSelectedTrackId(newId);
@@ -7953,8 +8015,14 @@ const App = () => {
}; };
}, },
exportAudio: async args => { exportAudio: async args => {
const tid = args.track_id || selectedTrackId; const currentTracks = window.DAWCommandDispatcher?.currentTracks || tracks;
const track = tid && tracks.find(t => t.id === tid); const currentSelTrackId = window.DAWCommandDispatcher?.currentSelectedTrackId || selectedTrackId;
let tid = args.track_id;
if (tid && window.DAWCommandDispatcher?.lastCutSourceTrackId && (String(tid) === String(window.DAWCommandDispatcher.lastCutSourceTrackId) || 'track_' + tid === String(window.DAWCommandDispatcher.lastCutSourceTrackId))) {
tid = window.DAWCommandDispatcher.lastCutNewTrackId;
}
if (!tid) tid = currentSelTrackId;
const track = tid && currentTracks.find(t => t.id === String(tid) || t.id === 'track_' + tid);
if (!track) return { if (!track) return {
success: false, success: false,
error: 'No track found' error: 'No track found'
@@ -8154,7 +8222,11 @@ const App = () => {
fadeIn: args => { fadeIn: args => {
const currentTracks = window.DAWCommandDispatcher?.currentTracks || tracks; const currentTracks = window.DAWCommandDispatcher?.currentTracks || tracks;
const currentSelTrackId = window.DAWCommandDispatcher?.currentSelectedTrackId || selectedTrackId; const currentSelTrackId = window.DAWCommandDispatcher?.currentSelectedTrackId || selectedTrackId;
const trackIdRaw = args.track_id || currentSelTrackId; let trackIdRaw = args.track_id;
if (trackIdRaw && window.DAWCommandDispatcher?.lastCutSourceTrackId && (String(trackIdRaw) === String(window.DAWCommandDispatcher.lastCutSourceTrackId) || 'track_' + trackIdRaw === String(window.DAWCommandDispatcher.lastCutSourceTrackId))) {
trackIdRaw = window.DAWCommandDispatcher.lastCutNewTrackId;
}
if (!trackIdRaw) trackIdRaw = currentSelTrackId;
const track = currentTracks.find(t => t.id === String(trackIdRaw) || t.id === 'track_' + trackIdRaw); const track = currentTracks.find(t => t.id === String(trackIdRaw) || t.id === 'track_' + trackIdRaw);
if (!track) return { if (!track) return {
success: false, success: false,
@@ -8245,7 +8317,11 @@ const App = () => {
fadeOut: args => { fadeOut: args => {
const currentTracks = window.DAWCommandDispatcher?.currentTracks || tracks; const currentTracks = window.DAWCommandDispatcher?.currentTracks || tracks;
const currentSelTrackId = window.DAWCommandDispatcher?.currentSelectedTrackId || selectedTrackId; const currentSelTrackId = window.DAWCommandDispatcher?.currentSelectedTrackId || selectedTrackId;
const trackIdRaw = args.track_id || currentSelTrackId; let trackIdRaw = args.track_id;
if (trackIdRaw && window.DAWCommandDispatcher?.lastCutSourceTrackId && (String(trackIdRaw) === String(window.DAWCommandDispatcher.lastCutSourceTrackId) || 'track_' + trackIdRaw === String(window.DAWCommandDispatcher.lastCutSourceTrackId))) {
trackIdRaw = window.DAWCommandDispatcher.lastCutNewTrackId;
}
if (!trackIdRaw) trackIdRaw = currentSelTrackId;
const track = currentTracks.find(t => t.id === String(trackIdRaw) || t.id === 'track_' + trackIdRaw); const track = currentTracks.find(t => t.id === String(trackIdRaw) || t.id === 'track_' + trackIdRaw);
if (!track) return { if (!track) return {
success: false, success: false,
@@ -8582,7 +8658,7 @@ const App = () => {
icon: 'settings', icon: 'settings',
action: () => setAiConfigModalOpen(true) action: () => setAiConfigModalOpen(true)
}, { }, {
label: 'Python DSP Tools Panel', label: 'DSP Tools Panel',
icon: 'wrench', icon: 'wrench',
action: () => openPanel('python_tools') action: () => openPanel('python_tools')
}] }]
@@ -9288,7 +9364,7 @@ const App = () => {
"data-lucide": "x", "data-lucide": "x",
className: "w-3 h-3" className: "w-3 h-3"
}))))), /*#__PURE__*/React.createElement("div", { }))))), /*#__PURE__*/React.createElement("div", {
className: "flex items-center gap-1.5 shrink-0" className: "flex items-center gap-1.5 w-full min-w-0 pb-1"
}, /*#__PURE__*/React.createElement("span", { }, /*#__PURE__*/React.createElement("span", {
className: "inline-flex items-center shrink-0" className: "inline-flex items-center shrink-0"
}, /*#__PURE__*/React.createElement("i", { }, /*#__PURE__*/React.createElement("i", {
@@ -9297,7 +9373,7 @@ const App = () => {
})), /*#__PURE__*/React.createElement("select", { })), /*#__PURE__*/React.createElement("select", {
value: selectedProviderId, value: selectedProviderId,
onChange: e => setSelectedProviderId(e.target.value), onChange: e => setSelectedProviderId(e.target.value),
className: "flex-1 bg-[#141414] text-zinc-200 border border-zinc-700 rounded px-1 py-0.5 text-xs font-mono focus:outline-none focus:border-purple-600" className: "flex-1 min-w-0 max-w-full bg-[#141414] text-zinc-200 border border-zinc-700 rounded px-1 py-0.5 text-xs font-mono focus:outline-none focus:border-purple-600 truncate"
}, aiProviders.length === 0 ? /*#__PURE__*/React.createElement("option", { }, aiProviders.length === 0 ? /*#__PURE__*/React.createElement("option", {
value: "" value: ""
}, "Chưa có provider") : aiProviders.map(p => /*#__PURE__*/React.createElement("option", { }, "Chưa có provider") : aiProviders.map(p => /*#__PURE__*/React.createElement("option", {
@@ -9423,7 +9499,7 @@ const App = () => {
}, /*#__PURE__*/React.createElement("i", { }, /*#__PURE__*/React.createElement("i", {
"data-lucide": "wrench", "data-lucide": "wrench",
className: "w-3.5 h-3.5 text-amber-400" className: "w-3.5 h-3.5 text-amber-400"
})), " Python DSP Tools"), /*#__PURE__*/React.createElement("button", { })), " DSP Tools"), /*#__PURE__*/React.createElement("button", {
onClick: () => closePanel('python_tools'), onClick: () => closePanel('python_tools'),
className: "text-zinc-600 hover:text-zinc-300" className: "text-zinc-600 hover:text-zinc-300"
}, /*#__PURE__*/React.createElement("span", { }, /*#__PURE__*/React.createElement("span", {
@@ -9432,8 +9508,16 @@ const App = () => {
"data-lucide": "x", "data-lucide": "x",
className: "w-3 h-3" className: "w-3 h-3"
})))), /*#__PURE__*/React.createElement("div", { })))), /*#__PURE__*/React.createElement("div", {
className: "p-1 bg-[#141414] rounded border border-zinc-800 text-xs font-mono text-zinc-400" className: "p-1.5 bg-[#141414] rounded border border-zinc-800 text-[10px] font-mono text-zinc-400 space-y-0.5 leading-relaxed"
}, "// Non-AI Audio Processing Tools"), /*#__PURE__*/React.createElement("div", { }, dspSelectionStats ? [/*#__PURE__*/React.createElement("div", {
key: "track"
}, `Track: ${dspSelectionStats.trackName}`), /*#__PURE__*/React.createElement("div", {
key: "range"
}, `Range: ${dspSelectionStats.timeRange}`), /*#__PURE__*/React.createElement("div", {
key: "ch"
}, `Channels: ${dspSelectionStats.channels}`), /*#__PURE__*/React.createElement("div", {
key: "peak"
}, `Peak Vol: ${dspSelectionStats.peakVolume}`)] : "Chưa chọn track"), /*#__PURE__*/React.createElement("div", {
className: "grid grid-cols-2 gap-1 text-xs" className: "grid grid-cols-2 gap-1 text-xs"
}, /*#__PURE__*/React.createElement("button", { }, /*#__PURE__*/React.createElement("button", {
onClick: () => runPythonTool('normalize'), onClick: () => runPythonTool('normalize'),
Binary file not shown.