playlist funcional. inserindo loops de uma mesma faixa de pattern
This commit is contained in:
1 parent
c22a6a4bf7
commit
34138a4e8d
2 files changed
+72
-2
No files matched your search
@@ -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) => {
|
||||
|
||||
Reference in new issue
Block a user