dj-big-cat-dj-mixer / BASIC_AUDIO_LOADING.py
Luis-Filipe's picture
Upload 6 files
4b793f5 verified
#!/usr/bin/env python3
"""
🎵 DJ SYSTEM - VERSÃO BÁSICA PARA CARREGAMENTO DE ÁUDIO
=======================================================
Versão ultra simplificada focada APENAS no carregamento de áudio.
Removidas todas as funcionalidades avançadas para eliminar complexidade.
"""
from fastapi import FastAPI, HTMLResponse
import time
app = FastAPI(title="DJ Audio Loading Test", version="1.0.0")
html_content = """
<!DOCTYPE html>
<html lang="pt">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🎵 Teste de Carregamento de Áudio</title>
<style>
body {
font-family: Arial, sans-serif;
background: #2c3e50;
color: white;
padding: 20px;
margin: 0;
}
.container {
max-width: 800px;
margin: 0 auto;
background: #34495e;
padding: 30px;
border-radius: 10px;
box-shadow: 0 0 20px rgba(0,0,0,0.3);
}
.header {
text-align: center;
margin-bottom: 30px;
}
.deck {
background: #2c3e50;
padding: 20px;
margin: 20px 0;
border-radius: 8px;
border: 2px solid #3498db;
}
.deck-title {
font-size: 20px;
font-weight: bold;
margin-bottom: 15px;
color: #3498db;
}
.file-input {
margin: 15px 0;
}
.file-input input[type="file"] {
display: none;
}
.file-button {
background: #e74c3c;
color: white;
padding: 15px 30px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
font-weight: bold;
display: block;
width: 100%;
text-align: center;
transition: background 0.3s;
}
.file-button:hover {
background: #c0392b;
}
.status {
margin: 10px 0;
padding: 10px;
border-radius: 5px;
font-weight: bold;
}
.status.idle {
background: #7f8c8d;
color: white;
}
.status.loading {
background: #f39c12;
color: black;
animation: pulse 1s infinite;
}
.status.success {
background: #27ae60;
color: white;
}
.status.error {
background: #e74c3c;
color: white;
}
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.7; }
100% { opacity: 1; }
}
.info {
margin: 10px 0;
padding: 10px;
background: #34495e;
border-radius: 5px;
}
.console {
background: #1a1a1a;
color: #00ff00;
padding: 15px;
border-radius: 5px;
font-family: 'Courier New', monospace;
font-size: 12px;
margin-top: 20px;
max-height: 300px;
overflow-y: auto;
}
.play-button {
background: #27ae60;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 14px;
margin: 5px;
transition: background 0.3s;
}
.play-button:hover:not(:disabled) {
background: #229954;
}
.play-button:disabled {
background: #7f8c8d;
cursor: not-allowed;
}
.test-section {
background: #8e44ad;
padding: 20px;
border-radius: 8px;
margin: 20px 0;
}
.test-button {
background: #9b59b6;
color: white;
padding: 10px 15px;
border: none;
border-radius: 5px;
cursor: pointer;
margin: 5px;
font-size: 12px;
}
.test-button:hover {
background: #8e44ad;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🎵 TESTE DE CARREGAMENTO DE ÁUDIO</h1>
<p>Versão Básica - Focada apenas no carregamento de arquivos</p>
</div>
<div class="test-section">
<h3>🧪 TESTES DE SISTEMA</h3>
<button class="test-button" onclick="testAudioContext()">Testar AudioContext</button>
<button class="test-button" onclick="testFileAPI()">Testar File API</button>
<button class="test-button" onclick="clearConsole()">Limpar Console</button>
</div>
<div class="console" id="console">🚀 Sistema inicializando...</div>
<!-- Deck A -->
<div class="deck">
<div class="deck-title">🔵 DECK A</div>
<div class="status idle" id="status-A">
🟢 Pronto - Clique no botão para carregar um arquivo
</div>
<div class="file-input">
<input type="file" id="file-A" accept="audio/*">
<label for="file-A" class="file-button">
📁 CARREGAR ARQUIVO - DECK A
</label>
</div>
<div class="info" id="info-A" style="display: none;">
<div><strong>Arquivo:</strong> <span id="filename-A">-</span></div>
<div><strong>Duração:</strong> <span id="duration-A">-</span></div>
<div><strong>Tamanho:</strong> <span id="size-A">-</span></div>
<button class="play-button" id="play-A" onclick="playAudio('A')" disabled>▶️ TOCAR</button>
</div>
</div>
<!-- Deck B -->
<div class="deck">
<div class="deck-title">🟣 DECK B</div>
<div class="status idle" id="status-B">
🟢 Pronto - Clique no botão para carregar um arquivo
</div>
<div class="file-input">
<input type="file" id="file-B" accept="audio/*">
<label for="file-B" class="file-button">
📁 CARREGAR ARQUIVO - DECK B
</label>
</div>
<div class="info" id="info-B" style="display: none;">
<div><strong>Arquivo:</strong> <span id="filename-B">-</span></div>
<div><strong>Duração:</strong> <span id="duration-B">-</span></div>
<div><strong>Tamanho:</strong> <span id="size-B">-</span></div>
<button class="play-button" id="play-B" onclick="playAudio('B')" disabled>▶️ TOCAR</button>
</div>
</div>
</div>
<script>
// Variáveis globais
let audioContext;
let decks = {
A: { buffer: null, source: null, isPlaying: false },
B: { buffer: null, source: null, isPlaying: false }
};
// Função para adicionar logs
function addLog(message) {
const console = document.getElementById('console');
const timestamp = new Date().toLocaleTimeString();
console.innerHTML += `<br>[${timestamp}] ${message}`;
console.scrollTop = console.scrollHeight;
console.log('LOG:', message);
}
function clearConsole() {
document.getElementById('console').innerHTML = '🚀 Console limpo - Pronto para testes';
}
// Inicialização
function initialize() {
addLog('🚀 Iniciando sistema básico...');
// Criar AudioContext
try {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
addLog('✅ AudioContext criado com sucesso');
// Se AudioContext estiver suspenso, requer interação do usuário
if (audioContext.state === 'suspended') {
addLog('⚠️ AudioContext suspenso - aguarde interação do usuário');
}
} catch (error) {
addLog('❌ Erro ao criar AudioContext: ' + error.message);
return false;
}
return true;
}
// Função para carregar arquivo
function loadAudioFile(file, deckId) {
addLog(`🎵 Iniciando carregamento do Deck ${deckId}: ${file.name}`);
// Atualizar status
updateStatus(deckId, 'loading', '🔄 Carregando arquivo...');
// Verificar tipo de arquivo
if (!file.type.startsWith('audio/')) {
addLog(`❌ Tipo de arquivo não suportado: ${file.type}`);
updateStatus(deckId, 'error', '❌ Tipo de arquivo não suportado');
return;
}
// Verificar tamanho
if (file.size > 50 * 1024 * 1024) { // 50MB
addLog('❌ Arquivo muito grande (máximo 50MB)');
updateStatus(deckId, 'error', '❌ Arquivo muito grande');
return;
}
addLog(`📁 Arquivo válido: ${file.type}, ${Math.round(file.size/1024/1024)}MB`);
// Criar FileReader
const reader = new FileReader();
reader.onload = async function(event) {
try {
addLog(`🔄 Decodificando áudio para Deck ${deckId}...`);
// Decodificar áudio
const audioBuffer = await audioContext.decodeAudioData(event.target.result);
addLog(`✅ Áudio decodificado com sucesso!`);
addLog(`📊 Duração: ${audioBuffer.duration.toFixed(1)}s`);
addLog(`🎛️ Sample Rate: ${audioBuffer.sampleRate}Hz`);
// Armazenar buffer
decks[deckId].buffer = audioBuffer;
// Atualizar interface
updateDeckInfo(deckId, file, audioBuffer);
updateStatus(deckId, 'success', `✅ ${file.name} carregado com sucesso!`);
// Habilitar botão play
document.getElementById(`play-${deckId}`).disabled = false;
addLog(`🎵 Deck ${deckId} pronto para reprodução!`);
} catch (error) {
addLog(`❌ Erro ao decodificar Deck ${deckId}: ${error.message}`);
updateStatus(deckId, 'error', `❌ Erro ao carregar: ${error.message}`);
}
};
reader.onerror = function() {
addLog(`❌ Erro na leitura do arquivo Deck ${deckId}`);
updateStatus(deckId, 'error', '❌ Erro na leitura do arquivo');
};
// Iniciar leitura
addLog(`📖 Iniciando leitura do arquivo...`);
reader.readAsArrayBuffer(file);
}
// Função para atualizar status
function updateStatus(deckId, status, message) {
const statusElement = document.getElementById(`status-${deckId}`);
statusElement.className = `status ${status}`;
statusElement.textContent = message;
}
// Função para atualizar informações do deck
function updateDeckInfo(deckId, file, buffer) {
document.getElementById(`filename-${deckId}`).textContent = file.name;
document.getElementById(`duration-${deckId}`).textContent = formatTime(buffer.duration);
document.getElementById(`size-${deckId}`).textContent = formatFileSize(file.size);
document.getElementById(`info-${deckId}`).style.display = 'block';
}
// Função para tocar áudio
function playAudio(deckId) {
const deck = decks[deckId];
if (!deck.buffer) {
addLog(`❌ Deck ${deckId}: Nenhum arquivo carregado`);
return;
}
// Parar reprodução atual se estiver tocando
if (deck.isPlaying) {
deck.source.stop();
deck.isPlaying = false;
document.getElementById(`play-${deckId}`).textContent = '▶️ TOCAR';
addLog(`⏸️ Deck ${deckId} pausado`);
return;
}
try {
// Criar nova fonte de áudio
deck.source = audioContext.createBufferSource();
deck.source.buffer = deck.buffer;
deck.source.connect(audioContext.destination);
// Iniciar reprodução
deck.source.start(0);
deck.isPlaying = true;
document.getElementById(`play-${deckId}`).textContent = '⏸️ PAUSAR';
addLog(`▶️ Deck ${deckId} tocando...`);
// Quando terminar
deck.source.onended = function() {
deck.isPlaying = false;
document.getElementById(`play-${deckId}`).textContent = '▶️ TOCAR';
addLog(`⏹️ Deck ${deckId} terminou`);
};
} catch (error) {
addLog(`❌ Erro ao tocar Deck ${deckId}: ${error.message}`);
}
}
// Funções de teste
function testAudioContext() {
addLog('🧪 Testando AudioContext...');
if (audioContext) {
addLog(`✅ AudioContext existe - Estado: ${audioContext.state}`);
if (audioContext.state === 'suspended') {
addLog('🔄 Tentando resumir AudioContext...');
audioContext.resume().then(() => {
addLog('✅ AudioContext resumido com sucesso!');
}).catch(error => {
addLog('❌ Erro ao resumir AudioContext: ' + error.message);
});
}
} else {
addLog('❌ AudioContext não existe!');
}
}
function testFileAPI() {
addLog('🧪 Testando File API...');
if (window.FileReader) {
addLog('✅ FileReader suportado');
} else {
addLog('❌ FileReader não suportado');
}
if (window.File) {
addLog('✅ File API suportado');
} else {
addLog('❌ File API não suportado');
}
}
// Funções auxiliares
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins}:${secs.toString().padStart(2, '0')}`;
}
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
// Event listeners para os inputs de arquivo
document.getElementById('file-A').addEventListener('change', function(event) {
const file = event.target.files[0];
if (file) {
addLog(`🎵 Arquivo selecionado para Deck A: ${file.name}`);
loadAudioFile(file, 'A');
}
});
document.getElementById('file-B').addEventListener('change', function(event) {
const file = event.target.files[0];
if (file) {
addLog(`🎵 Arquivo selecionado para Deck B: ${file.name}`);
loadAudioFile(file, 'B');
}
});
// Resumir AudioContext na primeira interação
document.addEventListener('click', function() {
if (audioContext && audioContext.state === 'suspended') {
audioContext.resume();
addLog('🔄 AudioContext resumido por interação do usuário');
}
});
// Inicializar quando a página carregar
window.addEventListener('load', function() {
setTimeout(() => {
initialize();
}, 100);
});
</script>
</body>
</html>
"""
@app.get("/", response_class=HTMLResponse)
async def get_home():
return HTMLResponse(content=html_content)
@app.get("/health")
async def health_check():
return {"status": "healthy", "system": "Basic Audio Loading Test", "timestamp": time.time()}
if __name__ == "__main__":
import uvicorn
print("🎵 Starting Basic Audio Loading Test...")
print("📡 Server: http://localhost:8000")
print("🎯 Focus: Simple and reliable audio file loading")
uvicorn.run(app, host="0.0.0.0", port=8000, log_level="info")