corrigindo play/stop do editor de patterns

This commit is contained in:
JotaChina committed 2025-12-27 10:12:23 -03:00
1 parent ba3f1befa1
commit 45ad819197
2 files changed
+189 -134

No files matched your search

+108 -77
View File
@@ -21,6 +21,7 @@ export function initializePatternState() {
try { track.player?.dispose(); } catch {}
try { track.buffer?.dispose?.(); } catch {}
try { track.instrument?.dispose(); } catch {}
try { track.previewPlayer?.dispose(); } catch {}
});
appState.pattern.tracks = [];
@@ -29,7 +30,7 @@ export function initializePatternState() {
}
export async function loadAudioForTrack(track) {
// 1. Garante a criação dos nós de Volume e Pan
// 1) Garante Volume/Pan
try {
if (!track.volumeNode) {
track.volumeNode = new Tone.Volume(
@@ -46,130 +47,157 @@ export async function loadAudioForTrack(track) {
track.pannerNode.pan.value = track.pan ?? 0;
}
try { track.instrument?.disconnect(); } catch {}
try { track.player?.disconnect(); } catch {}
// Desconecta o que existir
try { track.instrument?.disconnect(); } catch {}
try { track.player?.disconnect(); } catch {}
try { track.previewPlayer?.disconnect(); } catch {}
// Reconecta cadeia base
try { track.volumeNode.disconnect(); } catch {}
try { track.pannerNode.disconnect(); } catch {}
track.volumeNode.connect(track.pannerNode);
track.pannerNode.connect(getMainGainNode());
} catch (e) {
console.error("Erro ao criar nós de áudio base:", e);
}
// --- DETECÇÃO DE TIPO DE ARQUIVO ---
// Verifica se é um formato de áudio que o navegador suporta
const isStandardAudio = track.samplePath && /\.(wav|mp3|ogg|flac|m4a)$/i.test(track.samplePath);
// Se não for áudio padrão, assumimos Plugin (ou Kicker padrão)
// 2) Detecta se é um arquivo de áudio suportado
const isStandardAudio =
track.samplePath && /\.(wav|mp3|ogg|flac|m4a)$/i.test(track.samplePath);
// 3) Se não for áudio padrão → Plugin (ou fallback)
if (!track.samplePath || !isStandardAudio) {
try {
if (track.instrument) { try { track.instrument.dispose(); } catch {} }
// limpa sampler/preview/buffer
try { track.player?.dispose(); } catch {}
try { track.previewPlayer?.dispose(); } catch {}
try { track.buffer?.dispose?.(); } catch {}
track.player = null;
track.previewPlayer = null;
track.buffer = null;
if (track.instrument) {
try { track.instrument.dispose(); } catch {}
track.instrument = null;
}
let synth;
// Normaliza o nome do instrumento. Se vazio, assume kicker.
const name = (track.instrumentName || "kicker").toLowerCase();
const pluginData = {};
const pluginData = {};
// SELETOR DE PLUGINS
switch (name) {
case "tripleoscillator":
case "3osc":
synth = new TripleOscillator(Tone.getContext(), pluginData);
break;
case "kicker":
synth = new Kicker(Tone.getContext(), pluginData);
break;
case "lb302":
synth = new Lb302(Tone.getContext(), pluginData);
break;
case "nes":
case "freeboy":
case "papu":
case "sid":
synth = new Nes(Tone.getContext(), pluginData);
break;
synth = new TripleOscillator(Tone.getContext(), pluginData);
break;
case "zynaddsubfx":
case "watsyn":
case "monstro":
case "vibedstrings":
case "kicker":
synth = new Kicker(Tone.getContext(), pluginData);
break;
case "lb302":
synth = new Lb302(Tone.getContext(), pluginData);
break;
case "nes":
case "freeboy":
case "papu":
case "sid":
synth = new Nes(Tone.getContext(), pluginData);
break;
case "zynaddsubfx":
case "watsyn":
case "monstro":
case "vibedstrings":
case "supersaw":
synth = new SuperSaw(Tone.getContext(), pluginData);
break;
case "organic":
synth = new Tone.PolySynth(Tone.Synth, {
oscillator: { type: "sine", count: 8, spread: 20 }
});
break;
synth = new SuperSaw(Tone.getContext(), pluginData);
break;
case "organic":
synth = new Tone.PolySynth(Tone.Synth, {
oscillator: { type: "sine", count: 8, spread: 20 },
});
break;
default:
console.warn(`Plugin ${name} desconhecido, usando fallback (Kicker).`);
// Fallback seguro: Kicker
synth = new Kicker(Tone.getContext(), pluginData);
console.warn(`Plugin ${name} desconhecido, usando fallback (Kicker).`);
synth = new Kicker(Tone.getContext(), pluginData);
}
if (synth.output) {
synth.connect(track.volumeNode);
} else {
synth.connect(track.volumeNode);
}
// Conecta plugin na cadeia
if (synth.output) synth.connect(track.volumeNode);
else synth.connect(track.volumeNode);
track.instrument = synth;
track.player = null;
track.type = 'plugin';
// Atualiza o nome se ele estava vazio
if (!track.instrumentName) track.instrumentName = name;
console.log(`[Audio] Plugin carregado: ${name}`);
track.type = "plugin";
if (!track.instrumentName) track.instrumentName = name;
console.log(`[Audio] Plugin carregado: ${name}`);
return track;
} catch (e) {
console.error("Erro ao carregar plugin:", track.instrumentName, e);
return track;
}
return track;
}
// 3. Lógica para SAMPLERS
// 4) SAMPLER (áudio)
try {
try { track.player?.dispose(); } catch {}
track.player = null;
try { track.buffer?.dispose?.(); } catch {}
track.buffer = null;
// limpa plugin
if (track.instrument) {
try { track.instrument.dispose(); } catch {}
track.instrument = null;
try { track.instrument.dispose(); } catch {}
track.instrument = null;
}
const player = new Tone.Player({ url: track.samplePath, autostart: false, retrigger: true });
// limpa players/buffer antigos
try { track.player?.dispose(); } catch {}
try { track.previewPlayer?.dispose(); } catch {}
try { track.buffer?.dispose?.(); } catch {}
track.player = null;
track.previewPlayer = null;
track.buffer = null;
// Player principal (Playlist/steps)
const player = new Tone.Player({
url: track.samplePath,
autostart: false,
retrigger: true,
});
// redundância segura p/ builds diferentes do Tone:
try { player.retrigger = true; } catch {}
await player.load(track.samplePath);
await player.load(track.samplePath);
player.connect(track.volumeNode);
const buffer = new Tone.Buffer();
await buffer.load(track.samplePath);
// ✅ reutiliza o MESMO buffer do player (sem segundo download)
track.buffer = player.buffer;
track.player = player;
track.buffer = buffer;
track.type = 'sampler';
// Preview player (Pattern Editor) — separado pra não brigar com a playlist
const previewPlayer = new Tone.Player({
autostart: false,
retrigger: true,
});
try { previewPlayer.retrigger = true; } catch {}
previewPlayer.buffer = track.buffer;
previewPlayer.connect(track.volumeNode);
track.previewPlayer = previewPlayer;
track.type = "sampler";
return track;
} catch (error) {
console.error('Erro ao carregar sample:', track.samplePath);
console.error("Erro ao carregar sample:", track.samplePath, error);
try { track.player?.dispose(); } catch {}
try { track.previewPlayer?.dispose(); } catch {}
try { track.buffer?.dispose?.(); } catch {}
track.player = null;
track.previewPlayer = null;
track.buffer = null;
return track;
}
return track;
}
export function addTrackToState() {
@@ -229,6 +257,7 @@ export function removeTrackById(trackId) {
try { trackToRemove.instrument?.dispose(); } catch {}
try { trackToRemove.pannerNode?.disconnect(); } catch {}
try { trackToRemove.volumeNode?.disconnect(); } catch {}
try { trackToRemove.previewPlayer?.dispose(); } catch {}
// Remove do array
appState.pattern.tracks.splice(index, 1);
@@ -248,6 +277,7 @@ export function removeLastTrackFromState() {
const trackToRemove = appState.pattern.tracks[appState.pattern.tracks.length - 1];
try { trackToRemove.player?.dispose(); } catch {}
try { trackToRemove.previewPlayer?.dispose(); } catch {}
try { trackToRemove.buffer?.dispose?.(); } catch {}
try { trackToRemove.instrument?.dispose(); } catch {}
try { trackToRemove.pannerNode?.disconnect(); } catch {}
@@ -260,6 +290,7 @@ export function removeLastTrackFromState() {
}
}
export async function updateTrackSample(trackIndex, samplePath) {
const track = appState.pattern.tracks[trackIndex];
if (track) {