tentando obter playlist real do projeto mmp

This commit is contained in:
JotaChina committed 2025-12-20 13:54:50 -03:00
1 parent aa084edcb2
commit 3d5daea9fb
20 files changed
+767601 -376210

No files matched your search

+30 -40
View File
@@ -27,7 +27,7 @@ export function renderAudioEditor() {
if (!audioEditor || !existingTrackContainer) return;
// --- CORREÇÃO DO ERRO DOMException ---
// --- Identifica o pai real do container ---
const tracksParent = existingTrackContainer.parentElement;
// --- CRIAÇÃO E RENDERIZAÇÃO DA RÉGUA ---
@@ -235,12 +235,24 @@ export function renderAudioEditor() {
tracksParent.replaceChild(newTrackContainer, existingTrackContainer);
// === RENDERIZAÇÃO DAS PISTAS (LANES) ===
appState.audio.tracks.forEach((trackData) => {
// CORREÇÃO: Junta as pistas de áudio com as Basslines (que estão no Pattern State)
const tracksToRender = [...(appState.audio.tracks || [])];
if (appState.pattern && appState.pattern.tracks) {
appState.pattern.tracks.forEach(pTrack => {
// Adiciona se for bassline e ainda não existir na lista
if (pTrack.type === 'bassline' && !tracksToRender.find(t => t.id === pTrack.id)) {
tracksToRender.push(pTrack);
}
});
}
tracksToRender.forEach((trackData) => {
const audioTrackLane = document.createElement("div");
audioTrackLane.className = "audio-track-lane";
audioTrackLane.dataset.trackId = trackData.id;
// Ícone dinâmico baseado no tipo
// Ícone dinâmico
let iconHTML = '<i class="fa-solid fa-music"></i>';
if(trackData.type === 'bassline') iconHTML = '<i class="fa-solid fa-th-large" title="Bassline"></i>';
@@ -267,12 +279,12 @@ export function renderAudioEditor() {
const timelineContainer = audioTrackLane.querySelector(".timeline-container");
const grid = timelineContainer.querySelector(".spectrogram-view-grid");
// Configura variáveis CSS para a grade
// Configura variáveis CSS
grid.style.setProperty("--step-width", `${stepWidthPx}px`);
grid.style.setProperty("--beat-width", `${beatWidthPx}px`);
grid.style.setProperty("--bar-width", `${barWidthPx}px`);
// --- LÓGICA DE DRAG & DROP (Para Samples de Áudio) ---
// Drag & Drop
timelineContainer.addEventListener("dragover", (e) => {
e.preventDefault();
audioTrackLane.classList.add("drag-over");
@@ -308,18 +320,14 @@ export function renderAudioEditor() {
}
});
// =================================================================
// 👇 ADIÇÃO: RENDERIZAÇÃO DOS CLIPES DE BASSLINE (Blocos Azuis)
// =================================================================
// --- RENDERIZAÇÃO DOS CLIPES DE BASSLINE (Blocos Azuis) ---
if (trackData.type === "bassline" && trackData.playlist_clips) {
trackData.playlist_clips.forEach(clip => {
const clipDiv = document.createElement("div");
clipDiv.className = "timeline-clip bassline-clip"; // Use CSS para cor
clipDiv.className = "timeline-clip bassline-clip";
// CONVERSÃO DE TICKS (MMP) PARA PIXELS (UI)
// No LMMS: 1 passo (step) = 12 ticks.
// stepWidthPx é a largura de 1 passo na interface atual (com zoom).
// Logo: Pixels = (Ticks / 12) * stepWidthPx
// CONVERSÃO MMP (192 ticks/compasso?) vs StepWidth
// Se stepWidthPx representa 1/16, e cada step tem 12 ticks
const steps = clip.pos / 12;
const lengthInSteps = clip.len / 12;
@@ -330,14 +338,13 @@ export function renderAudioEditor() {
clipDiv.style.left = `${leftPos}px`;
clipDiv.style.width = `${widthDim}px`;
clipDiv.style.height = "100%";
clipDiv.style.backgroundColor = "rgba(0, 170, 170, 0.6)"; // Teal LMMS
clipDiv.style.backgroundColor = "rgba(0, 170, 170, 0.6)";
clipDiv.style.border = "1px solid #00aaaa";
clipDiv.style.boxSizing = "border-box";
clipDiv.style.cursor = "pointer";
clipDiv.style.zIndex = "5"; // Garante que fique clicável
clipDiv.style.zIndex = "5";
clipDiv.title = `${clip.name} (Pos: ${clip.pos})`;
// Label pequeno
const label = document.createElement("span");
label.innerText = clip.name;
label.style.fontSize = "0.7rem";
@@ -348,7 +355,6 @@ export function renderAudioEditor() {
label.style.overflow = "hidden";
clipDiv.appendChild(label);
// INTERAÇÃO: Clique duplo para abrir o editor de patterns
clipDiv.addEventListener("dblclick", (e) => {
e.stopPropagation();
if (window.openPatternEditor) {
@@ -358,19 +364,19 @@ export function renderAudioEditor() {
}
});
// Adiciona ao Grid da timeline
grid.appendChild(clipDiv);
});
}
});
// 👆 FIM DA ADIÇÃO
// === RENDERIZAÇÃO DE CLIPES DE ÁUDIO (Samples Editáveis) ===
// === RENDERIZAÇÃO DE CLIPES DE ÁUDIO (Samples) ===
appState.audio.clips.forEach((clip) => {
// Busca a pista correta (pode ser nova ou antiga)
const parentGrid = newTrackContainer.querySelector(
`.audio-track-lane[data-track-id="${clip.trackId}"] .spectrogram-view-grid`
);
if (!parentGrid) return;
if (!parentGrid) return; // Se o clipe aponta pra uma pista que não existe, ignora
const clipElement = document.createElement("div");
clipElement.className = "timeline-clip";
clipElement.dataset.clipId = clip.id;
@@ -390,7 +396,6 @@ export function renderAudioEditor() {
clipElement.innerHTML = ` <div class="clip-resize-handle left"></div> <span class="clip-name">${clip.name} ${pitchStr}</span> <canvas class="waveform-canvas-clip"></canvas> <div class="clip-resize-handle right"></div> `;
// Visualização de Steps (Pattern Clip)
if (
clip.patternData &&
Array.isArray(clip.patternData) &&
@@ -409,7 +414,6 @@ export function renderAudioEditor() {
parentGrid.appendChild(clipElement);
// Renderização do Canvas (Waveform)
if (clip.buffer) {
const canvas = clipElement.querySelector(".waveform-canvas-clip");
const canvasWidth = (clip.durationInSeconds || 0) * pixelsPerSecond;
@@ -432,7 +436,6 @@ export function renderAudioEditor() {
}
}
// Wheel listener (pitch)
clipElement.addEventListener("wheel", (e) => {
e.preventDefault();
const clipToUpdate = appState.audio.clips.find(
@@ -472,7 +475,6 @@ export function renderAudioEditor() {
document.getElementById("ruler-context-menu").style.display = "none";
const clipElement = e.target.closest(".timeline-clip");
// Desseleciona se clicar fora
if (!clipElement && e.button !== 2) {
if (appState.global.selectedClipId) {
appState.global.selectedClipId = null;
@@ -486,7 +488,7 @@ export function renderAudioEditor() {
const handle = e.target.closest(".clip-resize-handle");
// Slice Tool
if (appState.global.sliceToolActive && clipElement && !clipElement.classList.contains("bassline-clip")) { // Protege bassline
if (appState.global.sliceToolActive && clipElement && !clipElement.classList.contains("bassline-clip")) {
e.preventDefault();
e.stopPropagation();
const clipId = clipElement.dataset.clipId;
@@ -510,7 +512,7 @@ export function renderAudioEditor() {
return;
}
// Resize Handle (Apenas para Audio Clips por enquanto)
// Resize Handle
if (handle) {
e.preventDefault();
e.stopPropagation();
@@ -553,8 +555,6 @@ export function renderAudioEditor() {
clipElement.style.width = `${newWidthFinalPx}px`;
}
} else if (appState.global.resizeMode === "stretch") {
// (Lógica de Stretch omitida por brevidade, mas mantida igual ao original)
// ... (mantido igual ao original)
if (handleType === "right") {
let newWidthPx = initialWidthPx + deltaX;
let newDuration = newWidthPx / currentPixelsPerSecond;
@@ -578,7 +578,6 @@ export function renderAudioEditor() {
const onMouseUp = (upEvent) => {
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseup", onMouseUp);
// Aplicação das mudanças (mantida lógica original)
const finalLeftPx = clipElement.offsetLeft;
const finalWidthPx = clipElement.offsetWidth;
const newStartTime = finalLeftPx / currentPixelsPerSecond;
@@ -594,7 +593,6 @@ export function renderAudioEditor() {
sendActionSafe({ type: "UPDATE_AUDIO_CLIP", clipId, props: { startTimeInSeconds: newStartTime, durationInSeconds: newDuration, offset: newOffset, pitch: 0 } });
}
} else {
// Stretch Logic update
const newPlaybackRate = initialOriginalDuration / newDuration;
const newPitch = 12 * Math.log2(newPlaybackRate);
if(handleType === "right") {
@@ -613,7 +611,7 @@ export function renderAudioEditor() {
return;
}
// Drag Clip (Audio apenas, por enquanto)
// Drag Clip (Audio apenas)
if (clipElement && !clipElement.classList.contains("bassline-clip")) {
const clipId = clipElement.dataset.clipId;
if (appState.global.selectedClipId !== clipId) {
@@ -695,7 +693,6 @@ export function renderAudioEditor() {
if (!menu) return;
const clipElement = e.target.closest(".timeline-clip");
// Itens do menu
const copyItem = document.getElementById("copy-clip");
const cutItem = document.getElementById("cut-clip");
const pasteItem = document.getElementById("paste-clip");
@@ -705,7 +702,6 @@ export function renderAudioEditor() {
pasteItem.style.display = canPaste ? "block" : "none";
if (clipElement) {
// Bloqueia ações em Bassline clips por enquanto (pois são read-only na playlist)
if(clipElement.classList.contains("bassline-clip")) {
menu.style.display = "none";
return;
@@ -750,7 +746,6 @@ export function renderAudioEditor() {
});
}
// Helper para envio seguro
function sendActionSafe(action) {
try {
sendAction(action);
@@ -759,7 +754,6 @@ function sendActionSafe(action) {
}
}
// Funções de UI
export function updateAudioEditorUI() {
const playBtn = document.getElementById("audio-editor-play-btn");
if (!playBtn) return;
@@ -782,10 +776,6 @@ export function resetPlayheadVisual() {
});
}
/**
* Cria o elemento HTML (e seus filhos) para a visualização
* dos steps de um pattern clip.
*/
function createPatternViewElement(patternData) {
const view = document.createElement("div");
view.className = "pattern-clip-view";