renaming folders and files to python format

This commit is contained in:
dezeyer
2019-05-11 14:28:42 +00:00
parent ade378d128
commit 798775805c
19 changed files with 509 additions and 268 deletions
-91
View File
@@ -1,91 +0,0 @@
import time
import threading
import copy
from rgbUtils.debug import debug
class BaseEffect(threading.Thread):
# The Name and the Description of the Effect,
# should be overwritten by the inheritancing Effect
name = "Undefined"
desc = "No Description"
# 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 = []
stop = False
def __init__(self):
threading.Thread.__init__(self)
self.effectRGBStripList = []
# when a strip is added or removed or the options change, the thread will not restart,
# the changes are pushed to the thread at livetime. so avoid log running loops without
# accessing getRGBStrips and getEffectParams. It could happen, that a new effect for example already uses
# a rgbStip while the loop of the old effect is running and has not got the changes.
def run(self):
self.effectParameterValues = []
for effectParameterIndex, effectParameter in enumerate(self.effectParameters):
self.effectParameterValues.append([])
for option in effectParameter.options:
self.effectParameterValues[effectParameterIndex].append(option[2])
print(self.effectParameterValues)
self.init()
while not self.stop:
# run the effect in endless while
self.effect()
self.end()
# Init is called bevor the loop, use setEffectParams for init values
# and access them in the effect with getEffectParams
def init(self):
return
# see run(): never save effectRGBStrips() as a variable and access it as often as possible
# to avoid two effects accessing the rgbStrip
def effect(self):
while 1:
debug("ET "+self.name+" effect() function needs to be replaced in inheritancing Effect")
# called when the effect is stopped
def end(self):
return
# when called the effect loop will stop and the thread can be terminated
def stopEffect(self):
self.stop = True
# the effect itself will know its own strips. i don't know if it would be better if the effectController self
# should have this list, but then i must do something like nested arrays, naah.
def addRGBStrip(self,rgbStrip):
self.effectRGBStripList.append(rgbStrip)
self.onRGBStripAdded(rgbStrip)
# remove a strip, if the effect has no more strips, the effect thread guardian will kill it
def removeRGBStrip(self,rgbStrip):
self.effectRGBStripList.remove(rgbStrip)
# for overriding by the effect, when a strip is added
def onRGBStripAdded(self,rgbStrip):
return
# for overriding by the effect, when a strip is added
def onEffectParameterValuesUpdated(self):
return
# returns a list of the RGBStrips used by this effect
def effectRGBStrips(self):
return self.effectRGBStripList
def addEffectParameter(self,effectParameter):
self.effectParameters.append(effectParameter)
# set Params as descriped in getParamsDescription()
def updateEffectParameterValues(self,effectParameterIndex, effectParameterValues):
print("updateEffectParameterValues",effectParameterIndex,effectParameterValues)
for effectParameterValue in effectParameterValues:
if self.effectParameters[int(effectParameterIndex)].testValue(int(effectParameterValue),int(effectParameterValues[effectParameterValue])):
self.effectParameterValues[int(effectParameterIndex)][int(effectParameterValue)] = int(effectParameterValues[effectParameterValue])
self.onEffectParameterValuesUpdated()
-42
View File
@@ -1,42 +0,0 @@
import threading
class effectParameter(object):
# The Name and the Description of the EffectParameter,
# should be overwritten by the inheritancing EffectParameter
name="Undefined"
desc = "No Description"
# In the order you expect the options to be set
# [
# [min/off,max/on,current,"description"],
# [min/off,max/on,current,"description"],
# [min/off,max/on,current,"description"],
# ]
options = []
def __init__(self,name,desc,initOptions = []):
self.name = name
self.desc = desc
self.options = initOptions
# check if the given values are plausible
def testValue(self,index,value):
if value >= self.options[index][0] \
and value <= self.options[index][1]:
return True
else:
return False
class colorpicker(effectParameter):
name="UndefinedColorpicker"
desc="No Description"
type="colorpicker"
# check if the given values are plausible
def testValue(self,index,value):
return True
class slider(effectParameter):
name="UndefinedSlider"
desc="No Description"
type="slider"
-96
View File
@@ -1,96 +0,0 @@
from rgbUtils.debug import debug
import uuid
class RGBStrip:
# name = the name off the the strip, defined by the client connecting to the server
# uid = unique id, if the strip sends one, use this (later maybe, or never, whatever)
# lenght = the lenght off the strip, for future use of eg WS2812b strips, will be 1 by default
def __init__(self,name,onValuesUpdateHandler,lenght=1):
# UID should be updateable later, or not?
# when updating, be sure it does not exist
self.STRIP_UID = str(uuid.uuid4())
self.STRIP_NAME = name
self.STRIP_LENGHT = lenght
self.onValuesUpdateHandler = onValuesUpdateHandler
self.red = [0]*self.STRIP_LENGHT
self.green = [0]*self.STRIP_LENGHT
self.blue = [0]*self.STRIP_LENGHT
def RGB(self,red,green,blue,brightness = 100):
if(red < 0):
red = 0
if(red > 255):
red = 255
if(green < 0):
green = 0
if(green > 255):
green = 255
if(blue < 0):
blue = 0
if(blue > 255):
blue = 255
if(brightness < 0):
brightness = 0
if(brightness > 100):
brightness = 100
for x in range(self.STRIP_LENGHT):
self.red[x] = int(red/100*brightness)
self.green[x] = int(green/100*brightness)
self.blue[x] = int(blue/100*brightness)
self.show()
def WS2812b(self,id,red,green,blue,brightness=100):
if id < 0 and id > self.STRIP_LENGHT:
print(self.STRIP_NAME," is max ",self.STRIP_LENGHT," Pixels long!")
return
else:
if(red < 0):
red = 0
if(red > 255):
red = 255
if(green < 0):
green = 0
if(green > 255):
green = 255
if(blue < 0):
blue = 0
if(blue > 255):
blue = 255
if(brightness < 0):
brightness = 0
if(brightness > 100):
brightness = 100
self.red[id] = int(red/100*brightness)
self.green[id] = int(green/100*brightness)
self.blue[id] = int(blue/100*brightness)
def show(self):
self.onValuesUpdateHandler(self)
def off(self):
for x in range(self.STRIP_LENGHT):
self.red[x] = 0
self.green[x] = 0
self.blue[x] = 0
self.onValuesUpdateHandler(self)
def getData(self):
self.hasNewData = False
return [self.red,self.green,self.blue]
View File
-183
View File
@@ -1,183 +0,0 @@
# import offEffect
from effects.offEffect import offEffect
from rgbUtils.debug import debug
from rgbUtils.BaseEffect import BaseEffect
from rgbUtils.RGBStrip import RGBStrip
import time
import threading
import os
import sys
#
# handles all the effects:
# - start/stop effects
# - changes parameters of specific effects
# - moves the rgbStrips to the effects
# - runs a guardian that detects dead effectThreads and moves Strips to offEffect
#
class effectController:
# list of current running effects
effectThreads = []
offEffectThreadObject = None
# maybe i will seperate this later
onControllerChangeHandler = []
def __init__(self,rgbStripController):
self.rgbStripController = rgbStripController
# load the effects
self.effectsList = self.getEffectsListFromDir()
# start the offEffect by default
self.offEffectThreadObject = self.startEffect(offEffect,[])
# - a bit of failover handling, remove dead threads from effectThread array
# - move strips without an effect to the offEffect
self.effectGuardian = self.effectGuardian(self)
self.effectGuardian.start()
# starts a effect by given class, rgbStrips and params ([[index,[param,param,param]],[index,[param,param,param]]])
def startEffect(self, effectClass: BaseEffect, rgbStrips: list, params: list = []):
newEffect = effectClass()
if len(self.effectThreads) > 0 and len(rgbStrips) > 0 or len(self.effectThreads) == 0:
newEffect.start()
self.updateEffectParameters(newEffect, params)
self.effectThreads.append(newEffect)
for rgbStrip in rgbStrips:
self.moveRGBStripToEffectThread(rgbStrip, newEffect)
self.noticeControllerChange()
return newEffect
# returns all effectClasses but offEffect, since offEffect will never be killed
# and should not be running twice
def getEffects(self):
# alle außer offEffect
return self.effectsList
# returns all running effectThreads
def getEffectThreads(self):
return self.effectThreads
# returns a list of the RGBStrips used by this effect
def getEffectRGBStrips(self, effectThreadObject: BaseEffect):
return effectThreadObject.effectRGBStrips()
# move a rgbStip to a running effectThread
def moveRGBStripToEffectThread(self, rgbStrip: RGBStrip, effectThreadObject: BaseEffect):
# cycle throught all effects and
# remove Strip from effect if added
for et in self.effectThreads:
if rgbStrip in et.effectRGBStrips():
et.removeRGBStrip(rgbStrip)
if effectThreadObject.isAlive():
effectThreadObject.addRGBStrip(rgbStrip)
# check if any effectThread has no more rgbStrips and if so, stop it
# if the effectThread has no more strips, we stop it and remove it.
for x, effectThread in enumerate(self.effectThreads):
if len(effectThread.effectRGBStrips()) == 0 and x is not 0:
effectThread.stopEffect()
self.effectThreads.remove(effectThread)
self.noticeControllerChange()
# updates parameter of a running effectThread
def updateEffectParameters(self, effectThreadObject: BaseEffect, effectParameters):
for effectParameter in effectParameters:
effectThreadObject.updateEffectParameterValues(
effectParameter[0], effectParameter[1])
self.noticeControllerChange()
# stops all effectThreads and set the rgbStrips to off
def stopAll(self):
debug("effectController stopAll()")
for effectThread in self.effectThreads:
effectThread.stopEffect()
debug("effectController killed "+str(effectThread))
self.effectGuardian.stop()
time.sleep(0.5)
# GPIO.cleanup()
# inform the controllerChangeHandler to update the client
def noticeControllerChange(self):
for controllerChangeHandler in self.onControllerChangeHandler:
controllerChangeHandler()
# add onControllerChangeHandler
def addOnControllerChangeHandler(self, hander):
print("addOnControllerChangeHandler", str(hander))
self.onControllerChangeHandler.append(hander)
# send data to this client
hander()
# remove onControllerChangeHandler
def removeOnControllerChangeHandler(self, hander):
print("removeOnControllerChangeHandler", str(hander))
if hander in self.onControllerChangeHandler:
self.onControllerChangeHandler.remove(hander)
else:
print('\n\n -> client was never registered!')
# automaticly loads all modules from effects subdir and adds them to the list of effects if they have the BaseEffect as subclass
def getEffectsListFromDir(self):
effectsList = []
for raw_module in os.listdir(os.path.abspath(os.path.join(os.path.join(os.path.dirname(__file__), os.pardir),"effects"))):
if raw_module == '__init__.py' or raw_module == 'offEffect.py' or raw_module[-3:] != '.py':
continue
effectModule = __import__("effects."+raw_module[:-3], fromlist=[raw_module[:-3]])
effectClass = getattr(effectModule, raw_module[:-3])
if issubclass(effectClass,BaseEffect):
effectsList.append(effectClass)
print("Loaded effects: ",effectsList)
return effectsList
def onRGBStripRegistered(self,rgbStrip):
self.offEffectThreadObject.addRGBStrip(rgbStrip)
self.noticeControllerChange()
def onRGBStripUnRegistered(self,rgbStrip):
# cycle throught all effects and
# remove Strip from effect if added
for et in self.effectThreads:
if rgbStrip in et.effectRGBStrips():
et.removeRGBStrip(rgbStrip)
# if the effectThread has no more strips, we stop it and remove it.
for x, effectThread in enumerate(self.effectThreads):
if len(effectThread.effectRGBStrips()) == 0 and x is not 0:
effectThread.stopEffect()
self.effectThreads.remove(effectThread)
self.noticeControllerChange()
# - a bit of failover handling, remove dead threads from effectThread array
# - move strips without an effect to the offEffect
class effectGuardian(threading.Thread):
def __init__(self, effectController):
threading.Thread.__init__(self, name='effectGuardian')
self.effectController = effectController
self.stopped = False
def run(self):
while not self.stopped:
for effectThread in self.effectController.effectThreads:
# if Thread was killed by something else, we remove it from the list
if not effectThread.isAlive():
for rgbStrip in effectThread.effectRGBStrips():
self.effectController.moveRGBStripToEffectThread(rgbStrip,self.effectController.offEffectThreadObject)
self.effectController.effectThreads.remove(effectThread)
print("effectController:effectGuardian removed dead Thread " +
str(effectThread) + ". There must be an error in code!")
self.effectController.noticeControllerChange()
time.sleep(1)
def stop(self):
self.stopped = True
@@ -1,49 +0,0 @@
"""
Convert the effectController function outputs to json format
"""
def responseHandler(effectController,rgbStripController,data):
if "startEffect" in data:
enabledRGBStrips = []
for rgbStrip in rgbStripController.getRGBStrips():
for rgbStripJsonArray in data['startEffect']['rgbStrips']:
if rgbStrip.STRIP_UID in rgbStripJsonArray[0] and rgbStripJsonArray[1]:
enabledRGBStrips.append(rgbStrip)
effectController.startEffect(effectController.getEffects()[data['startEffect']['effect']],enabledRGBStrips,data['startEffect']['params'])
if "moveRGBStripToEffectThread" in data:
for rgbStrip in rgbStripController.getRGBStrips():
if rgbStrip.STRIP_UID in data['moveRGBStripToEffectThread']['rgbStrip']:
effectController.moveRGBStripToEffectThread( \
rgbStrip, \
effectController.getEffectThreads()[data['moveRGBStripToEffectThread']['effectThread']] \
)
if "effectThreadChangeEffectParam" in data:
effectController.updateEffectParameters(\
effectController.getEffectThreads()[data['effectThreadChangeEffectParam']['effectThread']], \
data['effectThreadChangeEffectParam']['params']
)
return 'ok'
# return json of all configured effects (except offEffect) with their paramDescriptions
def getEffects(effectController):
result = {}
for x, effect in enumerate(effectController.getEffects()):
effectParams = {}
for y, effectParam in enumerate(effect.effectParameters):
effectParams[y] = {'index': y,'type': effectParam.type, 'name': effectParam.name, 'desc': effectParam.desc, 'options': effectParam.options}
result[x] = {'index': x, 'name': effect.name, 'desc': effect.desc, 'effectParams': effectParams}
return result
# return json of all running effectThreads with their active rgbStrips and params
def getEffectThreads(effectController):
result = {}
for x, effectThread in enumerate(effectController.getEffectThreads()):
effectRGBStrips = {}
for effectRGBStrip in effectController.getEffectRGBStrips(effectThread):
effectRGBStrips[effectRGBStrip.STRIP_UID] = {'index': effectRGBStrip.STRIP_UID, 'name': effectRGBStrip.STRIP_NAME}
effectParams = {}
for z, effectParam in enumerate(effectThread.effectParameters):
effectParams[z] = {'index': z,'type': effectParam.type, 'name': effectParam.name, 'desc': effectParam.desc, 'options': effectParam.options, 'values': effectThread.effectParameterValues[z]}
result[x] = {'index': x, 'name': effectThread.name, 'desc': effectThread.desc,'activeRGBStips': effectRGBStrips, 'dump': str(effectThread), 'effectParams': effectParams}
return result
-140
View File
@@ -1,140 +0,0 @@
#
# The idea is to have only one thread accessing the audio input source instead
# of every music enabled thread itself. also, different fuctions calculating
# frequencys and so on shoud run in own threads to the leds get more updates
#
# in history one thread was calculating bpm, freqence average and max values in one thread
# before updating the leds, what the pi was a bit slow for and you cloud count every update
# of the leds
# i think most of it is from https://github.com/shunfu/python-beat-detector/
import numpy
import scipy
import pyaudio
import threading
import time
class pyAudioRecorder:
"""Simple, cross-platform class to record from the default input device."""
def __init__(self):
self.RATE = 44100
self.BUFFERSIZE = 2**12
self.secToRecord = .1
self.kill_threads = False
self.has_new_audio = False
self.setup()
# since the server only can handly one input (for now) this thread will calculate
# some basic things for the musicEffectsThreads, so they can update the leds more often.
# it is always posible to catch the fft() function and do your own thing in your musikEffect.
# calculate bpm, this is the same for all clientThreads
self.beats_idx = 0
self.bpm_list = []
self.prev_beat = time.perf_counter()
self.low_freq_avg_list = []
self.lastTime = time.time()
self.recorderClients = []
def setup(self):
self.buffers_to_record = int(
self.RATE * self.secToRecord / self.BUFFERSIZE)
if self.buffers_to_record == 0:
self.buffers_to_record = 1
self.samples_to_record = int(self.BUFFERSIZE * self.buffers_to_record)
self.chunks_to_record = int(self.samples_to_record / self.BUFFERSIZE)
self.sec_per_point = 1. / self.RATE
self.p = pyaudio.PyAudio()
# start the PyAudio class
for i in range(self.p.get_device_count()):
devinfo = self.p.get_device_info_by_index(i)
print(i, devinfo["name"])
# make sure the default input device is broadcasting the speaker output
# there are a few ways to do this
# e.g., stereo mix, VB audio cable for windows, soundflower for mac
self.in_stream = self.p.open(format=pyaudio.paInt16,
channels=1,
rate=self.RATE,
input=True,
frames_per_buffer=self.BUFFERSIZE)
print("Using default input device: {:s}".format(
self.p.get_default_input_device_info()['name']))
self.audio = numpy.empty(
(self.chunks_to_record * self.BUFFERSIZE), dtype=numpy.int16)
def close(self):
print("pyAudioRecorder closed")
self.kill_threads = True
self.p.close(self.in_stream)
### RECORDING AUDIO ###
def get_audio(self):
"""get a single buffer size worth of audio."""
audio_string = self.in_stream.read(self.BUFFERSIZE)
return numpy.fromstring(audio_string, dtype=numpy.int16)
def record(self):
while not self.kill_threads:
for i in range(self.chunks_to_record):
self.audio[i*self.BUFFERSIZE:(i+1)
* self.BUFFERSIZE] = self.get_audio()
self.has_new_audio = True
def start(self):
print("pyAudioRecorder started")
self.t = threading.Thread(target=self.record)
self.t.start()
### MATH ###
def downsample(self, data, mult):
"""Given 1D data, return the binned average."""
overhang = len(data) % mult
if overhang:
data = data[:-overhang]
data = numpy.reshape(data, (len(data) / mult, mult))
data = numpy.average(data, 1)
return data
def fft(self, data=None, trim_by=10, log_scale=False, div_by=100):
if not data:
data = self.audio.flatten()
left, right = numpy.split(numpy.abs(numpy.fft.fft(data)), 2)
ys = numpy.add(left, right[::-1])
if log_scale:
ys = numpy.multiply(20, numpy.log10(ys))
xs = numpy.arange(self.BUFFERSIZE/2, dtype=float)
if trim_by:
i = int((self.BUFFERSIZE/2) / trim_by)
ys = ys[:i]
xs = xs[:i] * self.RATE / self.BUFFERSIZE
if div_by:
ys = ys / float(div_by)
return xs, ys
### multithreading things ###
def registerRecorderClient(self,recorderClient):
self.recorderClients.append(recorderClient)
def unregisterRecorderClient(self,recorderClient):
self.recorderClients.remove(recorderClient)
class recorderClient(threading.Thread):
def __init__():
# toggle to true on beat, false when client got the value
self.onBeat = False
# when registering the client i want to be able to define how long the avg list should be
self.y_max_freq_avg_list = []
-54
View File
@@ -1,54 +0,0 @@
from rgbUtils.RGBStrip import RGBStrip
import time
import threading
import json
class rgbStripController():
def __init__(self):
#threading.Thread.__init__(self)
self.rgbStrips = []
self.onRGBStripRegisteredHandler = []
self.onRGBStripUnRegisteredHandler = []
def registerRGBStrip(self,rgbStripName,onValuesUpdateHandler,ledcount=1):
# maybe we can use an unique id if the strip reconnects later, eg push the uid
# to the client on first connect and if he reconnects he sould send it back again.
# the wmos could use the mac adress, if there is a python script it can save the uid
# in a file or so.
strip = RGBStrip(rgbStripName,onValuesUpdateHandler,ledcount)
self.rgbStrips.append(strip)
self.noticeRGBStripRegisteredHandler(strip)
return strip
def unregisterRGBStrip(self,strip):
self.rgbStrips.remove(strip)
self.noticeRGBStripUnRegisteredHandler(strip)
# returns all registered rgbStips
def getRGBStrips(self):
return self.rgbStrips
# inform all onRGBStripRegisteredHandler about the new RGBStrip
def noticeRGBStripRegisteredHandler(self,rgbStrip):
for hander in self.onRGBStripRegisteredHandler:
hander(rgbStrip)
# add onRGBStripRegisteredHandler
def addOnRGBStripRegisteredHandler(self, function):
self.onRGBStripRegisteredHandler.append(function)
# remove onRGBStripRegisteredHandler
def removeOnRGBStripRegisteredHandler(self, function):
self.onRGBStripRegisteredHandler.remove(function)
# inform all onRGBStripUnRegisteredHandder about the removed RGBStrip
def noticeRGBStripUnRegisteredHandler(self,rgbStrip):
for hander in self.onRGBStripUnRegisteredHandler:
hander(rgbStrip)
# add onRGBStripUnRegisteredHandler
def addOnRGBStripUnRegisteredHandler(self, function):
self.onRGBStripUnRegisteredHandler.append(function)
# remove onRGBStripUnRegisteredHandler
def removeOnRGBStripUnRegisteredHandler(self, function):
self.onRGBStripUnRegisteredHandler.remove(function)
@@ -1,14 +0,0 @@
"""
Convert the rgbStripController function outputs to json format
"""
# get the color values of a single led in json format
def getRGBData(rgbStrip,led = 0):
return {'led': led, 'red': rgbStrip.getData()[0][led], 'green': rgbStrip.getData()[1][led], 'blue': rgbStrip.getData()[2][led]}
# return json of all configured rgbStrips
def getRGBStrips(rgbStripController):
result = {}
for rgbStrip in rgbStripController.getRGBStrips():
result[rgbStrip.STRIP_UID] = {'index': rgbStrip.STRIP_UID, 'name': rgbStrip.STRIP_NAME}
return result