diff --git a/assets/js/creations/file.js b/assets/js/creations/file.js
index c6f3ff3..e31e345 100644
--- a/assets/js/creations/file.js
+++ b/assets/js/creations/file.js
@@ -67,14 +67,9 @@ export async function parseMmpContent(xmlString) {
const totalSteps = getTotalSteps();
const newSteps = new Array(totalSteps).fill(false);
- // ==================================================================
- // (CORREÇÃO DEFINITIVA)
- // 1. Simplificamos o cálculo: cada step de 1/16 vale 12 ticks.
const ticksPerStep = 12;
- // 2. Buscamos TODAS as notas da trilha, não importa em qual pattern elas estejam.
trackNode.querySelectorAll("note").forEach((noteNode) => {
- // ==================================================================
const pos = parseInt(noteNode.getAttribute("pos"), 10);
const stepIndex = Math.round(pos / ticksPerStep);
if (stepIndex < totalSteps) {
@@ -205,21 +200,11 @@ function modifyAndSaveExistingMmp() {
function createTrackXml(track) {
if (!track.samplePath) return "";
const totalSteps = track.steps.length || getTotalSteps();
- const ticksPerStep = 12; // Valor fixo de 12 ticks por step de 1/16
+ const ticksPerStep = 12;
const lmmsVolume = Math.round(track.volume * 100);
const lmmsPan = Math.round(track.pan * 100);
const sampleSrc = track.samplePath.replace("src/samples/", "");
- const notesXml = track.steps
- .map((isActive, index) => {
- if (isActive) {
- const notePos = Math.round(index * ticksPerStep);
- return ``;
- }
- return "";
- })
- .join("\n ");
- // Cria um pattern para cada compasso (16 steps)
let patternsXml = '';
const stepsPerBar = 16;
const numBars = Math.ceil(totalSteps / stepsPerBar);
diff --git a/assets/js/creations/ui.js b/assets/js/creations/ui.js
index 8fdfdef..a490d56 100644
--- a/assets/js/creations/ui.js
+++ b/assets/js/creations/ui.js
@@ -13,7 +13,7 @@ import { loadProjectFromServer } from "./file.js";
// Variável para armazenar o mapa de samples (nome do arquivo -> caminho completo)
let samplePathMap = {};
-// Função para exportar o mapa de samples para outros módulos
+// Função para exportar o mapa de samples, que estava faltando
export function getSamplePathMap() {
return samplePathMap;
}
@@ -60,7 +60,7 @@ export function renderApp() {
PAN
-
+
`;
trackLane.addEventListener("dragover", (e) => {
@@ -93,13 +93,24 @@ export function renderApp() {
}
export function redrawSequencer() {
- const beatsPerBar =
- parseInt(document.getElementById("compasso-a-input").value, 10) || 4;
+ const beatsPerBar = parseInt(document.getElementById("compasso-a-input").value, 10) || 4;
+ const noteValue = parseInt(document.getElementById("compasso-b-input").value, 10) || 4;
+ const subdivisions = Math.round(16 / noteValue);
+ const stepsPerBar = beatsPerBar * subdivisions;
const totalSteps = getTotalSteps();
- document.querySelectorAll(".step-sequencer").forEach((container) => {
- const parentTrackElement = container.closest(".track-lane");
+
+ 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.tracks.find((t) => t.id == trackId);
+
if (trackData && trackData.steps.length !== totalSteps) {
const newStepsState = new Array(totalSteps).fill(false);
for (let i = 0; i < Math.min(trackData.steps.length, totalSteps); i++) {
@@ -107,10 +118,12 @@ export function redrawSequencer() {
}
trackData.steps = newStepsState;
}
- container.innerHTML = "";
+
+ sequencerContainer.innerHTML = "";
for (let i = 0; i < totalSteps; i++) {
const stepWrapper = document.createElement("div");
stepWrapper.className = "step-wrapper";
+
const stepElement = document.createElement("div");
stepElement.className = "step";
if (trackData && trackData.steps[i] === true) {
@@ -123,27 +136,29 @@ export function redrawSequencer() {
playSample(trackData.samplePath, trackData.id);
}
});
+
const groupIndex = Math.floor(i / beatsPerBar);
if (groupIndex % 2 === 0) {
stepElement.classList.add("step-dark");
}
- if (i > 0 && i % beatsPerBar === 0) {
+
+ if (i > 0 && i % stepsPerBar === 0) {
const marker = document.createElement("div");
marker.className = "step-marker";
- marker.textContent = i;
+ marker.textContent = Math.floor(i / stepsPerBar) + 1;
stepWrapper.appendChild(marker);
}
+
stepWrapper.appendChild(stepElement);
- container.appendChild(stepWrapper);
+ sequencerContainer.appendChild(stepWrapper);
}
});
}
-// LÓGICA DE INTERAÇÃO DOS KNOBS
function addKnobInteraction(knobElement) {
const controlType = knobElement.dataset.control;
knobElement.addEventListener("mousedown", (e) => {
- if (e.button === 1) { // Middle mouse button
+ if (e.button === 1) {
e.preventDefault();
const trackId = knobElement.dataset.trackId;
const defaultValue = controlType === "volume" ? 0.8 : 0.0;
@@ -156,7 +171,7 @@ function addKnobInteraction(knobElement) {
}
});
knobElement.addEventListener("mousedown", (e) => {
- if (e.button !== 0) return; // Apenas botão esquerdo
+ if (e.button !== 0) return;
e.preventDefault();
const trackId = knobElement.dataset.trackId;
const track = appState.tracks.find((t) => t.id == trackId);
@@ -249,7 +264,6 @@ export function highlightStep(stepIndex, isActive) {
});
}
-// LÓGICA DA SIDEBAR E MODAL
export async function loadAndRenderSampleBrowser() {
const browserContent = document.getElementById("browser-content");
try {