audio-reactive-led-strip/python/dsp.py
Scott Lawson 17313c254b Major refactoring and update
* Moved all module settings to a new config.py file
* Completely overhauled visualize.py and added a new radiate effect that
colours the radiative beats according the beat frequency.
* Improved some constants like the decay constant to be parametric so
that they scale to any led strip size
* Added temporal dithering to Beat.update_pixels() so that it now
supports fractional speed values. Being limited to integral values was
starting to become a problem.
* Overhauled and simplified the LED module.
* When updating pixels, the LED module no longer sends UDP packets for
pixels that have not changed. This optimization reduces the packet load
significantly and should allow for higher refresh rates.
* Renamed lookup_table.npy to gamm_table.npy to better reflect that the
table is used for gamma correction of the LED strip
2016-10-13 22:27:45 -07:00

60 lines
2.0 KiB
Python

from __future__ import print_function
from __future__ import division
import numpy as np
from scipy.interpolate import interp1d
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pylab as plt
plt.style.use('lawson')
import microphone as mic
import config
# FFT statistics for a few previous updates
_ys_historical_energy = np.zeros(shape=(config.N_SUBBANDS, config.N_HISTORY))
def beat_detect(ys):
global _ys_historical_energy
# Beat energy criterion
current_energy = ys * ys
mean_energy = np.mean(_ys_historical_energy, axis=1)
has_beat_energy = current_energy > mean_energy * config.ENERGY_THRESHOLD
_ys_historical_energy = np.roll(_ys_historical_energy, shift=1, axis=1)
_ys_historical_energy[:, 0] = current_energy
# Beat variance criterion
ys_variance = np.var(_ys_historical_energy, axis=1)
has_beat_variance = ys_variance > config.VARIANCE_THRESHOLD
# Combined energy + variance detection
has_beat = has_beat_energy * has_beat_variance
return has_beat
def fft(data):
"""Returns |fft(data)|"""
yL, yR = np.split(np.abs(np.fft.fft(data)), 2)
ys = np.add(yL, yR[::-1])
xs = np.arange(int(config.MIC_RATE / config.FPS) / 2, dtype=float)
xs *= float(config.MIC_RATE) / int(config.MIC_RATE / config.FPS)
return xs, ys
# def fft(data):
# """Returns |fft(data)|"""
# yL, yR = np.split(np.abs(np.fft.fft(data)), 2)
# ys = np.add(yL, yR[::-1])
# xs = np.arange(mic.CHUNK / 2, dtype=float) * float(mic.RATE) / mic.CHUNK
# return xs, ys
def fft_log_partition(data, fmin=30, fmax=20000, subbands=64):
"""Returns FFT partitioned into subbands that are logarithmically spaced"""
xs, ys = fft(data)
xs_log = np.logspace(np.log10(fmin), np.log10(fmax), num=subbands * 32)
f = interp1d(xs, ys)
ys_log = f(xs_log)
X, Y = [], []
for i in range(0, subbands * 32, 32):
X.append(np.mean(xs_log[i:i + 32]))
Y.append(np.mean(ys_log[i:i + 32]))
return np.array(X), np.array(Y)