Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -4,196 +4,128 @@ import numpy as np
|
|
| 4 |
from pydub import AudioSegment
|
| 5 |
import os
|
| 6 |
|
| 7 |
-
|
| 8 |
-
SKULL_GIF = "https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExNGg1d244cWk2eXh6eWJ4MTY3aWd1cXFnaTdzZ3JhbmdxczY4YXFkMCZlcD12MV9pbnRlcm5hbF9naWZzX2dpZklkJmN0PXM/l4Fsve0tM4Wl5Y0eQ/giphy.gif" # Calavera con efecto glitch
|
| 9 |
|
| 10 |
-
def
|
| 11 |
if t is None:
|
| 12 |
-
return None, "SYSTEM:
|
|
|
|
| 13 |
try:
|
| 14 |
-
# --- ANALISIS PROFUNDO ---
|
| 15 |
y, sr = librosa.load(t, duration=30)
|
|
|
|
|
|
|
| 16 |
chroma = librosa.feature.chroma_cqt(y=y, sr=sr)
|
| 17 |
nt = ["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"]
|
| 18 |
k = nt[np.argmax(np.mean(chroma, axis=1))]
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
| 20 |
S = np.abs(librosa.stft(y))
|
| 21 |
f = librosa.fft_frequencies(sr=sr)
|
| 22 |
-
|
| 23 |
-
|
| 24 |
|
| 25 |
audio = AudioSegment.from_file(t)
|
| 26 |
-
log = "DIAGNOSTICANDO...\n\n"
|
| 27 |
|
| 28 |
-
# ---
|
| 29 |
if active_fix:
|
| 30 |
-
audio = audio.high_pass_filter(
|
| 31 |
-
if
|
| 32 |
-
audio = audio.low_pass_filter(
|
| 33 |
-
|
| 34 |
-
log += "[+] FIX ACTIVO: Eliminación de sub-graves no audibles.\n"
|
| 35 |
-
|
| 36 |
if active_master:
|
| 37 |
-
|
| 38 |
-
audio = audio.
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
audio.export("game_master.wav", format="wav")
|
| 42 |
|
| 43 |
-
|
| 44 |
-
diag = f"--- MISION: MEZCLA {k} ---\n\n" + log
|
| 45 |
-
diag += "\n[+] OBJETIVOS CRITICOS:\n"
|
| 46 |
-
diag += f"1. SYNTH BASS: Ajustar frecuencia fundamental a {k} ({librosa.note_to_hz(k+'1'):.1f}Hz).\n"
|
| 47 |
-
diag += "2. DRUMS: Usar compresor con Attack 20ms para transientes (Snare/Kick).\n"
|
| 48 |
-
diag += "3. AMBIENTE: Ensanchar la imagen estereo con delay/reverb en sintes.\n"
|
| 49 |
-
diag += "4. BALANCE: Atenuar -2dB en 400Hz (frecuencia 'muddy') si hay sobrecarga."
|
| 50 |
|
| 51 |
-
# ---
|
| 52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
if r is not None:
|
| 54 |
yr, _ = librosa.load(r, duration=30)
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
cp += f"• ENERGIA: Tu unidad está {round(diff_db, 1)} dB por debajo de la referencia.\n"
|
| 59 |
-
cp += "[!] ADVERTENCIA: Necesita mas densidad. Añadir capas de percusion o ambiente.\n"
|
| 60 |
-
cp += "[!] ALERTA: Referencia con +20% energia en 12kHz (brillo). Ajustar High-End."
|
| 61 |
else:
|
| 62 |
-
|
| 63 |
|
| 64 |
-
return "
|
| 65 |
|
| 66 |
except Exception as e:
|
| 67 |
-
return None, f"
|
| 68 |
|
| 69 |
-
# ---
|
| 70 |
css = """
|
| 71 |
-
/* Fondo y Fuentes Globales */
|
| 72 |
body, .gradio-container {
|
| 73 |
-
background-color: #
|
| 74 |
-
color: #
|
| 75 |
-
font-family: '
|
| 76 |
-
text-shadow: 0 0 5px #00ff00; /* Resplandor */
|
| 77 |
-
}
|
| 78 |
-
/* Barra de progreso de carga (invisible) */
|
| 79 |
-
.gradio-container.loading::before {
|
| 80 |
-
content: none !important;
|
| 81 |
-
}
|
| 82 |
-
|
| 83 |
-
/* Header con GIF de calavera */
|
| 84 |
-
#skull-header {
|
| 85 |
-
display: flex; justify-content: center; align-items: center;
|
| 86 |
-
padding: 10px;
|
| 87 |
-
background-color: #000;
|
| 88 |
-
border-bottom: 2px solid #00ff00;
|
| 89 |
-
margin-bottom: 20px;
|
| 90 |
-
box-shadow: 0 0 15px #00ff00;
|
| 91 |
-
}
|
| 92 |
-
#skull-header img {
|
| 93 |
-
filter: drop-shadow(0 0 10px #ff0000); /* Rojo para la calavera, como una alerta */
|
| 94 |
-
}
|
| 95 |
-
h1 {
|
| 96 |
-
text-align: center; text-transform: uppercase; letter-spacing: 7px;
|
| 97 |
-
color: #ff0000; /* Rojo para el título principal */
|
| 98 |
-
font-size: 2.5em; margin-left: 20px;
|
| 99 |
}
|
| 100 |
-
/* Paneles de cada columna */
|
| 101 |
.gr-box {
|
| 102 |
-
background-color: #
|
| 103 |
-
border: 2px solid #
|
| 104 |
-
border-radius:
|
| 105 |
-
box-shadow: 0 0 10px #
|
| 106 |
-
|
| 107 |
}
|
| 108 |
-
/* Labels de Input y Output */
|
| 109 |
-
.gr-text, .gr-label {
|
| 110 |
-
color: #00ffff !important; /* Azul cian para labels */
|
| 111 |
-
font-size: 1.1em;
|
| 112 |
-
text-shadow: 0 0 3px #00ffff;
|
| 113 |
-
}
|
| 114 |
-
/* Botón principal */
|
| 115 |
.gr-button-primary {
|
| 116 |
-
background:
|
| 117 |
-
color:
|
| 118 |
-
border:
|
| 119 |
-
|
| 120 |
-
|
|
|
|
| 121 |
}
|
| 122 |
.gr-button-primary:hover {
|
| 123 |
-
background:
|
| 124 |
-
box-shadow: 0 0
|
| 125 |
-
transform: scale(1.03);
|
| 126 |
-
}
|
| 127 |
-
/* Sliders (Barras de energía) */
|
| 128 |
-
.gr-slider-fill {
|
| 129 |
-
background: linear-gradient(90deg, #00ff00, #ffff00) !important; /* Verde a amarillo */
|
| 130 |
-
}
|
| 131 |
-
.gr-slider-thumb {
|
| 132 |
-
background-color: #ff0000 !important; /* Punto rojo */
|
| 133 |
-
border: 2px solid #00ff00 !important;
|
| 134 |
-
}
|
| 135 |
-
/* Checkboxes */
|
| 136 |
-
.gr-checkbox-label {
|
| 137 |
-
color: #00ff00 !important;
|
| 138 |
-
}
|
| 139 |
-
.gr-checkbox-input {
|
| 140 |
-
border: 2px solid #00ff00 !important;
|
| 141 |
-
background-color: #000 !important;
|
| 142 |
-
}
|
| 143 |
-
.gr-checkbox-input.selected {
|
| 144 |
-
background-color: #ff0000 !important; /* Marcado en rojo */
|
| 145 |
-
}
|
| 146 |
-
/* Textboxes de informes */
|
| 147 |
-
.gr-textbox {
|
| 148 |
-
background-color: #0a0a0a !important;
|
| 149 |
-
border: 1px dashed #00ff00 !important; /* Borde punteado */
|
| 150 |
-
color: #00ff00 !important;
|
| 151 |
-
font-size: 0.9em;
|
| 152 |
-
padding: 10px;
|
| 153 |
-
}
|
| 154 |
-
/* Audio players */
|
| 155 |
-
.gr-audio-player {
|
| 156 |
-
border: 1px solid #00ffff !important;
|
| 157 |
-
background-color: #0a0a0a !important;
|
| 158 |
-
}
|
| 159 |
-
/* GIF en proceso */
|
| 160 |
-
.gr-image {
|
| 161 |
-
border: 2px solid #ff0000 !important;
|
| 162 |
-
box-shadow: 0 0 15px #ff0000;
|
| 163 |
}
|
|
|
|
|
|
|
|
|
|
| 164 |
"""
|
| 165 |
|
| 166 |
with gr.Blocks(theme=gr.themes.Monochrome(), css=css) as demo:
|
| 167 |
-
gr.
|
|
|
|
|
|
|
|
|
|
| 168 |
|
| 169 |
with gr.Row():
|
| 170 |
-
|
| 171 |
-
with gr.Column(variant="panel"):
|
| 172 |
-
gr.Markdown("### >_ INPUT SELECTION")
|
| 173 |
-
in_t = gr.Audio(label="UNIT: AUDIO FILE", type="filepath")
|
| 174 |
-
in_r = gr.Audio(label="UNIT: REFERENCE FILE", type="filepath")
|
| 175 |
-
|
| 176 |
-
gr.Markdown("### >_ PROCESSING MODULES")
|
| 177 |
with gr.Row():
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
in_s = gr.Slider(0, 100, label="POWER: MASTER OUTPUT", value=85)
|
| 181 |
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
gr.
|
| 188 |
-
|
| 189 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
|
|
|
|
|
|
|
|
|
| 196 |
|
| 197 |
-
btn.click(
|
| 198 |
|
| 199 |
demo.launch()
|
|
|
|
| 4 |
from pydub import AudioSegment
|
| 5 |
import os
|
| 6 |
|
| 7 |
+
SKULL_GIF = "https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExNHJueGZ3bmZ3bmZ3bmZ3bmZ3bmZ3bmZ3bmZ3bmZ3bmZ3bmZ3JmVwPXYxX2ludGVybmFsX2dpZl9ieV9pZ25vcmUmY3Q9cw/3o7TKMGpxxcaOlbJp6/giphy.gif"
|
|
|
|
| 8 |
|
| 9 |
+
def ghost_engine_v18(t, r, p, active_fix, active_master):
|
| 10 |
if t is None:
|
| 11 |
+
return None, "SYSTEM: OFFLINE", "NO DATA", "...", "0", "..."
|
| 12 |
+
|
| 13 |
try:
|
|
|
|
| 14 |
y, sr = librosa.load(t, duration=30)
|
| 15 |
+
|
| 16 |
+
# KEY & BPM
|
| 17 |
chroma = librosa.feature.chroma_cqt(y=y, sr=sr)
|
| 18 |
nt = ["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"]
|
| 19 |
k = nt[np.argmax(np.mean(chroma, axis=1))]
|
| 20 |
+
tempo, _ = librosa.beat.beat_track(y=y, sr=sr)
|
| 21 |
+
bpm = str(int(tempo))
|
| 22 |
+
|
| 23 |
+
# ANALISIS DE FRECUENCIAS
|
| 24 |
S = np.abs(librosa.stft(y))
|
| 25 |
f = librosa.fft_frequencies(sr=sr)
|
| 26 |
+
lo = np.mean(S[f < 150])
|
| 27 |
+
mi = np.mean(S[(f >= 150) & (f < 2000)])
|
| 28 |
|
| 29 |
audio = AudioSegment.from_file(t)
|
|
|
|
| 30 |
|
| 31 |
+
# --- PROCESADO INDEPENDIENTE ---
|
| 32 |
if active_fix:
|
| 33 |
+
audio = audio.high_pass_filter(35)
|
| 34 |
+
if lo > mi * 1.3:
|
| 35 |
+
audio = audio.low_pass_filter(4000)
|
| 36 |
+
|
|
|
|
|
|
|
| 37 |
if active_master:
|
| 38 |
+
# FX: Compresión Paralela (Simulada) + Limitador
|
| 39 |
+
audio = audio.compressor_dynamic_range(threshold=-15.0, ratio=4.0, attack=5.0, release=100.0)
|
| 40 |
+
audio = audio.apply_gain((p / 10) - 3)
|
|
|
|
|
|
|
| 41 |
|
| 42 |
+
audio.export("ghost_v18.wav", format="wav")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
|
| 44 |
+
# --- INFORMES ---
|
| 45 |
+
consejos = f"--- TARGET ANALYZED: {k} ---\n\n"
|
| 46 |
+
consejos += f"▶ SUB: Cortado a 35Hz. Espacio libre para el Kick.\n"
|
| 47 |
+
consejos += f"▶ VST: Carga FabFilter Pro-C2 en Bus de Batería. Attack 25ms para dejar pasar el 'transiente'.\n"
|
| 48 |
+
consejos += f"▶ MEZCLA: {k} detectado. Afina tu sub-bajo a {librosa.note_to_hz(k+'1'):.1f}Hz."
|
| 49 |
+
|
| 50 |
+
ref_data = "--- VS HOSTILE DATA ---\n\n"
|
| 51 |
if r is not None:
|
| 52 |
yr, _ = librosa.load(r, duration=30)
|
| 53 |
+
df = 20 * np.log10(np.sqrt(np.mean(yr**2)) / (np.sqrt(np.mean(y**2)) + 1e-6))
|
| 54 |
+
ref_data += f"▶ GAP: {round(df, 1)} dB de potencia.\n"
|
| 55 |
+
ref_data += "▶ BALANCE: Tu track necesita +3dB en zona 5k-10k para igualar brillo."
|
|
|
|
|
|
|
|
|
|
| 56 |
else:
|
| 57 |
+
ref_data += "ESPERANDO REFERENCIA..."
|
| 58 |
|
| 59 |
+
return "ghost_v18.wav", consejos, ref_data, k, bpm, "https://images.unsplash.com/photo-1550684848-fac1c5b4e853?q=80&w=500"
|
| 60 |
|
| 61 |
except Exception as e:
|
| 62 |
+
return None, f"CRITICAL ERROR: {str(e)}", "!", "!", "0", None
|
| 63 |
|
| 64 |
+
# --- CSS DE VIDEOJUEGO (HUD NEÓN) ---
|
| 65 |
css = """
|
|
|
|
| 66 |
body, .gradio-container {
|
| 67 |
+
background-color: #000000 !important;
|
| 68 |
+
color: #ff3e3e !important;
|
| 69 |
+
font-family: 'Orbitron', 'Segoe UI', sans-serif !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
}
|
|
|
|
| 71 |
.gr-box {
|
| 72 |
+
background-color: #050505 !important;
|
| 73 |
+
border: 2px solid #ff3e3e !important;
|
| 74 |
+
border-radius: 0px !important;
|
| 75 |
+
box-shadow: 0 0 10px #ff3e3e55;
|
| 76 |
+
clip-path: polygon(0% 0%, 100% 0%, 100% 90%, 95% 100%, 0% 100%);
|
| 77 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
.gr-button-primary {
|
| 79 |
+
background: #ff3e3e !important;
|
| 80 |
+
color: #000 !important;
|
| 81 |
+
border: none !important;
|
| 82 |
+
font-weight: 900 !important;
|
| 83 |
+
text-transform: uppercase;
|
| 84 |
+
letter-spacing: 2px;
|
| 85 |
}
|
| 86 |
.gr-button-primary:hover {
|
| 87 |
+
background: #ffffff !important;
|
| 88 |
+
box-shadow: 0 0 20px #ffffff;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
}
|
| 90 |
+
.gr-label { color: #00f2ff !important; font-size: 0.7em !important; }
|
| 91 |
+
.gr-textbox textarea { background: #000 !important; color: #ff3e3e !important; border: 1px solid #ff3e3e33 !important; }
|
| 92 |
+
#skull-container { filter: hue-rotate(280deg); margin-bottom: -20px; }
|
| 93 |
"""
|
| 94 |
|
| 95 |
with gr.Blocks(theme=gr.themes.Monochrome(), css=css) as demo:
|
| 96 |
+
with gr.Row(elem_id="skull-container"):
|
| 97 |
+
gr.HTML(f"<div style='text-align:center'><img src='{SKULL_GIF}' width='100'></div>")
|
| 98 |
+
|
| 99 |
+
gr.Markdown("<h1 style='text-align:center; letter-spacing:10px;'>GHOST BRAIN V18</h1>")
|
| 100 |
|
| 101 |
with gr.Row():
|
| 102 |
+
with gr.Column(scale=1):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
with gr.Row():
|
| 104 |
+
out_k = gr.Label(label="KEY")
|
| 105 |
+
out_b = gr.Label(label="BPM")
|
|
|
|
| 106 |
|
| 107 |
+
with gr.Group():
|
| 108 |
+
gr.Markdown("### 📥 DATA INPUT")
|
| 109 |
+
in_t = gr.Audio(label="USER TRACK", type="filepath")
|
| 110 |
+
in_r = gr.Audio(label="REF TARGET", type="filepath")
|
| 111 |
+
|
| 112 |
+
with gr.Group():
|
| 113 |
+
gr.Markdown("### ⚙️ MODULES")
|
| 114 |
+
with gr.Row():
|
| 115 |
+
fix_check = gr.Checkbox(label="MIX FIX", value=False)
|
| 116 |
+
master_check = gr.Checkbox(label="GHOST MASTER", value=False)
|
| 117 |
+
in_p = gr.Slider(0, 100, label="CORE PRESSURE", value=80)
|
| 118 |
+
btn = gr.Button("ENGAGE SYSTEM", variant="primary")
|
| 119 |
|
| 120 |
+
with gr.Column(scale=2):
|
| 121 |
+
with gr.Group():
|
| 122 |
+
gr.Markdown("### 🔊 MONITORING")
|
| 123 |
+
out_a = gr.Audio(label="OUTPUT SIGNAL")
|
| 124 |
+
with gr.Row():
|
| 125 |
+
out_i = gr.Textbox(label="SYSTEM LOGS", lines=12)
|
| 126 |
+
out_c = gr.Textbox(label="INTEL REPORT", lines=12)
|
| 127 |
+
out_v = gr.Image(label="ATMOSPHERE GAUGE")
|
| 128 |
|
| 129 |
+
btn.click(ghost_engine_v18, [in_t, in_r, in_p, fix_check, master_check], [out_a, out_i, out_c, out_k, out_b, out_v])
|
| 130 |
|
| 131 |
demo.launch()
|