From 5e68b99b28a2a97e7bbc602d3201175cd794e091 Mon Sep 17 00:00:00 2001 From: not-matt <32398028+not-matt@users.noreply.github.com> Date: Wed, 27 Dec 2017 16:28:13 +0000 Subject: [PATCH] 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) --- python/melbank.py | 7 ++- python/visualization.py | 99 ++++++++++++++++++++++++++++++----------- 2 files changed, 78 insertions(+), 28 deletions(-) diff --git a/python/melbank.py b/python/melbank.py index 4badbcc..04989c7 100644 --- a/python/melbank.py +++ b/python/melbank.py @@ -31,6 +31,7 @@ Functions """ from numpy import abs, append, arange, insert, linspace, log10, round, zeros +from math import log def hertz_to_mel(freq): @@ -44,7 +45,8 @@ def hertz_to_mel(freq): mel : scalar or ndarray 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): @@ -58,7 +60,8 @@ def mel_to_hertz(mel): freq : scalar or ndarray 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): diff --git a/python/visualization.py b/python/visualization.py index 423f3ba..bb6474f 100644 --- a/python/visualization.py +++ b/python/visualization.py @@ -26,6 +26,7 @@ class Visualizer(): "Wavelength":self.visualize_wavelength, "Beat":self.visualize_beat, "Wave":self.visualize_wave, + "Bars":self.visualize_bars, "Single":self.visualize_single, "Fade":self.visualize_fade, "Gradient":self.visualize_gradient} @@ -88,7 +89,7 @@ class Visualizer(): "color_mode": "Spectral", # Colour mode of overlay "mirror": False, # Reflect output down centre of strip "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 "Scroll":{"decay": 0.95, # How quickly the colour fades away as it moves "blur": 0.2}, # Amount of blur to apply @@ -96,8 +97,14 @@ class Visualizer(): "Single":{"color": "Red"}, # Static color to show "Beat":{"color": "Red", # Colour of beat flash "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 - "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 "reverse": False}, # Reverse movement of gradient "Fade":{"color_mode":"Spectral", # Colour gradient to fade through @@ -150,6 +157,11 @@ class Visualizer(): "Single":[["color", "Color", "dropdown", self.colors]], "Beat":[["color", "Color", "dropdown", self.colors], ["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], ["roll_speed", "Roll Speed", "slider", (0,8,1)], ["mirror", "Mirror", "checkbox"], @@ -175,32 +187,32 @@ class Visualizer(): _gradient_half = _gradient_whole[::2] # Spectral colour mode 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"][2, :] = np.flipud(self.multicolor_modes["Spectral"][0]) + self.multicolor_modes["Spectral"][0, :] = np.flipud(self.multicolor_modes["Spectral"][2]) # Dancefloor colour mode 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 + self.multicolor_modes["Dancefloor"][2, :] = _gradient_whole[::-1] + self.multicolor_modes["Dancefloor"][0, :] = _gradient_whole # Brilliance colour mode 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"][2, :] = _gradient_whole + self.multicolor_modes["Brilliance"][0, :] = _gradient_whole # Jungle colour mode 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 + self.multicolor_modes["Jungle"][1, :] = _gradient_whole[::-1] + self.multicolor_modes["Jungle"][0, :] = _gradient_whole # Sky colour mode 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 + self.multicolor_modes["Sky"][1, :config.N_PIXELS//2] = _alt_gradient_half[::-1] + self.multicolor_modes["Sky"][0, config.N_PIXELS//2:] = _alt_gradient_half self.multicolor_modes["Sky"][2, :] = 255 # Acid colour mode 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"][2, config.N_PIXELS//2:] = _alt_gradient_half + self.multicolor_modes["Acid"][0, config.N_PIXELS//2:] = _alt_gradient_half # Ocean colour mode self.multicolor_modes["Ocean"] = np.zeros((3,config.N_PIXELS)) self.multicolor_modes["Ocean"][1, :] = _gradient_whole @@ -310,17 +322,16 @@ class Visualizer(): #g = np.abs(diff) b = b_filt.update(np.copy(y)) 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][ - (config.N_PIXELS if not self.effect_opts["Wavelength"]["reverse_grad"] else 0): - (None if not self.effect_opts["Wavelength"]["reverse_grad"] else config.N_PIXELS):]*r, + (config.N_PIXELS if self.effect_opts["Wavelength"]["reverse_grad"] else 0): + (None if self.effect_opts["Wavelength"]["reverse_grad"] else config.N_PIXELS):]*r, self.multicolor_modes[self.effect_opts["Wavelength"]["color_mode"]][1][ - (config.N_PIXELS if not self.effect_opts["Wavelength"]["reverse_grad"] else 0): - (None if not self.effect_opts["Wavelength"]["reverse_grad"] else config.N_PIXELS):]*r, + (config.N_PIXELS if self.effect_opts["Wavelength"]["reverse_grad"] else 0): + (None if self.effect_opts["Wavelength"]["reverse_grad"] else config.N_PIXELS):]*r, self.multicolor_modes[self.effect_opts["Wavelength"]["color_mode"]][2][ - (config.N_PIXELS if not self.effect_opts["Wavelength"]["reverse_grad"] else 0): - (None if not self.effect_opts["Wavelength"]["reverse_grad"] else config.N_PIXELS):]*r]) - self.prev_spectrum = y + (config.N_PIXELS if self.effect_opts["Wavelength"]["reverse_grad"] else 0): + (None if self.effect_opts["Wavelength"]["reverse_grad"] else config.N_PIXELS):]*r]) + #self.prev_spectrum = y self.multicolor_modes[self.effect_opts["Wavelength"]["color_mode"]] = np.roll( 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), @@ -424,7 +435,44 @@ class Visualizer(): output = np.multiply(self.prev_output,self.effect_opts["Beat"]["decay"]) 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): + "Displays a single colour, non audio reactive" output = np.zeros((3,config.N_PIXELS)) output[0][:]=self.colors[self.effect_opts["Single"]["color"]][0] output[1][:]=self.colors[self.effect_opts["Single"]["color"]][1] @@ -432,6 +480,7 @@ class Visualizer(): return output 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], 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]]) @@ -444,6 +493,7 @@ class Visualizer(): return output 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)], [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)]] @@ -757,9 +807,7 @@ def microphone_update(audio_samples): y_roll[:-1] = y_roll[1:] y_roll[-1, :] = np.copy(y) y_data = np.concatenate(y_roll, axis=0).astype(np.float32) - vol = np.max(np.abs(y_data)) - # Transform audio input into the frequency domain N = len(y_data) 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 mel = np.atleast_2d(YS).T * dsp.mel_y.T # Scale data to values more suitable for visualization - # mel = np.sum(mel, axis=0) mel = np.sum(mel, axis=0) - mel = mel**2.0 + mel = mel**0.8 # Gain normalization mel_gain.update(np.max(gaussian_filter1d(mel, sigma=1.0))) mel /= mel_gain.value