// js/pattern_ui.js import { appState } from "../state.js"; import { toggleStepState, updateTrackSample } from "./pattern_state.js"; import { playSample, stopPlayback } from "./pattern_audio.js"; // Será criado no próximo passo import { getTotalSteps } from "../utils.js"; // Função principal de renderização para o editor de patterns export function renderPatternEditor() { const trackContainer = document.getElementById("track-container"); trackContainer.innerHTML = ""; appState.pattern.tracks.forEach((trackData) => { const trackLane = document.createElement("div"); trackLane.className = "track-lane"; trackLane.dataset.trackId = trackData.id; if (trackData.id === appState.pattern.activeTrackId) { trackLane.classList.add('active-track'); } trackLane.innerHTML = `
${trackData.name}
VOL
PAN
`; trackLane.addEventListener('click', () => { if (appState.pattern.activeTrackId === trackData.id) return; stopPlayback(); appState.pattern.activeTrackId = trackData.id; document.querySelectorAll('.track-lane').forEach(lane => lane.classList.remove('active-track')); trackLane.classList.add('active-track'); updateGlobalPatternSelector(); redrawSequencer(); }); trackLane.addEventListener("dragover", (e) => { e.preventDefault(); trackLane.classList.add("drag-over"); }); trackLane.addEventListener("dragleave", () => trackLane.classList.remove("drag-over")); trackLane.addEventListener("drop", (e) => { e.preventDefault(); trackLane.classList.remove("drag-over"); const filePath = e.dataTransfer.getData("text/plain"); if (filePath) { updateTrackSample(trackData.id, filePath); } }); trackContainer.appendChild(trackLane); // A lógica dos knobs precisará ser reimplementada ou movida para um arquivo de componentes }); updateGlobalPatternSelector(); redrawSequencer(); } export function redrawSequencer() { const totalGridSteps = getTotalSteps(); document.querySelectorAll(".step-sequencer-wrapper").forEach((wrapper) => { let sequencerContainer = wrapper.querySelector(".step-sequencer"); if (!sequencerContainer) { sequencerContainer = document.createElement("div"); sequencerContainer.className = "step-sequencer"; wrapper.appendChild(sequencerContainer); } const parentTrackElement = wrapper.closest(".track-lane"); const trackId = parentTrackElement.dataset.trackId; const trackData = appState.pattern.tracks.find((t) => t.id == trackId); if (!trackData || !trackData.patterns || trackData.patterns.length === 0) { sequencerContainer.innerHTML = ""; return; } const activePattern = trackData.patterns[appState.pattern.activePatternIndex]; if (!activePattern) { sequencerContainer.innerHTML = ""; return; } const patternSteps = activePattern.steps; sequencerContainer.innerHTML = ""; for (let i = 0; i < totalGridSteps; i++) { const stepWrapper = document.createElement("div"); stepWrapper.className = "step-wrapper"; const stepElement = document.createElement("div"); stepElement.className = "step"; if (patternSteps[i] === true) { stepElement.classList.add("active"); } stepElement.addEventListener("click", () => { toggleStepState(trackData.id, i); stepElement.classList.toggle("active"); if (trackData && trackData.samplePath) { playSample(trackData.samplePath, trackData.id); } }); const beatsPerBar = parseInt(document.getElementById("compasso-a-input").value, 10) || 4; const groupIndex = Math.floor(i / beatsPerBar); if (groupIndex % 2 === 0) { stepElement.classList.add("step-dark"); } const stepsPerBar = 16; if (i > 0 && i % stepsPerBar === 0) { const marker = document.createElement("div"); marker.className = "step-marker"; marker.textContent = Math.floor(i / stepsPerBar) + 1; stepWrapper.appendChild(marker); } stepWrapper.appendChild(stepElement); sequencerContainer.appendChild(stepWrapper); } }); } export function updateGlobalPatternSelector() { const globalPatternSelector = document.getElementById('global-pattern-selector'); if (!globalPatternSelector) return; const referenceTrack = appState.pattern.tracks[0]; globalPatternSelector.innerHTML = ''; if (referenceTrack && referenceTrack.patterns.length > 0) { referenceTrack.patterns.forEach((pattern, index) => { const option = document.createElement('option'); option.value = index; option.textContent = pattern.name; globalPatternSelector.appendChild(option); }); globalPatternSelector.selectedIndex = appState.pattern.activePatternIndex; globalPatternSelector.disabled = false; } else { const option = document.createElement('option'); option.textContent = 'Sem patterns'; globalPatternSelector.appendChild(option); globalPatternSelector.disabled = true; } } export function highlightStep(stepIndex, isActive) { if (stepIndex < 0) return; document.querySelectorAll(".track-lane").forEach((track) => { const stepWrapper = track.querySelector( `.step-sequencer .step-wrapper:nth-child(${stepIndex + 1})` ); if (stepWrapper) { const stepElement = stepWrapper.querySelector(".step"); if (stepElement) { stepElement.classList.toggle("playing", isActive); } } }); }