tentando obter playlist real do projeto mmp
Deploy / Deploy (push) Successful in 2m1s
Details
Deploy / Deploy (push) Successful in 2m1s
Details
This commit is contained in:
parent
57ec600307
commit
73721f7b9b
|
|
@ -1,3 +1,5 @@
|
||||||
|
// js/creations/file.js
|
||||||
|
|
||||||
//--------------------------------------------------------------
|
//--------------------------------------------------------------
|
||||||
// IMPORTS NECESSÁRIOS
|
// IMPORTS NECESSÁRIOS
|
||||||
//--------------------------------------------------------------
|
//--------------------------------------------------------------
|
||||||
|
|
@ -35,7 +37,6 @@ export function handleLocalProjectReset() {
|
||||||
const bpmInput = document.getElementById("bpm-input");
|
const bpmInput = document.getElementById("bpm-input");
|
||||||
if(bpmInput) bpmInput.value = 140;
|
if(bpmInput) bpmInput.value = 140;
|
||||||
|
|
||||||
// Reseta inputs visuais se existirem
|
|
||||||
["bars-input", "compasso-a-input", "compasso-b-input"].forEach(id => {
|
["bars-input", "compasso-a-input", "compasso-b-input"].forEach(id => {
|
||||||
const el = document.getElementById(id);
|
const el = document.getElementById(id);
|
||||||
if(el) el.value = (id === "bars-input") ? 1 : 4;
|
if(el) el.value = (id === "bars-input") ? 1 : 4;
|
||||||
|
|
@ -87,7 +88,99 @@ export async function loadProjectFromServer(fileName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// =================================================================
|
// =================================================================
|
||||||
// 🔥 FUNÇÃO DE PARSING PRINCIPAL (CORRIGIDA)
|
// FUNÇÃO AUXILIAR: PARSE DE INSTRUMENTO ÚNICO
|
||||||
|
// =================================================================
|
||||||
|
function parseInstrumentNode(trackNode, sortedBBTrackNameNodes, pathMap) {
|
||||||
|
const instrumentNode = trackNode.querySelector("instrument");
|
||||||
|
const instrumentTrackNode = trackNode.querySelector("instrumenttrack");
|
||||||
|
|
||||||
|
// Se não tiver instrumento ou track válida, retorna null
|
||||||
|
if (!instrumentNode || !instrumentTrackNode) return null;
|
||||||
|
|
||||||
|
const trackName = trackNode.getAttribute("name");
|
||||||
|
const instrumentName = instrumentNode.getAttribute("name");
|
||||||
|
|
||||||
|
// Lógica de Patterns
|
||||||
|
const allPatternsNodeList = trackNode.querySelectorAll("pattern");
|
||||||
|
const allPatternsArray = Array.from(allPatternsNodeList).sort((a, b) => {
|
||||||
|
return (parseInt(a.getAttribute("pos"), 10) || 0) - (parseInt(b.getAttribute("pos"), 10) || 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
const patternsToCreate = sortedBBTrackNameNodes.length > 0
|
||||||
|
? sortedBBTrackNameNodes
|
||||||
|
: [{ getAttribute: () => "Pattern 1" }];
|
||||||
|
|
||||||
|
const patterns = patternsToCreate.map((bbTrack, index) => {
|
||||||
|
const patternNode = allPatternsArray[index];
|
||||||
|
const bbTrackName = bbTrack.getAttribute("name") || `Pattern ${index + 1}`;
|
||||||
|
|
||||||
|
if (!patternNode) {
|
||||||
|
return { name: bbTrackName, steps: new Array(16).fill(false), notes: [], pos: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
const patternSteps = parseInt(patternNode.getAttribute("steps"), 10) || 16;
|
||||||
|
const steps = new Array(patternSteps).fill(false);
|
||||||
|
const notes = [];
|
||||||
|
const ticksPerStep = 12;
|
||||||
|
|
||||||
|
patternNode.querySelectorAll("note").forEach((noteNode) => {
|
||||||
|
notes.push({
|
||||||
|
pos: parseInt(noteNode.getAttribute("pos"), 10),
|
||||||
|
len: parseInt(noteNode.getAttribute("len"), 10),
|
||||||
|
key: parseInt(noteNode.getAttribute("key"), 10),
|
||||||
|
vol: parseInt(noteNode.getAttribute("vol"), 10),
|
||||||
|
pan: parseInt(noteNode.getAttribute("pan"), 10),
|
||||||
|
});
|
||||||
|
const stepIndex = Math.round(parseInt(noteNode.getAttribute("pos"), 10) / ticksPerStep);
|
||||||
|
if (stepIndex < patternSteps) steps[stepIndex] = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: bbTrackName,
|
||||||
|
steps: steps,
|
||||||
|
notes: notes,
|
||||||
|
pos: parseInt(patternNode.getAttribute("pos"), 10) || 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Lógica de Sample vs Plugin
|
||||||
|
let finalSamplePath = null;
|
||||||
|
let trackType = "plugin";
|
||||||
|
|
||||||
|
if (instrumentName === "audiofileprocessor") {
|
||||||
|
trackType = "sampler";
|
||||||
|
const afpNode = instrumentNode.querySelector("audiofileprocessor");
|
||||||
|
const sampleSrc = afpNode ? afpNode.getAttribute("src") : null;
|
||||||
|
if (sampleSrc) {
|
||||||
|
const filename = sampleSrc.split("/").pop();
|
||||||
|
if (pathMap[filename]) {
|
||||||
|
finalSamplePath = pathMap[filename];
|
||||||
|
} else {
|
||||||
|
let cleanSrc = sampleSrc.startsWith("samples/") ? sampleSrc.substring("samples/".length) : sampleSrc;
|
||||||
|
finalSamplePath = `src/samples/${cleanSrc}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const volFromFile = parseFloat(instrumentTrackNode.getAttribute("vol"));
|
||||||
|
const panFromFile = parseFloat(instrumentTrackNode.getAttribute("pan"));
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: Date.now() + Math.random(),
|
||||||
|
name: trackName,
|
||||||
|
type: trackType,
|
||||||
|
samplePath: finalSamplePath,
|
||||||
|
patterns: patterns,
|
||||||
|
activePatternIndex: 0,
|
||||||
|
volume: !isNaN(volFromFile) ? volFromFile / 100 : DEFAULT_VOLUME,
|
||||||
|
pan: !isNaN(panFromFile) ? panFromFile / 100 : DEFAULT_PAN,
|
||||||
|
instrumentName: instrumentName,
|
||||||
|
instrumentXml: instrumentNode.innerHTML,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// =================================================================
|
||||||
|
// 🔥 FUNÇÃO DE PARSING PRINCIPAL
|
||||||
// =================================================================
|
// =================================================================
|
||||||
export async function parseMmpContent(xmlString) {
|
export async function parseMmpContent(xmlString) {
|
||||||
resetProjectState();
|
resetProjectState();
|
||||||
|
|
@ -105,7 +198,6 @@ export async function parseMmpContent(xmlString) {
|
||||||
appState.global.originalXmlDoc = xmlDoc;
|
appState.global.originalXmlDoc = xmlDoc;
|
||||||
let newTracks = [];
|
let newTracks = [];
|
||||||
|
|
||||||
// Configuração Global (BPM, Compasso)
|
|
||||||
const head = xmlDoc.querySelector("head");
|
const head = xmlDoc.querySelector("head");
|
||||||
if (head) {
|
if (head) {
|
||||||
const setVal = (id, attr, def) => {
|
const setVal = (id, attr, def) => {
|
||||||
|
|
@ -120,167 +212,97 @@ export async function parseMmpContent(xmlString) {
|
||||||
const pathMap = getSamplePathMap();
|
const pathMap = getSamplePathMap();
|
||||||
|
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
// 1. EXTRAÇÃO DE INSTRUMENTOS (Normal)
|
// 1. PREPARAÇÃO
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
|
|
||||||
// Seleciona todos os instrumentos (Song Editor + Beat/Bassline internos)
|
|
||||||
// Nota: Isso pega os instrumentos DENTRO das basslines, o que é correto para o Pattern Editor.
|
|
||||||
const allInstrumentTrackNodes = Array.from(xmlDoc.querySelectorAll('track[type="0"]'));
|
|
||||||
|
|
||||||
// Identifica colunas de beat (bbtco) para dar nome aos patterns
|
// Identifica colunas de beat (bbtco) para dar nome aos patterns
|
||||||
const bbTrackNodes = Array.from(xmlDoc.querySelectorAll('track[type="1"]'));
|
const bbTrackNodes = Array.from(xmlDoc.querySelectorAll('track[type="1"]'));
|
||||||
let sortedBBTrackNameNodes = [];
|
let sortedBBTrackNameNodes = [];
|
||||||
if (bbTrackNodes.length > 0) {
|
if (bbTrackNodes.length > 0) {
|
||||||
// Pega do primeiro container para usar como referência de nomes de coluna
|
|
||||||
sortedBBTrackNameNodes = Array.from(bbTrackNodes[0].querySelectorAll("bbtco")).sort((a, b) => {
|
sortedBBTrackNameNodes = Array.from(bbTrackNodes[0].querySelectorAll("bbtco")).sort((a, b) => {
|
||||||
return (parseInt(a.getAttribute("pos"), 10) || 0) - (parseInt(b.getAttribute("pos"), 10) || 0);
|
return (parseInt(a.getAttribute("pos"), 10) || 0) - (parseInt(b.getAttribute("pos"), 10) || 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Processamento dos Instrumentos ---
|
// -------------------------------------------------------------
|
||||||
const instrumentTracks = allInstrumentTrackNodes.map((trackNode) => {
|
// 2. EXTRAÇÃO DE INSTRUMENTOS (Song Editor)
|
||||||
const instrumentNode = trackNode.querySelector("instrument");
|
// -------------------------------------------------------------
|
||||||
const instrumentTrackNode = trackNode.querySelector("instrumenttrack");
|
// Pega apenas os instrumentos que estão soltos no Song Editor (não dentro de BBTracks)
|
||||||
if (!instrumentNode || !instrumentTrackNode) return null;
|
const songInstrumentNodes = Array.from(xmlDoc.querySelectorAll('song > trackcontainer > track[type="0"]'));
|
||||||
|
|
||||||
const trackName = trackNode.getAttribute("name");
|
const songTracks = songInstrumentNodes
|
||||||
const instrumentName = instrumentNode.getAttribute("name");
|
.map(node => parseInstrumentNode(node, sortedBBTrackNameNodes, pathMap))
|
||||||
|
.filter(t => t !== null);
|
||||||
// ... (Lógica de Patterns Mantida) ...
|
|
||||||
const allPatternsNodeList = trackNode.querySelectorAll("pattern");
|
|
||||||
const allPatternsArray = Array.from(allPatternsNodeList).sort((a, b) => {
|
|
||||||
return (parseInt(a.getAttribute("pos"), 10) || 0) - (parseInt(b.getAttribute("pos"), 10) || 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
const patternsToCreate = sortedBBTrackNameNodes.length > 0
|
|
||||||
? sortedBBTrackNameNodes
|
|
||||||
: [{ getAttribute: () => "Pattern 1" }];
|
|
||||||
|
|
||||||
const patterns = patternsToCreate.map((bbTrack, index) => {
|
|
||||||
const patternNode = allPatternsArray[index];
|
|
||||||
const bbTrackName = bbTrack.getAttribute("name") || `Pattern ${index + 1}`;
|
|
||||||
|
|
||||||
if (!patternNode) {
|
|
||||||
return { name: bbTrackName, steps: new Array(16).fill(false), notes: [], pos: 0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
const patternSteps = parseInt(patternNode.getAttribute("steps"), 10) || 16;
|
|
||||||
const steps = new Array(patternSteps).fill(false);
|
|
||||||
const notes = [];
|
|
||||||
const ticksPerStep = 12;
|
|
||||||
|
|
||||||
patternNode.querySelectorAll("note").forEach((noteNode) => {
|
|
||||||
notes.push({
|
|
||||||
pos: parseInt(noteNode.getAttribute("pos"), 10),
|
|
||||||
len: parseInt(noteNode.getAttribute("len"), 10),
|
|
||||||
key: parseInt(noteNode.getAttribute("key"), 10),
|
|
||||||
vol: parseInt(noteNode.getAttribute("vol"), 10),
|
|
||||||
pan: parseInt(noteNode.getAttribute("pan"), 10),
|
|
||||||
});
|
|
||||||
const stepIndex = Math.round(parseInt(noteNode.getAttribute("pos"), 10) / ticksPerStep);
|
|
||||||
if (stepIndex < patternSteps) steps[stepIndex] = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: bbTrackName,
|
|
||||||
steps: steps,
|
|
||||||
notes: notes,
|
|
||||||
pos: parseInt(patternNode.getAttribute("pos"), 10) || 0,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Lógica de Sample vs Plugin
|
|
||||||
let finalSamplePath = null;
|
|
||||||
let trackType = "plugin";
|
|
||||||
|
|
||||||
if (instrumentName === "audiofileprocessor") {
|
|
||||||
trackType = "sampler";
|
|
||||||
const afpNode = instrumentNode.querySelector("audiofileprocessor");
|
|
||||||
const sampleSrc = afpNode ? afpNode.getAttribute("src") : null;
|
|
||||||
if (sampleSrc) {
|
|
||||||
const filename = sampleSrc.split("/").pop();
|
|
||||||
if (pathMap[filename]) {
|
|
||||||
finalSamplePath = pathMap[filename];
|
|
||||||
} else {
|
|
||||||
let cleanSrc = sampleSrc.startsWith("samples/") ? sampleSrc.substring("samples/".length) : sampleSrc;
|
|
||||||
finalSamplePath = `src/samples/${cleanSrc}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const volFromFile = parseFloat(instrumentTrackNode.getAttribute("vol"));
|
|
||||||
const panFromFile = parseFloat(instrumentTrackNode.getAttribute("pan"));
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: Date.now() + Math.random(),
|
|
||||||
name: trackName,
|
|
||||||
type: trackType,
|
|
||||||
samplePath: finalSamplePath,
|
|
||||||
patterns: patterns,
|
|
||||||
activePatternIndex: 0,
|
|
||||||
volume: !isNaN(volFromFile) ? volFromFile / 100 : DEFAULT_VOLUME,
|
|
||||||
pan: !isNaN(panFromFile) ? panFromFile / 100 : DEFAULT_PAN,
|
|
||||||
instrumentName: instrumentName,
|
|
||||||
instrumentXml: instrumentNode.innerHTML,
|
|
||||||
};
|
|
||||||
}).filter(t => t !== null);
|
|
||||||
|
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
// 2. EXTRAÇÃO DAS TRILHAS DE BASSLINE (Playlist Container)
|
// 3. EXTRAÇÃO DAS TRILHAS DE BASSLINE (E SEUS INSTRUMENTOS)
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
// 👇 AQUI ESTAVA FALTANDO! 👇
|
|
||||||
|
|
||||||
const basslineTracks = bbTrackNodes.map(trackNode => {
|
const basslineTracks = bbTrackNodes.map(trackNode => {
|
||||||
const trackName = trackNode.getAttribute("name") || "Beat/Bassline";
|
const trackName = trackNode.getAttribute("name") || "Beat/Bassline";
|
||||||
|
|
||||||
// Extrai os clipes da timeline (tags <bbtco>)
|
// A. Extrai os clipes da timeline (blocos azuis)
|
||||||
// Eles são filhos diretos de <track type="1">
|
|
||||||
const playlistClips = Array.from(trackNode.querySelectorAll(":scope > bbtco")).map(bbtco => {
|
const playlistClips = Array.from(trackNode.querySelectorAll(":scope > bbtco")).map(bbtco => {
|
||||||
return {
|
return {
|
||||||
pos: parseInt(bbtco.getAttribute("pos"), 10) || 0,
|
pos: parseInt(bbtco.getAttribute("pos"), 10) || 0,
|
||||||
len: parseInt(bbtco.getAttribute("len"), 10) || 192,
|
len: parseInt(bbtco.getAttribute("len"), 10) || 192,
|
||||||
name: trackName // O clipe leva o nome da trilha (ex: "Caixa")
|
name: trackName
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// Se não tiver clipes, não precisa criar a trilha visual na playlist,
|
// B. Extrai os instrumentos INTERNOS desta Bassline
|
||||||
// mas mantemos para consistência se desejar.
|
// Eles estão dentro de <bbtrack><trackcontainer><track type="0">
|
||||||
if (playlistClips.length === 0) return null;
|
const internalInstrumentNodes = Array.from(trackNode.querySelectorAll('bbtrack > trackcontainer > track[type="0"]'));
|
||||||
|
|
||||||
|
const internalInstruments = internalInstrumentNodes
|
||||||
|
.map(node => parseInstrumentNode(node, sortedBBTrackNameNodes, pathMap))
|
||||||
|
.filter(t => t !== null);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: `bassline_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
id: `bassline_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
||||||
name: trackName,
|
name: trackName,
|
||||||
type: "bassline", // Tipo especial que o audio_ui.js reconhece
|
type: "bassline",
|
||||||
playlist_clips: playlistClips,
|
playlist_clips: playlistClips,
|
||||||
// Propriedades dummy para não quebrar o pattern_state/ui
|
instruments: internalInstruments, // <--- AQUI ESTÁ A CORREÇÃO CRUCIAL!
|
||||||
|
// Fallbacks para evitar crashes
|
||||||
volume: 1,
|
volume: 1,
|
||||||
pan: 0,
|
pan: 0,
|
||||||
patterns: [],
|
patterns: [],
|
||||||
isMuted: trackNode.getAttribute("muted") === "1"
|
isMuted: trackNode.getAttribute("muted") === "1"
|
||||||
};
|
};
|
||||||
}).filter(t => t !== null);
|
}).filter(t => t !== null && (t.playlist_clips.length > 0 || t.instruments.length > 0));
|
||||||
|
|
||||||
// Une tudo: Instrumentos + Basslines
|
// Une tudo: Instrumentos Soltos + Basslines
|
||||||
// Adicionamos as basslines ao final para organização
|
newTracks = [...songTracks, ...basslineTracks];
|
||||||
newTracks = [...instrumentTracks, ...basslineTracks];
|
|
||||||
|
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
// 3. INICIALIZAÇÃO DE ÁUDIO E ESTADO
|
// 4. INICIALIZAÇÃO DE ÁUDIO E ESTADO
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
|
|
||||||
// Inicializa nós de áudio para os instrumentos (ignora basslines pois não tocam áudio direto)
|
// Inicializa nós de áudio
|
||||||
newTracks.forEach((track) => {
|
newTracks.forEach((track) => {
|
||||||
|
// Se for instrumento normal
|
||||||
if (track.type !== 'bassline') {
|
if (track.type !== 'bassline') {
|
||||||
track.volumeNode = new Tone.Volume(Tone.gainToDb(track.volume));
|
track.volumeNode = new Tone.Volume(Tone.gainToDb(track.volume));
|
||||||
track.pannerNode = new Tone.Panner(track.pan);
|
track.pannerNode = new Tone.Panner(track.pan);
|
||||||
track.volumeNode.connect(track.pannerNode);
|
track.volumeNode.connect(track.pannerNode);
|
||||||
track.pannerNode.connect(getMainGainNode());
|
track.pannerNode.connect(getMainGainNode());
|
||||||
}
|
}
|
||||||
|
// Se for Bassline, inicializa os nós dos instrumentos INTERNOS
|
||||||
|
else if (track.instruments && track.instruments.length > 0) {
|
||||||
|
track.instruments.forEach(inst => {
|
||||||
|
inst.volumeNode = new Tone.Volume(Tone.gainToDb(inst.volume));
|
||||||
|
inst.pannerNode = new Tone.Panner(inst.pan);
|
||||||
|
inst.volumeNode.connect(inst.pannerNode);
|
||||||
|
inst.pannerNode.connect(getMainGainNode());
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Configura tamanho da timeline baseado no conteúdo
|
// Configura tamanho da timeline
|
||||||
let isFirstTrackWithNotes = true;
|
let isFirstTrackWithNotes = true;
|
||||||
newTracks.forEach(track => {
|
newTracks.forEach(track => {
|
||||||
|
// Verifica track normal
|
||||||
if (track.type !== 'bassline' && isFirstTrackWithNotes) {
|
if (track.type !== 'bassline' && isFirstTrackWithNotes) {
|
||||||
const activePattern = track.patterns[track.activePatternIndex || 0];
|
const activePattern = track.patterns[track.activePatternIndex || 0];
|
||||||
if (activePattern && activePattern.steps && activePattern.steps.length > 0) {
|
if (activePattern && activePattern.steps && activePattern.steps.length > 0) {
|
||||||
|
|
@ -290,23 +312,55 @@ export async function parseMmpContent(xmlString) {
|
||||||
isFirstTrackWithNotes = false;
|
isFirstTrackWithNotes = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Verifica dentro da bassline
|
||||||
|
else if (track.type === 'bassline' && isFirstTrackWithNotes && track.instruments.length > 0) {
|
||||||
|
const firstInst = track.instruments[0];
|
||||||
|
const activePattern = firstInst.patterns[firstInst.activePatternIndex || 0];
|
||||||
|
if (activePattern && activePattern.steps && activePattern.steps.length > 0) {
|
||||||
|
const bars = Math.ceil(activePattern.steps.length / 16);
|
||||||
|
const barsInput = document.getElementById("bars-input");
|
||||||
|
if(barsInput) barsInput.value = bars > 0 ? bars : 1;
|
||||||
|
isFirstTrackWithNotes = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Carrega samples/plugins
|
// Carrega samples/plugins (Async)
|
||||||
try {
|
try {
|
||||||
const trackLoadPromises = newTracks
|
const promises = [];
|
||||||
.filter(t => t.type !== 'bassline') // Apenas instrumentos reais
|
|
||||||
.map(track => loadAudioForTrack(track));
|
newTracks.forEach(track => {
|
||||||
await Promise.all(trackLoadPromises);
|
if (track.type !== 'bassline') {
|
||||||
|
promises.push(loadAudioForTrack(track));
|
||||||
|
} else {
|
||||||
|
// Carrega áudio dos instrumentos internos da bassline
|
||||||
|
track.instruments.forEach(inst => {
|
||||||
|
promises.push(loadAudioForTrack(inst));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(promises);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Ocorreu um erro ao carregar os áudios do projeto:", error);
|
console.error("Ocorreu um erro ao carregar os áudios do projeto:", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Atualiza estado global
|
// Atualiza estado global
|
||||||
appState.pattern.tracks = newTracks;
|
appState.pattern.tracks = newTracks;
|
||||||
// Define o track ativo como o primeiro instrumento real encontrado
|
|
||||||
const firstInstrument = newTracks.find(t => t.type !== 'bassline');
|
// Define faixa ativa (tenta pegar a primeira normal ou a primeira de dentro da bassline)
|
||||||
appState.pattern.activeTrackId = firstInstrument ? firstInstrument.id : null;
|
let firstInstrumentId = null;
|
||||||
|
const firstInstTrack = newTracks.find(t => t.type !== 'bassline');
|
||||||
|
if (firstInstTrack) {
|
||||||
|
firstInstrumentId = firstInstTrack.id;
|
||||||
|
} else {
|
||||||
|
const firstBassline = newTracks.find(t => t.type === 'bassline' && t.instruments.length > 0);
|
||||||
|
if (firstBassline) {
|
||||||
|
firstInstrumentId = firstBassline.instruments[0].id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appState.pattern.activeTrackId = firstInstrumentId;
|
||||||
appState.pattern.activePatternIndex = 0;
|
appState.pattern.activePatternIndex = 0;
|
||||||
|
|
||||||
loadStateFromSession();
|
loadStateFromSession();
|
||||||
|
|
@ -351,9 +405,14 @@ function generateXmlFromState() {
|
||||||
if (bbTrackContainer) {
|
if (bbTrackContainer) {
|
||||||
bbTrackContainer.querySelectorAll('track[type="0"]').forEach((node) => node.remove());
|
bbTrackContainer.querySelectorAll('track[type="0"]').forEach((node) => node.remove());
|
||||||
|
|
||||||
// Apenas instrumentos reais vão para dentro do bbtrack
|
// Procura por instrumentos que estão dentro de objetos bassline no state
|
||||||
|
// (Esta lógica de exportação é básica e pode precisar de ajustes se você editar muito os instrumentos internos)
|
||||||
const tracksXml = appState.pattern.tracks
|
const tracksXml = appState.pattern.tracks
|
||||||
.filter(t => t.type !== 'bassline')
|
.flatMap(track => {
|
||||||
|
if (track.type === 'bassline') return track.instruments;
|
||||||
|
return [track];
|
||||||
|
})
|
||||||
|
.filter(t => t && t.type !== 'bassline')
|
||||||
.map((track) => createTrackXml(track))
|
.map((track) => createTrackXml(track))
|
||||||
.join("");
|
.join("");
|
||||||
|
|
||||||
|
|
@ -434,7 +493,11 @@ function generateNewMmp() {
|
||||||
const num_bars = document.getElementById("bars-input").value;
|
const num_bars = document.getElementById("bars-input").value;
|
||||||
|
|
||||||
const tracksXml = appState.pattern.tracks
|
const tracksXml = appState.pattern.tracks
|
||||||
.filter(t => t.type !== 'bassline')
|
.flatMap(track => {
|
||||||
|
if (track.type === 'bassline') return track.instruments;
|
||||||
|
return [track];
|
||||||
|
})
|
||||||
|
.filter(t => t && t.type !== 'bassline')
|
||||||
.map((track) => createTrackXml(track))
|
.map((track) => createTrackXml(track))
|
||||||
.join("");
|
.join("");
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue