Last active
January 14, 2024 02:28
-
-
Save daniel-j/f1406e301ab2c38ba53c to your computer and use it in GitHub Desktop.
PiGlow FFT audio visualizer | https://youtu.be/lJcLoAAGdoo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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") |
Going to try this code over the weekend, but a couple of comments:
- "smoothbins[i] *= 0.93" seems redundant, isn't smoothbins array all 0?
- 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
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
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