From 66b0811f550f0d20cb5722cfba8b1b20746039f1 Mon Sep 17 00:00:00 2001 From: 3dtours Date: Sun, 19 Jul 2026 11:32:48 +0700 Subject: [PATCH] =?UTF-8?q?fix:=20passthrough=20c=C3=B4ng=20c=E1=BB=A5=20t?= =?UTF-8?q?=E1=BB=AB=20main=20sang=20sub?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/templates/index.html | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/app/templates/index.html b/app/templates/index.html index 3d21a73..4d05401 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -1869,7 +1869,31 @@ const contextMenuCopy = () => { const track = tracks.find(t => t.id === contextMenu.trackId); - if (!track) return; + if (!track || !track.buffer) return; + + const sr = track.buffer.sampleRate; + const data = track.buffer.getChannelData(0); + + // Copy selected region if selection exists + if (selLeft !== null && selRight !== null && selRight > selLeft) { + const trackStart = track.startTime || 0; + const relSelLeft = Math.max(0, selLeft - trackStart); + const relSelRight = Math.max(0, selRight - trackStart); + const startSample = Math.floor(relSelLeft * sr); + const endSample = Math.min(data.length, Math.floor(relSelRight * sr)); + const len = endSample - startSample; + if (len > 0) { + const ctx = getAudioContext(); + const clipBuffer = ctx.createBuffer(1, len, sr); + clipBuffer.copyToChannel(data.subarray(startSample, endSample), 0); + clipboardRef.current = { buffer: clipBuffer, name: track.name, volume: track.volume, color: track.color }; + closeContextMenu(); + showToast('Đã sao chép vùng chọn.', 'info'); + return; + } + } + + // No selection: copy entire track clipboardRef.current = { buffer: track.buffer, name: track.name, @@ -1877,7 +1901,7 @@ color: track.color, }; closeContextMenu(); - showToast('Đã sao chép track vào clipboard.', 'info'); + showToast('Đã sao chép toàn bộ track.', 'info'); }; const contextMenuCut = () => {