tentando melhorar a abertura dos arquivos no MMPCreator
Deploy / Deploy (push) Successful in 2m19s
Details
Deploy / Deploy (push) Successful in 2m19s
Details
This commit is contained in:
parent
be3e1ff9e9
commit
44abcf855a
|
|
@ -3,7 +3,6 @@
|
||||||
- 210424.wav
|
- 210424.wav
|
||||||
- 43yu.wav
|
- 43yu.wav
|
||||||
- 4r3st.wav
|
- 4r3st.wav
|
||||||
- 618.wav
|
|
||||||
- 7-is-the-answer-060224.wav
|
- 7-is-the-answer-060224.wav
|
||||||
- advait.wav
|
- advait.wav
|
||||||
- aelig.wav
|
- aelig.wav
|
||||||
|
|
|
||||||
|
|
@ -3147,6 +3147,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Teste_Testes": {
|
"Teste_Testes": {
|
||||||
|
"gravacao_17-14-15.ogg": {
|
||||||
|
"_isFile": true
|
||||||
|
},
|
||||||
"gravacao_22-04-40.ogg": {
|
"gravacao_22-04-40.ogg": {
|
||||||
"_isFile": true
|
"_isFile": true
|
||||||
},
|
},
|
||||||
|
|
|
||||||
BIN
_data/users.db
BIN
_data/users.db
Binary file not shown.
204
creation.html
204
creation.html
|
|
@ -12,13 +12,12 @@
|
||||||
<link rel="stylesheet" href="./assets/css/creator.css" />
|
<link rel="stylesheet" href="./assets/css/creator.css" />
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* Estilo para clipes de pattern */
|
/* --- ESTILOS ORIGINAIS --- */
|
||||||
.timeline-clip.pattern-clip {
|
.timeline-clip.pattern-clip {
|
||||||
background: linear-gradient(to bottom, #4a4f57, #3b3f45);
|
background: linear-gradient(to bottom, #4a4f57, #3b3f45);
|
||||||
height: 70px; /* Mais alto para ver as notas */
|
height: 70px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
/* Container para as notas do pattern */
|
|
||||||
.pattern-clip-view {
|
.pattern-clip-view {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
@ -32,13 +31,11 @@
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
gap: 1px;
|
gap: 1px;
|
||||||
}
|
}
|
||||||
/* Linha de trilha dentro do clipe */
|
|
||||||
.pattern-clip-track-row {
|
.pattern-clip-track-row {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
/* Cada "nota" (bloco branco) */
|
|
||||||
.pattern-step-note {
|
.pattern-step-note {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background-color: rgba(255, 255, 255, 0.9);
|
background-color: rgba(255, 255, 255, 0.9);
|
||||||
|
|
@ -47,7 +44,6 @@
|
||||||
border-radius: 1px;
|
border-radius: 1px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
/* Menu de contexto */
|
|
||||||
#timeline-context-menu .menu-divider {
|
#timeline-context-menu .menu-divider {
|
||||||
height: 1px;
|
height: 1px;
|
||||||
background-color: var(--border-color);
|
background-color: var(--border-color);
|
||||||
|
|
@ -67,6 +63,56 @@
|
||||||
color: var(--text-dark);
|
color: var(--text-dark);
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --- NOVOS ESTILOS PARA O BASSLINE EDITOR (Lógica 3) --- */
|
||||||
|
|
||||||
|
/* Linha do instrumento (Nome à esquerda) */
|
||||||
|
.instrument-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 40px;
|
||||||
|
border-bottom: 1px solid #333;
|
||||||
|
padding-left: 10px;
|
||||||
|
background-color: #2b2b2b;
|
||||||
|
color: #ddd;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Linha dos steps (Botões à direita) */
|
||||||
|
.steps-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 40px;
|
||||||
|
border-bottom: 1px solid #333;
|
||||||
|
padding-left: 5px;
|
||||||
|
background-color: #222; /* Fundo ligeiramente diferente para distinguir */
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Botão individual do Step */
|
||||||
|
.step-btn {
|
||||||
|
width: 20px;
|
||||||
|
height: 30px;
|
||||||
|
margin-right: 2px;
|
||||||
|
background-color: #444;
|
||||||
|
border: 1px solid #555;
|
||||||
|
border-radius: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-btn:hover {
|
||||||
|
border-color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Estado Ativo (Ligado) */
|
||||||
|
.step-btn.active {
|
||||||
|
background-color: #0f0; /* Verde LMMS */
|
||||||
|
box-shadow: 0 0 4px rgba(0, 255, 0, 0.4);
|
||||||
|
border-color: #0c0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -332,6 +378,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="sequencer-grid" class="sequencer-container"></div>
|
<div id="sequencer-grid" class="sequencer-container"></div>
|
||||||
|
|
||||||
<div class="tool-icons"></div>
|
<div class="tool-icons"></div>
|
||||||
<div id="timeline-context-menu">
|
<div id="timeline-context-menu">
|
||||||
<div id="copy-clip">Copiar</div>
|
<div id="copy-clip">Copiar</div>
|
||||||
|
|
@ -348,6 +395,7 @@
|
||||||
<div id="ruler-set-loop-end">Definir Fim do Loop</div>
|
<div id="ruler-set-loop-end">Definir Fim do Loop</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="track-container"></div>
|
<div id="track-container"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -565,7 +613,88 @@
|
||||||
const previewSynth = new Tone.PolySynth(Tone.Synth).toDestination();
|
const previewSynth = new Tone.PolySynth(Tone.Synth).toDestination();
|
||||||
previewSynth.volume.value = -10;
|
previewSynth.volume.value = -10;
|
||||||
|
|
||||||
// --- FUNÇÃO GLOBAL PARA ABRIR O EDITOR ---
|
// =======================================================
|
||||||
|
// LÓGICA 3: FUNÇÃO PARA ABRIR O EDITOR DE BASSLINE
|
||||||
|
// Esta função popula a área superior (Beat Editor)
|
||||||
|
// quando se clica duas vezes num clipe da playlist.
|
||||||
|
// =======================================================
|
||||||
|
|
||||||
|
window.openPatternEditor = function(basslineTrack) {
|
||||||
|
console.log("Abrindo editor para:", basslineTrack.track_name);
|
||||||
|
|
||||||
|
// 1. Identificar containers
|
||||||
|
// No seu HTML, 'sequencer-grid' está em cima e 'track-container' embaixo (na toolbar e body do editor)
|
||||||
|
const nameContainer = document.getElementById("track-container");
|
||||||
|
const stepsContainer = document.getElementById("sequencer-grid");
|
||||||
|
|
||||||
|
if(!nameContainer || !stepsContainer) {
|
||||||
|
console.error("Containers do editor não encontrados!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Limpar
|
||||||
|
nameContainer.innerHTML = "";
|
||||||
|
stepsContainer.innerHTML = "";
|
||||||
|
|
||||||
|
// 3. Iterar sobre os instrumentos internos
|
||||||
|
const instruments = basslineTrack.instruments || [];
|
||||||
|
|
||||||
|
if (instruments.length === 0) {
|
||||||
|
nameContainer.innerHTML = "<div style='padding:10px; color:#ccc'>Nenhum instrumento.</div>";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
instruments.forEach(inst => {
|
||||||
|
// --- A. Nome do Instrumento (Coluna Esquerda) ---
|
||||||
|
const nameRow = document.createElement("div");
|
||||||
|
nameRow.className = "instrument-row";
|
||||||
|
|
||||||
|
// Texto do nome
|
||||||
|
const label = document.createElement("span");
|
||||||
|
label.innerText = inst.instrument_name || inst.plugin_name || "Sem Nome";
|
||||||
|
nameRow.appendChild(label);
|
||||||
|
|
||||||
|
nameContainer.appendChild(nameRow);
|
||||||
|
|
||||||
|
// --- B. Steps (Coluna Direita - Grid) ---
|
||||||
|
// Recupera steps (True/False array)
|
||||||
|
let stepData = [];
|
||||||
|
if (inst.patterns && inst.patterns.length > 0) {
|
||||||
|
stepData = inst.patterns[0].steps;
|
||||||
|
} else {
|
||||||
|
stepData = Array(16).fill(false); // Default
|
||||||
|
}
|
||||||
|
|
||||||
|
const stepsRow = document.createElement("div");
|
||||||
|
stepsRow.className = "steps-row";
|
||||||
|
|
||||||
|
stepData.forEach((isActive, index) => {
|
||||||
|
const stepBtn = document.createElement("div");
|
||||||
|
stepBtn.className = "step-btn";
|
||||||
|
if (isActive) stepBtn.classList.add("active");
|
||||||
|
|
||||||
|
// Interação de Clique (Toggle)
|
||||||
|
stepBtn.addEventListener("click", () => {
|
||||||
|
// Inverte estado
|
||||||
|
const newState = !stepBtn.classList.contains("active");
|
||||||
|
|
||||||
|
if(newState) stepBtn.classList.add("active");
|
||||||
|
else stepBtn.classList.remove("active");
|
||||||
|
|
||||||
|
// Atualiza dado em memória
|
||||||
|
if(!inst.patterns) inst.patterns = [{steps: []}];
|
||||||
|
if(!inst.patterns[0]) inst.patterns[0] = {steps: []};
|
||||||
|
inst.patterns[0].steps[index] = newState;
|
||||||
|
});
|
||||||
|
|
||||||
|
stepsRow.appendChild(stepBtn);
|
||||||
|
});
|
||||||
|
|
||||||
|
stepsContainer.appendChild(stepsRow);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- FUNÇÃO GLOBAL PARA ABRIR O PIANO ROLL (JÁ EXISTENTE) ---
|
||||||
window.openPianoRoll = function (trackId) {
|
window.openPianoRoll = function (trackId) {
|
||||||
const track = appState.pattern.tracks.find((t) => t.id === trackId);
|
const track = appState.pattern.tracks.find((t) => t.id === trackId);
|
||||||
if (!track) return;
|
if (!track) return;
|
||||||
|
|
@ -585,12 +714,10 @@
|
||||||
gridContainer.scrollTop = middleY - 200;
|
gridContainer.scrollTop = middleY - 200;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- DESENHO E LÓGICA ---
|
// --- DESENHO E LÓGICA DO PIANO ROLL ---
|
||||||
|
|
||||||
function resizeCanvas() {
|
function resizeCanvas() {
|
||||||
const totalHeight = CONSTANTS.TOTAL_KEYS * CONSTANTS.NOTE_HEIGHT;
|
const totalHeight = CONSTANTS.TOTAL_KEYS * CONSTANTS.NOTE_HEIGHT;
|
||||||
// 64 compassos * 192 ticks / (ticks por beat) * largura... simplificando:
|
|
||||||
// Vamos fixar uma largura grande por enquanto
|
|
||||||
const totalWidth = 3000;
|
const totalWidth = 3000;
|
||||||
|
|
||||||
keysCanvas.width = CONSTANTS.KEY_WIDTH;
|
keysCanvas.width = CONSTANTS.KEY_WIDTH;
|
||||||
|
|
@ -598,10 +725,6 @@
|
||||||
gridCanvas.width = totalWidth;
|
gridCanvas.width = totalWidth;
|
||||||
gridCanvas.height = totalHeight;
|
gridCanvas.height = totalHeight;
|
||||||
|
|
||||||
// Importante: Sincronizar a conversão de Pixel <-> Tick
|
|
||||||
// 1 Beat = 48 ticks (em 16th) ou 192 ticks por bar?
|
|
||||||
// No seu file.js: ticksPerStep = 12 (1/16).
|
|
||||||
// Então BEAT_WIDTH (40px) = 4 steps = 48 ticks.
|
|
||||||
CONSTANTS.TICKS_PER_PIXEL = 48 / CONSTANTS.BEAT_WIDTH;
|
CONSTANTS.TICKS_PER_PIXEL = 48 / CONSTANTS.BEAT_WIDTH;
|
||||||
|
|
||||||
drawKeys();
|
drawKeys();
|
||||||
|
|
@ -674,13 +797,9 @@
|
||||||
gridCtx.strokeStyle = "#000";
|
gridCtx.strokeStyle = "#000";
|
||||||
|
|
||||||
notes.forEach((note) => {
|
notes.forEach((note) => {
|
||||||
// Converter MIDI para Y (Invertido)
|
|
||||||
const keyIndex =
|
const keyIndex =
|
||||||
CONSTANTS.TOTAL_KEYS - 1 - (note.key - CONSTANTS.START_NOTE);
|
CONSTANTS.TOTAL_KEYS - 1 - (note.key - CONSTANTS.START_NOTE);
|
||||||
const y = keyIndex * CONSTANTS.NOTE_HEIGHT;
|
const y = keyIndex * CONSTANTS.NOTE_HEIGHT;
|
||||||
|
|
||||||
// Converter Ticks (pos) para X
|
|
||||||
// Se 48 ticks = BEAT_WIDTH (40px) -> pos / 1.2
|
|
||||||
const x = note.pos / CONSTANTS.TICKS_PER_PIXEL;
|
const x = note.pos / CONSTANTS.TICKS_PER_PIXEL;
|
||||||
const width = note.len / CONSTANTS.TICKS_PER_PIXEL;
|
const width = note.len / CONSTANTS.TICKS_PER_PIXEL;
|
||||||
|
|
||||||
|
|
@ -694,7 +813,6 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- INTERAÇÃO: CRIAR NOTAS ---
|
|
||||||
gridCanvas.addEventListener("mousedown", (e) => {
|
gridCanvas.addEventListener("mousedown", (e) => {
|
||||||
if (!currentTrackId) return;
|
if (!currentTrackId) return;
|
||||||
|
|
||||||
|
|
@ -702,47 +820,34 @@
|
||||||
const x = e.clientX - rect.left;
|
const x = e.clientX - rect.left;
|
||||||
const y = e.clientY - rect.top;
|
const y = e.clientY - rect.top;
|
||||||
|
|
||||||
// 1. Calcular Nota (Y)
|
|
||||||
const keyIndex = Math.floor(y / CONSTANTS.NOTE_HEIGHT);
|
const keyIndex = Math.floor(y / CONSTANTS.NOTE_HEIGHT);
|
||||||
const midiNote =
|
const midiNote =
|
||||||
CONSTANTS.START_NOTE + (CONSTANTS.TOTAL_KEYS - 1 - keyIndex);
|
CONSTANTS.START_NOTE + (CONSTANTS.TOTAL_KEYS - 1 - keyIndex);
|
||||||
|
|
||||||
// 2. Calcular Posição (X) e Snap
|
|
||||||
// Snap padrão 1/16 = 12 ticks
|
|
||||||
const snapTicks = 12;
|
const snapTicks = 12;
|
||||||
const rawTicks = x * CONSTANTS.TICKS_PER_PIXEL;
|
const rawTicks = x * CONSTANTS.TICKS_PER_PIXEL;
|
||||||
const quantizedPos = Math.floor(rawTicks / snapTicks) * snapTicks;
|
const quantizedPos = Math.floor(rawTicks / snapTicks) * snapTicks;
|
||||||
|
|
||||||
// 3. Criar Objeto Nota
|
|
||||||
const newNote = {
|
const newNote = {
|
||||||
pos: quantizedPos,
|
pos: quantizedPos,
|
||||||
len: 48, // Duração padrão (1 beat/seminima) - ajuste conforme desejar
|
len: 48,
|
||||||
key: midiNote,
|
key: midiNote,
|
||||||
vol: 100,
|
vol: 100,
|
||||||
pan: 0,
|
pan: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 4. Atualizar Estado e Redesenhar
|
|
||||||
const track = appState.pattern.tracks.find(
|
const track = appState.pattern.tracks.find(
|
||||||
(t) => t.id === currentTrackId
|
(t) => t.id === currentTrackId
|
||||||
);
|
);
|
||||||
if (track) {
|
if (track) {
|
||||||
const pattern = track.patterns[track.activePatternIndex];
|
const pattern = track.patterns[track.activePatternIndex];
|
||||||
|
|
||||||
// Se não existir array de notas, cria
|
|
||||||
if (!pattern.notes) pattern.notes = [];
|
if (!pattern.notes) pattern.notes = [];
|
||||||
|
|
||||||
pattern.notes.push(newNote);
|
pattern.notes.push(newNote);
|
||||||
|
|
||||||
// Toca som
|
|
||||||
const noteName = Tone.Frequency(midiNote, "midi").toNote();
|
const noteName = Tone.Frequency(midiNote, "midi").toNote();
|
||||||
previewSynth.triggerAttackRelease(noteName, "8n");
|
previewSynth.triggerAttackRelease(noteName, "8n");
|
||||||
|
|
||||||
// Redesenha Piano Roll
|
|
||||||
drawNotes();
|
drawNotes();
|
||||||
|
|
||||||
// IMPORTANTE: Atualizar a UI da lista de trilhas (para aparecer a miniatura)
|
|
||||||
// E enviar via Socket para colaboradores
|
|
||||||
renderAll();
|
renderAll();
|
||||||
sendAction({
|
sendAction({
|
||||||
type: "UPDATE_PATTERN_NOTES",
|
type: "UPDATE_PATTERN_NOTES",
|
||||||
|
|
@ -753,12 +858,10 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Scroll Sync
|
|
||||||
gridContainer.addEventListener("scroll", () => {
|
gridContainer.addEventListener("scroll", () => {
|
||||||
keysContainer.scrollTop = gridContainer.scrollTop;
|
keysContainer.scrollTop = gridContainer.scrollTop;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fechar
|
|
||||||
document
|
document
|
||||||
.getElementById("close-piano-roll-btn")
|
.getElementById("close-piano-roll-btn")
|
||||||
.addEventListener("click", () => {
|
.addEventListener("click", () => {
|
||||||
|
|
@ -778,27 +881,18 @@
|
||||||
|
|
||||||
if (downloadBtn) {
|
if (downloadBtn) {
|
||||||
downloadBtn.addEventListener("click", () => {
|
downloadBtn.addEventListener("click", () => {
|
||||||
// 1. Pega o parâmetro 'project' da URL (ex: creation.html?project=drake)
|
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
let projectName = params.get("project");
|
let projectName = params.get("project");
|
||||||
|
|
||||||
if (projectName) {
|
if (projectName) {
|
||||||
// 2. Garante a extensão para a API (opcional, mas seguro)
|
|
||||||
if (!projectName.toLowerCase().endsWith(".mmp")) {
|
if (!projectName.toLowerCase().endsWith(".mmp")) {
|
||||||
projectName += ".mmp";
|
projectName += ".mmp";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Monta a URL da API Python e inicia o download
|
|
||||||
const apiUrl = `/api/download/${projectName}`;
|
const apiUrl = `/api/download/${projectName}`;
|
||||||
|
|
||||||
// Feedback visual rápido
|
|
||||||
downloadBtn.style.opacity = "0.5";
|
downloadBtn.style.opacity = "0.5";
|
||||||
setTimeout(() => downloadBtn.style.opacity = "1", 500);
|
setTimeout(() => downloadBtn.style.opacity = "1", 500);
|
||||||
|
|
||||||
// Dispara o download
|
|
||||||
window.location.href = apiUrl;
|
window.location.href = apiUrl;
|
||||||
} else {
|
} else {
|
||||||
// Caso o usuário tenha entrado direto em creation.html sem parâmetro
|
|
||||||
alert("Nenhum projeto selecionado na URL. Abra ou Salve um projeto primeiro.");
|
alert("Nenhum projeto selecionado na URL. Abra ou Salve um projeto primeiro.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -806,44 +900,35 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
// --- LÓGICA DE UPLOAD DE SAMPLE AVULSO ---
|
|
||||||
const uploadSampleBtn = document.getElementById("upload-sample-btn");
|
const uploadSampleBtn = document.getElementById("upload-sample-btn");
|
||||||
const sampleInput = document.getElementById("sample-file-input");
|
const sampleInput = document.getElementById("sample-file-input");
|
||||||
|
|
||||||
if (uploadSampleBtn && sampleInput) {
|
if (uploadSampleBtn && sampleInput) {
|
||||||
|
|
||||||
// 1. Botão clica no input invisível
|
|
||||||
uploadSampleBtn.addEventListener("click", () => {
|
uploadSampleBtn.addEventListener("click", () => {
|
||||||
sampleInput.click();
|
sampleInput.click();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 2. Quando o arquivo é selecionado
|
|
||||||
sampleInput.addEventListener("change", async () => {
|
sampleInput.addEventListener("change", async () => {
|
||||||
if (sampleInput.files.length === 0) return;
|
if (sampleInput.files.length === 0) return;
|
||||||
|
|
||||||
const file = sampleInput.files[0];
|
const file = sampleInput.files[0];
|
||||||
|
|
||||||
// Pergunta a categoria para organizar no servidor (opcional)
|
|
||||||
// O backend usa isso para criar pastas: samples/drums, samples/vocals, etc.
|
|
||||||
const category = prompt(
|
const category = prompt(
|
||||||
"Em qual categoria este sample se encaixa? (Ex: drums, effects, vocals)",
|
"Em qual categoria este sample se encaixa? (Ex: drums, effects, vocals)",
|
||||||
"imported"
|
"imported"
|
||||||
);
|
);
|
||||||
|
|
||||||
if (category === null) {
|
if (category === null) {
|
||||||
// Usuário cancelou
|
|
||||||
sampleInput.value = "";
|
sampleInput.value = "";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepara o formulário
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("sample_file", file); // Deve bater com 'sample_file' no Python
|
formData.append("sample_file", file);
|
||||||
formData.append("subfolder", category); // Deve bater com 'subfolder' no Python
|
formData.append("subfolder", category);
|
||||||
|
|
||||||
// Feedback Visual (ícone girando ou ficando transparente)
|
|
||||||
const originalIcon = uploadSampleBtn.className;
|
const originalIcon = uploadSampleBtn.className;
|
||||||
uploadSampleBtn.className = "fa-solid fa-spinner fa-spin"; // Ícone de loading
|
uploadSampleBtn.className = "fa-solid fa-spinner fa-spin";
|
||||||
uploadSampleBtn.style.pointerEvents = "none";
|
uploadSampleBtn.style.pointerEvents = "none";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -856,8 +941,6 @@
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
alert("Sucesso! " + result.message);
|
alert("Sucesso! " + result.message);
|
||||||
// Opcional: Recarregar a lista de samples lateral se você tiver uma função para isso
|
|
||||||
// reloadBrowser();
|
|
||||||
} else {
|
} else {
|
||||||
alert("Erro ao enviar: " + (result.error || "Desconhecido"));
|
alert("Erro ao enviar: " + (result.error || "Desconhecido"));
|
||||||
}
|
}
|
||||||
|
|
@ -866,7 +949,6 @@
|
||||||
console.error("Erro no upload:", error);
|
console.error("Erro no upload:", error);
|
||||||
alert("Erro de conexão com o servidor.");
|
alert("Erro de conexão com o servidor.");
|
||||||
} finally {
|
} finally {
|
||||||
// Restaura o botão e limpa o input
|
|
||||||
uploadSampleBtn.className = originalIcon;
|
uploadSampleBtn.className = originalIcon;
|
||||||
uploadSampleBtn.style.pointerEvents = "auto";
|
uploadSampleBtn.style.pointerEvents = "auto";
|
||||||
sampleInput.value = "";
|
sampleInput.value = "";
|
||||||
|
|
@ -876,12 +958,10 @@
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
|
|
||||||
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.7.77/Tone.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.7.77/Tone.js"></script>
|
||||||
<script src="assets/js/creations/main.js" type="module"></script>
|
<script src="assets/js/creations/main.js" type="module"></script>
|
||||||
<script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
|
<script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
|
||||||
<script src="assets/js/creations/socket.js" type="module"></script>
|
<script src="assets/js/creations/socket.js" type="module"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -64,6 +64,26 @@ def parse_mmp_file(file_path):
|
||||||
elif track_type == "1": # Bassline (aparentemente, correto)
|
elif track_type == "1": # Bassline (aparentemente, correto)
|
||||||
bassline_info = parse_basslines(track)
|
bassline_info = parse_basslines(track)
|
||||||
if bassline_info:
|
if bassline_info:
|
||||||
|
playlist_clips = []
|
||||||
|
bbtrack = track.find("bbtrack")
|
||||||
|
if bbtrack is not None:
|
||||||
|
trackcontent = bbtrack.find("trackcontent")
|
||||||
|
if trackcontent is not None:
|
||||||
|
for pattern in trackcontent.findall("pattern"):
|
||||||
|
playlist_clips.append({
|
||||||
|
"pos": int(pattern.attrib.get("pos", 0)),
|
||||||
|
"len": int(pattern.attrib.get("len", 192)), # Padrão 1 bar
|
||||||
|
"steps": int(pattern.attrib.get("steps", 16)),
|
||||||
|
"name": track_name # O clipe leva o nome da trilha
|
||||||
|
})
|
||||||
|
# Adiciona essa lista de clipes ao objeto final
|
||||||
|
bassline_info["playlist_clips"] = playlist_clips
|
||||||
|
|
||||||
|
# Garante que o tipo e nome estão corretos no nível superior
|
||||||
|
bassline_info["type"] = "bassline"
|
||||||
|
bassline_info["track_name"] = track_name
|
||||||
|
|
||||||
|
track_info.append(bassline_info)
|
||||||
track_info.append(bassline_info)
|
track_info.append(bassline_info)
|
||||||
if bassline_info["tags"] is not None:
|
if bassline_info["tags"] is not None:
|
||||||
if "bassline" not in tags["TAG"]: # certo
|
if "bassline" not in tags["TAG"]: # certo
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue