Forca-grid / app.py
Luis-Filipe's picture
Upload 10 files
d173899 verified
Raw
History Blame Contribute Delete
4.94 kB
import gradio as gr
import os
import json
import tempfile
import shutil
import re
import subprocess
import sys
from pathlib import Path
from grid_fixer_v2 import fix_grid_advanced
def sanitize_filename(name):
"""Remove espaços e caracteres especiais do nome do ficheiro."""
name = re.sub(r'[\s]+', '_', name)
name = re.sub(r'[^\w\-\.]', '', name)
return name
def process_audio(input_file, target_bpm, pitch_semitones, phase_lock, verbose):
if input_file is None:
return "Por favor, faz upload de um ficheiro de áudio.", "", ""
try:
base_name = sanitize_filename(Path(input_file).stem)
# Guardar na pasta de trabalho atual (onde está o app_v2.py)
# O Gradio permite servir ficheiros desta pasta por defeito
output_dir = Path.cwd() / "output"
output_dir.mkdir(parents=True, exist_ok=True)
output_wav = str(output_dir / f"{base_name}_fixed.wav")
bpm_value = target_bpm if target_bpm > 0 else None
metadata = fix_grid_advanced(
input_file,
output_wav,
target_bpm=bpm_value,
pitch_semitones=float(pitch_semitones),
phase_lock=phase_lock,
verbose=verbose
)
if metadata is None:
return "❌ Erro no processamento. Verifica o terminal para detalhes.", "", ""
# Ler metadados
meta_path = str(Path(output_wav).with_suffix(".json"))
if os.path.exists(meta_path):
with open(meta_path, 'r', encoding='utf-8') as f:
meta = json.load(f)
else:
meta = metadata
pitch_info = f"{meta['pitch_shift_semitons']:+.1f} semitons" if meta['pitch_shift_semitons'] != 0 else "Sem alteração"
status = (f"✅ Processamento concluído!\n\n"
f"📊 BPM Original: {meta['original_bpm']:.2f}\n"
f"🎯 BPM Alvo: {meta['target_bpm']:.2f}\n"
f"🎵 Pitch: {pitch_info}\n"
f"🔒 Phase-Lock: {'Ativo' if meta['phase_lock'] else 'Desativado'}\n"
f"⚡ Modo: {'Metronómico (Linear)' if meta.get('is_metronomic') else 'Variável (Warp)'}\n"
f"📈 Variação Rítmica: {meta.get('ibi_cv', 0)*100:.2f}%\n"
f"🎹 Key Estimada: {meta.get('estimated_key', 'N/A')}\n"
f"⏱️ Primeiro Beat: {meta['first_beat_time_original']:.3f}s\n"
f"🌀 Fase Offset: {meta.get('phase_offset_degrees', 0):.1f}°\n"
f"🔢 Beats Corrigidos: {meta['beats_count']}")
file_info = f"📁 {output_wav}"
return status, file_info, output_wav
except Exception as e:
import traceback
traceback.print_exc()
return f"❌ Erro: {str(e)}", "", ""
def open_folder():
"""Abre a pasta de saída no explorador de ficheiros."""
output_dir = Path.cwd() / "output"
output_dir.mkdir(parents=True, exist_ok=True)
if os.name == 'nt': # Windows
os.startfile(str(output_dir))
elif os.name == 'posix': # Linux/Mac
subprocess.call(['open' if sys.platform == 'darwin' else 'xdg-open', str(output_dir)])
return f"📂 Pasta aberta: {output_dir}"
with gr.Blocks() as demo:
gr.Markdown("# 🎛️ Forca-Grid v2")
gr.Markdown("Beatgrid + Pitch + Phase")
with gr.Row():
with gr.Column():
input_audio = gr.Audio(label="Upload Áudio", type="filepath")
target_bpm = gr.Number(label="BPM Alvo (0 = auto)", value=0)
pitch_shift = gr.Slider(label="Pitch (semitons)", minimum=-12, maximum=12, step=0.5, value=0)
phase_lock = gr.Checkbox(label="Phase-Lock", value=True)
verbose_mode = gr.Checkbox(label="Verbose", value=True)
with gr.Row():
btn_process = gr.Button("🚀 Processar", variant="primary")
btn_open = gr.Button("📂 Abrir Pasta de Saída")
with gr.Column():
status_text = gr.Textbox(label="📋 Status / Metadados", interactive=False, lines=12)
file_path = gr.Textbox(label="📁 Path do Ficheiro", interactive=False)
# Preview de áudio - agora deve funcionar porque o ficheiro está na pasta permitida
output_preview = gr.Audio(label="🔊 Preview", type="filepath")
# Processamento
btn_process.click(
fn=process_audio,
inputs=[input_audio, target_bpm, pitch_shift, phase_lock, verbose_mode],
outputs=[status_text, file_path, output_preview]
)
# Abrir pasta
btn_open.click(
fn=open_folder,
inputs=[],
outputs=[file_path]
)
if __name__ == "__main__":
# allowed_paths garante que o Gradio pode servir ficheiros da pasta output
output_dir = str(Path.cwd() / "output")
demo.launch(
share=False,
server_name="0.0.0.0",
allowed_paths=[output_dir]
)