240 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			240 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from rgbUtils.BaseEffect import BaseEffect
 | |
| from rgbUtils.EffectParameter import slider, colorpicker
 | |
| from rgbUtils.debug import debug
 | |
| import time
 | |
| 
 | |
| import sys
 | |
| import numpy
 | |
| from rgbUtils.pyAudioRecorder import pyAudioRecorder
 | |
| 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 = [
 | |
|     #     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]
 | |
| 
 | |
|         # used by strobe() 
 | |
|         self.lastmode = 0
 | |
| 
 | |
|         self.recorderClient = pyAudioRecorder.recorderClient()
 | |
|         self.rgbStripController.pyAudioRecorder.registerRecorderClient(self.recorderClient)
 | |
| 
 | |
|         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(.001)
 | |
| 
 | |
|     def end(self):
 | |
|        self.rgbStripController.pyAudioRecorder.unregisterRecorderClient(self.recorderClient)
 | |
| 
 | |
|     def plot_audio_and_detect_beats(self):
 | |
|         if not self.rgbStripController.pyAudioRecorder.has_new_audio: 
 | |
|             return
 | |
| 
 | |
|         # get x and y values from FFT
 | |
|         xs, ys = self.rgbStripController.pyAudioRecorder.fft()
 | |
| 
 | |
|         # 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:67])
 | |
|         mid_freq = numpy.mean(ys[68:135])
 | |
|         hig_freq = numpy.mean(ys[136:204])
 | |
|         
 | |
|         #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]
 | |
|                 )
 | |
|         
 | |
|         # 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.rgbStripController.pyAudioRecorder.newAudio = 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 |