Skip to content

Instantly share code, notes, and snippets.

@netom
Last active July 24, 2023 21:51
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save netom/8221b3588158021704d5891a4f9c0edd to your computer and use it in GitHub Desktop.
Save netom/8221b3588158021704d5891a4f9c0edd to your computer and use it in GitHub Desktop.
Simple spectrum analyzer in python using pyaudio and matplotlib
#!/usr/bin/env python
# -*- charset utf8 -*-
import pyaudio
import numpy
import math
import matplotlib.pyplot as plt
import matplotlib.animation
RATE = 44100
BUFFER = 882
p = pyaudio.PyAudio()
stream = p.open(
format = pyaudio.paFloat32,
channels = 1,
rate = RATE,
input = True,
output = False,
frames_per_buffer = BUFFER
)
fig = plt.figure()
line1 = plt.plot([],[])[0]
line2 = plt.plot([],[])[0]
r = range(0,int(RATE/2+1),int(RATE/BUFFER))
l = len(r)
def init_line():
line1.set_data(r, [-1000]*l)
line2.set_data(r, [-1000]*l)
return (line1,line2,)
def update_line(i):
try:
data = numpy.fft.rfft(numpy.fromstring(
stream.read(BUFFER), dtype=numpy.float32)
)
except IOError:
pass
data = numpy.log10(numpy.sqrt(
numpy.real(data)**2+numpy.imag(data)**2) / BUFFER) * 10
line1.set_data(r, data)
line2.set_data(numpy.maximum(line1.get_data(), line2.get_data()))
return (line1,line2,)
plt.xlim(0, RATE/2+1)
plt.ylim(-60, 0)
plt.xlabel('Frequency')
plt.ylabel('dB')
plt.title('Spectrometer')
plt.grid()
line_ani = matplotlib.animation.FuncAnimation(
fig, update_line, init_func=init_line, interval=0, blit=True
)
plt.show()
@netom
Copy link
Author

netom commented Jan 5, 2017

Revision 2 is compatible with Python 3

@amcolash
Copy link

amcolash commented Jun 3, 2019

awesome, thanks for the starting point for a project of mine!

@netom
Copy link
Author

netom commented Jun 3, 2019

You're welcome. It's nice to know that it's useful for somebody else too. :)

@amcolash
Copy link

amcolash commented Jun 5, 2019

I am using it with my hyperion setup to have the leds pulse like a visualizer! Looks pretty slick so far: repo

@netom
Copy link
Author

netom commented Jun 6, 2019

Sounds nice :)

@m1zar
Copy link

m1zar commented Oct 16, 2020

Thanks for this, useful code, I'm sure it will be the starting point of many a good project. Most all other examples I've found are out of date and non-functional. Thanks for this!

@netom
Copy link
Author

netom commented Oct 19, 2020

Thank you @m1zar, it's always good to hear positive feedback :)

@thecompoundingdev
Copy link

thecompoundingdev commented May 26, 2021

In python 3.9, I keep getting an error at startup saying that data is undefined:

"in update_line
np.real(data)**2+np.imag(data)**2) / BUFFER) * 10
UnboundLocalError: local variable 'data' referenced before assignment"

@lony
Copy link

lony commented Aug 29, 2021

@netom I have similar problems as @thecompoundingdev. After tinkering around, it seemed this first error was the OSX microphone access. Still now the next error seems to be related to numpy and the spectrometer values. I tinkered around but could not solve this, do you have any idea what could be wrong?

...
File "/Users/lony/Desktop/dump/audio_filter/./spectrum.py.py", line 46, in update_line
    line2.set_data(np.maximum(line1.get_data(), line2.get_data()))
ValueError: operands could not be broadcast together with shapes (2,) (2,2206)

I use the followng versions

❯ python --version
Python 3.9.6

❯ cat requirements.txt
matplotlib==3.4.3
numpy==1.21.2
PyAudio==0.2.11

@djsm83
Copy link

djsm83 commented Jul 24, 2023

@netom any chance you have an example with an logarithmic frequency axis? I am not able to get it to work using semilogx etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment