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 = () => {