versão 2.0
This commit is contained in:
1 parent
d506332268
commit
fe735bf0a6
16 files changed
+1735
-1626
No files matched your search
@@ -0,0 +1,154 @@
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user