Add files via upload

New effect: Bars
Better frequency scaling by modifying parameters in melbank.py
Mel graph [before](https://imgur.com/a/xN9PA), [after](https://imgur.com/a/YYGLk)
This stretches out the lower end with vocals and bass, and squishes up the high end which usually takes up moer space on the strip for similar "sounds". Now it looks more like you would expect it to, based on what you hear (more pitch-like than frequency)
This commit is contained in:
not-matt 2017-12-27 16:28:13 +00:00 committed by GitHub
parent 24289b61ca
commit 5e68b99b28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 78 additions and 28 deletions

View File

@ -31,6 +31,7 @@ Functions
""" """
from numpy import abs, append, arange, insert, linspace, log10, round, zeros from numpy import abs, append, arange, insert, linspace, log10, round, zeros
from math import log
def hertz_to_mel(freq): def hertz_to_mel(freq):
@ -44,7 +45,8 @@ def hertz_to_mel(freq):
mel : scalar or ndarray mel : scalar or ndarray
Mel-frequency value or ndarray in Mel Mel-frequency value or ndarray in Mel
""" """
return 2595.0 * log10(1 + (freq / 700.0)) #return 2595.0 * log10(1 + (freq / 700.0))
return 3340.0 * log(1 + (freq / 250.0), 9)
def mel_to_hertz(mel): def mel_to_hertz(mel):
@ -58,7 +60,8 @@ def mel_to_hertz(mel):
freq : scalar or ndarray freq : scalar or ndarray
Frequency value or array in Hz. Frequency value or array in Hz.
""" """
return 700.0 * (10**(mel / 2595.0)) - 700.0 #return 700.0 * (10**(mel / 2595.0)) - 700.0
return 250.0 * (9**(mel / 3340.0)) - 250.0
def melfrequencies_mel_filterbank(num_bands, freq_min, freq_max, num_fft_bands): def melfrequencies_mel_filterbank(num_bands, freq_min, freq_max, num_fft_bands):

View File

@ -26,6 +26,7 @@ class Visualizer():
"Wavelength":self.visualize_wavelength, "Wavelength":self.visualize_wavelength,
"Beat":self.visualize_beat, "Beat":self.visualize_beat,
"Wave":self.visualize_wave, "Wave":self.visualize_wave,
"Bars":self.visualize_bars,
"Single":self.visualize_single, "Single":self.visualize_single,
"Fade":self.visualize_fade, "Fade":self.visualize_fade,
"Gradient":self.visualize_gradient} "Gradient":self.visualize_gradient}
@ -88,7 +89,7 @@ class Visualizer():
"color_mode": "Spectral", # Colour mode of overlay "color_mode": "Spectral", # Colour mode of overlay
"mirror": False, # Reflect output down centre of strip "mirror": False, # Reflect output down centre of strip
"reverse_grad": False, # Flip (LR) gradient "reverse_grad": False, # Flip (LR) gradient
"reverse_roll": False, # Reverse movement of gradient "reverse_roll": False, # Reverse movement of gradient roll
"blur": 3.0}, # Amount of blur to apply "blur": 3.0}, # Amount of blur to apply
"Scroll":{"decay": 0.95, # How quickly the colour fades away as it moves "Scroll":{"decay": 0.95, # How quickly the colour fades away as it moves
"blur": 0.2}, # Amount of blur to apply "blur": 0.2}, # Amount of blur to apply
@ -96,8 +97,14 @@ class Visualizer():
"Single":{"color": "Red"}, # Static color to show "Single":{"color": "Red"}, # Static color to show
"Beat":{"color": "Red", # Colour of beat flash "Beat":{"color": "Red", # Colour of beat flash
"decay": 0.7}, # How quickly the flash fades away "decay": 0.7}, # How quickly the flash fades away
"Bars":{"resolution":4, # Number of "bars"
"color_mode":"Spectral", # Multicolour mode to use
"roll_speed":0, # How fast (if at all) to cycle colour colours across strip
"mirror": False, # Mirror down centre of strip
#"reverse_grad": False, # Flip (LR) gradient
"reverse_roll": False}, # Reverse movement of gradient roll
"Gradient":{"color_mode":"Spectral", # Colour gradient to display "Gradient":{"color_mode":"Spectral", # Colour gradient to display
"roll_speed": 0, # How fast (if at all) to cycle colour overlay across strip "roll_speed": 0, # How fast (if at all) to cycle colour colours across strip
"mirror": False, # Mirror gradient down central axis "mirror": False, # Mirror gradient down central axis
"reverse": False}, # Reverse movement of gradient "reverse": False}, # Reverse movement of gradient
"Fade":{"color_mode":"Spectral", # Colour gradient to fade through "Fade":{"color_mode":"Spectral", # Colour gradient to fade through
@ -150,6 +157,11 @@ class Visualizer():
"Single":[["color", "Color", "dropdown", self.colors]], "Single":[["color", "Color", "dropdown", self.colors]],
"Beat":[["color", "Color", "dropdown", self.colors], "Beat":[["color", "Color", "dropdown", self.colors],
["decay", "Flash Decay", "float_slider", (0.3,0.98,0.005)]], ["decay", "Flash Decay", "float_slider", (0.3,0.98,0.005)]],
"Bars":[["color_mode", "Color Mode", "dropdown", self.multicolor_mode_names],
["resolution", "Resolution", "slider", (1, config.N_FFT_BINS, 1)],
["roll_speed", "Roll Speed", "slider", (0,8,1)],
["mirror", "Mirror", "checkbox"],
["reverse_roll", "Reverse Roll", "checkbox"]],
"Gradient":[["color_mode", "Color Mode", "dropdown", self.multicolor_mode_names], "Gradient":[["color_mode", "Color Mode", "dropdown", self.multicolor_mode_names],
["roll_speed", "Roll Speed", "slider", (0,8,1)], ["roll_speed", "Roll Speed", "slider", (0,8,1)],
["mirror", "Mirror", "checkbox"], ["mirror", "Mirror", "checkbox"],
@ -175,32 +187,32 @@ class Visualizer():
_gradient_half = _gradient_whole[::2] _gradient_half = _gradient_whole[::2]
# Spectral colour mode # Spectral colour mode
self.multicolor_modes["Spectral"] = np.zeros((3,config.N_PIXELS)) self.multicolor_modes["Spectral"] = np.zeros((3,config.N_PIXELS))
self.multicolor_modes["Spectral"][0, :config.N_PIXELS//2] = _gradient_half[::-1] self.multicolor_modes["Spectral"][2, :config.N_PIXELS//2] = _gradient_half[::-1]
self.multicolor_modes["Spectral"][1, :] = _gradient_half + _gradient_half[::-1] self.multicolor_modes["Spectral"][1, :] = _gradient_half + _gradient_half[::-1]
self.multicolor_modes["Spectral"][2, :] = np.flipud(self.multicolor_modes["Spectral"][0]) self.multicolor_modes["Spectral"][0, :] = np.flipud(self.multicolor_modes["Spectral"][2])
# Dancefloor colour mode # Dancefloor colour mode
self.multicolor_modes["Dancefloor"] = np.zeros((3,config.N_PIXELS)) self.multicolor_modes["Dancefloor"] = np.zeros((3,config.N_PIXELS))
self.multicolor_modes["Dancefloor"][0, :] = _gradient_whole[::-1] self.multicolor_modes["Dancefloor"][2, :] = _gradient_whole[::-1]
self.multicolor_modes["Dancefloor"][2, :] = _gradient_whole self.multicolor_modes["Dancefloor"][0, :] = _gradient_whole
# Brilliance colour mode # Brilliance colour mode
self.multicolor_modes["Brilliance"] = np.zeros((3,config.N_PIXELS)) self.multicolor_modes["Brilliance"] = np.zeros((3,config.N_PIXELS))
self.multicolor_modes["Brilliance"][0, :] = _gradient_whole[::-1] self.multicolor_modes["Brilliance"][2, :] = _gradient_whole[::-1]
self.multicolor_modes["Brilliance"][1, :] = 255 self.multicolor_modes["Brilliance"][1, :] = 255
self.multicolor_modes["Brilliance"][2, :] = _gradient_whole self.multicolor_modes["Brilliance"][0, :] = _gradient_whole
# Jungle colour mode # Jungle colour mode
self.multicolor_modes["Jungle"] = np.zeros((3,config.N_PIXELS)) self.multicolor_modes["Jungle"] = np.zeros((3,config.N_PIXELS))
self.multicolor_modes["Jungle"][0, :] = _gradient_whole[::-1] self.multicolor_modes["Jungle"][1, :] = _gradient_whole[::-1]
self.multicolor_modes["Jungle"][1, :] = _gradient_whole self.multicolor_modes["Jungle"][0, :] = _gradient_whole
# Sky colour mode # Sky colour mode
self.multicolor_modes["Sky"] = np.zeros((3,config.N_PIXELS)) self.multicolor_modes["Sky"] = np.zeros((3,config.N_PIXELS))
self.multicolor_modes["Sky"][0, :config.N_PIXELS//2] = _alt_gradient_half[::-1] self.multicolor_modes["Sky"][1, :config.N_PIXELS//2] = _alt_gradient_half[::-1]
self.multicolor_modes["Sky"][1, config.N_PIXELS//2:] = _alt_gradient_half self.multicolor_modes["Sky"][0, config.N_PIXELS//2:] = _alt_gradient_half
self.multicolor_modes["Sky"][2, :] = 255 self.multicolor_modes["Sky"][2, :] = 255
# Acid colour mode # Acid colour mode
self.multicolor_modes["Acid"] = np.zeros((3,config.N_PIXELS)) self.multicolor_modes["Acid"] = np.zeros((3,config.N_PIXELS))
self.multicolor_modes["Acid"][0, :config.N_PIXELS//2] = _alt_gradient_half[::-1] self.multicolor_modes["Acid"][2, :config.N_PIXELS//2] = _alt_gradient_half[::-1]
self.multicolor_modes["Acid"][1, :] = 255 self.multicolor_modes["Acid"][1, :] = 255
self.multicolor_modes["Acid"][2, config.N_PIXELS//2:] = _alt_gradient_half self.multicolor_modes["Acid"][0, config.N_PIXELS//2:] = _alt_gradient_half
# Ocean colour mode # Ocean colour mode
self.multicolor_modes["Ocean"] = np.zeros((3,config.N_PIXELS)) self.multicolor_modes["Ocean"] = np.zeros((3,config.N_PIXELS))
self.multicolor_modes["Ocean"][1, :] = _gradient_whole self.multicolor_modes["Ocean"][1, :] = _gradient_whole
@ -310,17 +322,16 @@ class Visualizer():
#g = np.abs(diff) #g = np.abs(diff)
b = b_filt.update(np.copy(y)) b = b_filt.update(np.copy(y))
r = np.array([j for i in zip(r,r) for j in i]) r = np.array([j for i in zip(r,r) for j in i])
#b = np.array([j for i in zip(b,b) for j in i])
output = np.array([self.multicolor_modes[self.effect_opts["Wavelength"]["color_mode"]][0][ output = np.array([self.multicolor_modes[self.effect_opts["Wavelength"]["color_mode"]][0][
(config.N_PIXELS if not self.effect_opts["Wavelength"]["reverse_grad"] else 0): (config.N_PIXELS if self.effect_opts["Wavelength"]["reverse_grad"] else 0):
(None if not self.effect_opts["Wavelength"]["reverse_grad"] else config.N_PIXELS):]*r, (None if self.effect_opts["Wavelength"]["reverse_grad"] else config.N_PIXELS):]*r,
self.multicolor_modes[self.effect_opts["Wavelength"]["color_mode"]][1][ self.multicolor_modes[self.effect_opts["Wavelength"]["color_mode"]][1][
(config.N_PIXELS if not self.effect_opts["Wavelength"]["reverse_grad"] else 0): (config.N_PIXELS if self.effect_opts["Wavelength"]["reverse_grad"] else 0):
(None if not self.effect_opts["Wavelength"]["reverse_grad"] else config.N_PIXELS):]*r, (None if self.effect_opts["Wavelength"]["reverse_grad"] else config.N_PIXELS):]*r,
self.multicolor_modes[self.effect_opts["Wavelength"]["color_mode"]][2][ self.multicolor_modes[self.effect_opts["Wavelength"]["color_mode"]][2][
(config.N_PIXELS if not self.effect_opts["Wavelength"]["reverse_grad"] else 0): (config.N_PIXELS if self.effect_opts["Wavelength"]["reverse_grad"] else 0):
(None if not self.effect_opts["Wavelength"]["reverse_grad"] else config.N_PIXELS):]*r]) (None if self.effect_opts["Wavelength"]["reverse_grad"] else config.N_PIXELS):]*r])
self.prev_spectrum = y #self.prev_spectrum = y
self.multicolor_modes[self.effect_opts["Wavelength"]["color_mode"]] = np.roll( self.multicolor_modes[self.effect_opts["Wavelength"]["color_mode"]] = np.roll(
self.multicolor_modes[self.effect_opts["Wavelength"]["color_mode"]], self.multicolor_modes[self.effect_opts["Wavelength"]["color_mode"]],
self.effect_opts["Wavelength"]["roll_speed"]*(-1 if self.effect_opts["Wavelength"]["reverse_roll"] else 1), self.effect_opts["Wavelength"]["roll_speed"]*(-1 if self.effect_opts["Wavelength"]["reverse_roll"] else 1),
@ -424,7 +435,44 @@ class Visualizer():
output = np.multiply(self.prev_output,self.effect_opts["Beat"]["decay"]) output = np.multiply(self.prev_output,self.effect_opts["Beat"]["decay"])
return output return output
def visualize_bars(self, y):
# Bit of fiddling with the y values
y = np.copy(interpolate(y, config.N_PIXELS // 2))
common_mode.update(y)
self.prev_spectrum = np.copy(y)
# Color channel mappings
r = r_filt.update(y - common_mode.value)
r = np.array([j for i in zip(r,r) for j in i])
# Split y into [resulution] chunks and calculate the average of each
max_values = np.array([max(i) for i in np.array_split(r, self.effect_opts["Bars"]["resolution"])])
max_values = np.clip(max_values, 0, 1)
color_sets = []
for i in range(self.effect_opts["Bars"]["resolution"]):
# [r,g,b] values from a multicolour gradient array at [resulution] equally spaced intervals
color_sets.append([self.multicolor_modes[self.effect_opts["Bars"]["color_mode"]]\
[j][i*(config.N_PIXELS//self.effect_opts["Bars"]["resolution"])] for j in range(3)])
output = np.zeros((3,config.N_PIXELS))
chunks = np.array_split(output[0], self.effect_opts["Bars"]["resolution"])
n = 0
# Assign blocks with heights corresponding to max_values and colours from color_sets
for i in range(len(chunks)):
m = len(chunks[i])
for j in range(3):
output[j][n:n+m] = color_sets[i][j]*max_values[i]
n += m
self.multicolor_modes[self.effect_opts["Bars"]["color_mode"]] = np.roll(
self.multicolor_modes[self.effect_opts["Bars"]["color_mode"]],
self.effect_opts["Bars"]["roll_speed"]*(-1 if self.effect_opts["Bars"]["reverse_roll"] else 1),
axis=1)
if self.effect_opts["Bars"]["mirror"]:
output = np.concatenate((output[:, ::-2], output[:, ::2]), axis=1)
return output
def visualize_single(self, y): def visualize_single(self, y):
"Displays a single colour, non audio reactive"
output = np.zeros((3,config.N_PIXELS)) output = np.zeros((3,config.N_PIXELS))
output[0][:]=self.colors[self.effect_opts["Single"]["color"]][0] output[0][:]=self.colors[self.effect_opts["Single"]["color"]][0]
output[1][:]=self.colors[self.effect_opts["Single"]["color"]][1] output[1][:]=self.colors[self.effect_opts["Single"]["color"]][1]
@ -432,6 +480,7 @@ class Visualizer():
return output return output
def visualize_gradient(self, y): def visualize_gradient(self, y):
"Displays a multicolour gradient, non audio reactive"
output = np.array([self.multicolor_modes[self.effect_opts["Gradient"]["color_mode"]][0][:config.N_PIXELS], output = np.array([self.multicolor_modes[self.effect_opts["Gradient"]["color_mode"]][0][:config.N_PIXELS],
self.multicolor_modes[self.effect_opts["Gradient"]["color_mode"]][1][:config.N_PIXELS], self.multicolor_modes[self.effect_opts["Gradient"]["color_mode"]][1][:config.N_PIXELS],
self.multicolor_modes[self.effect_opts["Gradient"]["color_mode"]][2][:config.N_PIXELS]]) self.multicolor_modes[self.effect_opts["Gradient"]["color_mode"]][2][:config.N_PIXELS]])
@ -444,6 +493,7 @@ class Visualizer():
return output return output
def visualize_fade(self, y): def visualize_fade(self, y):
"Fades through a multicolour gradient, non audio reactive"
output = [[self.multicolor_modes[self.effect_opts["Fade"]["color_mode"]][0][0] for i in range(config.N_PIXELS)], output = [[self.multicolor_modes[self.effect_opts["Fade"]["color_mode"]][0][0] for i in range(config.N_PIXELS)],
[self.multicolor_modes[self.effect_opts["Fade"]["color_mode"]][1][0] for i in range(config.N_PIXELS)], [self.multicolor_modes[self.effect_opts["Fade"]["color_mode"]][1][0] for i in range(config.N_PIXELS)],
[self.multicolor_modes[self.effect_opts["Fade"]["color_mode"]][2][0] for i in range(config.N_PIXELS)]] [self.multicolor_modes[self.effect_opts["Fade"]["color_mode"]][2][0] for i in range(config.N_PIXELS)]]
@ -757,9 +807,7 @@ def microphone_update(audio_samples):
y_roll[:-1] = y_roll[1:] y_roll[:-1] = y_roll[1:]
y_roll[-1, :] = np.copy(y) y_roll[-1, :] = np.copy(y)
y_data = np.concatenate(y_roll, axis=0).astype(np.float32) y_data = np.concatenate(y_roll, axis=0).astype(np.float32)
vol = np.max(np.abs(y_data)) vol = np.max(np.abs(y_data))
# Transform audio input into the frequency domain # Transform audio input into the frequency domain
N = len(y_data) N = len(y_data)
N_zeros = 2**int(np.ceil(np.log2(N))) - N N_zeros = 2**int(np.ceil(np.log2(N))) - N
@ -770,9 +818,8 @@ def microphone_update(audio_samples):
# Construct a Mel filterbank from the FFT data # Construct a Mel filterbank from the FFT data
mel = np.atleast_2d(YS).T * dsp.mel_y.T mel = np.atleast_2d(YS).T * dsp.mel_y.T
# Scale data to values more suitable for visualization # Scale data to values more suitable for visualization
# mel = np.sum(mel, axis=0)
mel = np.sum(mel, axis=0) mel = np.sum(mel, axis=0)
mel = mel**2.0 mel = mel**0.8
# Gain normalization # Gain normalization
mel_gain.update(np.max(gaussian_filter1d(mel, sigma=1.0))) mel_gain.update(np.max(gaussian_filter1d(mel, sigma=1.0)))
mel /= mel_gain.value mel /= mel_gain.value