Imageform / wavetopic.py
electric-otter's picture
Create wavetopic.py
fc5c959 verified
import numpy as np
import matplotlib.pyplot as plt
import sounddevice as sd
from scipy.fftpack import fft
import time
import os
# Configuration
SAMPLE_RATE = 44100 # Hz
DURATION = 5 # seconds
CHUNK_SIZE = 1024 # samples
PLOT_REFRESH_RATE = 0.1 # seconds
# Create a figure with two subplots (waveform and spectrum)
plt.ion() # Interactive mode on
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8))
fig.suptitle('Live Microphone Waveform & Spectrum')
# Initialize empty plots
line_wave, = ax1.plot(np.arange(CHUNK_SIZE), np.zeros(CHUNK_SIZE))
line_spectrum, = ax2.plot(np.arange(CHUNK_SIZE//2), np.zeros(CHUNK_SIZE//2))
# Axis settings
ax1.set_ylim(-1, 1)
ax1.set_xlim(0, CHUNK_SIZE)
ax1.set_title('Waveform')
ax1.set_ylabel('Amplitude')
ax2.set_xlim(0, CHUNK_SIZE//2)
ax2.set_ylim(0, 1)
ax2.set_title('Spectrum')
ax2.set_ylabel('Magnitude')
ax2.set_xlabel('Frequency Bin')
# Audio callback function
def audio_callback(indata, frames, time, status):
if status:
print(status, flush=True)
# Update waveform plot
line_wave.set_ydata(indata[:, 0])
# Compute and update spectrum
N = len(indata[:, 0])
yf = fft(indata[:, 0])
xf = np.linspace(0, SAMPLE_RATE//2, N//2)
line_spectrum.set_ydata(2/N * np.abs(yf[:N//2]))
# Redraw the plots
fig.canvas.draw()
fig.canvas.flush_events()
# Start streaming
stream = sd.InputStream(
callback=audio_callback,
samplerate=SAMPLE_RATE,
channels=1,
blocksize=CHUNK_SIZE
)
try:
print("Starting audio capture... Press Ctrl+C to stop.")
with stream:
while True:
time.sleep(PLOT_REFRESH_RATE)
except KeyboardInterrupt:
print("\nStopping audio capture...")
# Save the final plot as an image
timestamp = time.strftime("%Y%m%d-%H%M%S")
filename = f"waveform_{timestamp}.png"
fig.savefig(filename)
print(f"Saved waveform image as {filename}")
plt.close()
except Exception as e:
print(f"Error: {e}")
plt.close()