playlist funcional. inserindo loops de uma mesma faixa de pattern

This commit is contained in:
JotaChina committed 2025-12-25 17:10:46 -03:00
1 parent c22a6a4bf7
commit 34138a4e8d
2 files changed
+72 -2

No files matched your search

+66
View File
@@ -277,6 +277,47 @@ export function renderAudioEditor() {
});
}
function getLoopStepsForBasslineLane(basslineTrack) {
const patternIndex = basslineTrack.patternIndex ?? 0;
// pega os instrumentos que pertencem a esse rack (mesma lógica do pattern_ui) :contentReference[oaicite:1]{index=1}
const srcId = basslineTrack.instrumentSourceId || basslineTrack.id;
const children = (appState.pattern.tracks || []).filter(
(t) => t.type !== "bassline" && t.parentBasslineId === srcId && !t.muted
);
let maxSteps = 0;
for (const t of children) {
const p = t.patterns?.[patternIndex];
if (!p) continue;
if (Array.isArray(p.steps) && p.steps.length > 0) {
maxSteps = Math.max(maxSteps, p.steps.length);
continue;
}
// fallback pra patterns que só têm notes
if (Array.isArray(p.notes) && p.notes.length > 0) {
let endTick = 0;
for (const n of p.notes) {
const pos = Number(n.pos) || 0;
const len = Math.max(0, Number(n.len) || 0);
endTick = Math.max(endTick, pos + len);
}
const steps = Math.ceil(endTick / TICKS_PER_STEP);
maxSteps = Math.max(maxSteps, steps);
}
}
if (maxSteps <= 0) maxSteps = 16; // default
// arredonda pra múltiplo de 16 (bem “LMMS feel”)
maxSteps = Math.ceil(maxSteps / 16) * 16;
return maxSteps;
}
tracksToRender.forEach((trackData) => {
const audioTrackLane = document.createElement("div");
audioTrackLane.className = "audio-track-lane";
@@ -369,6 +410,29 @@ export function renderAudioEditor() {
clipDiv.style.left = `${leftPos}px`;
clipDiv.style.width = `${widthDim}px`;
clipDiv.style.height = "100%";
// ✅ overlay de “marquinhas pretas” (loop do pattern)
const loopSteps = getLoopStepsForBasslineLane(trackData);
const loopPx = loopSteps * stepWidthPx;
if (loopPx > 0) {
clipDiv.style.position = "absolute"; // garante
const markers = document.createElement("div");
markers.style.position = "absolute";
markers.style.inset = "0";
markers.style.pointerEvents = "none";
markers.style.opacity = "0.9";
markers.style.backgroundImage = `repeating-linear-gradient(
to right,
rgba(0,0,0,0.75) 0px,
rgba(0,0,0,0.75) 2px,
transparent 2px,
transparent ${loopPx}px
)`;
// deixa o texto por cima
markers.style.zIndex = "6";
clipDiv.appendChild(markers);
}
const gridStyle = getComputedStyle(grid);
clipDiv.style.backgroundImage = gridStyle.backgroundImage;
clipDiv.style.backgroundSize = gridStyle.backgroundSize;
@@ -391,6 +455,8 @@ export function renderAudioEditor() {
label.style.pointerEvents = "none";
label.style.whiteSpace = "nowrap";
label.style.overflow = "hidden";
label.style.position = "relative";
label.style.zIndex = "7";
clipDiv.appendChild(label);
clipDiv.addEventListener("dblclick", (e) => {