import numpy as np import matplotlib.pyplot as plt import sounddevice as sd import pywt import threading # PARAMETROS --------------------------- N_CELLS = 120 FREQ_MIN = 100 FREQ_MAX = 8000 fs = 44100 frame = 2048 # ~46ms center_freqs = np.logspace(np.log10(FREQ_MIN), np.log10(FREQ_MAX), N_CELLS) latest_audio = None lock = threading.Lock() def cochlea_waveletbank(frame, fs): wavelet = 'morl' fc = pywt.central_frequency(wavelet) scales = fc * fs / center_freqs coeffs, freqs = pywt.cwt(frame, scales, wavelet, sampling_period=1/fs) power = np.mean(np.abs(coeffs) ** 2, axis=1) # Converte energia para dB (escala logarítmica) power_db = 10 * np.log10(power + 1e-12) return power_db def audio_callback(indata, frames, time, status): global latest_audio mono = indata[:, 0] with lock: latest_audio = mono.copy() # só copia o frame, nada pesado plt.ion() fig, ax = plt.subplots(figsize=(14,5)) larguras = np.diff(np.logspace(np.log10(FREQ_MIN), np.log10(FREQ_MAX), N_CELLS+1)) bars = ax.bar(center_freqs, np.zeros(N_CELLS), width=larguras, bottom=-80, # <<--- faz as barras nascerem em -80 dB color="dodgerblue", alpha=0.7, align="edge") ax.set_xscale("log") ax.set_ylim(-80, 20) # de -80 dB (silêncio) até 0 dB (máximo) ax.set_xlabel("Frequência (Hz)") ax.set_ylabel("Intensidade (dB)") ax.set_title("Demonstração de Cóclea em Tempo Real") # LOOP PRINCIPAL --------------------------------------------------- with sd.InputStream(channels=1, samplerate=fs, blocksize=frame, callback=audio_callback): print("!! rodando em tempo real !!") while True: plt.pause(0.001) with lock: audio = latest_audio if audio is None: continue # wavelet ativ = cochlea_waveletbank(audio, fs) # atualiza grafico for b, h in zip(bars, ativ): b.set_height(h + 80) regions = [ (3000, 6000, "#0f62fe"), # azul (0, 150, "#42be65"), # verde (1500, 3000, "#be95ff"), # roxo (150, 375,"#ff832b"), # laranja (375, 750,"#fa4d56"), # vermelho (750, 1500,"#ff7eb6"), # rosa (6000, 10000,"#08bdba") # ciano ] for b, f in zip(bars, center_freqs): for fmin, fmax, color in regions: if fmin <= f < fmax: b.set_color(color) break fig.canvas.draw() fig.canvas.flush_events()