Amostras de áudio funcionais até o momento. Agulha de tempo, mute/solo e ajustado com a velocidade de reprodução, loop funcional.

This commit is contained in:
JotaChina committed 2025-10-12 10:42:27 -03:00
1 parent 602df1db6d
commit d506332268
6 files changed
+163 -95

No files matched your search

+48 -26
View File
@@ -31,7 +31,6 @@ export function initializeAudioContext() {
}
}
// ... (funções de master volume/pan, formatTime, metronome, sample player, tick, etc. permanecem iguais)...
export function updateMasterVolume(volume) {
if (mainGainNode) {
mainGainNode.gain.setValueAtTime(volume, audioContext.currentTime);
@@ -195,23 +194,33 @@ export function togglePlayback() {
function animationLoop() {
if (!appState.isAudioEditorPlaying || !audioContext) return;
const bpm = parseInt(document.getElementById("bpm-input").value, 10) || 120;
const stepsPerSecond = (bpm / 60) * 4;
const pixelsPerSecond = stepsPerSecond * PIXELS_PER_STEP;
const totalElapsedTime = (audioContext.currentTime - appState.audioEditorStartTime) + appState.audioEditorPlaybackTime;
const newPositionPx = totalElapsedTime * pixelsPerSecond;
const maxDuration = appState.audioTracks.reduce((max, track) => (track.audioBuffer && track.audioBuffer.duration > max) ? track.audioBuffer.duration : max, 0);
if (totalElapsedTime >= maxDuration && maxDuration > 0) {
stopAudioEditorPlayback();
appState.audioEditorPlaybackTime = 0;
resetPlayheadVisual();
return;
let totalElapsedTime = (audioContext.currentTime - appState.audioEditorStartTime) + appState.audioEditorPlaybackTime;
const maxDuration = appState.audioTracks.reduce((max, track) =>
(track.audioBuffer && track.audioBuffer.duration > max) ? track.audioBuffer.duration : max, 0
);
if (appState.isAudioEditorLoopEnabled && maxDuration > 0) {
totalElapsedTime = totalElapsedTime % maxDuration;
} else {
if (totalElapsedTime >= maxDuration && maxDuration > 0) {
stopAudioEditorPlayback();
appState.audioEditorPlaybackTime = 0;
resetPlayheadVisual();
return;
}
}
const newPositionPx = totalElapsedTime * pixelsPerSecond;
updatePlayheadVisual(newPositionPx);
appState.audioEditorAnimationId = requestAnimationFrame(animationLoop);
}
// --- LÓGICA DE REPRODUÇÃO ATUALIZADA ---
export function startAudioEditorPlayback() {
if (appState.isAudioEditorPlaying || appState.audioTracks.length === 0) return;
initializeAudioContext();
@@ -223,25 +232,13 @@ export function startAudioEditorPlayback() {
const startTime = audioContext.currentTime;
appState.audioEditorStartTime = startTime;
// Verifica se existe alguma faixa no modo "solo"
const isAnyTrackSoloed = appState.audioTracks.some(t => t.isSoloed);
appState.audioTracks.forEach(track => {
// Condições para tocar:
// 1. A faixa deve ter um buffer de áudio.
// 2. A faixa não pode estar mutada.
const canPlay = track.audioBuffer && !track.isMuted;
// 3. Lógica de solo:
// - Se houver alguma faixa solada, esta faixa TAMBÉM deve estar solada.
// - Se NENHUMA faixa estiver solada, todas podem tocar.
const shouldPlay = isAnyTrackSoloed ? track.isSoloed : true;
if (canPlay && shouldPlay) {
if (track.audioBuffer && !track.isMuted && track.isSoloed) {
if (appState.audioEditorPlaybackTime >= track.audioBuffer.duration) return;
const source = audioContext.createBufferSource();
source.buffer = track.audioBuffer;
source.loop = appState.isAudioEditorLoopEnabled;
source.connect(track.gainNode);
source.start(startTime, appState.audioEditorPlaybackTime);
appState.activeAudioSources.push(source);
@@ -261,17 +258,35 @@ export function startAudioEditorPlayback() {
export function stopAudioEditorPlayback() {
if (!appState.isAudioEditorPlaying) return;
const elapsedTime = (audioContext.currentTime - appState.audioEditorStartTime);
appState.audioEditorPlaybackTime += elapsedTime;
let totalElapsedTime = (audioContext.currentTime - appState.audioEditorStartTime) + appState.audioEditorPlaybackTime;
const maxDuration = appState.audioTracks.reduce((max, track) =>
(track.audioBuffer && track.audioBuffer.duration > max) ? track.audioBuffer.duration : max, 0
);
// --- CORREÇÃO FINAL E ROBUSTA ---
// Sempre aplica o módulo ao salvar o tempo.
// Se não estava em loop, totalElapsedTime < maxDuration, e o módulo não faz nada.
// Se estava em loop, ele corrige o valor para a posição visual correta.
if (maxDuration > 0) {
appState.audioEditorPlaybackTime = totalElapsedTime % maxDuration;
} else {
appState.audioEditorPlaybackTime = totalElapsedTime;
}
// --- FIM DA CORREÇÃO ---
if (appState.audioEditorAnimationId) {
cancelAnimationFrame(appState.audioEditorAnimationId);
appState.audioEditorAnimationId = null;
}
appState.activeAudioSources.forEach(source => {
try {
source.stop(0);
} catch (e) { /* Ignora erros */ }
});
appState.activeAudioSources = [];
appState.isAudioEditorPlaying = false;
updateAudioEditorUI();
@@ -291,4 +306,11 @@ export function seekAudioEditor(newTime) {
if (wasPlaying) {
startAudioEditorPlayback();
}
}
export function restartAudioEditorIfPlaying() {
if (appState.isAudioEditorPlaying) {
stopAudioEditorPlayback();
startAudioEditorPlayback();
}
}