mmpSearch/assets/js/creations/main.js

254 lines
10 KiB
JavaScript

// js/main.js
import {
appState,
addTrackToState,
removeLastTrackFromState,
} from "./state.js";
import {
togglePlayback,
stopPlayback,
rewindPlayback,
initializeAudioContext,
updateMasterVolume,
updateMasterPan,
} from "./audio.js";
import { handleFileLoad, generateMmpFile } from "./file.js";
import {
renderApp,
redrawSequencer,
loadAndRenderSampleBrowser,
showOpenProjectModal,
closeOpenProjectModal,
handleSampleUpload, // Importa handleSampleUpload, embora não seja mais usado diretamente
} from "./ui.js";
import { adjustValue, enforceNumericInput } from "./utils.js";
import { DEFAULT_PAN, DEFAULT_VOLUME } 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 rewindBtn = document.getElementById("rewind-btn");
const metronomeBtn = document.getElementById("metronome-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 masterVolumeKnob = document.getElementById("master-volume-knob");
const masterPanKnob = document.getElementById("master-pan-knob");
newProjectBtn.addEventListener("click", () => {
if (
appState.tracks.length > 0 &&
!confirm("Você tem certeza? Alterações não salvas serão perdidas.")
)
return;
Object.assign(appState, {
tracks: [],
activeTrackId: null,
isPlaying: false,
playbackIntervalId: null,
currentStep: 0,
metronomeEnabled: false,
originalXmlDoc: null,
currentBeatBasslineName: 'Novo Projeto',
masterVolume: DEFAULT_VOLUME,
masterPan: DEFAULT_PAN
});
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';
renderApp();
setupMasterKnobs();
});
addBarBtn.addEventListener("click", () => {
const barsInput = document.getElementById("bars-input");
if (barsInput) adjustValue(barsInput, 1);
});
function setupMasterKnobs() {
function updateMasterKnobVisual(knobElement, controlType) {
const indicator = knobElement.querySelector(".knob-indicator");
if (!indicator) return;
const minAngle = -135;
const maxAngle = 135;
let percentage = 0.5;
let title = "";
if (controlType === "volume") {
const value = appState.masterVolume;
percentage = value / 1.5;
title = `Volume Master: ${Math.round(value * 100)}%`;
} else {
const value = appState.masterPan;
percentage = (value + 1) / 2;
const panDisplay = Math.round(value * 100);
title = `Pan Master: ${ panDisplay === 0 ? "Centro" : panDisplay < 0 ? `${-panDisplay} L` : `${panDisplay} R` }`;
}
const angle = minAngle + percentage * (maxAngle - minAngle);
indicator.style.transform = `translateX(-50%) rotate(${angle}deg)`;
knobElement.title = title;
}
function addMasterKnobInteraction(knobElement, controlType) {
knobElement.addEventListener("wheel", (e) => {
e.preventDefault();
const step = 0.05;
const direction = e.deltaY < 0 ? 1 : -1;
if (controlType === "volume") {
const newValue = appState.masterVolume + direction * step;
appState.masterVolume = Math.max(0, Math.min(1.5, newValue));
updateMasterVolume(appState.masterVolume);
} else {
const newValue = appState.masterPan + direction * step;
appState.masterPan = Math.max(-1, Math.min(1, newValue));
updateMasterPan(appState.masterPan);
}
updateMasterKnobVisual(knobElement, controlType);
});
knobElement.addEventListener("mousedown", (e) => {
if (e.button !== 0) return;
e.preventDefault();
const startY = e.clientY;
const startValue = controlType === "volume" ? appState.masterVolume : appState.masterPan;
document.body.classList.add("knob-dragging");
function onMouseMove(moveEvent) {
const deltaY = startY - moveEvent.clientY;
const sensitivity = controlType === "volume" ? 150 : 200;
const newValue = startValue + deltaY / sensitivity;
if (controlType === "volume") {
appState.masterVolume = Math.max(0, Math.min(1.5, newValue));
updateMasterVolume(appState.masterVolume);
} else {
appState.masterPan = Math.max(-1, Math.min(1, newValue));
updateMasterPan(appState.masterPan);
}
updateMasterKnobVisual(knobElement, controlType);
}
function onMouseUp() {
document.body.classList.remove("knob-dragging");
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseup", onMouseUp);
}
document.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseup", onMouseUp);
});
}
addMasterKnobInteraction(masterVolumeKnob, "volume");
updateMasterKnobVisual(masterVolumeKnob, "volume");
addMasterKnobInteraction(masterPanKnob, "pan");
updateMasterKnobVisual(masterPanKnob, "pan");
}
openMmpBtn.addEventListener("click", showOpenProjectModal);
loadFromComputerBtn.addEventListener("click", () => mmpFileInput.click());
mmpFileInput.addEventListener("change", async (event) => {
const file = event.target.files[0];
if (file) {
await handleFileLoad(file);
closeOpenProjectModal();
}
});
uploadSampleBtn.addEventListener("click", () => sampleFileInput.click());
// --- INÍCIO DA CORREÇÃO ---
// Lógica de upload de sample para o servidor Flask
sampleFileInput.addEventListener("change", async (event) => {
const file = event.target.files[0];
if (!file) return;
const formData = new FormData();
formData.append("sampleFile", file);
try {
// ATENÇÃO: Verifique se a URL e a porta estão corretas para o seu servidor Flask
const response = await fetch('http://localhost:5000/upload-sample', {
method: 'POST',
body: formData,
});
const result = await response.json();
if (response.ok) {
alert("Sample enviado com sucesso!");
// Recarrega a lista de samples para exibir o novo arquivo
await loadAndRenderSampleBrowser();
} else {
throw new Error(result.error || "Erro desconhecido no servidor.");
}
} catch (error) {
console.error("Erro ao enviar o sample:", error);
alert(`Falha no upload: ${error.message}`);
}
event.target.value = null; // Limpa o input para permitir o mesmo arquivo de novo
});
// --- FIM DA CORREÇÃO ---
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.metronomeEnabled = !appState.metronomeEnabled;
metronomeBtn.classList.toggle("active", appState.metronomeEnabled);
});
openModalCloseBtn.addEventListener("click", closeOpenProjectModal);
openProjectModal.addEventListener("click", (e) => {
if (e.target === openProjectModal) closeOpenProjectModal();
});
sidebarToggle.addEventListener("click", () => {
document.body.classList.toggle("sidebar-hidden");
const icon = sidebarToggle.querySelector("i");
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.isPlaying && (event.target.id.startsWith("compasso-") || event.target.id === 'bars-input')) {
stopPlayback();
}
if (event.target.id.startsWith("compasso-") || event.target.id === 'bars-input') {
redrawSequencer();
}
});
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);
}
});
});
loadAndRenderSampleBrowser();
renderApp();
setupMasterKnobs();
});