diff --git a/assets/js/creations/audio.js b/assets/js/creations/audio.js index 9cdd9c9..7b548a3 100644 --- a/assets/js/creations/audio.js +++ b/assets/js/creations/audio.js @@ -1,5 +1,3 @@ -//TODO ver Tone.js - // js/audio.js import { appState } from "./state.js"; import { highlightStep } from "./ui.js"; @@ -44,23 +42,44 @@ export function playMetronomeSound(isDownbeat) { oscillator.stop(audioContext.currentTime + 0.05); } +// (ALTERADO) Função reescrita para usar AudioBuffers pré-carregados export function playSample(filePath, trackId) { initializeAudioContext(); if (!filePath) return; const track = trackId ? appState.tracks.find((t) => t.id == trackId) : null; - const audio = new Audio(filePath); - const source = audioContext.createMediaElementSource(audio); - if (track && track.gainNode) { - source.connect(track.gainNode); - } else { - source.connect(mainGainNode); + // Se a função for chamada sem um ID de track (ex: clique no browser de samples), + // usa o método antigo como fallback para uma prévia rápida. + if (!track) { + const audio = new Audio(filePath); + audio.play(); + return; } - audio.play(); + // Se a track não tiver o buffer de áudio pronto, avisa no console e não toca. + if (!track.audioBuffer) { + console.warn(`Buffer para a track ${track.name} ainda não carregado.`); + return; + } + + // 1. Cria uma fonte de áudio leve (BufferSource) + const source = audioContext.createBufferSource(); + // 2. Conecta o buffer de áudio já decodificado + source.buffer = track.audioBuffer; + + // 3. Conecta na cadeia de áudio da track (respeitando volume e pan) + if (track.gainNode) { + source.connect(track.gainNode); + } else { + source.connect(mainGainNode); // Fallback + } + + // 4. Toca o som imediatamente + source.start(0); } + function tick() { const totalSteps = getTotalSteps(); if (totalSteps === 0) { @@ -131,4 +150,4 @@ export function togglePlayback() { } else { startPlayback(); } -} +} \ No newline at end of file diff --git a/assets/js/creations/state.js b/assets/js/creations/state.js index c58a477..64d74dc 100644 --- a/assets/js/creations/state.js +++ b/assets/js/creations/state.js @@ -26,6 +26,7 @@ export function addTrackToState() { id: Date.now(), name: "novo instrumento", samplePath: null, + audioBuffer: null, // (NOVO) Adicionado para armazenar o áudio decodificado steps: [], volume: DEFAULT_VOLUME, pan: DEFAULT_PAN, @@ -46,13 +47,34 @@ export function removeLastTrackFromState() { renderApp(); } -export function updateTrackSample(trackId, samplePath) { +// (ALTERADO) A função agora é 'async' para carregar e decodificar o áudio +export async function updateTrackSample(trackId, samplePath) { const track = appState.tracks.find((t) => t.id == trackId); if (track) { track.samplePath = samplePath; track.name = samplePath.split("/").pop(); + track.audioBuffer = null; // Limpa o buffer antigo enquanto carrega o novo + renderApp(); // Renderiza imediatamente para mostrar o novo nome + + // (NOVO) Lógica para carregar e decodificar o áudio em segundo plano + try { + const audioContext = getAudioContext(); + if (!audioContext) initializeAudioContext(); // Garante que o contexto de áudio exista + + const response = await fetch(samplePath); + const arrayBuffer = await response.arrayBuffer(); + const decodedAudio = await audioContext.decodeAudioData(arrayBuffer); + + track.audioBuffer = decodedAudio; // Armazena o buffer decodificado no estado da track + console.log(`Sample ${track.name} carregado e decodificado com sucesso.`); + + } catch (error) { + console.error("Erro ao carregar ou decodificar o sample:", error); + track.samplePath = null; + track.name = "erro ao carregar"; + renderApp(); // Re-renderiza para mostrar a mensagem de erro + } } - renderApp(); } export function toggleStepState(trackId, stepIndex) { @@ -87,4 +109,4 @@ export function updateTrackPan(trackId, pan) { track.pannerNode.pan.setValueAtTime(clampedPan, audioContext.currentTime); } } -} +} \ No newline at end of file