93 lines
2.5 KiB
Python
Executable File
93 lines
2.5 KiB
Python
Executable File
#!/usr/bin/env nix-script
|
|
#!>python
|
|
#! python3 | matplotlib numpy scipy pyaudio
|
|
|
|
## Real-time sound spectrum analysis.
|
|
|
|
import pyaudio
|
|
import scipy.fftpack
|
|
import scipy.interpolate
|
|
import numpy as np
|
|
import matplotlib.pyplot as plt
|
|
from matplotlib.animation import FuncAnimation
|
|
|
|
# pyAudio settings
|
|
settings = {
|
|
"format": pyaudio.paInt16,
|
|
"channels": 2,
|
|
"rate": 48000,
|
|
"input": True,
|
|
"frames_per_buffer": 1024
|
|
}
|
|
audio = pyaudio.PyAudio()
|
|
stream = audio.open(**settings)
|
|
|
|
# plt configurations
|
|
plt.style.use('seaborn-v0_8-dark')
|
|
fig, (spectrum_log, spectrum, wave) = plt.subplots(nrows=3, ncols=1)
|
|
fig.dpi = 200
|
|
|
|
|
|
def init():
|
|
plt.subplots_adjust(hspace=0.5, left=0.1)
|
|
global curve1, curve2, curve3
|
|
|
|
# Plot settings
|
|
spectrum_log.set_ylabel("a / dB")
|
|
spectrum_log.set_xlabel("ƒ / Hz")
|
|
spectrum_log.ticklabel_format(style="sci", scilimits=(0, 0),
|
|
axis="x", useMathText=True)
|
|
spectrum_log.grid(True)
|
|
curve1, = spectrum_log.plot([0, 8 * 10 ** 3], [0, 10 ** 2], "b-")
|
|
|
|
spectrum.yaxis.set_visible(False)
|
|
spectrum_log.set_ylabel("a")
|
|
spectrum.set_xlabel("ƒ / Hz")
|
|
spectrum.ticklabel_format(style="sci", scilimits=(0, 0),
|
|
axis="x", useMathText=True)
|
|
spectrum.grid(True)
|
|
curve2, = spectrum.plot([0, 8 * 10 ** 3], [0, 10 ** 5])
|
|
|
|
wave.set_xlim(0, 8 * 10 ** 3)
|
|
wave.xaxis.set_visible(False)
|
|
wave.yaxis.set_visible(False)
|
|
curve3, = wave.plot([0, 8 * 10 ** 3], [-2 * 10 ** 3, 2 * 10 ** 3], "g-")
|
|
|
|
return curve1, curve2, curve3
|
|
|
|
|
|
def update(frame):
|
|
# Acquire data from microphone
|
|
block = np.array(np.frombuffer(
|
|
stream.read(settings["frames_per_buffer"],
|
|
exception_on_overflow=False),
|
|
dtype="int16"))
|
|
|
|
# FFT of registred block
|
|
fftx = scipy.fftpack.rfftfreq(
|
|
settings["frames_per_buffer"],
|
|
1 / settings["rate"])
|
|
|
|
# Calculate log version
|
|
ffty = abs(scipy.fftpack.fft(block)[0:len(fftx)])
|
|
ffty_log = 10 * np.log10(ffty)
|
|
|
|
# Data interpolation
|
|
wave = scipy.interpolate.interp1d(fftx, block[0:len(fftx)])(fftx)
|
|
|
|
# Update plot data
|
|
curve1.set_xdata(fftx)
|
|
curve2.set_xdata(fftx)
|
|
curve3.set_xdata(fftx)
|
|
|
|
curve1.set_ydata(ffty_log)
|
|
curve2.set_ydata(ffty)
|
|
curve3.set_ydata(wave)
|
|
|
|
return curve1, curve2, curve3
|
|
|
|
ani = FuncAnimation(fig, func=update, init_func=init,
|
|
interval=10,
|
|
blit=True, cache_frame_data=False)
|
|
plt.show()
|