I recently ran across the Build a spectrum analyser with Scroll pHAT and pHAT DAC tutorial and since I had the component parts I thought I would put one together. The one difference was that I had a Scroll pHat HD and so I had a lot more LEDs to play with. So I wanted to share, in case anyone is interested, my updated code for the Scroll pHat HD. I had to do some experimenting with the weighting and I had to guess about how to break up the power_index ranges for the additional LEDs. I really don’t know much about Fast Fourier Transforms or audio so if folks have any thoughts on how I might break things up differently that would be awesome.
Mostly I just like the blinky lights
import sys
import wave
from struct import unpack
import alsaaudio as aa
import numpy as np
import scrollphathd
wavfile = wave.open(sys.argv[1], 'r')
sample_rate = wavfile.getframerate()
no_channels = wavfile.getnchannels()
chunk = 4096
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(chunk)
matrix = [0] * scrollphathd.DISPLAY_WIDTH
power = []
weighting = [1, 1, 2, 4, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16]
#
# weighting using a Fibonacci sequence. Makes the right end very active
# weighting = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597]
#
scrollphathd.set_brightness(0.75)
scrollphathd.rotate(degrees=180)
def power_index(val):
return int(2 * chunk * val / sample_rate)
def compute_fft(data, chunk, sample_rate):
global matrix
data = unpack("%dh" % (len(data) / 2), data)
data = np.array(data, dtype='h')
fourier = np.fft.rfft(data)
fourier = np.delete(fourier, len(fourier) - 1)
power = np.abs(fourier)
matrix[0] = int(np.mean(power[power_index(0):power_index(156):1]))
matrix[1] = int(np.mean(power[power_index(156):power_index(313):1]))
matrix[2] = int(np.mean(power[power_index(313):power_index(625):1]))
matrix[3] = int(np.mean(power[power_index(625):power_index(1000):1]))
matrix[4] = int(np.mean(power[power_index(1000):power_index(1500):1]))
matrix[5] = int(np.mean(power[power_index(1500):power_index(2000):1]))
matrix[6] = int(np.mean(power[power_index(2000):power_index(2500):1]))
matrix[7] = int(np.mean(power[power_index(2500):power_index(3000):1]))
matrix[8] = int(np.mean(power[power_index(3000):power_index(3500):1]))
matrix[9] = int(np.mean(power[power_index(3500):power_index(4000):1]))
matrix[10] = int(np.mean(power[power_index(4000):power_index(4500):1]))
matrix[11] = int(np.mean(power[power_index(4500):power_index(5000):1]))
matrix[12] = int(np.mean(power[power_index(5000):power_index(5500):1]))
matrix[13] = int(np.mean(power[power_index(5500):power_index(6000):1]))
matrix[14] = int(np.mean(power[power_index(6000):power_index(6500):1]))
matrix[15] = int(np.mean(power[power_index(6500):power_index(7000):1]))
matrix[16] = int(np.mean(power[power_index(7000):power_index(8000):1]))
matrix = np.divide(np.multiply(matrix, weighting), 1000000)
matrix = matrix.clip(0, scrollphathd.DISPLAY_HEIGHT)
matrix = [float(m) for m in matrix]
return matrix
data = wavfile.readframes(chunk)
while data != '':
output.write(data)
matrix = compute_fft(data, chunk, sample_rate)
scrollphathd.set_graph(matrix, 0, scrollphathd.DISPLAY_HEIGHT)
scrollphathd.show()
data = wavfile.readframes(chunk)