mmpSearch/assets/js/creations/pattern/pattern_bounce.js

108 lines
3.9 KiB
JavaScript

// js/pattern/pattern_bounce.js
import { appState } from '../state.js';
import { getSecondsPerStep } from '../utils.js';
import { addAudioClipToTimeline, addAudioTrackLane } from '../audio/audio_state.js';
import { getAudioContext } from '../audio.js';
import { renderAudioEditor } from '../audio/audio_ui.js';
/**
* Renderiza (bounce) o pattern de beat atualmente ativo para uma nova pista de áudio.
*/
export async function bounceActivePatternToAudio() {
console.log("Iniciando 'bounce' do pattern...");
// 1. Encontrar o pattern ativo
const activeTrackId = appState.pattern.activeTrackId;
// --- DEBUG ---
console.log(`[DEBUG bounce] activeTrackId lido do estado: ${activeTrackId}`);
const activeTrack = appState.pattern.tracks.find(t => t.id === activeTrackId);
// --- DEBUG ---
if (activeTrack) {
console.log(`[DEBUG bounce] Pista ativa encontrada:`, activeTrack.name);
console.log(`[DEBUG bounce] Verificando track.buffer:`, activeTrack.buffer);
} else {
console.error(`[DEBUG bounce] NENHUMA PISTA ATIVA ENCONTRADA. activeTrackId é nulo ou inválido.`);
console.log(`[DEBUG bounce] Pistas disponíveis no estado:`, appState.pattern.tracks.map(t => ({id: t.id, name: t.name})));
}
// --- FIM DEBUG ---
if (!activeTrack) {
alert('Nenhuma pista de pattern selecionada para renderizar.');
return;
}
const activePattern = activeTrack.patterns[activeTrack.activePatternIndex];
if (!activePattern) {
alert('Nenhum pattern ativo encontrado na pista.');
return;
}
const trackBuffer = activeTrack.buffer;
if (!trackBuffer) {
alert('O áudio (sample) desta pista ainda não foi carregado.');
return;
}
// 2. Calcular a duração do pattern
const steps = activePattern.steps;
const totalSteps = steps.length;
const secondsPerStep = getSecondsPerStep(); //
const duration = totalSteps * secondsPerStep;
if (duration <= 0) {
alert("Pattern está vazio ou com duração zero.");
return;
}
try {
// 3. Usar Tone.Offline para renderizar o áudio
const audioBuffer = await Tone.Offline(async (offlineCtx) => {
const gainNode = new Tone.Gain(Tone.gainToDb(activeTrack.volume)).connect(offlineCtx.destination);
const pannerNode = new Tone.Panner(activeTrack.pan).connect(gainNode); //
const now = offlineCtx.currentTime;
// --- INÍCIO DA CORREÇÃO (que estava na versão anterior) ---
const offlineBuffer = offlineCtx.createBuffer(
trackBuffer.numberOfChannels,
trackBuffer.length,
trackBuffer.sampleRate
);
for (let i = 0; i < trackBuffer.numberOfChannels; i++) {
offlineBuffer.copyToChannel(trackBuffer.getChannelData(i), i);
}
// --- FIM DA CORREÇÃO ---
// Agendar todas as notas (steps)
steps.forEach((isActive, index) => {
if (isActive) {
const time = now + (index * secondsPerStep);
const source = new Tone.BufferSource(offlineBuffer).connect(pannerNode);
source.start(time);
}
});
}, duration);
// 4. Áudio renderizado. Agora, adicione-o ao editor de áudio.
addAudioTrackLane(); //
const newTrack = appState.audio.tracks[appState.audio.tracks.length - 1]; //
const newTrackId = newTrack.id;
const clipName = `${activeTrack.name}_(${activePattern.name})`;
addAudioClipToTimeline(null, newTrackId, 0, clipName, audioBuffer); //
console.log("Pattern renderizado com sucesso!");
} catch (err) {
console.error("Erro ao renderizar o pattern:", err);
alert(`Erro ao renderizar pattern: ${err.message}`);
}
}