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
|
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'),
|
||||||
|
|||||||
@@ -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.
Reference in New Issue
Block a user