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