criação de novas patterns de composição nos projetos
Deploy / Deploy (push) Successful in 2m5s
Details
Deploy / Deploy (push) Successful in 2m5s
Details
This commit is contained in:
parent
17d3419475
commit
43418094f8
|
|
@ -544,31 +544,31 @@ export async function parseMmpContent(xmlString) {
|
|||
const basslineContainers = bbTrackNodes
|
||||
.map((trackNode, idx) => {
|
||||
const trackName = trackNode.getAttribute("name") || "Beat/Bassline";
|
||||
|
||||
const playlistClips = Array.from(
|
||||
trackNode.querySelectorAll(":scope > bbtco")
|
||||
).map((bbtco) => ({
|
||||
pos: parseInt(bbtco.getAttribute("pos"), 10) || 0,
|
||||
len: parseInt(bbtco.getAttribute("len"), 10) || 192,
|
||||
name: trackName,
|
||||
}));
|
||||
|
||||
// ❌ remove esta linha:
|
||||
// if (playlistClips.length === 0) return null;
|
||||
|
||||
// ✅ mantém mesmo vazia
|
||||
const playlistClips = Array.from(trackNode.querySelectorAll(":scope > bbtco")).map((bbtco, cidx) => {
|
||||
const pos = parseInt(bbtco.getAttribute("pos"), 10) || 0;
|
||||
const len = parseInt(bbtco.getAttribute("len"), 10) || 192;
|
||||
return {
|
||||
id: `bassline_${Date.now()}_${Math.random().toString(36).slice(2)}`,
|
||||
id: `plc_${idx}_${pos}_${len}_${cidx}`, // determinístico
|
||||
pos,
|
||||
len,
|
||||
name: trackName,
|
||||
type: "bassline",
|
||||
playlist_clips: playlistClips, // pode ser []
|
||||
patternIndex: idx,
|
||||
instrumentSourceId: rackId,
|
||||
volume: 1,
|
||||
pan: 0,
|
||||
patterns: [],
|
||||
isMuted: trackNode.getAttribute("muted") === "1",
|
||||
};
|
||||
});
|
||||
|
||||
// NÃO retornar null quando não tem clips:
|
||||
return {
|
||||
id: `bb_container_${idx}`,
|
||||
name: trackName,
|
||||
type: "bassline",
|
||||
patternIndex: idx,
|
||||
playlist_clips: playlistClips, // pode ser []
|
||||
patterns: [],
|
||||
isMuted: false,
|
||||
instrumentSourceId: bbRackId, // ou algo equivalente no teu parse
|
||||
volume: 1,
|
||||
pan: 0,
|
||||
};
|
||||
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
|
|
|
|||
|
|
@ -213,8 +213,27 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||
}
|
||||
});
|
||||
|
||||
//Seleção de pattern
|
||||
// --- Criar/Remover Pattern (toolbar) ---
|
||||
const addPatternBtn = document.getElementById("add-pattern-btn");
|
||||
const removePatternBtn = document.getElementById("remove-pattern-btn");
|
||||
|
||||
addPatternBtn?.addEventListener("click", () => {
|
||||
const refTrack = (appState.pattern.tracks || []).find(t => t.type !== "bassline");
|
||||
const nextIndex = refTrack?.patterns?.length ?? 0;
|
||||
|
||||
const defaultName = `Pattern ${nextIndex + 1}`;
|
||||
const name = (prompt("Nome do novo pattern:", defaultName) || defaultName).trim();
|
||||
|
||||
// cria e já seleciona
|
||||
sendAction({ type: "ADD_PATTERN", patternIndex: nextIndex, name, select: true });
|
||||
});
|
||||
|
||||
// opcional (se quiser implementar remover depois)
|
||||
removePatternBtn?.addEventListener("click", () => {
|
||||
sendAction({ type: "REMOVE_LAST_PATTERN" });
|
||||
});
|
||||
|
||||
//Seleção de pattern
|
||||
const globalPatternSelector = document.getElementById(
|
||||
"global-pattern-selector"
|
||||
);
|
||||
|
|
|
|||
|
|
@ -499,11 +499,15 @@ function _ensureBasslineForPatternIndex(patternIndex) {
|
|||
instrumentSourceId: null,
|
||||
volume: 1,
|
||||
pan: 0,
|
||||
instrumentSourceId: _getDefaultRackId(),
|
||||
};
|
||||
appState.pattern.tracks.push(b);
|
||||
}
|
||||
|
||||
if (!Array.isArray(b.playlist_clips)) b.playlist_clips = [];
|
||||
|
||||
// Isso deixa o modo focado funcionando em patterns recém-criados.
|
||||
if (!b.instrumentSourceId) b.instrumentSourceId = _getDefaultRackId();
|
||||
|
||||
// garante ids nos clips antigos
|
||||
b.playlist_clips.forEach((c) => {
|
||||
|
|
@ -513,6 +517,13 @@ function _ensureBasslineForPatternIndex(patternIndex) {
|
|||
return b;
|
||||
}
|
||||
|
||||
function _getDefaultRackId() {
|
||||
const inst = (appState.pattern.tracks || []).find(
|
||||
(t) => t.type !== "bassline" && t.parentBasslineId
|
||||
);
|
||||
return inst?.parentBasslineId ?? null;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// BROADCAST
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
@ -708,6 +719,71 @@ async function handleActionBroadcast(action) {
|
|||
break;
|
||||
}
|
||||
|
||||
case "ADD_PATTERN": {
|
||||
const who = actorOf(action);
|
||||
|
||||
const desiredIndex = Number.isFinite(Number(action.patternIndex))
|
||||
? Number(action.patternIndex)
|
||||
: null;
|
||||
|
||||
const nonBass = (appState.pattern.tracks || []).filter(t => t.type !== "bassline");
|
||||
const currentCount = nonBass.reduce((m, t) => Math.max(m, t.patterns?.length ?? 0), 0);
|
||||
|
||||
const idx = desiredIndex != null ? desiredIndex : currentCount;
|
||||
const finalName = String(action.name || `Pattern ${idx + 1}`).trim();
|
||||
|
||||
// 1) cria patterns vazios em TODAS as tracks (respeita bars-input)
|
||||
_ensurePatternsUpTo(idx);
|
||||
|
||||
// 2) garante nome/pos estáveis no índice criado
|
||||
for (const t of nonBass) {
|
||||
t.patterns[idx] = t.patterns[idx] || _makeEmptyPattern(idx);
|
||||
t.patterns[idx].name = finalName;
|
||||
if (t.patterns[idx].pos == null) t.patterns[idx].pos = idx * LMMS_BAR_TICKS;
|
||||
}
|
||||
|
||||
// 3) cria a lane "bassline" (a coluna do pattern)
|
||||
const b = _ensureBasslineForPatternIndex(idx);
|
||||
b.patternIndex = idx;
|
||||
b.name = finalName;
|
||||
if (!b.instrumentSourceId) b.instrumentSourceId = _getDefaultRackId();
|
||||
|
||||
// 4) opcional: já selecionar
|
||||
if (action.select) {
|
||||
appState.pattern.activePatternIndex = idx;
|
||||
appState.pattern.tracks.forEach((track) => (track.activePatternIndex = idx));
|
||||
}
|
||||
|
||||
renderAll();
|
||||
showToast(`➕ ${who} criou: ${finalName}`, "success");
|
||||
saveStateToSession();
|
||||
break;
|
||||
}
|
||||
|
||||
case "REMOVE_LAST_PATTERN": {
|
||||
const nonBass = (appState.pattern.tracks || []).filter(t => t.type !== "bassline");
|
||||
const count = nonBass.reduce((m, t) => Math.max(m, t.patterns?.length ?? 0), 0);
|
||||
const last = count - 1;
|
||||
if (last <= 0) break;
|
||||
|
||||
// remove patterns nas tracks
|
||||
for (const t of nonBass) t.patterns.pop();
|
||||
|
||||
// remove a lane bassline correspondente
|
||||
appState.pattern.tracks = appState.pattern.tracks.filter(
|
||||
t => !(t.type === "bassline" && Number(t.patternIndex) === last)
|
||||
);
|
||||
|
||||
// ajusta seleção
|
||||
const newIdx = Math.min(appState.pattern.activePatternIndex, last - 1);
|
||||
appState.pattern.activePatternIndex = newIdx;
|
||||
appState.pattern.tracks.forEach((t) => (t.activePatternIndex = newIdx));
|
||||
|
||||
renderAll();
|
||||
saveStateToSession();
|
||||
break;
|
||||
}
|
||||
|
||||
case "ADD_PLAYLIST_PATTERN_CLIP": {
|
||||
const { patternIndex, pos, len, clipId, name } = action;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue