From b0c28e151059bfe91b8b6a741fcec0906a75ab2e Mon Sep 17 00:00:00 2001 From: alban Date: Sat, 10 Oct 2020 13:23:01 +0200 Subject: [PATCH 1/2] [enh] clitools: adds a cool audio based particle generater --- clitools/generators/redilysis_particles.py | 288 +++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100755 clitools/generators/redilysis_particles.py diff --git a/clitools/generators/redilysis_particles.py b/clitools/generators/redilysis_particles.py new file mode 100755 index 0000000..59e775a --- /dev/null +++ b/clitools/generators/redilysis_particles.py @@ -0,0 +1,288 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# -*- mode: Python -*- + + +''' + +v0.1.0 + + +LICENCE : CC + +by cocoa + +''' +from __future__ import print_function +import math +import random +import sys +import os +import time +import redis +import ast +import argparse + + +MAX_PARTICLES = 50 +MAX_TIME = 500 + +argsparser = argparse.ArgumentParser(description="Dummy generator") +argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int) +argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output") +# Redis Args +argsparser.add_argument("-i","--ip",help="IP address of the Redis server ",default="127.0.0.1",type=str) +argsparser.add_argument("-p","--port",help="Port of the Redis server ",default="6379",type=str) +# +argsparser.add_argument("-M","--max-particles",help="Max Particles. Default:{}".format(MAX_PARTICLES),default=MAX_PARTICLES,type=int) +argsparser.add_argument("-m","--max-time",help="Max Particles. Default:{}".format(MAX_TIME),default=MAX_TIME,type=int) + + +args = argsparser.parse_args() +verbose = args.verbose +ip = args.ip +port = args.port +max_particles = args.max_particles +max_time = args.max_time + +def debug(*args, **kwargs): + if( verbose == False ): + return + print(*args, file=sys.stderr, **kwargs) + + +def rgb2int(rgb): + #debug(name,"::rgb2int rbg:{}".format(rgb)) + return int('0x%02x%02x%02x' % tuple(rgb),0) + +def spectrum_120( ): + return ast.literal_eval(redisData["spectrum_10"]) + + +def rgb2int(rgb): + #debug(name,"::rgb2int rbg:{}".format(rgb)) + return int('0x%02x%02x%02x' % tuple(rgb),0) + +def msNow(): + return time.time() + +def refreshRedis(): + global redisData + for key in redisKeys: + redisData[key] = ast.literal_eval(r.get(key).decode('ascii')) + +name="generator::redilisys_particles" + +class UnpreparedParticle(Exception): + pass + +class Particle(object): + def __init__(self, x, y, m): + self.x = x + self.y = y + self.m = m + self.dx = 0 + self.dy = 0 + self.connectedTo = [] + + self.decay = random.randint(10,max_time) + self.color = (random.randint(128,256) - int(12.8 * self.m), + random.randint(128,256) - int(12.8 * self.m), + random.randint(128,256) - int(12.8 * self.m)) + self.color = (255,255,255) + #debug( self.color ) + + def interact(self, bodies): + self.connectedTo = [] + spec = redisData["spectrum_10"] + power = int(sum(spec[4:6])) + for other in bodies: + if other is self: + continue + dx = other.x - self.x + dy = other.y - self.y + dist = math.sqrt(dx*dx + dy*dy) + if dist == 0: + dist = 1 + if dist < 100 and random.randint(0,power) > 0.5 : + self.connectedTo.append(other) + self.decay += 2 + factor = other.m / dist**2 + high_power = sum(spec[8:9]) if sum(spec[8:9]) != 0 else 0.01 + self.dx += (dx * factor * self.m) + self.dy += (dy * factor * self.m) + #print "factor %f" % (factor,) + + def move(self): + spec = redisData["spectrum_10"] + x_friction = (2.2-(1+spec[7]/2)) + y_friction = (2.2-(1+spec[7]/2)) + #x_friction = 1.02 + #y_friction = 1.04 + self.dx /= x_friction if x_friction != 0 else 0.01 + self.dy /= y_friction if y_friction != 0 else 0.01 + self.x += self.dx + self.y += self.dy + if self.x > max_width: + self.dx = - self.dx /8 + self.x = max_width + if self.x < 1: + self.dx = - self.dx /8 + self.x = 1 + if self.y > max_height: + self.dy = - self.dy /4 + self.y = max_height + if self.y < 1: + self.dy = - self.dy /4 + self.y = 1 + #print "(%.2f,%.2f) -> (%.2f,%.2f)" % (ox, oy, self.x, self.y) + + def attractor(self,attractor): + spec = redisData["spectrum_10"] + power = sum(spec[0:4])/3 + # If we're going in the direction of center, reverse + next_x = self.x + self.dx + next_y = self.y + self.dy + next_dx = attractor["x"] - self.x + next_dy = attractor["y"] - self.y + next_dist = math.sqrt(next_dx*next_dx + next_dy*next_dy) + + dx = attractor["x"] - self.x + dy = attractor["y"] - self.y + dist = math.sqrt(dx*dx + dy*dy) + if dist == 0: + dist = 1 + factor = power/ dist**2 + x_acceleration = (dx * factor * power * power) + y_acceleration = (dx * factor * power * power) + + + if next_dist > dist: + self.dx -= x_acceleration * power + self.dy -= y_acceleration * power + else: + self.dx += x_acceleration + self.dy += y_acceleration + + +class Attractor(Particle): + def move(self): + pass + + +class ParticleViewer(object): + def __init__(self, particles, size=(800,800)): + (self.width, self.height) = size + self.size = size + self.particles = particles + self.xoff = 0 + self.yoff = 0 + self.scalefactor = 1 + + def redraw(self): + + pl = [] + drawnVectors = [] + for p in self.particles: + x = int(self.scalefactor * p.x) - self.xoff + y = int(self.scalefactor * p.y) - self.yoff + if x > max_width: + x = max_width + if x < 1: + x = 1 + if y > max_height: + y = max_height + if y < 1: + y = 1 + + color = rgb2int(p.color) + pl.append([x+1,y+1,0]) + pl.append([x+1,y+1,color]) + pl.append([x,y,color]) + + for other in p.connectedTo: + + if [other,self] in drawnVectors: + continue + drawnVectors.append([other,self]) + pl.append([x,y,0]) + pl.append([x,y,color]) + pl.append([other.x,other.y,color]) + + print(pl,flush = True) + + def decayParticles(self): + for i,p in enumerate(self.particles): + # Handle positional decay + if p.decay == 0: + del self.particles[i] + continue + p.decay = p.decay - 1 + # Handle color decay + n = int(255 * (p.decay / max_time )) + p.color = (n,n,n) + + + def emitParticles(self): + spec = redisData["spectrum_10"] + power = sum(spec[6:]) + if len(self.particles ) > math.sqrt(max_particles): + if len(self.particles) > max_particles: + return + if random.random() > power: + return + # x is either left or right + d = 600 + rx = 100 if random.randint(0,1) else 700 + #rx = random.randint(1,max_width) + ry = random.randint(1,max_height) + spec = redisData["spectrum_10"] + m = random.randint(1,1+int(10*spec[7])) + particles.append(Particle(rx, ry, m)) + + + def tick(self): + self.decayParticles() + self.emitParticles() + for p in self.particles: + p.interact(self.particles) + p.attractor({ + "x":max_width/2, + "y":max_height/2 + }) + for p in particles: + p.move() + self.redraw() + + def scale(self, factor): + self.scalefactor += factor + + + + +max_width = 800 +max_height = 800 +redisKeys = ["spectrum_120","spectrum_10"] +redisData = {} +redisLastHit = msNow() - 99999 +r = redis.Redis( + host=ip, + port=port) + +white = 16777215 + +refreshRedis() +if __name__ == "__main__": + particles = [] +# particles.append(Attractor(320, 200, 10)) +# particles.append(Attractor(100, 100, 10)) + + win = ParticleViewer(particles) + try: + while True: + win.tick() + refreshRedis() + time.sleep(.03) + + except KeyboardInterrupt: + pass From a06e3ba07e838cd72a1f15b2de45374672891e1c Mon Sep 17 00:00:00 2001 From: alban Date: Sat, 10 Oct 2020 16:52:42 +0200 Subject: [PATCH 2/2] [enh] clitools : adds a color redilysis filter --- clitools/filters/redilysis_colors.py | 186 +++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 clitools/filters/redilysis_colors.py diff --git a/clitools/filters/redilysis_colors.py b/clitools/filters/redilysis_colors.py new file mode 100644 index 0000000..230fa08 --- /dev/null +++ b/clitools/filters/redilysis_colors.py @@ -0,0 +1,186 @@ + +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# -*- mode: Python -*- + + +''' + +redilysis colors +v0.1.0 + +A complex effect that depends on redis keys for audio analysis + +see https://git.interhacker.space/teamlase/redilysis for more informations +about the redilysis project + +LICENCE : CC + +by cocoa + + +''' +from __future__ import print_function +import argparse +import ast +import os +import math +import random +import redis +import sys +import time +name = "filters::redilysis_colors" + +def debug(*args, **kwargs): + if( verbose == False ): + return + print(*args, file=sys.stderr, **kwargs) +def msNow(): + return time.time() + +# The list of available modes => redis keys each requires to run +oModeList = { + } + +def rgb2int(rgb): + return int('0x%02x%02x%02x' % tuple(rgb),0) + +def int2rgb(intcode): + #hexcode = hex(intcode)[2:] + hexcode = '{0:06X}'.format(intcode) + return tuple(int(hexcode[i:i+2], 16) for i in (0, 2, 4)) + #return tuple(map(ord,hexcode[1:].decode('hex'))) + + + +CHAOS = 1 +REDIS_FREQ = 100 + +# General Args +argsparser = argparse.ArgumentParser(description="Redilysis filter") +argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int) +argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose") +# Redis Args +argsparser.add_argument("-i","--ip",help="IP address of the Redis server ",default="127.0.0.1",type=str) +argsparser.add_argument("-p","--port",help="Port of the Redis server ",default="6379",type=str) +argsparser.add_argument("-s","--redis-freq",help="Query Redis every x (in milliseconds). Default:{}".format(REDIS_FREQ),default=REDIS_FREQ,type=int) +# Modes And Common Modes Parameters +#argsparser.add_argument("-m","--modelist",required=False,help="Comma separated list of modes to use from: {}".format("i, ".join(oModeList.keys())),type=str) +argsparser.add_argument("-c","--chaos",help="How much disorder to bring. High value = More chaos. Default {}".format(CHAOS), default=CHAOS, type=float) + +args = argsparser.parse_args() +fps = args.fps +ip = args.ip +port = args.port +redisFreq = args.redis_freq / 1000 +verbose = args.verbose +chaos = float(args.chaos) +optimal_looptime = 1 / fps + +max_width = 800 +max_height = 800 + +redisKeys = ["rms","spectrum_10","spectrum_120"] + +debug(name,"Redis Keys:{}".format(redisKeys)) +redisData = {} +redisLastHit = msNow() - 99999 +r = redis.Redis( + host=ip, + port=port) + + +def refreshRedis(): + global redisData + for key in redisKeys: + try: + redisData[key] = ast.literal_eval(r.get(key).decode('ascii')) + except : + debug("Error when reading redis key '{}".format(key)) + +def gauss(x, mu, sigma): + return( math.exp(-math.pow((x-mu),2)/(2*math.pow(sigma,2))/math.sqrt(2*math.pi*math.pow(sigma,2)))) + + +spect10Correct = [ + + 6.0, + 1.5, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 0.8, + 0.6, + 0.5, + +] + +def default( pl ): + global redisData + spect = redisData["spectrum_10"] + debug(name, "spect:{}".format(spect)) + new_list = [] + + # We want to color points that are on left and right when high is strong + # i.e. the farther the distance from spectrum, the higher notes have influence + # power = 0-1 + # x = 800 spec[2]= 6.0 spec[7]=0.0 power=0.0 + # x = 0 spec[2]= 6.0 spec[7]=0.0 power=0.0 + # x = 0 spec[2]= 1.0 spec[7]=0.5 power=1.0 + + # dist 0 = 1 + # 400 - 400 : maxW/2 -x + # 399 = -1 : x - 400 + # 401 = 1 + # x = 400 spec[2]= 6.0 spec[7]=0.0 power=1.0 + # x = 400 spec[2]= 1.0 spec[7]=0.5 power=0.0 + + for i, point in enumerate(pl): + ocolor = pl[i][2] + if ocolor == 0 : + new_list.append(point) + continue + colorTuple = int2rgb(ocolor) + x = point[0] + dist = abs(x - max_width/2) + key = int(2* dist / max_width * 8) + power = spect[key] / spect10Correct[key] * chaos + color = [] + for i in colorTuple: + new_color = int(i * power) + if new_color > 255 : + new_color = 255 + if new_color < 0 : + new_color = 0 + color.append( new_color ) + color = rgb2int(tuple(color)) + + point[2] = color + new_list.append(point) + #debug(name,"x:{}\t dist:{}\t key:{}\t power:{}\t ocolor:{}\t color:{}".format(point[0], dist, key,power, ocolor, pl[i][2])) + debug( name,"rms_noise output:{}".format(new_list)) + return new_list + + +try: + while True: + refreshRedis() + start = time.time() + line = sys.stdin.readline() + if line == "": + time.sleep(0.01) + line = line.rstrip('\n') + pointsList = ast.literal_eval(line) + # Do the filter + pointsList = default(pointsList) + print( pointsList, flush=True ) + looptime = time.time() - start + # debug(name+" looptime:"+str(looptime)) + if( looptime < optimal_looptime ): + time.sleep( optimal_looptime - looptime) + # debug(name+" micro sleep:"+str( optimal_looptime - looptime)) +except EOFError: + debug(name+" break")# no more information +