176 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			176 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
// js/main.js
 | 
						|
import { appState, resetProjectState } from "./state.js";
 | 
						|
import { addTrackToState, removeLastTrackFromState } from "./pattern/pattern_state.js";
 | 
						|
import { addAudioTrackLane } from "./audio/audio_state.js";
 | 
						|
import { updateTransportLoop } from "./audio/audio_audio.js";
 | 
						|
import {
 | 
						|
  togglePlayback,
 | 
						|
  stopPlayback,
 | 
						|
  rewindPlayback,
 | 
						|
} from "./pattern/pattern_audio.js";
 | 
						|
import {
 | 
						|
  startAudioEditorPlayback,
 | 
						|
  stopAudioEditorPlayback,
 | 
						|
  restartAudioEditorIfPlaying,
 | 
						|
} from "./audio/audio_audio.js";
 | 
						|
import { initializeAudioContext } from "./audio.js";
 | 
						|
import { handleFileLoad, generateMmpFile } from "./file.js";
 | 
						|
import { renderAll, loadAndRenderSampleBrowser, showOpenProjectModal, closeOpenProjectModal } from "./ui.js";
 | 
						|
import { renderAudioEditor } from "./audio/audio_ui.js";
 | 
						|
import { adjustValue, enforceNumericInput } from "./utils.js";
 | 
						|
import { ZOOM_LEVELS } from "./config.js";
 | 
						|
 | 
						|
