154 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			154 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
// js/audio_audio.js
 | 
						|
import { appState } from "../state.js";
 | 
						|
import { updateAudioEditorUI, updatePlayheadVisual, resetPlayheadVisual } from "./audio_ui.js";
 | 
						|
import { PIXELS_PER_STEP } from "../config.js";
 | 
						|
import { initializeAudioContext } from "../audio.js";
 | 
						|
import { getPixelsPerSecond } from "../utils.js";
 | 
						|
 | 
						|
function animationLoop() {
 | 
						|
    if (!appState.global.isAudioEditorPlaying) return;
 | 
						|
 | 
						|
    const pixelsPerSecond = getPixelsPerSecond();
 | 
						|
    const totalElapsedTime = Tone.Transport.seconds;
 | 
						|
    
 | 
						|
    let maxTime = 0;
 | 
						|
    appState.audio.clips.forEach(clip => {
 | 
						|
        const endTime = clip.startTime + clip.duration;
 | 
						|
        if (endTime > maxTime) maxTime = endTime;
 | 
						|
    });
 | 
						|
 | 
						|
    if (!appState.global.isLoopActive && totalElapsedTime >= maxTime && maxTime > 0) {
 | 
						|
        stopAudioEditorPlayback();
 | 
						|
        resetPlayheadVisual();
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    
 | 
						|
    const newPositionPx = totalElapsedTime * pixelsPerSecond;
 | 
						|
    updatePlayheadVisual(newPositionPx);
 | 
						|
 | 
						|
    // ##### CORREÇÃO 1 #####
 | 
						|
    // Salva o ID da animação para que o stop possa cancelá-lo
 | 
						|
    appState.audio.audioEditorAnimationId = requestAnimationFrame(animationLoop);
 | 
						|
}
 | 
						|
 | 
						|
export function updateTransportLoop() {
 | 
						|
    Tone.Transport.loop = appState.global.isLoopActive;
 | 
						|
    Tone.Transport.loopStart = appState.global.loopStartTime;
 | 
						|
    Tone.Transport.loopEnd = appState.global.loopEndTime;
 | 
						|
}
 | 
						|
 | 
						|
export function startAudioEditorPlayback() {
 | 
						|
  if (appState.global.isAudioEditorPlaying) return;
 | 
						|
  initializeAudioContext();
 | 
						|
  Tone.Transport.cancel(); // Limpa eventos agendados anteriormente
 | 
						|
  
 | 
						|
  updateTransportLoop(); // Isso deve definir Tone.Transport.loop = true e Tone.Transport.loopEnd
 | 
						|
 | 
						|
  // 1. Pegue a duração total do loop que a função acima definiu
 | 
						|
  const loopInterval = Tone.Transport.loopEnd;
 | 
						|
 | 
						|
  // Se loopEnd não foi definido (ex: 0 ou undefined), o loop não funcionará.
 | 
						|
  if (!loopInterval || loopInterval === 0) {
 | 
						|
      console.error("LoopEnd não está definido no Tone.Transport! O áudio não repetirá.");
 | 
						|
      // Você pode querer definir um padrão aqui, mas o ideal é 
 | 
						|
      // garantir que 'updateTransportLoop' esteja definindo 'loopEnd' corretamente.
 | 
						|
      // ex: const loopInterval = "1m"; (se for um compasso por padrão)
 | 
						|
  }
 | 
						|
 | 
						|
  appState.audio.clips.forEach(clip => {
 | 
						|
    if (!clip.player || !clip.player.loaded) return;
 | 
						|
    
 | 
						|
    // 2. CORREÇÃO: Use scheduleRepeat no lugar de scheduleOnce
 | 
						|
    Tone.Transport.scheduleRepeat((time) => {
 | 
						|
      // Sua lógica de parâmetros está correta
 | 
						|
      clip.gainNode.gain.value = Tone.gainToDb(clip.volume);
 | 
						|
      clip.pannerNode.pan.value = clip.pan;
 | 
						|
      clip.player.playbackRate = Math.pow(2, clip.pitch / 12);
 | 
						|
      
 | 
						|
      // Inicia o player no tempo agendado
 | 
						|
      clip.player.start(time, clip.offset, clip.duration);
 | 
						|
 | 
						|
    }, 
 | 
						|
    loopInterval,   // <--- O intervalo de repetição (ex: "4m", "8m")
 | 
						|
    clip.startTime  // <--- Onde o clip começa dentro da linha do tempo
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  // 3. ADIÇÃO CRÍTICA: Inicie o transporte e atualize o estado
 | 
						|
  Tone.Transport.start();
 | 
						|
  appState.global.isAudioEditorPlaying = true;
 | 
						|
 | 
						|
  // 4. (CORRIGIDO) Atualize a UI do botão de play
 | 
						|
  const playBtn = document.getElementById("audio-editor-play-btn");
 | 
						|
  if (playBtn) {
 | 
						|
      playBtn.classList.add("active"); 
 | 
						|
      // Verifica se o ícone existe antes de tentar mudá-lo
 | 
						|
      const icon = playBtn.querySelector('i');
 | 
						|
      if (icon) {
 | 
						|
          icon.className = 'fa-solid fa-pause';
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  // ##### CORREÇÃO 2 #####
 | 
						|
  // Inicia o loop de animação da agulha
 | 
						|
  animationLoop();
 | 
						|
}
 | 
						|
 | 
						|
export function stopAudioEditorPlayback() {
 | 
						|
  if (!appState.global.isAudioEditorPlaying) return;
 | 
						|
  Tone.Transport.stop();
 | 
						|
 | 
						|
  appState.audio.clips.forEach(clip => {
 | 
						|
    if (clip.player && clip.player.state === 'started') {
 | 
						|
      clip.player.stop();
 | 
						|
    }
 | 
						|
  });
 | 
						|
 | 
						|
  appState.audio.audioEditorPlaybackTime = Tone.Transport.seconds;
 | 
						|
  
 | 
						|
  // Esta lógica agora funcionará corretamente graças à Correção 1
 | 
						|
  if (appState.audio.audioEditorAnimationId) {
 | 
						|
    cancelAnimationFrame(appState.audio.audioEditorAnimationId);
 | 
						|
    appState.audio.audioEditorAnimationId = null;
 | 
						|
  }
 | 
						|
  
 | 
						|
  // (CORRIGIDO) Atualiza a UI do botão de play
 | 
						|
  const playBtn = document.getElementById("audio-editor-play-btn");
 | 
						|
  if (playBtn) {
 | 
						|
      playBtn.classList.remove("active");
 | 
						|
      // Verifica se o ícone existe antes de tentar mudá-lo
 | 
						|
      const icon = playBtn.querySelector('i');
 | 
						|
      if (icon) {
 | 
						|
          icon.className = 'fa-solid fa-play'; // Muda de volta para "play"
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  appState.global.isAudioEditorPlaying = false;
 | 
						|
  updateAudioEditorUI();
 | 
						|
}
 | 
						|
 | 
						|
export function seekAudioEditor(newTime) {
 | 
						|
    const wasPlaying = appState.global.isAudioEditorPlaying;
 | 
						|
    if (wasPlaying) {
 | 
						|
        stopAudioEditorPlayback();
 | 
						|
    }
 | 
						|
    
 | 
						|
    appState.audio.audioEditorPlaybackTime = newTime;
 | 
						|
    Tone.Transport.seconds = newTime;
 | 
						|
 | 
						|
    const pixelsPerSecond = getPixelsPerSecond();
 | 
						|
    const newPositionPx = newTime * pixelsPerSecond;
 | 
						|
    updatePlayheadVisual(newPositionPx);
 | 
						|
 | 
						|
    if (wasPlaying) {
 | 
						|
        startAudioEditorPlayback();
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
export function restartAudioEditorIfPlaying() {
 | 
						|
    if (appState.global.isAudioEditorPlaying) {
 | 
						|
        appState.audio.audioEditorPlaybackTime = Tone.Transport.seconds;
 | 
						|
        stopAudioEditorPlayback();
 | 
						|
        startAudioEditorPlayback();
 | 
						|
    }
 | 
						|
} |