david174 commited on
Commit
da2b151
·
verified ·
1 Parent(s): 87378e6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +94 -74
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 de inteligencia de sesión
8
- ghost_brain = {
9
- "key": "--", "bpm": 0, "low_level": 0, "mid_level": 0, "high_level": 0, "status": "Inactivo"
 
10
  }
11
 
12
- def ghost_analyser_v23(t, r, p, active_fix, active_master):
13
- global ghost_brain
14
  if t is None:
15
- return None, "SISTEMA: OFFLINE", "NO DATA", "--", "0", None
16
 
17
  try:
18
- y, sr = librosa.load(t, duration=30)
 
19
 
20
- # KEY & BPM
 
 
 
 
 
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
- tempo, _ = librosa.beat.beat_track(y=y, sr=sr)
25
- bpm = int(np.atleast_1d(tempo)[0])
 
 
 
 
26
 
27
- # Análisis Espectral Detallado
28
  S = np.abs(librosa.stft(y))
29
  f = librosa.fft_frequencies(sr=sr)
30
 
31
- ghost_brain.update({
32
- "key": k, "bpm": bpm,
33
- "low_level": np.mean(S[f < 200]),
34
- "mid_level": np.mean(S[(f >= 200) & (f < 2500)]),
35
- "high_level": np.mean(S[f >= 2500]),
36
- "status": "Analizado"
 
 
 
 
 
37
  })
38
 
39
  audio = AudioSegment.from_file(t)
40
- if active_fix:
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 active_master:
46
- audio = audio.compressor_dynamic_range(threshold=-16.0, ratio=4.0, attack=10.0, release=150.0)
47
- audio = audio.apply_gain((p / 10) - 3)
 
 
 
48
 
49
- audio.export("ghost_v23.wav", format="wav")
 
 
 
 
50
 
51
- diag = f"--- REPORTE DINÁMICO: {k} ---\n\n"
52
- diag += f" BALANCE: {'Grave/Pesado' if ghost_brain['low_level'] > ghost_brain['mid_level'] else 'Medio/Agudo'}\n"
53
- diag += f" ENERGÍA: {bpm} BPM detectados. Ritmo optimizado.\n"
54
- diag += "\n[!] El mentor ya conoce tu track. Hazle una pregunta abajo."
55
 
56
- return "ghost_v23.wav", diag, "Análisis completado.", k, str(bpm), "https://images.unsplash.com/photo-1550684848-fac1c5b4e853?q=80&w=500"
57
 
58
  except Exception as e:
59
- return None, f"ERROR: {str(e)}", "!", "!", "0", None
60
 
61
- def dynamic_chat(pregunta):
62
- if ghost_brain["status"] == "Inactivo":
63
- return "ERROR: Primero debes procesar un audio para que pueda conocer tu sonido."
64
 
65
- msg = pregunta.lower()
66
- k = ghost_brain["key"]
67
- b = ghost_brain["bpm"]
68
- f_fund = round(librosa.note_to_hz(k+'1'), 1)
 
69
 
70
- # LÓGICA DE RESPUESTA BASADA EN DATOS REALES
71
- if "bajo" in msg or "grave" in msg:
72
- if ghost_brain["low_level"] > ghost_brain["mid_level"]:
73
- return f"He detectado que tus graves están saturados. Como tu nota es {k}, haz un corte quirúrgico en {f_fund*2}Hz (el primer armónico) para limpiar el barro sin perder potencia en el sub ({f_fund}Hz)."
74
- else:
75
- return f"Tus graves están controlados. Para que el bajo en {k} destaque más, añade saturación tipo 'Tube' y asegúrate de que nada por debajo de 100Hz esté en estéreo."
 
 
 
76
 
77
- elif "pegada" in msg or "kick" in msg or "snare" in msg:
78
- release_val = round(60000 / b / 4, 1) # Cálculo de release basado en BPM (1/16 note)
79
- return f"Para este tempo de {b} BPM, configura tu compresor con un Attack de 30ms y un Release de {release_val}ms. Esto hará que el compresor 'respire' al ritmo de la música."
 
80
 
81
- elif "brillo" in msg or "agudo" in msg:
82
- if ghost_brain["high_level"] < ghost_brain["mid_level"] * 0.5:
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
- else:
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-color: #000 !important; color: #ff8800 !important;} .gr-box {border: 2px solid #ff8800 !important;} .gr-button-primary {background: #ff8800 !important; color: #000 !important; font-weight: bold;}"
92
 
93
  with gr.Blocks(theme=gr.themes.Monochrome(), css=css) as demo:
94
- gr.Markdown("# 💀 GHOST DYNAMIC MENTOR v23")
 
95
  with gr.Row():
96
  with gr.Column(scale=1):
97
- out_k = gr.Label(label="KEY")
98
- out_b = gr.Label(label="BPM")
99
- in_t = gr.Audio(label="TU TRACK", type="filepath")
100
- in_r = gr.Audio(label="REFERENCIA", type="filepath")
101
- fix_check = gr.Checkbox(label="AUTO-FIX", value=False)
102
- mst_check = gr.Checkbox(label="MASTER", value=False)
103
- in_p = gr.Slider(0, 100, label="POWER", value=80)
104
- btn = gr.Button("🚀 PROCESAR SEÑAL", variant="primary")
 
 
105
 
106
  with gr.Column(scale=2):
107
- out_a = gr.Audio(label="RESULTADO")
108
- out_i = gr.Textbox(label="DIAGNÓSTICO TÉCNICO", lines=6)
109
 
110
  with gr.Group():
111
- gr.Markdown("### 💬 CONSULTA AL INGENIERO (Dinámico)")
112
- user_msg = gr.Textbox(placeholder="Ej: ¿Cómo arreglo el bajo? / ¿Qué tal el brillo?", label="Tu pregunta")
113
- chat_btn = gr.Button("OBTENER ASESORÍA PERSONALIZADA")
114
- chat_out = gr.Textbox(label="RESPUESTA BASADA EN TU MEZCLA", lines=4)
115
 
116
- btn.click(ghost_analyser_v23, [in_t, in_r, in_p, fix_check, mst_check], [out_a, out_i, out_k, out_b])
117
- chat_btn.click(dynamic_chat, [user_msg], [chat_out])
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()