tentando obter playlist real do projeto mmp
This commit is contained in:
1 parent
aa084edcb2
commit
3d5daea9fb
20 files changed
+767601
-376210
No files matched your search
@@ -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";
|
||||
|
||||
Reference in new issue
Block a user