diff --git a/main.py b/main.py new file mode 100644 index 0000000..644d519 --- /dev/null +++ b/main.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +import numpy as np +import sounddevice as sd +import matplotlib.pyplot as plt +from matplotlib.colors import LogNorm + +# ========== USER SETTINGS ========== +samplerate = 48000 # sample rate of your system +blocksize = 2048 # larger block -> better frequency resolution +fft_size = 2048 # number of samples per FFT +n_lines = 300 # number of lines in the waterfall (vertical scrolling) +freq_max = 10000 # get the full 20khz audio range +device_name = None # set to your monitor source if you know it# "None" if you dont (without quotes) +delay = 0 +# Example: device_name = "alsa_output.pci-0000_00_1b.0.analog-stereo.monitor" +# Leave as None to be prompted + +# =================================== + +print("\n=== Available audio devices ===") +print(sd.query_devices()) + +if device_name is None: + device_name = input("\nEnter the name or number of your Monitor device: ").strip() + +window = np.hanning(fft_size) +freqs = np.fft.rfftfreq(fft_size, d=1/samplerate) +freq_bins = freqs <= freq_max + +waterfall = np.zeros((n_lines, np.sum(freq_bins))) +fig, ax = plt.subplots(figsize=(10, 6)) +img = ax.imshow(waterfall, origin='lower', aspect='auto', cmap='inferno', + extent=[0, freq_max, 0, n_lines], + norm=LogNorm(vmin=1e-6, vmax=1)) +ax.set_xlabel("Frequency (Hz)") +ax.set_ylabel("Time (scrolling up)") +ax.set_title("Hydrophone Waterfall Spectrogram (0–1 kHz)") +plt.tight_layout() + +def audio_callback(indata, frames, time, status): + global delay + global waterfall + if status: + print(status) + data = indata[:, 0] * window[:frames] + spectrum = np.abs(np.fft.rfft(data))**2 + spectrum = spectrum[freq_bins] + waterfall = np.roll(waterfall, -1, axis=0) + waterfall[-1, :] = spectrum + if delay > 40: + img.set_data(waterfall) + fig.canvas.draw_idle() + delay = 0 + else: + delay = delay + 1 + #plt.pause(0.001) + +with sd.InputStream(device=device_name, channels=1, + samplerate=samplerate, blocksize=blocksize, + callback=audio_callback): + print("\nāœ… Listening to output via:", device_name) + print("Close the window or Ctrl+C to stop.\n") + plt.show() +