[enh] clitools: adds a cool audio based particle generater

This commit is contained in:
alban 2020-10-10 13:23:01 +02:00
parent 4faf53168d
commit b0c28e1510

View File

@ -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