// js/audio/audio_clipboard.js import { appState } from '../state.js'; import { removeAudioClip, loadAudioForClip } from './audio_state.js'; import { renderAudioEditor } from './audio_ui.js'; import { getMainGainNode } from '../audio.js'; /** * Copia o clipe selecionado para a área de transferência global. */ export function copyAudioClip() { const clipId = appState.global.selectedClipId; if (!clipId) return; const clip = appState.audio.clips.find(c => c.id == clipId); if (!clip) return; // Remove a marca de "recortado" se houver if (appState.global.clipboard?.cutSourceId) { appState.global.clipboard.cutSourceId = null; } // Cria uma cópia limpa dos dados do clipe const clipData = { ...clip }; // Remove referências a nós de áudio, que devem ser únicos delete clipData.gainNode; delete clipData.pannerNode; delete clipData.player; appState.global.clipboard = { type: 'audio', clip: clipData, cutSourceId: null }; console.log("Clipe copiado:", appState.global.clipboard.clip.name); renderAudioEditor(); // Re-renderiza para remover o visual "cut" } /** * Recorta o clipe selecionado para a área de transferência global. */ export function cutAudioClip() { const clipId = appState.global.selectedClipId; if (!clipId) return; // Limpa o "cut" anterior if (appState.global.clipboard?.cutSourceId) { appState.global.clipboard.cutSourceId = null; } const clip = appState.audio.clips.find(c => c.id == clipId); if (!clip) return; // Cria uma cópia limpa dos dados do clipe const clipData = { ...clip }; delete clipData.gainNode; delete clipData.pannerNode; delete clipData.player; appState.global.clipboard = { type: 'audio', clip: clipData, cutSourceId: clipId // Marca o ID original para exclusão }; console.log("Clipe recortado:", appState.global.clipboard.clip.name); renderAudioEditor(); // Re-renderiza para adicionar o visual "cut" } /** * Cola o clipe da área de transferência na timeline. * @param {number} targetTrackId - O ID da pista onde colar. * @param {number} targetTimeInSeconds - O tempo (em segundos) onde colar. */ export function pasteAudioClip(targetTrackId, targetTimeInSeconds) { const clipboard = appState.global.clipboard; if (!clipboard || clipboard.type !== 'audio' || !clipboard.clip) { console.warn("Área de transferência vazia ou inválida para colar áudio."); return; } const clipToPaste = clipboard.clip; // Se for um "recorte", primeiro remove o clipe original if (clipboard.cutSourceId) { removeAudioClip(clipboard.cutSourceId); // clipboard.cutSourceId = null; // Limpa para que não remova de novo } // Cria um novo clipe a partir dos dados copiados const newClip = { ...clipToPaste, id: Date.now() + Math.random(), // ID novo e único trackId: targetTrackId, startTimeInSeconds: targetTimeInSeconds, // Cria novos nós de áudio gainNode: new Tone.Gain(Tone.gainToDb(clipToPaste.volume || 1.0)), pannerNode: new Tone.Panner(clipToPaste.pan || 0), player: null, // O buffer será copiado/referenciado }; newClip.gainNode.connect(newClip.pannerNode); newClip.pannerNode.connect(getMainGainNode()); // appState.audio.clips.push(newClip); // Como o buffer já deve existir no clipe original, // não precisamos de 'loadAudioForClip', mas chamamos // para garantir (caso a fonte seja um 'sourcePath'). // A função 'loadAudioForClip' precisa ser inteligente // para não recarregar se o buffer já existir. loadAudioForClip(newClip).then(() => { // renderAudioEditor(); }); }