inserindo server flask de upload e watchdog para verificar alterações em samples

This commit is contained in:
JotaChina committed 2025-10-07 23:01:32 -03:00
1 parent c35f3233b7
commit 8c391412e1
6 files changed
+450 -177

No files matched your search

+79 -31
View File
@@ -6,33 +6,35 @@ import {
updateTrackVolume,
updateTrackPan,
} from "./state.js";
import { playSample } from "./audio.js";
import { playSample, stopPlayback } from "./audio.js";
import { getTotalSteps } from "./utils.js";
import { loadProjectFromServer } from "./file.js";
let samplePathMap = {};
const globalPatternSelector = document.getElementById('global-pattern-selector');
globalPatternSelector.addEventListener('change', () => {
// Atualiza o índice GLOBAL
appState.activePatternIndex = parseInt(globalPatternSelector.value, 10);
const firstTrack = appState.tracks[0];
if (firstTrack) {
const activePattern = firstTrack.patterns[appState.activePatternIndex];
if (activePattern) {
const stepsPerBar = 16;
const requiredBars = Math.ceil(activePattern.steps.length / stepsPerBar);
document.getElementById("bars-input").value = requiredBars > 0 ? requiredBars : 1;
if (globalPatternSelector) {
globalPatternSelector.addEventListener('change', () => {
// A linha stopPlayback() foi REMOVIDA daqui, permitindo a troca em tempo real.
appState.activePatternIndex = parseInt(globalPatternSelector.value, 10);
const firstTrack = appState.tracks[0];
if (firstTrack) {
const activePattern = firstTrack.patterns[appState.activePatternIndex];
if (activePattern) {
const stepsPerBar = 16;
const requiredBars = Math.ceil(activePattern.steps.length / stepsPerBar);
document.getElementById("bars-input").value = requiredBars > 0 ? requiredBars : 1;
}
}
}
redrawSequencer();
});
redrawSequencer();
});
}
export function updateGlobalPatternSelector() {
if (!globalPatternSelector) return;
const referenceTrack = appState.tracks[0];
globalPatternSelector.innerHTML = '';
if (referenceTrack && referenceTrack.patterns.length > 0) {
referenceTrack.patterns.forEach((pattern, index) => {
const option = document.createElement('option');
@@ -40,7 +42,6 @@ export function updateGlobalPatternSelector() {
option.textContent = pattern.name;
globalPatternSelector.appendChild(option);
});
// Usa o índice GLOBAL
globalPatternSelector.selectedIndex = appState.activePatternIndex;
globalPatternSelector.disabled = false;
} else {
@@ -51,6 +52,42 @@ export function updateGlobalPatternSelector() {
}
}
export function handleSampleUpload(file) {
const validExtensions = ['.wav', '.flac', '.ogg', '.mp3'];
const fileExtension = '.' + file.name.split('.').pop().toLowerCase();
if (!validExtensions.includes(fileExtension)) {
alert("Formato de arquivo inválido. Por favor, envie .wav, .flac, .ogg, ou .mp3.");
return;
}
const reader = new FileReader();
reader.onload = (e) => {
const dataURL = e.target.result;
const browserContent = document.getElementById("browser-content");
const list = browserContent.querySelector("ul");
if (list) {
const li = document.createElement("li");
li.innerHTML = `<i class="fa-solid fa-file-audio"></i> ${file.name}`;
li.setAttribute("draggable", true);
li.addEventListener("click", (event) => {
event.stopPropagation();
playSample(dataURL, null);
});
li.addEventListener("dragstart", (event) => {
event.dataTransfer.setData("text/plain", dataURL);
event.dataTransfer.effectAllowed = "copy";
});
list.prepend(li);
}
};
reader.readAsDataURL(file);
}
export function getSamplePathMap() {
return samplePathMap;
}
@@ -89,15 +126,11 @@ export function renderApp() {
</div>
<div class="track-controls">
<div class="knob-container">
<div class="knob" data-control="volume" data-track-id="${trackData.id}">
<div class="knob-indicator"></div>
</div>
<div class="knob" data-control="volume" data-track-id="${trackData.id}"><div class="knob-indicator"></div></div>
<span>VOL</span>
</div>
<div class="knob-container">
<div class="knob" data-control="pan" data-track-id="${trackData.id}">
<div class="knob-indicator"></div>
</div>
<div class="knob" data-control="pan" data-track-id="${trackData.id}"><div class="knob-indicator"></div></div>
<span>PAN</span>
</div>
</div>
@@ -106,11 +139,25 @@ export function renderApp() {
trackLane.addEventListener('click', () => {
if (appState.activeTrackId === trackData.id) return;
// A linha stopPlayback() também foi REMOVIDA daqui
appState.activeTrackId = trackData.id;
document.querySelectorAll('.track-lane').forEach(lane => lane.classList.remove('active-track'));
trackLane.classList.add('active-track');
updateGlobalPatternSelector();
redrawSequencer();
// Apenas redesenha a UI, sem parar a música
const activeTrack = appState.tracks.find(t => t.id === appState.activeTrackId);
if (activeTrack) {
const activePattern = activeTrack.patterns[activeTrack.activePatternIndex];
if (activePattern) {
const stepsPerBar = 16;
const requiredBars = Math.ceil(activePattern.steps.length / stepsPerBar);
document.getElementById("bars-input").value = requiredBars > 0 ? requiredBars : 1;
redrawSequencer();
}
}
});
trackLane.addEventListener("dragover", (e) => { e.preventDefault(); trackLane.classList.add("drag-over"); });
@@ -152,15 +199,12 @@ export function redrawSequencer() {
const trackData = appState.tracks.find((t) => t.id == trackId);
if (!trackData || !trackData.patterns || trackData.patterns.length === 0) {
sequencerContainer.innerHTML = "";
return;
sequencerContainer.innerHTML = ""; return;
}
// A CORREÇÃO FINAL: Usa o índice GLOBAL para desenhar CADA faixa
const activePattern = trackData.patterns[appState.activePatternIndex];
if (!activePattern) {
sequencerContainer.innerHTML = "";
return;
sequencerContainer.innerHTML = ""; return;
}
const patternSteps = activePattern.steps;
@@ -315,7 +359,11 @@ export function highlightStep(stepIndex, isActive) {
export async function loadAndRenderSampleBrowser() {
const browserContent = document.getElementById("browser-content");
try {
const response = await fetch("metadata/samples-manifest.json");
// --- CORREÇÃO AQUI ---
// Adiciona um timestamp à URL para evitar que o navegador use uma versão antiga (em cache) do arquivo.
const response = await fetch(`metadata/samples-manifest.json?v=${Date.now()}`);
// --- FIM DA CORREÇÃO ---
if (!response.ok) {
throw new Error("Arquivo samples-manifest.json não encontrado.");
}
@@ -323,7 +371,7 @@ export async function loadAndRenderSampleBrowser() {
samplePathMap = {};
buildSamplePathMap(fileTree, "src/samples");
renderFileTree(fileTree, browserContent, "src/samples");
} catch (error) {
console.error("Erro ao carregar samples:", error);