diff --git a/assets/css/style.css b/assets/css/style.css index 86ff83e..fbc2d92 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -332,7 +332,7 @@ body.sidebar-hidden .global-toolbar { background: #555; } - +/* (CORREÇÃO) CSS para as marcações de compasso */ .step-wrapper { position: relative; } @@ -522,7 +522,7 @@ body.sidebar-hidden .global-toolbar { } /* =============================================== */ -/* MODAL (CAIXA DE DIÁLOGO) - (REVISADO) +/* MODAL (CAIXA DE DIÁLOGO) /* =============================================== */ .modal-overlay { position: fixed; @@ -535,7 +535,7 @@ body.sidebar-hidden .global-toolbar { display: flex; justify-content: center; align-items: center; - padding: 1rem; /* Adiciona um respiro nas laterais */ + padding: 1rem; visibility: hidden; opacity: 0; transition: visibility 0s 0.3s, opacity 0.3s; @@ -556,13 +556,9 @@ body.sidebar-hidden .global-toolbar { width: 100%; max-width: 500px; position: relative; - - /* (NOVO) Usando Flexbox para organizar o conteúdo interno */ display: flex; flex-direction: column; - gap: 1.5rem; /* Espaçamento consistente entre as seções */ - - /* (NOVO) Controle de altura para telas pequenas ou listas grandes */ + gap: 1.5rem; max-height: 90vh; } @@ -582,16 +578,16 @@ body.sidebar-hidden .global-toolbar { } .modal-title { - margin: 0; /* Removido margin para usar o 'gap' do flexbox */ + margin: 0; padding-bottom: 0.5rem; border-bottom: 1px solid var(--bg-toolbar); color: var(--text-light); text-align: center; - flex-shrink: 0; /* Impede que o título encolha */ + flex-shrink: 0; } .modal-section { - margin: 0; /* Removido margin para usar o 'gap' do flexbox */ + margin: 0; } .modal-section h3 { @@ -601,18 +597,16 @@ body.sidebar-hidden .global-toolbar { color: var(--text-light); } -/* (NOVO) Estilos para a lista de projetos do servidor */ #server-projects-list { - max-height: 250px; /* Altura máxima para a lista */ - overflow-y: auto; /* Barra de rolagem SÓ para a lista */ + max-height: 250px; + overflow-y: auto; background-color: var(--bg-toolbar); border: 1px solid var(--border-color); border-radius: 4px; padding: 0.5rem; - min-height: 50px; /* Altura mínima para não colapsar se estiver vazio */ + min-height: 50px; } -/* (REVISADO) Estilos para cada item na lista */ #server-projects-list .project-item { background-color: var(--bg-editor); padding: 10px 15px; @@ -707,9 +701,8 @@ body.sidebar-hidden .global-toolbar { .step-sequencer-wrapper { width: 100%; } - /* (REVISADO) Ajuste do modal para telas pequenas */ .modal-content { - max-width: 95vw; /* Usa quase toda a largura da tela */ + max-width: 95vw; padding: 1rem 1.5rem; gap: 1rem; } diff --git a/assets/js/creations/audio.js b/assets/js/creations/audio.js index 8791ea7..b4d7337 100644 --- a/assets/js/creations/audio.js +++ b/assets/js/creations/audio.js @@ -6,6 +6,8 @@ import { getTotalSteps } from "./utils.js"; let audioContext; let mainGainNode; +const timerDisplay = document.getElementById('timer-display'); + export function getAudioContext() { return audioContext; } @@ -24,6 +26,14 @@ export function initializeAudioContext() { } } +function formatTime(milliseconds) { + const totalSeconds = Math.floor(milliseconds / 1000); + const minutes = Math.floor(totalSeconds / 60).toString().padStart(2, '0'); + const seconds = (totalSeconds % 60).toString().padStart(2, '0'); + const centiseconds = Math.floor((milliseconds % 1000) / 10).toString().padStart(2, '0'); + return `${minutes}:${seconds}:${centiseconds}`; +} + export function playMetronomeSound(isDownbeat) { initializeAudioContext(); const oscillator = audioContext.createOscillator(); @@ -42,38 +52,32 @@ export function playMetronomeSound(isDownbeat) { oscillator.stop(audioContext.currentTime + 0.05); } -// Função otimizada para usar AudioBuffers export function playSample(filePath, trackId) { initializeAudioContext(); if (!filePath) return; const track = trackId ? appState.tracks.find((t) => t.id == trackId) : null; - // Se for uma prévia (sem trilha), usa o método antigo e rápido if (!track) { const audio = new Audio(filePath); audio.play(); return; } - // Se a trilha não tiver o buffer carregado, não toca if (!track.audioBuffer) { console.warn(`Buffer para a trilha ${track.name} ainda não carregado.`); return; } - // Cria uma fonte de áudio leve a partir do buffer const source = audioContext.createBufferSource(); source.buffer = track.audioBuffer; - // Conecta na cadeia de áudio da trilha (respeitando volume e pan) if (track.gainNode) { source.connect(track.gainNode); } else { - source.connect(mainGainNode); // Fallback + source.connect(mainGainNode); } - // Toca o som imediatamente source.start(0); } @@ -87,6 +91,13 @@ function tick() { appState.currentStep === 0 ? totalSteps - 1 : appState.currentStep - 1; highlightStep(lastStepIndex, false); + const bpm = parseInt(document.getElementById("bpm-input").value, 10) || 120; + const stepInterval = (60 * 1000) / (bpm * 4); + const currentTime = appState.currentStep * stepInterval; + if (timerDisplay) { + timerDisplay.textContent = formatTime(currentTime); + } + if (appState.metronomeEnabled) { const noteValue = parseInt(document.getElementById("compasso-b-input").value, 10) || 4; @@ -128,6 +139,9 @@ export function stopPlayback() { appState.isPlaying = false; highlightStep(appState.currentStep - 1, false); appState.currentStep = 0; + + if (timerDisplay) timerDisplay.textContent = '00:00:00'; + document.getElementById("play-btn").classList.remove("fa-pause"); document.getElementById("play-btn").classList.add("fa-play"); } @@ -135,6 +149,7 @@ export function stopPlayback() { export function rewindPlayback() { appState.currentStep = 0; if (!appState.isPlaying) { + if (timerDisplay) timerDisplay.textContent = '00:00:00'; document .querySelectorAll(".step.playing") .forEach((s) => s.classList.remove("playing"));