from Utils.BaseEffect import BaseEffect from Utils.EffectParameter import slider, colorpicker import time import sys import numpy from time import perf_counter, sleep from random import randint, shuffle class MusikEffect(BaseEffect): name = "musikEffect" desc = "LED-Band *sollte* nach musik blinken" # Something that will be used to show descriptions and value options # of the parameters the effect will accept, in a way, that eg the webclient can decide, # if the parameters can be toggeled by a button/checkbox/slider/whatever effectParameters: list = [ # radio(\ # "Shuffle LED to Freq Order",\ # "Off -> Mapping ",\ # [\ # [0,255,255,"red"],\ # [0,255,255,"green"],\ # [0,255,255,"blue"]\ # ]\ # ),\ # slider(\ # "Effect Brightnes",\ # "Choose a brightness for your LED's",\ # [\ # [0,100,100,"brightness"],\ # ]\ # )\ ] def init(self): self.fft_random_keys = [0,1,2,3] self.fft_random = [0,0,0,0] self.y_max_freq_avg_list = [] self.low_freq_avg_list = [] self.bpm_list = [] self.prev_beat = 0 # timestamp # used by strobe() self.lastmode = 0 return #loop effect as long as not stopped def effect(self): self.plot_audio_and_detect_beats() #self.freqtocolor() #if(time.time() - self.lastTime >= 0.002): #for RGBStrip in self.effectRGBStrips(): # r= RGBStrip.red-1 # if(r<0): # r=0 # g= RGBStrip.green-1 # if(g<0): # g=0 # b= RGBStrip.blue-1 # if(b<0): # b=0 # RGBStrip.RGB(r,g,b) #self.lastTime = time.time() sleep(0.00833333333) def end(self): pass def plot_audio_and_detect_beats(self): if not self.hasNewFttValues: return # get x and y values from FFT xs, ys = self.ftt # calculate average for all frequency ranges y_avg = numpy.mean(ys) #low_freq = numpy.mean(ys[20:47]) #mid_freq = numpy.mean(ys[88:115]) #hig_freq = numpy.mean(ys[156:184]) low_freq = numpy.mean(ys[0:int(ys.__len__() / 3 * 1)]) mid_freq = numpy.mean(ys[int(ys.__len__() / 3 * 1):int(ys.__len__() / 3 * 2)]) hig_freq = numpy.mean(ys[int(ys.__len__() / 3 * 2):int(ys.__len__() / 3 * 3)]) #get the maximum of all freq if len(self.y_max_freq_avg_list) < 250 or y_avg > 10 and numpy.amax([low_freq,mid_freq,hig_freq])/2 > numpy.amin(self.y_max_freq_avg_list): self.y_max_freq_avg_list.append(numpy.amax([low_freq,mid_freq,hig_freq])) y_max = numpy.amax(self.y_max_freq_avg_list) #y_max = numpy.mean([numpy.amax(ys),y_max]) #print(low_freq,mid_freq,hig_freq,y_max) for i,item in enumerate([low_freq,mid_freq,hig_freq]): if item is None: item = 0 low = round(low_freq/(y_max+10)*255) mid = round(mid_freq/(y_max+10)*255) hig = round(hig_freq/(y_max+10)*255) #print(low,mid,hig,y_max, numpy.amax(ys), y_avg) #print("------") self.fft_random[self.fft_random_keys[0]] = low self.fft_random[self.fft_random_keys[1]] = mid self.fft_random[self.fft_random_keys[2]] = hig self.fft_random[self.fft_random_keys[3]] = 0 # calculate low frequency average #low_freq = [ys[i] for i in range(len(xs)) if xs[i] < 1000] low_freq = ys[0:47] low_freq_avg = numpy.mean(low_freq) if len(self.low_freq_avg_list) < 250 or low_freq_avg > numpy.amin(self.low_freq_avg_list)/2: self.low_freq_avg_list.append(low_freq_avg) cumulative_avg = numpy.mean(self.low_freq_avg_list) bass = low_freq[:int(len(low_freq)/2)] bass_avg = numpy.mean(bass) #print("bass: {:.2f} vs cumulative: {:.2f}".format(bass_avg, cumulative_avg)) # check if there is a beat # song is pretty uniform across all frequencies if (y_avg > y_avg/5 and (bass_avg > cumulative_avg * 1.8 or (low_freq_avg < y_avg * 1.2 and bass_avg > cumulative_avg))): #self.prev_beat curr_time = perf_counter() # print(curr_time - self.prev_beat) if curr_time - self.prev_beat > 60/360*2: # 180 BPM max shuffle(self.fft_random_keys) # change the button color #self.beats_idx += 1 #self.strobe() #print("beat {}".format(self.beats_idx)) #print("bass: {:.2f} vs cumulative: {:.2f}".format(bass_avg, cumulative_avg)) #print(self.fft_random) # change the button text bpm = int(60 / (curr_time - self.prev_beat)) if len(self.bpm_list) < 4: if bpm > 60: self.bpm_list.append(bpm) else: bpm_avg = int(numpy.mean(self.bpm_list)) if abs(bpm_avg - bpm) < 35: self.bpm_list.append(bpm) print("bpm: {:d}".format(bpm_avg)) # reset the timer self.prev_beat = curr_time if y_avg > 10: for RGBStrip in self.effectRGBStrips(): RGBStrip.RGB( self.fft_random[0], self.fft_random[1], self.fft_random[2] ) """ rgbStrip: RGBStrip for rgbStrip in self.effectRGBStrips(): for i in range(rgbStrip.STRIP_LENGHT): if rgbStrip.STRIP_LENGHT-1-10 is not i: rgbStrip.WS2812b(rgbStrip.STRIP_LENGHT-i-1, rgbStrip.red[rgbStrip.STRIP_LENGHT-i-2], rgbStrip.green[rgbStrip.STRIP_LENGHT-i-2], rgbStrip.blue[rgbStrip.STRIP_LENGHT-i-2]) else: rgbStrip.WS2812b(rgbStrip.STRIP_LENGHT-i-1, self.fft_random[0], self.fft_random[1], self.fft_random[2]) rgbStrip.show() """ # shorten the cumulative list to account for changes in dynamics if len(self.low_freq_avg_list) > 500: self.low_freq_avg_list = self.low_freq_avg_list[250:] #print("REFRESH!!") # shorten the cumulative list to account for changes in dynamics if len(self.y_max_freq_avg_list ) > 500: self.y_max_freq_avg_list = self.y_max_freq_avg_list[250:] print("--REFRESH y_max_freq_avg_list") # keep two 8-counts of BPMs so we can maybe catch tempo changes if len(self.bpm_list) > 24: self.bpm_list = self.bpm_list[8:] # reset song data if the song has stopped if y_avg < 10: self.bpm_list = [] self.low_freq_avg_list = [] print("new song") self.off() self.hasNewFttValues = False # print(self.bpm_list)250 def strobe(self): x = randint(0,5) while x is self.lastmode: x = randint(0,5) self.lastmode = x r = 255#randint(0,255) g = 255#randint(0,255) b = 255#randint(0,255) if x is 0: for RGBStrip in self.effectRGBStrips(): RGBStrip.RGB(r,g,0) if x is 1: for RGBStrip in self.effectRGBStrips(): RGBStrip.RGB(0,g,b) if x is 2: for RGBStrip in self.effectRGBStrips(): RGBStrip.RGB(r,0,b) if x is 3: for RGBStrip in self.effectRGBStrips(): RGBStrip.RGB(r,0,0) if x is 4: for RGBStrip in self.effectRGBStrips(): RGBStrip.RGB(0,g,0) if x is 5: for RGBStrip in self.effectRGBStrips(): RGBStrip.RGB(0,0,b) if x is 6: for RGBStrip in self.effectRGBStrips(): RGBStrip.RGB(r,g,b) def off(self): for RGBStrip in self.effectRGBStrips(): RGBStrip.RGB(0,0,0) def left_rotate(self,arr): if not arr: return arr left_most_element = arr[0] length = len(arr) for i in range(length - 1): arr[i], arr[i + 1] = arr[i + 1], arr[i] arr[length - 1] = left_most_element return arr