document.addEventListener("DOMContentLoaded", () => {
 | 
						|
  const newProjectBtn = document.getElementById("new-project-btn");
 | 
						|
  const openMmpBtn = document.getElementById("open-mmp-btn");
 | 
						|
  const saveMmpBtn = document.getElementById("save-mmp-btn");
 | 
						|
  const uploadSampleBtn = document.getElementById("upload-sample-btn");
 | 
						|
  const addInstrumentBtn = document.getElementById("add-instrument-btn");
 | 
						|
  const removeInstrumentBtn = document.getElementById("remove-instrument-btn");
 | 
						|
  const playBtn = document.getElementById("play-btn");
 | 
						|
  const stopBtn = document.getElementById("stop-btn");
 | 
						|
  const audioEditorPlayBtn = document.getElementById("audio-editor-play-btn");
 | 
						|
  const audioEditorStopBtn = document.getElementById("audio-editor-stop-btn");
 | 
						|
  const audioEditorLoopBtn = document.getElementById("audio-editor-loop-btn");
 | 
						|
  const addAudioTrackBtn = document.getElementById("add-audio-track-btn");
 | 
						|
  const rewindBtn = document.getElementById("rewind-btn");
 | 
						|
  const metronomeBtn = document.getElementById("metronome-btn");
 | 
						|
  const sliceToolBtn = document.getElementById("slice-tool-btn");
 | 
						|
  const mmpFileInput = document.getElementById("mmp-file-input");
 | 
						|
  const sampleFileInput = document.getElementById("sample-file-input");
 | 
						|
  const openProjectModal = document.getElementById("open-project-modal");
 | 
						|
  const openModalCloseBtn = document.getElementById("open-modal-close-btn");
 | 
						|
  const loadFromComputerBtn = document.getElementById("load-from-computer-btn");
 | 
						|
  const sidebarToggle = document.getElementById("sidebar-toggle");
 | 
						|
  const addBarBtn = document.getElementById("add-bar-btn");
 | 
						|
  const zoomInBtn = document.getElementById("zoom-in-btn");
 | 
						|
  const zoomOutBtn = document.getElementById("zoom-out-btn");
 | 
						|
 | 
						|
  newProjectBtn.addEventListener("click", () => {
 | 
						|
    if ((appState.pattern.tracks.length > 0 || appState.audio.clips.length > 0) && !confirm("Você tem certeza? Alterações não salvas serão perdidas.")) return;
 | 
						|
    resetProjectState();
 | 
						|
    document.getElementById('bpm-input').value = 140;
 | 
						|
    document.getElementById('bars-input').value = 1;
 | 
						|
    document.getElementById('compasso-a-input').value = 4;
 | 
						|
    document.getElementById('compasso-b-input').value = 4;
 | 
						|
    const titleElement = document.getElementById('beat-bassline-title');
 | 
						|
    if(titleElement) titleElement.textContent = 'Novo Projeto';
 | 
						|
    renderAll();
 | 
						|
  });
 | 
						|
 | 
						|
  addBarBtn.addEventListener("click", () => {
 | 
						|
    const barsInput = document.getElementById("bars-input");
 | 
						|
    if (barsInput) adjustValue(barsInput, 1);
 | 
						|
  });
 | 
						|
  
 | 
						|
  openMmpBtn.addEventListener("click", showOpenProjectModal);
 | 
						|
  loadFromComputerBtn.addEventListener("click", () => mmpFileInput.click());
 | 
						|
  mmpFileInput.addEventListener("change", (event) => { const file = event.target.files[0]; if (file) { handleFileLoad(file).then(() => closeOpenProjectModal()); } });
 | 
						|
  uploadSampleBtn.addEventListener("click", () => sampleFileInput.click());
 | 
						|
  saveMmpBtn.addEventListener("click", generateMmpFile);
 | 
						|
  addInstrumentBtn.addEventListener("click", addTrackToState);
 | 
						|
  removeInstrumentBtn.addEventListener("click", removeLastTrackFromState);
 | 
						|
  playBtn.addEventListener("click", togglePlayback);
 | 
						|
  stopBtn.addEventListener("click", stopPlayback);
 | 
						|
  rewindBtn.addEventListener("click", rewindPlayback);
 | 
						|
  metronomeBtn.addEventListener("click", () => { initializeAudioContext(); appState.global.metronomeEnabled = !appState.global.metronomeEnabled; metronomeBtn.classList.toggle("active", appState.global.metronomeEnabled); });
 | 
						|
  if(sliceToolBtn) { sliceToolBtn.addEventListener("click", () => { appState.global.sliceToolActive = !appState.global.sliceToolActive; sliceToolBtn.classList.toggle("active", appState.global.sliceToolActive); document.body.classList.toggle("slice-tool-active", appState.global.sliceToolActive); }); }
 | 
						|
  openModalCloseBtn.addEventListener("click", closeOpenProjectModal);
 | 
						|
 | 
						|
  // ### CORREÇÃO 2: Adicionada verificação 'if (icon)' ###
 | 
						|
  sidebarToggle.addEventListener("click", () => { 
 | 
						|
    document.body.classList.toggle("sidebar-hidden"); 
 | 
						|
    const icon = sidebarToggle.querySelector("i"); 
 | 
						|
    if (icon) {
 | 
						|
      icon.className = document.body.classList.contains("sidebar-hidden") ? "fa-solid fa-caret-right" : "fa-solid fa-caret-left"; 
 | 
						|
    }
 | 
						|
  });
 | 
						|
  
 | 
						|
  const inputs = document.querySelectorAll(".value-input");
 | 
						|
  inputs.forEach((input) => {
 | 
						|
    input.addEventListener("input", (event) => {
 | 
						|
      enforceNumericInput(event);
 | 
						|
      if (appState.global.isPlaying && (event.target.id.startsWith("compasso-") || event.target.id === 'bars-input')) { stopPlayback(); }
 | 
						|
      if (event.target.id.startsWith("compasso-") || event.target.id === 'bars-input' || event.target.id === 'bpm-input') { renderAll(); }
 | 
						|
    });
 | 
						|
    input.addEventListener("wheel", (event) => { event.preventDefault(); const step = event.deltaY < 0 ? 1 : -1; adjustValue(event.target, step); });
 | 
						|
  });
 | 
						|
 | 
						|
  const buttons = document.querySelectorAll(".adjust-btn");
 | 
						|
  buttons.forEach((button) => { button.addEventListener("click", () => { const targetId = button.dataset.target + "-input"; const targetInput = document.getElementById(targetId); const step = parseInt(button.dataset.step, 10) || 1; if (targetInput) { adjustValue(targetInput, step); } }); });
 | 
						|
 | 
						|
  if (zoomInBtn) {
 | 
						|
    zoomInBtn.addEventListener("click", () => {
 | 
						|
        if (appState.global.zoomLevelIndex < ZOOM_LEVELS.length - 1) {
 | 
						|
            appState.global.zoomLevelIndex++;
 | 
						|
            renderAll();
 | 
						|
        }
 | 
						|
    });
 | 
						|
  }
 | 
						|
  if (zoomOutBtn) {
 | 
						|
    zoomOutBtn.addEventListener("click", () => {
 | 
						|
        if (appState.global.zoomLevelIndex > 0) {
 | 
						|
            appState.global.zoomLevelIndex--;
 | 
						|
            renderAll();
 | 
						|
        }
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  audioEditorPlayBtn.addEventListener("click", () => { if (appState.global.isAudioEditorPlaying) { stopAudioEditorPlayback(); } else { startAudioEditorPlayback(); } });
 | 
						|
  audioEditorStopBtn.addEventListener("click", stopAudioEditorPlayback);
 | 
						|
  
 | 
						|
  // ### CORREÇÃO 1: Listeners duplicados combinados em um só ###
 | 
						|
  // No main.js
 | 
						|
  audioEditorLoopBtn.addEventListener("click", () => {
 | 
						|
    console.log("--- Botão de Loop Clicado ---"); // DEBUG 1
 | 
						|
 | 
						|
    // 1. Altera o estado global de loop
 | 
						|
    appState.global.isLoopActive = !appState.global.isLoopActive;
 | 
						|
    console.log("Estado appState.global.isLoopActive:", appState.global.isLoopActive); // DEBUG 2
 | 
						|
    
 | 
						|
    // 2. Sincroniza o estado do loop do editor
 | 
						|
    appState.audio.isAudioEditorLoopEnabled = appState.global.isLoopActive;
 | 
						|
 | 
						|
    // 3. Atualiza a aparência do botão
 | 
						|
    audioEditorLoopBtn.classList.toggle("active", appState.global.isLoopActive);
 | 
						|
    
 | 
						|
    // 4. Sincroniza o Tone.Transport
 | 
						|
    updateTransportLoop();
 | 
						|
 | 
						|
    // 5. Mostra/esconde a área de loop
 | 
						|
    const loopArea = document.getElementById("loop-region");
 | 
						|
    
 | 
						|
    // ESTE É O TESTE MAIS IMPORTANTE:
 | 
						|
    if (loopArea) {
 | 
						|
        console.log("Elemento #loop-region ENCONTRADO. Alterando classe 'visible'."); // DEBUG 3
 | 
						|
        loopArea.classList.toggle("visible", appState.global.isLoopActive);
 | 
						|
    } else {
 | 
						|
        console.error("ERRO GRAVE: Elemento #loop-region NÃO FOI ENCONTRADO!"); // DEBUG 4
 | 
						|
    }
 | 
						|
    
 | 
						|
    // 6. Reinicia o playback se estiver tocando
 | 
						|
    restartAudioEditorIfPlaying();
 | 
						|
  });
 | 
						|
  
 | 
						|
  if (addAudioTrackBtn) { addAudioTrackBtn.addEventListener("click", () => { addAudioTrackLane(); renderAudioEditor(); }); }
 | 
						|
 | 
						|
  // ### CORREÇÃO 3: Ordem de execução corrigida ###
 | 
						|
 | 
						|
  // 1. Carrega o conteúdo do navegador de samples
 | 
						|
  loadAndRenderSampleBrowser();
 | 
						|
 | 
						|
  // 2. Adiciona o listener DEPOIS que o conteúdo supostamente existe
 | 
						|
  const browserContent = document.getElementById('browser-content');
 | 
						|
  if (browserContent) {
 | 
						|
      browserContent.addEventListener('click', function(event) {
 | 
						|
          const folderName = event.target.closest('.folder-name');
 | 
						|
          if (folderName) {
 | 
						|
              const folderItem = folderName.parentElement;
 | 
						|
              folderItem.classList.toggle('open');
 | 
						|
          }
 | 
						|
      });
 | 
						|
  }
 | 
						|
 | 
						|
  // 3. Renderiza o resto
 | 
						|
  renderAll();
 | 
						|
}); |