diff --git a/app/static/js/app.jsx b/app/static/js/app.jsx index 6ad54b7..c582d62 100644 --- a/app/static/js/app.jsx +++ b/app/static/js/app.jsx @@ -3203,44 +3203,6 @@ 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); @@ -5087,6 +5049,45 @@ const App = () => { return Math.max(selectionStart, selectionEnd); }, [selectionStart, selectionEnd, selectionMode, localSelectionStart, localSelectionEnd]); + 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]); + // ── Toast helper ── const showToast = (text, type = 'info') => { if (toastTimeoutRef.current) clearTimeout(toastTimeoutRef.current); diff --git a/app/static/js/app.precompiled.js b/app/static/js/app.precompiled.js index b7276bc..33827ba 100644 --- a/app/static/js/app.precompiled.js +++ b/app/static/js/app.precompiled.js @@ -3246,45 +3246,6 @@ 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); @@ -5143,6 +5104,44 @@ const App = () => { if (selectionStart === null || selectionEnd === null) return null; return Math.max(selectionStart, selectionEnd); }, [selectionStart, selectionEnd, selectionMode, localSelectionStart, localSelectionEnd]); + 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]); // ── Toast helper ── const showToast = (text, type = 'info') => {