|
|
import numpy as np |
|
|
import matplotlib.pyplot as plt |
|
|
import sounddevice as sd |
|
|
from scipy.fftpack import fft |
|
|
import time |
|
|
import os |
|
|
|
|
|
|
|
|
SAMPLE_RATE = 44100 |
|
|
DURATION = 5 |
|
|
CHUNK_SIZE = 1024 |
|
|
PLOT_REFRESH_RATE = 0.1 |
|
|
|
|
|
|
|
|
plt.ion() |
|
|
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8)) |
|
|
fig.suptitle('Live Microphone Waveform & Spectrum') |
|
|
|
|
|
|
|
|
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)) |
|
|
|
|
|
|
|
|
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') |
|
|
|
|
|
|
|
|
def audio_callback(indata, frames, time, status): |
|
|
if status: |
|
|
print(status, flush=True) |
|
|
|
|
|
|
|
|
line_wave.set_ydata(indata[:, 0]) |
|
|
|
|
|
|
|
|
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])) |
|
|
|
|
|
|
|
|
fig.canvas.draw() |
|
|
fig.canvas.flush_events() |
|
|
|
|
|
|
|
|
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...") |
|
|
|
|
|
|
|
|
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() |