melhorando a leitura de projetos no mmpCreator
Deploy / Deploy (push) Successful in 2m41s Details

This commit is contained in:
JotaChina 2025-12-25 12:03:23 -03:00
parent d86348cfac
commit 08302947ad
1 changed files with 52 additions and 45 deletions

View File

@ -225,7 +225,7 @@ export async function loadProjectFromServer(fileName) {
// ================================================================= // =================================================================
function parseInstrumentNode( function parseInstrumentNode(
trackNode, trackNode,
sortedBBTrackNameNodes, sortedBBTrackNameNodes, // Esse argumento agora será ignorado para evitar o bug
pathMap, pathMap,
parentBasslineId = null parentBasslineId = null
) { ) {
@ -237,8 +237,14 @@ function parseInstrumentNode(
const trackName = trackNode.getAttribute("name"); const trackName = trackNode.getAttribute("name");
const instrumentName = instrumentNode.getAttribute("name"); const instrumentName = instrumentNode.getAttribute("name");
// Lógica de Patterns // Lógica de Patterns:
// CORREÇÃO: Iteramos diretamente sobre os patterns encontrados no XML do instrumento.
// Não tentamos mais mapear 1-para-1 com os clipes da timeline, pois instrumentos de
// Beat/Bassline reutilizam o mesmo pattern várias vezes.
const allPatternsNodeList = trackNode.querySelectorAll("pattern"); const allPatternsNodeList = trackNode.querySelectorAll("pattern");
// Ordena os patterns pela posição (importante para Song Editor, neutro para BB Editor)
const allPatternsArray = Array.from(allPatternsNodeList).sort((a, b) => { const allPatternsArray = Array.from(allPatternsNodeList).sort((a, b) => {
return ( return (
(parseInt(a.getAttribute("pos"), 10) || 0) - (parseInt(a.getAttribute("pos"), 10) || 0) -
@ -246,55 +252,56 @@ function parseInstrumentNode(
); );
}); });
const patternsToCreate = // Se não houver patterns no XML, criamos um vazio para não quebrar a UI
sortedBBTrackNameNodes.length > 0 let patterns = [];
? sortedBBTrackNameNodes
: [{ getAttribute: () => "Pattern 1" }];
const patterns = patternsToCreate.map((bbTrack, index) => { if (allPatternsArray.length > 0) {
const patternNode = allPatternsArray[index]; patterns = allPatternsArray.map((patternNode, index) => {
const bbTrackName = bbTrack.getAttribute("name") || `Pattern ${index + 1}`; // Tenta pegar o nome do atributo, ou gera um genérico
const patternName = patternNode.getAttribute("name") || `Pattern ${index}`;
const patternSteps = parseInt(patternNode.getAttribute("steps"), 10) || 16;
const steps = new Array(patternSteps).fill(false);
const notes = [];
if (!patternNode) { // Constante de conversão LMMS (192 ticks = 1 beat, 48 ticks = 1 step)
return { const ticksPerStep = 48;
name: bbTrackName,
steps: new Array(16).fill(false),
notes: [],
pos: 0,
};
}
const patternSteps = parseInt(patternNode.getAttribute("steps"), 10) || 16; patternNode.querySelectorAll("note").forEach((noteNode) => {
const steps = new Array(patternSteps).fill(false); const pos = parseInt(noteNode.getAttribute("pos"), 10);
const notes = []; const len = parseInt(noteNode.getAttribute("len"), 10);
const vol = parseInt(noteNode.getAttribute("vol"), 10);
const pan = parseInt(noteNode.getAttribute("pan"), 10);
const key = parseInt(noteNode.getAttribute("key"), 10);
// === CORREÇÃO MATEMÁTICA === notes.push({ pos, len, key, vol, pan });
// No LMMS, 1 semínima (beat) = 192 ticks.
// 1 semicolcheia (1/16 step) = 192 / 4 = 48 ticks.
const ticksPerStep = 48;
patternNode.querySelectorAll("note").forEach((noteNode) => { // Calcula qual step acender
const pos = parseInt(noteNode.getAttribute("pos"), 10); // Nota: B/B Editor no LMMS geralmente usa notas de len=48.
notes.push({ // Se a nota for longa, isso marca apenas o step de início.
pos: pos, const stepIndex = Math.round(pos / ticksPerStep);
len: parseInt(noteNode.getAttribute("len"), 10),
key: parseInt(noteNode.getAttribute("key"), 10), if (stepIndex >= 0 && stepIndex < patternSteps) {
vol: parseInt(noteNode.getAttribute("vol"), 10), steps[stepIndex] = true;
pan: parseInt(noteNode.getAttribute("pan"), 10), }
}); });
// Calcula qual quadradinho acender return {
const stepIndex = Math.round(pos / ticksPerStep); name: patternName,
if (stepIndex < patternSteps) steps[stepIndex] = true; steps: steps,
notes: notes,
pos: parseInt(patternNode.getAttribute("pos"), 10) || 0,
};
}); });
} else {
return { // Fallback: Nenhum pattern encontrado no XML, cria um padrão vazio
name: bbTrackName, patterns.push({
steps: steps, name: "Pattern 0",
notes: notes, steps: new Array(16).fill(false),
pos: parseInt(patternNode.getAttribute("pos"), 10) || 0, notes: [],
}; pos: 0
}); });
}
// Lógica de Sample vs Plugin // Lógica de Sample vs Plugin
let finalSamplePath = null; let finalSamplePath = null;
@ -326,12 +333,12 @@ function parseInstrumentNode(
type: trackType, type: trackType,
samplePath: finalSamplePath, samplePath: finalSamplePath,
patterns: patterns, patterns: patterns,
activePatternIndex: 0, activePatternIndex: 0, // Sempre começa mostrando o primeiro pattern disponível
volume: !isNaN(volFromFile) ? volFromFile / 100 : DEFAULT_VOLUME, volume: !isNaN(volFromFile) ? volFromFile / 100 : DEFAULT_VOLUME,
pan: !isNaN(panFromFile) ? panFromFile / 100 : DEFAULT_PAN, pan: !isNaN(panFromFile) ? panFromFile / 100 : DEFAULT_PAN,
instrumentName: instrumentName, instrumentName: instrumentName,
instrumentXml: instrumentNode.innerHTML, instrumentXml: instrumentNode.innerHTML,
parentBasslineId: parentBasslineId, // Guarda o ID do pai para filtragem na UI parentBasslineId: parentBasslineId,
}; };
} }