melhorando a leitura de projetos no mmpCreator
Deploy / Deploy (push) Successful in 2m7s
Details
Deploy / Deploy (push) Successful in 2m7s
Details
This commit is contained in:
parent
9b73c3ba33
commit
8d2380c704
|
|
@ -10,6 +10,11 @@ import {
|
||||||
getAudioContext,
|
getAudioContext,
|
||||||
getMainGainNode,
|
getMainGainNode,
|
||||||
} from "../audio.js";
|
} from "../audio.js";
|
||||||
|
import {
|
||||||
|
startSongPatternPlaybackOnTransport,
|
||||||
|
stopSongPatternPlaybackOnTransport,
|
||||||
|
} from "../pattern/pattern_audio.js";
|
||||||
|
|
||||||
import { getPixelsPerSecond } from "../utils.js";
|
import { getPixelsPerSecond } from "../utils.js";
|
||||||
// 🔊 ADIÇÃO: usar a MESMA instância do Tone que o projeto usa
|
// 🔊 ADIÇÃO: usar a MESMA instância do Tone que o projeto usa
|
||||||
import * as Tone from "https://esm.sh/tone";
|
import * as Tone from "https://esm.sh/tone";
|
||||||
|
|
@ -313,10 +318,6 @@ export async function startAudioEditorPlayback(seekTime) {
|
||||||
// alinhamento de relógio próprio (mantido para o seu scheduler)
|
// alinhamento de relógio próprio (mantido para o seu scheduler)
|
||||||
startTime = audioCtx.currentTime;
|
startTime = audioCtx.currentTime;
|
||||||
|
|
||||||
// =================================================================
|
|
||||||
// 👇 INÍCIO DA CORREÇÃO (Bugs 1 & 2)
|
|
||||||
// =================================================================
|
|
||||||
|
|
||||||
// 1. Determine o tempo de início:
|
// 1. Determine o tempo de início:
|
||||||
let timeToStart =
|
let timeToStart =
|
||||||
seekTime !== null && seekTime !== undefined && !isNaN(seekTime)
|
seekTime !== null && seekTime !== undefined && !isNaN(seekTime)
|
||||||
|
|
@ -334,16 +335,13 @@ export async function startAudioEditorPlayback(seekTime) {
|
||||||
Tone.Transport.seconds = timeToStart; // 👈 Usa o tempo sincronizado
|
Tone.Transport.seconds = timeToStart; // 👈 Usa o tempo sincronizado
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
// =================================================================
|
|
||||||
// 👆 FIM DA CORREÇÃO
|
|
||||||
// =================================================================
|
|
||||||
|
|
||||||
updateTransportLoop();
|
updateTransportLoop();
|
||||||
|
|
||||||
console.log("%cIniciando Playback...", "color: #3498db;");
|
console.log("%cIniciando Playback...", "color: #3498db;");
|
||||||
|
|
||||||
// inicia o Transport (para disparar os Players .sync())
|
// inicia o Transport (para disparar os Players .sync())
|
||||||
try {
|
try {
|
||||||
|
startSongPatternPlaybackOnTransport();
|
||||||
Tone.Transport.start();
|
Tone.Transport.start();
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
|
|
@ -366,6 +364,7 @@ export function stopAudioEditorPlayback(rewind = false) {
|
||||||
|
|
||||||
// para o Transport (para Players .sync())
|
// para o Transport (para Players .sync())
|
||||||
try {
|
try {
|
||||||
|
stopSongPatternPlaybackOnTransport();
|
||||||
Tone.Transport.stop();
|
Tone.Transport.stop();
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -520,7 +520,7 @@ export async function parseMmpContent(xmlString) {
|
||||||
|
|
||||||
const firstInst = newTracks.find((t) => t.type !== "bassline");
|
const firstInst = newTracks.find((t) => t.type !== "bassline");
|
||||||
appState.pattern.activeTrackId = firstInst ? firstInst.id : null;
|
appState.pattern.activeTrackId = firstInst ? firstInst.id : null;
|
||||||
//appState.pattern.activePatternIndex = 0;
|
appState.pattern.activePatternIndex = 0;
|
||||||
|
|
||||||
loadStateFromSession();
|
loadStateFromSession();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -320,7 +320,7 @@ function schedulePianoRoll() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Renderizar o Pattern atual para um Blob de Áudio (MANTIDO ORIGINAL)
|
// Renderizar o Pattern atual para um Blob de Áudio
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
export async function renderActivePatternToBlob() {
|
export async function renderActivePatternToBlob() {
|
||||||
|
|
@ -477,7 +477,7 @@ export async function renderActivePatternToBlob() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// FUNÇÃO UTILITÁRIA: Converte AudioBuffer para Blob WAV (MANTIDO ORIGINAL)
|
// FUNÇÃO UTILITÁRIA: Converte AudioBuffer para Blob WAV
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
function bufferToWave(abuffer) {
|
function bufferToWave(abuffer) {
|
||||||
|
|
@ -539,3 +539,81 @@ function bufferToWave(abuffer) {
|
||||||
|
|
||||||
return new Blob([buffer], { type: "audio/wav" });
|
return new Blob([buffer], { type: "audio/wav" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===============================
|
||||||
|
// Song/Playlist Pattern Scheduler
|
||||||
|
// (toca patterns arranjadas na Playlist)
|
||||||
|
// ===============================
|
||||||
|
|
||||||
|
const LMMS_TICKS_PER_STEP = 12;
|
||||||
|
let songPatternScheduleId = null;
|
||||||
|
|
||||||
|
export function startSongPatternPlaybackOnTransport() {
|
||||||
|
initializeAudioContext();
|
||||||
|
if (songPatternScheduleId !== null) return;
|
||||||
|
|
||||||
|
songPatternScheduleId = Tone.Transport.scheduleRepeat((time) => {
|
||||||
|
// bpm atual
|
||||||
|
const bpm = parseInt(document.getElementById("bpm-input")?.value, 10) || 120;
|
||||||
|
const stepIntervalSec = 60 / (bpm * 4);
|
||||||
|
|
||||||
|
// step absoluto do song (considera seek do Transport)
|
||||||
|
const songStep = Math.floor(Tone.Transport.seconds / stepIntervalSec + 1e-6);
|
||||||
|
const songTick = songStep * LMMS_TICKS_PER_STEP;
|
||||||
|
|
||||||
|
// quais patterns (colunas) estão ativas neste tick?
|
||||||
|
const basslineTracks = appState.pattern.tracks.filter(
|
||||||
|
(t) => t.type === "bassline" && !t.isMuted
|
||||||
|
);
|
||||||
|
|
||||||
|
const activePatternHits = [];
|
||||||
|
for (const b of basslineTracks) {
|
||||||
|
const clips = b.playlist_clips || [];
|
||||||
|
const clip = clips.find((c) => songTick >= c.pos && songTick < c.pos + c.len);
|
||||||
|
if (!clip) continue;
|
||||||
|
|
||||||
|
const localStep = Math.floor((songTick - clip.pos) / LMMS_TICKS_PER_STEP);
|
||||||
|
activePatternHits.push({ patternIndex: b.patternIndex, localStep });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activePatternHits.length === 0) return;
|
||||||
|
|
||||||
|
// dispara instrumentos reais (samplers/plugins)
|
||||||
|
for (const track of appState.pattern.tracks) {
|
||||||
|
if (track.type === "bassline") continue;
|
||||||
|
if (track.muted) continue;
|
||||||
|
|
||||||
|
for (const hit of activePatternHits) {
|
||||||
|
const patt = track.patterns?.[hit.patternIndex];
|
||||||
|
if (!patt?.steps) continue;
|
||||||
|
|
||||||
|
if (patt.steps[hit.localStep]) {
|
||||||
|
// SAMPLER
|
||||||
|
if (track.type === "sampler" && track.player) {
|
||||||
|
track.player.restart = true; // baterias precisam retrigger
|
||||||
|
try {
|
||||||
|
track.player.start(time);
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
// PLUGIN (step sem piano roll)
|
||||||
|
else if (track.type === "plugin" && track.instrument) {
|
||||||
|
const hasNotes = patt.notes && patt.notes.length > 0;
|
||||||
|
if (!hasNotes) {
|
||||||
|
try {
|
||||||
|
track.instrument.triggerAttackRelease("C5", "16n", time);
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, "16n");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stopSongPatternPlaybackOnTransport() {
|
||||||
|
if (songPatternScheduleId === null) return;
|
||||||
|
try {
|
||||||
|
Tone.Transport.clear(songPatternScheduleId);
|
||||||
|
} catch {}
|
||||||
|
songPatternScheduleId = null;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue