Audio Visualization on 64 leds with blinkstick pro


#1

For everyone who wants audio visualization - here’s a slightly hardcoded script to run audio visualization with 64 leds. The colors for each led are hardcoded for now so if you want to change it to a different amount of leds - you’ll have to figure out your own colors. Also you’ll likely have to change the input device number on the pyaudio stream. Anyone running this on something like a raspi or very weak laptop might want to consider lowering the chunk size to 512.

The color of the LED represents the frequency, while the brightness is essentially the volume.

Any improvements/optimizations to the code are very much appreciated, as this definitely isn’t an extremely elegant solution at this point, but it works.

My favorite thing about this script is that it leaves you with a ‘colors’ list, which represents the entire frequency-domain sound wave in terms of RGB colors, so it becomes very easy to add additional light effects to the visualization itself.

import pyaudio
import numpy as np
import math, struct
from blinkstick import blinkstick
chunk = 1024
ledCount = 64
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100

binSize = int(chunk/2)
freq = np.fft.fftfreq(chunk, 1.0 / RATE)
freq = freq[:int(len(freq)/2)]

class Main(blinkstick.BlinkStickPro):

    def setColor(self, data):
        ledNumber = 0
        for led in data:
            self.set_color(0, ledNumber, int(led[0]), int(led[1]), int(led[2]))
            ledNumber += 1
        self.send_data_all()

weightsForWindow = np.hanning(chunk)
def Pitch(data):
    data = struct.unpack('{n}h'.format(n=chunk), data)
    fft = np.array(data)
    fft = np.divide(fft, 10000)
    fft = np.multiply(fft, weightsForWindow)
    fft = np.fft.fftshift(fft)
    fft = np.abs(np.fft.fft(data))
    return fft[:binSize]

p = pyaudio.PyAudio()

stream = p.open(format = FORMAT,
channels = CHANNELS,
rate = RATE,
input = True,
output = True,
frames_per_buffer = chunk,
input_device_index = 2)

main = Main(r_led_count=ledCount, max_rgb_value=255)
if main.connect():
    pass
else:
    print "couldn't connect to blinkstick"
    exit()

spectrum = [(255, 0, 0),(255, 15, 0),(255, 23, 0),(255, 31, 0),(255, 39, 0),(255, 47, 0),(255, 55, 0),(255, 71, 0),(255, 87, 0),(255, 95, 0),(255, 103, 0),(255, 111, 0),(255, 119, 0),(255, 127, 0),(255, 135, 0),(255, 143, 0),(255, 151, 0),(255, 167, 0),(255, 175, 0),(255, 191, 0),(255, 199, 0),(255, 223, 0),(255, 231, 0),(255, 239, 0),(255, 247, 0),(255, 255, 0),(223, 255, 0),(207, 255, 0),(191, 255, 0),(175, 255, 0),(159, 255, 0),(143, 255, 0),(127, 255, 0),(111, 255, 0),(95, 255, 0),(79, 255, 0),(63, 255, 0),(47, 255, 0),(31, 255, 0),(15, 255, 0),(0, 255, 0),(0, 239, 15),(0, 223, 31),(0, 207, 47),(0, 191, 63),(0, 175, 79),(0, 159, 95),(0, 143, 111),(0, 111, 143),(0, 95, 159),(0, 79, 175),(0, 63, 191),(0, 47, 207),(0, 31, 223),(0, 15, 239),(0, 0, 255),(9, 0, 239),(13, 0, 231),(27, 0, 207),(37, 0, 192),(51, 0, 168),(60, 0, 153),(65, 0, 145),(79, 0, 135)]


maximumFFTValue = 10
counter= 0
maxFFTValueCounter = 0
binAverageCount = binSize / ledCount
while True:
    data = stream.read(chunk, exception_on_overflow=False)
    Frequency=Pitch(data)
    value = 0
    newFrequency = []
    while True:
        newValue = 0
        for step in range(binAverageCount):
            newValue += Frequency[value+step]
        newValue = newValue/binAverageCount
        newFrequency.append(newValue)
        value += binAverageCount
        if value >= binSize:
            break
    
    tmpMax = max(newFrequency)

    if maximumFFTValue < tmpMax:
        maxFFTValueCounter = 0
        maximumFFTValue = tmpMax
    else:
        maxFFTValueCounter += 1

    colors = [ [spectrum[i][0] * newFrequency[i]/maximumFFTValue, spectrum[i][1] * 
newFrequency[i]/maximumFFTValue, spectrum[i][2] * newFrequency[i]/maximumFFTValue] for i in range(ledCount) ]

    main.setColor(colors)

    if counter == 200:
        if maxFFTValueCounter > 200:
            maximumFFTValue = int(maximumFFTValue) >> 1
            maximumFFTValue = max(maximumFFTValue, 10)
        counter = 0
    counter += 1

#2

Hey Edwin,

thank you for sharing :slight_smile: