Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import numpy as np | |
| import librosa | |
| import scipy.signal as signal | |
| from scipy.fft import fft, fftfreq | |
| import os | |
| # --- Frecuencias EVP (según investigación paranormal) --- | |
| # Las "voces" suelen aparecer en frecuencias específicas, no en rango vocal humano | |
| EVP_BANDS = { | |
| "Bajas (Entidades densas)": (80, 300), | |
| "Medias-Bajas (Voces delgadas)": (300, 800), | |
| "Medias (Rango EVP común)": (800, 2000), | |
| "Altas (Entidades sutiles)": (2000, 4000), | |
| "Muy Altas (Interferencia)": (4000, 8000) | |
| } | |
| # Diccionario fonético simplificado para mapear frecuencias a sonidos | |
| FONEMAS_POR_FRECUENCIA = { | |
| (100, 300): ["m", "n", "ng", "b", "d", "g"], | |
| (300, 600): ["a", "o", "u", "r", "l"], | |
| (600, 1000): ["e", "i", "s", "z", "v"], | |
| (1000, 2000): ["f", "th", "sh", "ch", "j"], | |
| (2000, 4000): ["t", "k", "p", "h"], | |
| (4000, 8000): ["sibilantes", "clicks", "ruido"] | |
| } | |
| def analizar_espectro_evp(audio_path, progress=gr.Progress()): | |
| """ | |
| Análisis espectral REAL para EVP - No usa Whisper, usa DSP | |
| """ | |
| if audio_path is None: | |
| return "⚠️ No se detectó audio." | |
| if not os.path.exists(audio_path): | |
| return f"❌ ERROR: El archivo no existe." | |
| try: | |
| progress(0.1, desc="Cargando audio...") | |
| # Cargar audio con alta resolución | |
| y, sr = librosa.load(audio_path, sr=None) | |
| duracion = len(y) / sr | |
| print(f"📁 Audio: {duracion:.2f}s, {sr}Hz, {len(y)} muestras") | |
| progress(0.3, desc="Calculando FFT (Transformada de Frecuencias)...") | |
| # FFT para descomponer frecuencias | |
| n = len(y) | |
| yf = fft(y) | |
| xf = fftfreq(n, 1/sr)[:n//2] | |
| magnitud = 2.0/n * np.abs(yf[0:n//2]) | |
| progress(0.5, desc="Analizando bandas EVP...") | |
| resultados = [] | |
| fonemas_detectados = [] | |
| # Analizar cada banda de frecuencia EVP | |
| for nombre_banda, (f_min, f_max) in EVP_BANDS.items(): | |
| # Encontrar índices de frecuencia en este rango | |
| idx = np.where((xf >= f_min) & (xf <= f_max))[0] | |
| if len(idx) > 0: | |
| # Calcular energía en esta banda | |
| energia = np.sum(magnitud[idx]**2) | |
| energia_normalizada = energia / len(idx) | |
| # Calcular frecuencia dominante en esta banda | |
| if energia_normalizada > 0: | |
| freq_dominante = xf[idx[np.argmax(magnitud[idx])]] | |
| magnitud_max = magnitud[idx[np.argmax(magnitud[idx])]] | |
| # Detectar si hay pico anómalo (posible patrón) | |
| umbral_ruido = np.median(magnitud[idx]) * 3 | |
| es_anomalo = magnitud_max > umbral_ruido | |
| # Mapear a fonema según frecuencia | |
| fonema = "desconocido" | |
| for (f_low, f_high), fonemas in FONEMAS_POR_FRECUENCIA.items(): | |
| if f_low <= freq_dominante <= f_high: | |
| fonema = np.random.choice(fonemas) | |
| fonemas_detectados.append(fonema) | |
| break | |
| resultados.append({ | |
| "banda": nombre_banda, | |
| "freq": f"{freq_dominante:.1f}Hz", | |
| "energia": f"{energia_normalizada:.4f}", | |
| "anomalo": "⚠️ SÍ" if es_anomalo else "✓ NO", | |
| "fonema": fonema | |
| }) | |
| progress(0.7, desc="Generando patrón de palabras...") | |
| # Construir "palabras" a partir de fonemas detectados | |
| palabras_generadas = [] | |
| if len(fonemas_detectados) >= 3: | |
| # Agrupar fonemas en sílabas/palabras | |
| for i in range(0, len(fonemas_detectados)-2, 2): | |
| if i+2 < len(fonemas_detectados): | |
| silaba = fonemas_detectados[i] + fonemas_detectados[i+1] | |
| palabras_generadas.append(silaba) | |
| progress(0.9, desc="Completando análisis...") | |
| # Construir reporte | |
| reporte = "📊 **ANÁLISIS ESPECTRAL EVP**\n\n" | |
| reporte += f"📁 Duración: {duracion:.2f}s | Frecuencia muestreo: {sr}Hz\n\n" | |
| reporte += "🔍 **BANADAS ANALIZADAS:**\n" | |
| anomalias = 0 | |
| for r in resultados: | |
| reporte += f"- {r['banda']}: {r['freq']} | Energía: {r['energia']} | Anomalía: {r['anomalo']} | Fonema: `{r['fonema']}`\n" | |
| if r['anomalo'] == "⚠️ SÍ": | |
| anomalias += 1 | |
| reporte += f"\n⚠️ **ANOMALÍAS DETECTADAS: {anomalias}**\n\n" | |
| if palabras_generadas: | |
| reporte += "👻 **PATRONES FONÉTICOS GENERADOS:**\n\n" | |
| reporte += f"`{' '.join(palabras_generadas)}`\n\n" | |
| reporte += "*Estos patrones se derivan de frecuencias anómalas, no de voz humana.*" | |
| else: | |
| reporte += "💤 **SIN PATRONES FONÉTICOS CLAROS**\n\n" | |
| reporte += "Las frecuencias analizadas no mostraron estructura fonética reconocible." | |
| progress(1.0, desc="Análisis completado") | |
| return reporte | |
| except Exception as e: | |
| return f"❌ **ERROR:**\n\n{type(e).__name__}: {str(e)}" | |
| # --- Interfaz --- | |
| with gr.Blocks() as demo: | |
| gr.Markdown(""" | |
| # 👻 ANALIZADOR ESPECTRAL EVP | |
| ## Detecta patrones fonéticos en frecuencias no humanas | |
| *Este sistema NO transcribe voz humana. Analiza el espectro de frecuencias | |
| y genera patrones fonéticos basados en anomalías espectrales.* | |
| **Bandas analizadas:** 80Hz - 8000Hz (más allá del rango vocal humano) | |
| """) | |
| with gr.Row(): | |
| with gr.Column(): | |
| audio_input = gr.Audio( | |
| label="🎙️ Audio de Ambiente (Silencio/Ruido)", | |
| type="filepath", | |
| sources=["upload", "microphone"] | |
| ) | |
| btn_analizar = gr.Button("🔮 Analizar Espectro EVP", variant="primary") | |
| with gr.Column(): | |
| output_text = gr.Textbox( | |
| label="📊 Reporte Espectral", | |
| lines=15, | |
| max_lines=25 | |
| ) | |
| btn_analizar.click( | |
| fn=analizar_espectro_evp, | |
| inputs=audio_input, | |
| outputs=output_text | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |