File size: 6,462 Bytes
4f66327
12361b7
 
 
 
18404a6
f9619b4
12361b7
 
 
 
 
 
 
 
 
f9619b4
12361b7
 
 
 
 
 
 
 
 
f9619b4
12361b7
 
 
 
5859700
18404a6
 
 
12361b7
18404a6
12361b7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5859700
18404a6
 
5859700
12361b7
 
 
 
 
 
 
5859700
 
4f66327
5859700
 
12361b7
cfce041
18404a6
5859700
12361b7
5859700
 
 
12361b7
 
 
5859700
 
 
12361b7
5859700
 
 
f9619b4
5859700
e312a32
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
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()