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:
+97
-10
@@ -549,6 +549,17 @@ const WaveformLane = ({
|
||||
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
|
||||
if (e.shiftKey) {
|
||||
e.preventDefault();
|
||||
@@ -3192,6 +3203,45 @@ const App = () => {
|
||||
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 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) ──
|
||||
const [tempTabActive, setTempTabActive] = useState(false);
|
||||
const [tempTabBuffer, setTempTabBuffer] = useState(null);
|
||||
@@ -3306,6 +3356,14 @@ const App = () => {
|
||||
if (data && data.preferences) loadPrefs(data.preferences);
|
||||
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)); }
|
||||
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) {
|
||||
window.DAWCommandDispatcher.currentSelectedTrackId = selectedTrackId;
|
||||
window.DAWCommandDispatcher.currentTracks = tracks;
|
||||
window.DAWCommandDispatcher.lastCutSourceTrackId = null;
|
||||
window.DAWCommandDispatcher.lastCutNewTrackId = null;
|
||||
}
|
||||
setAiProcessing(true);
|
||||
setAiActionLog(prev => [...prev, { type: 'status', text: ` ⏳ Đang gửi prompt đến AI...`, time: Date.now() }]);
|
||||
@@ -7570,6 +7630,8 @@ const App = () => {
|
||||
if (window.DAWCommandDispatcher) {
|
||||
window.DAWCommandDispatcher.currentTracks = nextTracks;
|
||||
window.DAWCommandDispatcher.currentSelectedTrackId = newId;
|
||||
window.DAWCommandDispatcher.lastCutSourceTrackId = tid;
|
||||
window.DAWCommandDispatcher.lastCutNewTrackId = newId;
|
||||
}
|
||||
setTracks(nextTracks);
|
||||
setSelectedTrackId(newId);
|
||||
@@ -7643,8 +7705,16 @@ const App = () => {
|
||||
return { success: true, time: parseFloat(time.toFixed(3)) };
|
||||
},
|
||||
exportAudio: async (args) => {
|
||||
const tid = args.track_id || selectedTrackId;
|
||||
const track = tid && tracks.find(t => t.id === tid);
|
||||
const currentTracks = window.DAWCommandDispatcher?.currentTracks || tracks;
|
||||
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' };
|
||||
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' };
|
||||
@@ -7773,7 +7843,13 @@ const App = () => {
|
||||
fadeIn: (args) => {
|
||||
const currentTracks = window.DAWCommandDispatcher?.currentTracks || tracks;
|
||||
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);
|
||||
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 }] : []);
|
||||
@@ -7833,7 +7909,13 @@ const App = () => {
|
||||
fadeOut: (args) => {
|
||||
const currentTracks = window.DAWCommandDispatcher?.currentTracks || tracks;
|
||||
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);
|
||||
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 }] : []);
|
||||
@@ -8131,7 +8213,7 @@ const App = () => {
|
||||
icon: 'settings',
|
||||
action: () => setAiConfigModalOpen(true)
|
||||
}, {
|
||||
label: 'Python DSP Tools Panel',
|
||||
label: 'DSP Tools Panel',
|
||||
icon: 'wrench',
|
||||
action: () => openPanel('python_tools')
|
||||
}]
|
||||
@@ -8790,7 +8872,7 @@ const App = () => {
|
||||
"data-lucide": "x",
|
||||
className: "w-3 h-3"
|
||||
}))))), /*#__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", {
|
||||
className: "inline-flex items-center shrink-0"
|
||||
}, /*#__PURE__*/React.createElement("i", {
|
||||
@@ -8799,7 +8881,7 @@ const App = () => {
|
||||
})), /*#__PURE__*/React.createElement("select", {
|
||||
value: selectedProviderId,
|
||||
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", {
|
||||
value: ""
|
||||
}, "Chưa có provider") : aiProviders.map(p => /*#__PURE__*/React.createElement("option", {
|
||||
@@ -8917,7 +8999,7 @@ const App = () => {
|
||||
}, /*#__PURE__*/React.createElement("i", {
|
||||
"data-lucide": "wrench",
|
||||
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'),
|
||||
className: "text-zinc-600 hover:text-zinc-300"
|
||||
}, /*#__PURE__*/React.createElement("span", {
|
||||
@@ -8926,8 +9008,13 @@ const App = () => {
|
||||
"data-lucide": "x",
|
||||
className: "w-3 h-3"
|
||||
})))), /*#__PURE__*/React.createElement("div", {
|
||||
className: "p-1 bg-[#141414] rounded border border-zinc-800 text-xs font-mono text-zinc-400"
|
||||
}, "// Non-AI Audio Processing Tools"), /*#__PURE__*/React.createElement("div", {
|
||||
className: "p-1.5 bg-[#141414] rounded border border-zinc-800 text-[10px] font-mono text-zinc-400 space-y-0.5 leading-relaxed"
|
||||
}, 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"
|
||||
}, /*#__PURE__*/React.createElement("button", {
|
||||
onClick: () => runPythonTool('normalize'),
|
||||
|
||||
@@ -549,6 +549,17 @@ const WaveformLane = ({
|
||||
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
|
||||
if (e.shiftKey) {
|
||||
e.preventDefault();
|
||||
@@ -3235,6 +3246,45 @@ const App = () => {
|
||||
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 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) ──
|
||||
const [tempTabActive, setTempTabActive] = useState(false);
|
||||
const [tempTabBuffer, setTempTabBuffer] = useState(null);
|
||||
@@ -3356,6 +3406,14 @@ const App = () => {
|
||||
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) {}
|
||||
})();
|
||||
}
|
||||
};
|
||||
@@ -7277,6 +7335,8 @@ const App = () => {
|
||||
if (window.DAWCommandDispatcher) {
|
||||
window.DAWCommandDispatcher.currentSelectedTrackId = selectedTrackId;
|
||||
window.DAWCommandDispatcher.currentTracks = tracks;
|
||||
window.DAWCommandDispatcher.lastCutSourceTrackId = null;
|
||||
window.DAWCommandDispatcher.lastCutNewTrackId = null;
|
||||
}
|
||||
setAiProcessing(true);
|
||||
setAiActionLog(prev => [...prev, {
|
||||
@@ -7861,6 +7921,8 @@ const App = () => {
|
||||
if (window.DAWCommandDispatcher) {
|
||||
window.DAWCommandDispatcher.currentTracks = nextTracks;
|
||||
window.DAWCommandDispatcher.currentSelectedTrackId = newId;
|
||||
window.DAWCommandDispatcher.lastCutSourceTrackId = tid;
|
||||
window.DAWCommandDispatcher.lastCutNewTrackId = newId;
|
||||
}
|
||||
setTracks(nextTracks);
|
||||
setSelectedTrackId(newId);
|
||||
@@ -7953,8 +8015,14 @@ const App = () => {
|
||||
};
|
||||
},
|
||||
exportAudio: async args => {
|
||||
const tid = args.track_id || selectedTrackId;
|
||||
const track = tid && tracks.find(t => t.id === tid);
|
||||
const currentTracks = window.DAWCommandDispatcher?.currentTracks || tracks;
|
||||
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'
|
||||
@@ -8154,7 +8222,11 @@ const App = () => {
|
||||
fadeIn: args => {
|
||||
const currentTracks = window.DAWCommandDispatcher?.currentTracks || tracks;
|
||||
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);
|
||||
if (!track) return {
|
||||
success: false,
|
||||
@@ -8245,7 +8317,11 @@ const App = () => {
|
||||
fadeOut: args => {
|
||||
const currentTracks = window.DAWCommandDispatcher?.currentTracks || tracks;
|
||||
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);
|
||||
if (!track) return {
|
||||
success: false,
|
||||
@@ -8582,7 +8658,7 @@ const App = () => {
|
||||
icon: 'settings',
|
||||
action: () => setAiConfigModalOpen(true)
|
||||
}, {
|
||||
label: 'Python DSP Tools Panel',
|
||||
label: 'DSP Tools Panel',
|
||||
icon: 'wrench',
|
||||
action: () => openPanel('python_tools')
|
||||
}]
|
||||
@@ -9288,7 +9364,7 @@ const App = () => {
|
||||
"data-lucide": "x",
|
||||
className: "w-3 h-3"
|
||||
}))))), /*#__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", {
|
||||
className: "inline-flex items-center shrink-0"
|
||||
}, /*#__PURE__*/React.createElement("i", {
|
||||
@@ -9297,7 +9373,7 @@ const App = () => {
|
||||
})), /*#__PURE__*/React.createElement("select", {
|
||||
value: selectedProviderId,
|
||||
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", {
|
||||
value: ""
|
||||
}, "Chưa có provider") : aiProviders.map(p => /*#__PURE__*/React.createElement("option", {
|
||||
@@ -9423,7 +9499,7 @@ const App = () => {
|
||||
}, /*#__PURE__*/React.createElement("i", {
|
||||
"data-lucide": "wrench",
|
||||
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'),
|
||||
className: "text-zinc-600 hover:text-zinc-300"
|
||||
}, /*#__PURE__*/React.createElement("span", {
|
||||
@@ -9432,8 +9508,16 @@ const App = () => {
|
||||
"data-lucide": "x",
|
||||
className: "w-3 h-3"
|
||||
})))), /*#__PURE__*/React.createElement("div", {
|
||||
className: "p-1 bg-[#141414] rounded border border-zinc-800 text-xs font-mono text-zinc-400"
|
||||
}, "// Non-AI Audio Processing Tools"), /*#__PURE__*/React.createElement("div", {
|
||||
className: "p-1.5 bg-[#141414] rounded border border-zinc-800 text-[10px] font-mono text-zinc-400 space-y-0.5 leading-relaxed"
|
||||
}, 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"
|
||||
}, /*#__PURE__*/React.createElement("button", {
|
||||
onClick: () => runPythonTool('normalize'),
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user