Skip to content

Instantly share code, notes, and snippets.

@daniel-j
Last active January 14, 2024 02:28
Show Gist options
  • Save daniel-j/f1406e301ab2c38ba53c to your computer and use it in GitHub Desktop.
Save daniel-j/f1406e301ab2c38ba53c to your computer and use it in GitHub Desktop.
PiGlow FFT audio visualizer | https://youtu.be/lJcLoAAGdoo
#!/usr/bin/env python
# by djazz, using various bits of code found over the web
# works with both python2 and python3
# requires: python-alsaaudio, python-numpy, python-smbus, piglow
# install piglow: curl get.pimoroni.com/piglow | bash
# usage:
# this script accepts raw audio in this format: S16LE 44100 kHz Mono
# script-that-outputs-audio | python piglow_fft.py
# echo raw.pcm | piglow_fft.py
# see usage suggestions below
# examples:
# mpg123 -s --no-seekbuffer -m -r 44100 http://icecast.djazz.se:8000/radio | python piglow_fft.py
# avconv -i http://icecast.djazz.se:8000/radio -f s16le -acodec pcm_s16le -ar 44100 -ac 1 - -nostats -loglevel info | python piglow_fft.py
# you can replace the url with a local file path
# currently it's pointing to http://radio.djazz.se
import sys
import io
from time import sleep
from struct import unpack
import numpy as np
import alsaaudio as aa
# comment out all lines referencing piglow
# if you want to try just the fft analyzer
import piglow
# Return power array index corresponding to a particular frequency
def piff(val):
return int(2 * chunksize * val/sample_rate)
# Initialize the arrays
bins = [0,0,0,0,0,0]
smoothbins = [0,0,0,0,0,0] # for smoothing
weighting = [1, 1.5, 3, 4, 6.5, 9] # Change these according to taste
# Precalculate weighting bins
weighting = np.true_divide(weighting, 1000000)
# audio settings
sample_rate = 44100
no_channels = 1 # mono only
chunksize = 2048
# stdin acts as a file, read() method
stdin = getattr(sys.stdin, 'buffer', sys.stdin)
# setp up audio output
output = aa.PCM(aa.PCM_PLAYBACK, aa.PCM_NORMAL)
output.setchannels(no_channels)
output.setrate(sample_rate)
output.setformat(aa.PCM_FORMAT_S16_LE)
output.setperiodsize(chunksize*no_channels)
print("Loading...")
data = stdin.read(chunksize*5)
print("Playing...")
output.write(data)
counter = 0
while data!='':
data = stdin.read(chunksize)
output.write(data)
npdata = np.array(unpack("%dh"%(len(data)/2), data), dtype='h')
fourier = np.fft.rfft(npdata)
fourier = np.delete(fourier, len(fourier) -1)
power = np.abs(fourier)
lower_bound = 0
upper_bound = 64
for i in range(len(bins)):
mean = np.mean(power[piff(lower_bound) : piff(upper_bound):1])
bins[i] = int(mean) if np.isnan(mean) == False else 0
# if counter == 0:
# print([piff(lower_bound), piff(upper_bound)])
lower_bound = upper_bound
upper_bound = upper_bound << 1
bins = np.divide(np.multiply(bins,weighting),5)
a = ''
for i in range(6):
m = bins[i]
smoothbins[i] *= 0.93
if m > smoothbins[i]:
smoothbins[i] = m
value = smoothbins[i]
if value > 1:
value = 1
brightness = int(value*255)
if brightness < 1:
brightness = 1
piglow.ring(i, brightness)
s = "|"
s = s.ljust(int(value*20), "#")
s = s.ljust(20)
a += s
a += "|"
# print bars
# if counter % 1 == 0:
# print(a)
piglow.show()
counter += 1
print("Finished")
@pbouthil
Copy link

pbouthil commented Jan 20, 2016

I have to be missing something. I have tried over and over to get this working with no luck. I am running Raspbian Wheezy on a Raspberry Pi 1 Model B w/PiGlow installed. I have followed all directions and installed all dependencies required. When executing in terminal all I get is "Loading...." with no Piglow LED's. Please help...thx

@gazzer2558
Copy link

When i run this i get a error message saying syntax is wrong have looked at it and it is exactly what it says here.Thev error message comes up where 35 is the return comes up as a error any help on this would be appreciated

@Tom-Archer
Copy link

Going to try this code over the weekend, but a couple of comments:

  1. "smoothbins[i] *= 0.93" seems redundant, isn't smoothbins array all 0?
  2. Am I correct that the piff function converts the frequencies: 64Hz, 128Hz, 256Hz, .. 2048Hz to power array indicies? Why did you use those particular ranges?

Cheers

@hardcyder
Copy link

hardcyder commented Aug 26, 2016

I was able to get this up and running on my Raspberry Pi 3 (running a fresh install of Jessi). The only trouble I had was that I also needed to install avconv in order to run the 2nd example command. You can do that by running: apt-get install libav-tools

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