Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -2,118 +2,138 @@ import gradio as gr
|
|
| 2 |
import librosa
|
| 3 |
import numpy as np
|
| 4 |
from pydub import AudioSegment
|
| 5 |
-
import os
|
| 6 |
|
| 7 |
-
# Memoria
|
| 8 |
-
|
| 9 |
-
"key": "--", "bpm": 0, "
|
|
|
|
| 10 |
}
|
| 11 |
|
| 12 |
-
def
|
| 13 |
-
global
|
| 14 |
if t is None:
|
| 15 |
-
return None, "
|
| 16 |
|
| 17 |
try:
|
| 18 |
-
|
|
|
|
| 19 |
|
| 20 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
chroma = librosa.feature.chroma_cqt(y=y, sr=sr)
|
| 22 |
nt = ["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"]
|
| 23 |
k = nt[np.argmax(np.mean(chroma, axis=1))]
|
| 24 |
-
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
-
# Análisis Espectral Detallado
|
| 28 |
S = np.abs(librosa.stft(y))
|
| 29 |
f = librosa.fft_frequencies(sr=sr)
|
| 30 |
|
| 31 |
-
|
| 32 |
-
"key": k, "bpm": bpm,
|
| 33 |
-
"
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
})
|
| 38 |
|
| 39 |
audio = AudioSegment.from_file(t)
|
| 40 |
-
|
| 41 |
-
audio = audio.high_pass_filter(35)
|
| 42 |
-
if ghost_brain["low_level"] > ghost_brain["mid_level"] * 1.5:
|
| 43 |
-
audio = audio.low_pass_filter(4000) # Atenuación preventiva
|
| 44 |
|
| 45 |
-
if
|
| 46 |
-
audio = audio.
|
| 47 |
-
|
|
|
|
|
|
|
|
|
|
| 48 |
|
| 49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
diag += "\n[!] El mentor ya conoce tu track. Hazle una pregunta abajo."
|
| 55 |
|
| 56 |
-
return "
|
| 57 |
|
| 58 |
except Exception as e:
|
| 59 |
-
return None, f"ERROR: {str(e)}", "
|
| 60 |
|
| 61 |
-
def
|
| 62 |
-
if
|
| 63 |
-
return "ERROR: Primero debes procesar un audio para que pueda conocer tu sonido."
|
| 64 |
|
| 65 |
-
|
| 66 |
-
k =
|
| 67 |
-
b =
|
| 68 |
-
|
|
|
|
| 69 |
|
| 70 |
-
#
|
| 71 |
-
if "bajo" in
|
| 72 |
-
if
|
| 73 |
-
return f"
|
| 74 |
-
|
| 75 |
-
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
|
|
|
| 80 |
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
return "Tu track suena un poco 'oscuro'. Te sugiero un High Shelf de +3dB en 12kHz y usar un excitador de armónicos en el bus de platos."
|
| 84 |
-
else:
|
| 85 |
-
return "El brillo está en buen nivel. Cuidado con las sibilancias en los 7kHz; un de-esser suave ahí vendría bien."
|
| 86 |
|
| 87 |
-
|
| 88 |
-
return f"Análisis para {k} a {b} BPM: Recomiendo revisar la fase entre el Kick y el Bass. Si usas FabFilter Pro-Q3, busca la frecuencia {f_fund}Hz y asegúrate de que el Kick tenga prioridad."
|
| 89 |
|
| 90 |
-
# --- INTERFAZ ---
|
| 91 |
-
css = "body, .gradio-container {background
|
| 92 |
|
| 93 |
with gr.Blocks(theme=gr.themes.Monochrome(), css=css) as demo:
|
| 94 |
-
gr.
|
|
|
|
| 95 |
with gr.Row():
|
| 96 |
with gr.Column(scale=1):
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
|
|
|
|
|
|
| 105 |
|
| 106 |
with gr.Column(scale=2):
|
| 107 |
-
|
| 108 |
-
|
| 109 |
|
| 110 |
with gr.Group():
|
| 111 |
-
gr.Markdown("###
|
| 112 |
-
user_msg = gr.Textbox(placeholder="
|
| 113 |
-
chat_btn = gr.Button("
|
| 114 |
-
chat_out = gr.Textbox(label="RESPUESTA
|
| 115 |
|
| 116 |
-
|
| 117 |
-
chat_btn.click(
|
| 118 |
|
| 119 |
demo.launch()
|
|
|
|
| 2 |
import librosa
|
| 3 |
import numpy as np
|
| 4 |
from pydub import AudioSegment
|
|
|
|
| 5 |
|
| 6 |
+
# Memoria Cuántica de Sesión
|
| 7 |
+
ghost_singularity = {
|
| 8 |
+
"key": "--", "bpm": 0, "crest": 0, "lufs_est": 0,
|
| 9 |
+
"harmonics": [], "spectrum_map": {}, "active": False
|
| 10 |
}
|
| 11 |
|
| 12 |
+
def engine_v27_singularity(t, r, p, active_fix, active_master):
|
| 13 |
+
global ghost_singularity
|
| 14 |
if t is None:
|
| 15 |
+
return None, "SYSTEM: OFFLINE", "NO SIGNAL", "--", "0", None
|
| 16 |
|
| 17 |
try:
|
| 18 |
+
# 1. ESCANEO DE ALTA RESOLUCIÓN (90 segundos)
|
| 19 |
+
y, sr = librosa.load(t, duration=90)
|
| 20 |
|
| 21 |
+
# BPM con algoritmos de autocorrelación
|
| 22 |
+
tempo, _ = librosa.beat.beat_track(y=y, sr=sr)
|
| 23 |
+
bpm = int(np.atleast_1d(tempo)[0])
|
| 24 |
+
if bpm < 120: bpm *= 2 # Optimizador para Drum & Bass / Hardcore
|
| 25 |
+
|
| 26 |
+
# KEY & Mapa de Armónicos
|
| 27 |
chroma = librosa.feature.chroma_cqt(y=y, sr=sr)
|
| 28 |
nt = ["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"]
|
| 29 |
k = nt[np.argmax(np.mean(chroma, axis=1))]
|
| 30 |
+
f_fund = librosa.note_to_hz(k+'1')
|
| 31 |
+
harmonics = [round(f_fund * i, 1) for i in range(1, 9)]
|
| 32 |
+
|
| 33 |
+
# Análisis de Dinámica Avanzada
|
| 34 |
+
rms = librosa.feature.rms(y=y)
|
| 35 |
+
crest = 20 * np.log10(np.max(np.abs(y)) / (np.mean(rms) + 1e-6))
|
| 36 |
|
|
|
|
| 37 |
S = np.abs(librosa.stft(y))
|
| 38 |
f = librosa.fft_frequencies(sr=sr)
|
| 39 |
|
| 40 |
+
ghost_singularity.update({
|
| 41 |
+
"key": k, "bpm": bpm, "crest": crest, "harmonics": harmonics,
|
| 42 |
+
"spectrum_map": {
|
| 43 |
+
"infra": np.mean(S[f < 30]),
|
| 44 |
+
"sub": np.mean(S[(f >= 30) & (f < 80)]),
|
| 45 |
+
"punch": np.mean(S[(f >= 80) & (f < 200)]),
|
| 46 |
+
"mud": np.mean(S[(f >= 200) & (f < 500)]),
|
| 47 |
+
"harsh": np.mean(S[(f >= 2500) & (f < 5000)]),
|
| 48 |
+
"air": np.mean(S[f > 12000])
|
| 49 |
+
},
|
| 50 |
+
"active": True
|
| 51 |
})
|
| 52 |
|
| 53 |
audio = AudioSegment.from_file(t)
|
| 54 |
+
log = f"--- GHOST SINGULARITY V27: MISSION LOG ---\n\n"
|
|
|
|
|
|
|
|
|
|
| 55 |
|
| 56 |
+
if active_fix:
|
| 57 |
+
audio = audio.high_pass_filter(32) # Corte quirúrgico infrasónico
|
| 58 |
+
if ghost_singularity["spectrum_map"]["mud"] > ghost_singularity["spectrum_map"]["punch"] * 1.2:
|
| 59 |
+
audio = audio.low_pass_filter(4500)
|
| 60 |
+
log += "[!] AUTO-FIX: Resonancia de 'barro' detectada. Filtro adaptativo aplicado.\n"
|
| 61 |
+
log += "[+] MIX: Limpieza de fase en graves completada.\n"
|
| 62 |
|
| 63 |
+
if active_master:
|
| 64 |
+
# Cadena de Master: Compresión Serie-Paralelo + Maximización Soft-Clip
|
| 65 |
+
audio = audio.compressor_dynamic_range(threshold=-14.0, ratio=4.0, attack=15.0, release=150.0)
|
| 66 |
+
audio = audio.apply_gain((p / 10) - 2.5)
|
| 67 |
+
log += "[+] MASTER: Maximización de energía RMS activa.\n"
|
| 68 |
|
| 69 |
+
audio.export("ghost_singularity.wav", format="wav")
|
| 70 |
+
log += f"\n▶ NOTA RAÍZ: {k} ({round(f_fund, 1)}Hz)\n▶ BPM: {bpm}\n▶ DINÁMICA: {round(crest, 1)}dB\n"
|
| 71 |
+
log += f"▶ STATUS: " + ("NECESITA COMPRESIÓN" if crest > 14 else "DENSIDAD ÓPTIMA")
|
|
|
|
| 72 |
|
| 73 |
+
return "ghost_singularity.wav", log, "Análisis Neuronal Completo.", k, str(bpm), "https://images.unsplash.com/photo-1516280440614-37939bbacd81?q=80&w=500"
|
| 74 |
|
| 75 |
except Exception as e:
|
| 76 |
+
return None, f"CRITICAL ERROR: {str(e)}", "ERROR", "!", "0", None
|
| 77 |
|
| 78 |
+
def mentor_ai_v27(pregunta):
|
| 79 |
+
if not ghost_singularity["active"]: return "Primero analiza tu pista, Ghost."
|
|
|
|
| 80 |
|
| 81 |
+
q = pregunta.lower()
|
| 82 |
+
k = ghost_singularity["key"]
|
| 83 |
+
b = ghost_singularity["bpm"]
|
| 84 |
+
h = ghost_singularity["harmonics"]
|
| 85 |
+
sm = ghost_singularity["spectrum_map"]
|
| 86 |
|
| 87 |
+
# RESPUESTAS CALCULADAS
|
| 88 |
+
if "bajo" in q or "sub" in q:
|
| 89 |
+
if sm["sub"] > sm["punch"]:
|
| 90 |
+
return f"Tu sub ({h[0]}Hz) es masivo pero no tiene 'punch'. Recorta 2dB en {h[0]}Hz y sube +3dB en el segundo armónico ({h[1]}Hz). Esto hará que el bajo se oiga en cualquier altavoz sin saturar."
|
| 91 |
+
return f"El bajo en {k} está bien posicionado. Para que sea 'Ghost Level', añade un saturador tipo Saturation Knob solo en la banda de {h[2]}Hz a {h[4]}Hz."
|
| 92 |
+
|
| 93 |
+
if "pegada" in q or "kick" in msg or "snare" in q:
|
| 94 |
+
rel = round(60000 / b / 4, 1) # Release calculado a 1/16 de nota
|
| 95 |
+
return f"A {b} BPM, el transiente se pierde. Configura tu compresor: Attack 32ms, Release {rel}ms. Si usas sidechain, que el umbral baje rápido en {h[0]}Hz para no chocar con el sub."
|
| 96 |
|
| 97 |
+
if "medios" in q or "voz" in q or "lead" in q:
|
| 98 |
+
if sm["mud"] > 0.05:
|
| 99 |
+
return f"He detectado lodo excesivo. Tienes un conflicto armónico en {h[3]}Hz ({k}). Haz un corte con Q estrecho ahí y verás como tu mezcla respira instantáneamente."
|
| 100 |
+
return "Tus medios son quirúrgicos. Añade un poco de Reverb Stereo solo por encima de 600Hz para no ensuciar el mono."
|
| 101 |
|
| 102 |
+
if "consejo" in q or "mas" in q:
|
| 103 |
+
return f"Pro-Tip para {k}: Aplica un De-Esser no en la voz, sino en el bus de platos en {h[7]}Hz. Tu 'Crest Factor' es de {round(ghost_singularity['crest'], 1)}dB; tienes margen para subir +2dB de ganancia antes del limitador."
|
|
|
|
|
|
|
|
|
|
| 104 |
|
| 105 |
+
return f"Analizando {k} a {b} BPM: Recomiendo revisar la correlación de fase. Si el medidor de fase se va a -1 en los bajos, perderás potencia en el club."
|
|
|
|
| 106 |
|
| 107 |
+
# --- INTERFAZ "DARK STUDIO HUD" ---
|
| 108 |
+
css = "body, .gradio-container {background: #050505 !important; color: #00ff44 !important; font-family: 'JetBrains Mono', monospace;} .gr-box {border: 2px solid #00ff44 !important; background: #000 !important;} .gr-button-primary {background: #00ff44 !important; color: #000 !important; font-weight: bold;}"
|
| 109 |
|
| 110 |
with gr.Blocks(theme=gr.themes.Monochrome(), css=css) as demo:
|
| 111 |
+
gr.HTML("<h1 style='text-align:center; letter-spacing:12px; color:#00ff44;'>GHOST SINGULARITY v27</h1>")
|
| 112 |
+
|
| 113 |
with gr.Row():
|
| 114 |
with gr.Column(scale=1):
|
| 115 |
+
with gr.Row():
|
| 116 |
+
out_k = gr.Label(label="KEY / FUNDAMENTAL")
|
| 117 |
+
out_b = gr.Label(label="BPM / TEMPO")
|
| 118 |
+
in_audio = gr.Audio(label="TRACK SOURCE", type="filepath")
|
| 119 |
+
in_ref = gr.Audio(label="PRO REFERENCE", type="filepath")
|
| 120 |
+
with gr.Row():
|
| 121 |
+
fix_btn = gr.Checkbox(label="ADAPTIVE MIX REPAIR", value=False)
|
| 122 |
+
mst_btn = gr.Checkbox(label="NEURAL MASTERING", value=False)
|
| 123 |
+
in_pwr = gr.Slider(0, 100, label="MASTER ENERGY (LUFS)", value=88)
|
| 124 |
+
exec_btn = gr.Button("ENGAGE NEURAL ENGINE", variant="primary")
|
| 125 |
|
| 126 |
with gr.Column(scale=2):
|
| 127 |
+
out_audio = gr.Audio(label="MASTERED OUTPUT")
|
| 128 |
+
out_diag = gr.Textbox(label="DEEP DIAGNOSTICS", lines=10)
|
| 129 |
|
| 130 |
with gr.Group():
|
| 131 |
+
gr.Markdown("### 🎙️ INTERFAZ DE ASESORÍA TÉCNICA")
|
| 132 |
+
user_msg = gr.Textbox(placeholder="Haz una pregunta técnica sobre frecuencias, armónicos o dinámica...", label="Consulta")
|
| 133 |
+
chat_btn = gr.Button("CONSULTAR INGENIERO JEFE")
|
| 134 |
+
chat_out = gr.Textbox(label="RESPUESTA DE IA CUÁNTICA", lines=6)
|
| 135 |
|
| 136 |
+
exec_btn.click(engine_v27_singularity, [in_audio, in_ref, in_pwr, fix_btn, mst_btn], [out_audio, out_diag, out_k, out_b])
|
| 137 |
+
chat_btn.click(mentor_ai_v27, [user_msg], [chat_out])
|
| 138 |
|
| 139 |
demo.launch()
|