tinnitus / app.py
vitorcalvi
first commit
ffc9ee0
import gradio as gr
import numpy as np
from scipy import signal
import soundfile as sf
import matplotlib.pyplot as plt
import io
def generate_test_tone(frequency, duration=1.0, sample_rate=44100):
t = np.linspace(0, duration, int(sample_rate * duration))
tone = np.sin(2 * np.pi * frequency * t)
return tone * np.hanning(len(tone))
def create_audiogram(left_ear_results, right_ear_results):
frequencies = [250, 500, 1000, 2000, 4000, 8000]
plt.figure(figsize=(10, 8))
plt.fill_between([125, 8000], -10, 25, color='#e6f3ff', alpha=0.3, label='Normal Hearing')
plt.fill_between([125, 8000], 25, 40, color='#b3d9ff', alpha=0.3, label='Mild Loss')
plt.fill_between([125, 8000], 40, 55, color='#80bfff', alpha=0.3, label='Moderate Loss')
plt.fill_between([125, 8000], 55, 70, color='#4da6ff', alpha=0.3, label='Moderate-Severe Loss')
plt.plot(frequencies, left_ear_results, 'x-', color='blue', label='Left Ear')
plt.plot(frequencies, right_ear_results, 'o-', color='red', label='Right Ear')
plt.xscale('log')
plt.xlim(125, 8000)
plt.ylim(70, -10)
plt.grid(True)
plt.xlabel('Frequency (Hz)')
plt.ylabel('Hearing Level (dB)')
plt.title('Audiogram Results')
plt.legend()
buf = io.BytesIO()
plt.savefig(buf, format='png')
plt.close()
return buf
def hearing_test(frequency, volume, ear_selection):
sample_rate = 44100
tone = generate_test_tone(float(frequency), 1.0, sample_rate)
volume_adjusted = tone * (10 ** (volume / 20))
stereo_tone = np.zeros((2, len(tone)))
if ear_selection == "Left":
stereo_tone[0] = volume_adjusted
elif ear_selection == "Right":
stereo_tone[1] = volume_adjusted
else:
stereo_tone[0] = stereo_tone[1] = volume_adjusted
output_path = f"test_tone_{frequency}Hz.wav"
sf.write(output_path, stereo_tone.T, sample_rate)
return output_path
def generate_audio(duration, selected_frequencies):
sample_rate = 44100
num_samples = int(float(duration) * sample_rate)
noise = np.random.normal(0, 1, num_samples)
if selected_frequencies:
frequencies = [int(f) for f in selected_frequencies]
for freq in frequencies:
depth = -40 if freq == 4000 else -30
width = freq / 10
nyquist = sample_rate / 2
freq_normalized = freq / nyquist
quality_factor = freq / width
b, a = signal.iirnotch(freq_normalized, quality_factor)
noise = signal.filtfilt(b, a, noise)
noise *= 10 ** (depth / 20)
noise = noise / np.max(np.abs(noise))
output_path = "notched_noise.wav"
sf.write(output_path, noise, sample_rate)
return output_path
def create_interface():
with gr.Blocks(title="Hearing Test & White Noise Generator") as app:
with gr.Tabs():
with gr.Tab("Hearing Test"):
gr.Markdown("## Hearing Test")
with gr.Row():
with gr.Column():
frequency = gr.Dropdown(
choices=["250", "500", "1000", "2000", "4000", "8000"],
value="1000",
label="Test Frequency (Hz)"
)
volume = gr.Slider(
minimum=-60,
maximum=0,
value=-20,
step=5,
label="Volume (dB)"
)
ear_select = gr.Radio(
choices=["Both", "Left", "Right"],
value="Both",
label="Ear Selection"
)
test_btn = gr.Button("Play Test Tone")
with gr.Column():
audio_output = gr.Audio(label="Test Tone")
with gr.Row():
with gr.Column():
left_thresholds = [gr.Number(value=0, label=f"{freq}Hz Left") for freq in [250, 500, 1000, 2000, 4000, 8000]]
with gr.Column():
right_thresholds = [gr.Number(value=0, label=f"{freq}Hz Right") for freq in [250, 500, 1000, 2000, 4000, 8000]]
generate_audiogram_btn = gr.Button("Generate Audiogram")
audiogram_output = gr.Image(label="Audiogram")
with gr.Tab("White Noise Generator"):
gr.Markdown("## Notched White Noise Generator")
with gr.Row():
with gr.Column():
duration = gr.Slider(
minimum=1,
maximum=30,
value=5,
step=1,
label="Duration (seconds)"
)
frequencies = gr.CheckboxGroup(
choices=["250", "500", "1000", "2000", "4000", "8000"],
label="Frequencies to Notch (Hz)",
value=["4000", "2000"]
)
generate_noise_btn = gr.Button("Generate Noise")
with gr.Column():
noise_output = gr.Audio(label="Generated Noise")
test_btn.click(
fn=hearing_test,
inputs=[frequency, volume, ear_select],
outputs=audio_output
)
generate_audiogram_btn.click(
fn=lambda *args: create_audiogram(args[:6], args[6:]).getvalue(),
inputs=left_thresholds + right_thresholds,
outputs=audiogram_output
)
generate_noise_btn.click(
fn=generate_audio,
inputs=[duration, frequencies],
outputs=noise_output
)
return app
if __name__ == "__main__":
app = create_interface()
app.launch(share=False)