// js/state.js import { DEFAULT_VOLUME, DEFAULT_PAN } from "./config.js"; import { initializeAudioContext, getAudioContext, getMainGainNode, } from "./audio.js"; import { renderApp } from "./ui.js"; // O "cérebro" da aplicação export let appState = { tracks: [], isPlaying: false, playbackIntervalId: null, currentStep: 0, metronomeEnabled: false, originalXmlDoc: null, }; // ESSA É A FUNÇÃO QUE ESTÁ FALTANDO NO SEU ARQUIVO ATUAL // Função auxiliar para carregar o buffer de áudio para uma track específica export async function loadAudioForTrack(track) { if (!track.samplePath) { console.warn("Track sem samplePath, pulando o carregamento de áudio."); return track; } try { const audioContext = getAudioContext(); if (!audioContext) initializeAudioContext(); const response = await fetch(track.samplePath); if (!response.ok) throw new Error(`Erro ao buscar o sample: ${response.statusText}`); const arrayBuffer = await response.arrayBuffer(); track.audioBuffer = await audioContext.decodeAudioData(arrayBuffer); console.log(`Áudio carregado para a trilha: ${track.name}`); } catch (error) { console.error(`Falha ao carregar áudio para a trilha ${track.name}:`, error); track.audioBuffer = null; // Marca como falha para não tentar tocar } return track; } export function addTrackToState() { initializeAudioContext(); const audioContext = getAudioContext(); const mainGainNode = getMainGainNode(); const newTrack = { id: Date.now(), name: "novo instrumento", samplePath: null, audioBuffer: null, steps: [], volume: DEFAULT_VOLUME, pan: DEFAULT_PAN, gainNode: audioContext.createGain(), pannerNode: audioContext.createStereoPanner(), }; newTrack.gainNode.connect(newTrack.pannerNode); newTrack.pannerNode.connect(mainGainNode); newTrack.gainNode.gain.value = newTrack.volume; newTrack.pannerNode.pan.value = newTrack.pan; appState.tracks.push(newTrack); renderApp(); } export function removeLastTrackFromState() { appState.tracks.pop(); renderApp(); } 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; renderApp(); await loadAudioForTrack(track); // Reutiliza a nova função aqui } } export function toggleStepState(trackId, stepIndex) { const track = appState.tracks.find((t) => t.id == trackId); if (track) { track.steps[stepIndex] = !track.steps[stepIndex]; } } export function updateTrackVolume(trackId, volume) { const track = appState.tracks.find((t) => t.id == trackId); const audioContext = getAudioContext(); if (track) { const clampedVolume = Math.max(0, Math.min(1.5, volume)); track.volume = clampedVolume; if (track.gainNode) { track.gainNode.gain.setValueAtTime( clampedVolume, audioContext.currentTime ); } } } export function updateTrackPan(trackId, pan) { const track = appState.tracks.find((t) => t.id == trackId); const audioContext = getAudioContext(); if (track) { const clampedPan = Math.max(-1, Math.min(1, pan)); track.pan = clampedPan; if (track.pannerNode) { track.pannerNode.pan.setValueAtTime(clampedPan, audioContext.currentTime); } } }