WebUI bugfixs

This commit is contained in:
nrhck 2018-12-15 20:03:32 +01:00
parent 12e62bb2f0
commit 4720922ed6
10 changed files with 88 additions and 114 deletions

View File

@ -9,13 +9,13 @@ LICENCE : CC BY
A software server with gui for up to 4 lasers live actions. Think creative like Laser "battles", planetarium,...
No .ild file here, you run your client that generate/send point lists to LJ. Any redis capable programming langage is fine.
This software is in python 2.7 but you run and write your clients separatly in any redis capable programming langage (50+ : https://redis.io/clients).
Needs at least : an etherdream DAC connected to an ILDA laser, RJ 45 IP network (gigabits only !! no wifi, 100 mpbs doesn't work well with several lasers)
Nozosc : Semi modular synthetizers from Nozoids can send a lot of their inner sound curves and be displayed in many ways, i.e VCO 1 on X axis and LFO 2 on Y axis.
The server approach is based on redis. One process per etherdream is spawn to : retrieve the given point list from redis, warp, resample and manage the given etherdream DAC dialog.
The server approach is based on redis. One process per etherdream is spawn : to retrieve the given point list from redis, warp, resample and manage the given etherdream dialog.
LJ supports Linux and OS X. Windows is unkown but welcome, if someone want to jump in and care about it.
@ -48,10 +48,12 @@ LJ supports Linux and OS X. Windows is unkown but welcome, if someone want to ju
LJ is meant for Live, so a lot of parameters can be changed via OSC/midi, webUI,...
This is *critical and flickering reason #1* if not managed properly : use static network configuration, especially if you move your gear for different venues.
This is *critical and flickering reason #1* if not managed properly, especially you have several lasers.
Our "always working solution" :
We use static network configuration, as we regularly move our gear for different venues.
Our Etherdreams controllers have static IPs defined in their SDcard from 192.168.1.1 to 192.168.1.9. Because wifi will always finally sucks for many reasons, our computers are *gigabits wired connected* with 192.168.1.10 and after. Don't trust end user gear marketing on wifi.
We have a big *laser dedicated gigabit switch*. We provide Internet through wifi on a different network address like 192.168.2.x

View File

@ -2,7 +2,7 @@
// In compatible LJay string format (pythonic lists)
var redis = require("redis"),
client = redis.createClient(6379,'192.168.1.13');
client = redis.createClient(6379,'127.0.0.1');

29
gstt.py
View File

@ -34,11 +34,6 @@ simuPL = 1
lasersIPS = ['192.168.1.5','192.168.1.6','192.168.1.3','192.168.1.4']
# gstt.laserPLS : What point list is sent to what laser.
# ** Will be overridden by the ConfigName (see below) file values **
lasersPLS = [0,1,2,0]
# gstt.kpps stores kpps for each laser.
# ** Will be overridden by the ConfigName (see below) file values **
kpps = [25000,25000,25000,25000]
@ -46,10 +41,6 @@ kpps = [25000,25000,25000,25000]
# gstt.GridDisplay : if = 1 Curve points actually sent to PL are replaced by a grid
GridDisplay = [0,0,0,0]
# with 4 laser available, 4 PL only are necessary
PL = [[],[],[],[]]
# Transformation Matrix for each laser
EDH = [[], [], [], []]
@ -72,8 +63,8 @@ maxCurvesByLaser = 4
# For glitch art : change position and decrease number of points added by newdac.py
# shortline for lines shorter than 4000 (in etherdream coordinates)
# i.e (0.25,3) means add 3 points at 25% on the line.
stepshortline = [ (1.0, 8)]
stepslongline = [ (0.25, 3), (0.75, 3), (1.0, 10)]
stepshortline = [(1.0, 8)]
stepslongline = [(0.25, 3), (0.75, 3), (1.0, 10)]
#curveColor = [255,0,0] * maxCurvesByLaser
@ -91,8 +82,6 @@ YTimeAxe=30000
#curveX = [255,255,255] * maxCurvesByLaser
#curveY = [255,255,255] * maxCurvesByLaser
Mode = 5
point = [0,0,0]
# gstt.colormode select what to display. Can be changed with /noteon 57-64
@ -125,22 +114,8 @@ cc[22]= 60
fov = 4 * cc[22]
'''
Also vailable with args : -v Value
if debug = 1 you get :
if debug = 2 you get :
- dac errors
'''
JumpFlag =0
# nice X (cc 5) Y (cc 6) curve at first
cc[5] = cc[6] = 60

View File

@ -221,16 +221,21 @@ def newEDH(mylaser):
# EDH matrix is H x Hwarp
#gstt.EDH[mylaser] = np.dot(H,Hwarp)
print "Laser",mylaser,"NEW EDH computed, sending to redis..."
r.set('/EDH/'+str(mylaser), np.array2string(gstt.EDH[mylaser], separator=','))
print "Laser",mylaser,"New EDH computed, sending to redis..."
if r.set('/EDH/'+str(mylaser), np.array2string(gstt.EDH[mylaser], separator=',')) == True:
r.set('/order/'+str(mylaser), 1)
print "New EDH sent."
else:
print "New EDH not sent."
'''
# Laser bit 0 = 0 and bit 1 = 1 : New EDH
order = r.get('/order')
print order
neworder = order & ~(1<< mylaser*2)
neworder = neworder | (1<< 1+mylaser*2)
r.set('/order', str(neworder))
'''
if gstt.debug >1:
print ""
print "laser ", mylaser

49
las.py
View File

@ -39,9 +39,11 @@ def UserOn(laser):
def NewEDH(laser):
print "New EDH requested for laser ", laser
settings.Write()
print "New EDH for laser ", laser
r.set('/order/'+str(laser), 1)
homographyp.newEDH(laser)
#r.set('/order/'+str(laser), 1)
# Laser bit 0 = 0 and bit 1 = 1 : New EDH
#order = r.get('/order')
#neworder = order & ~(1<< laser*2)
@ -69,22 +71,21 @@ def GridOn(laser):
#r.set('/order', str(neworder))
def Resampler(laser):
def Resampler(laser,lsteps):
# lsteps is a string like : "[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]"
print "Resampler change for laser ", laser
r.set('/resampler/' + str(laser), lsteps)
r.set('/order/'+str(laser), 4)
def handler(oscpath, args):
pathlength = len(oscpath)
if pathlength == 2:
if pathlength == 3:
laser = int(oscpath[2])
else:
laser = int(oscpath[2])
laser = int(oscpath[3])
# /grid/lasernumber value (0 or 1)
if oscpath[1] == "grid":
@ -113,31 +114,35 @@ def handler(oscpath, args):
if oscpath[1] == "ip":
print "New IP for laser ", laser
gstt.lasersIPS[laser]= args[0]
NewEDH(laser)
settings.Write()
# /kpps/lasernumber value
# Live change of kpps is not implemented in newdac.py. Change will effect next startup.
if oscpath[1] == "kpps":
print "New kpps for laser ", laser, " next startup", args[0]
gstt.kpps[laser]= int(args[0])
NewEDH(laser)
settings.Write()
# /angle/lasernumber value
if oscpath[1] == "angle":
print "New Angle modification for laser ", oscpath[2], ":", args[0]
gstt.finANGLE[laser] += int(args[0])
homographyp.newEDH(laser)
NewEDH(laser)
# /intens/lasernumber value
if oscpath[1] == "intens":
print "New intensity requested for laser ", oscpath[2], ":", args[0]
print "New intensity requested for laser ", laser, ":", args[0]
print "Change not implemented yet"
# /resampler/lasernumber lsteps
# lsteps is a string like "[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]"
if oscpath[1] == "resampler":
Resampler(laser,args[0])
# /mouse/lasernumber value (0 or 1)
if oscpath[1] == "mouse":
@ -154,13 +159,11 @@ def handler(oscpath, args):
if args[0] == "0":
print "swap X : -1 for laser ", laser
gstt.swapX[laser]= -1
homographyp.newEDH(laser)
NewEDH(laser)
else:
print "swap X : 1 for laser ", laser
gstt.swapX[laser]= 1
homographyp.newEDH(laser)
NewEDH(laser)
# /swap/Y/lasernumber value (0 or 1)
@ -168,41 +171,35 @@ def handler(oscpath, args):
if args[0] == "0":
print "swap Y : -1 for laser ", laser
gstt.swapY[laser]= -1
homographyp.newEDH(laser)
NewEDH(laser)
else:
print "swap Y : 1 for laser ", laser
gstt.swapY[laser]= 1
homographyp.newEDH(laser)
NewEDH(laser)
# /loffset/X/lasernumber value
if oscpath[1] == "loffset" and oscpath[2] == "X":
print "offset/X laser ", laser, "modified : ", args[0]
print "offset/X laser", laser, "modified to", args[0]
gstt.centerX[laser] -= int(args[0])
homographyp.newEDH(laser)
NewEDH(laser)
# /loffset/Y/lasernumber value
if oscpath[1] == "loffset" and oscpath[2] == "Y":
print "offset/Y laser ", laser, "modified : ", args[0]
print "offset/Y laser", laser, "modified to", args[0]
gstt.centerY[laser] -= int(args[0])
homographyp.newEDH(laser)
NewEDH(laser)
# /scale/X/lasernumber value
if oscpath[1] == "scale" and oscpath[2] == "X":
print "scale/X laser ", laser , "modified : ", args[0]
print "scale/X laser", laser , "modified to", args[0]
gstt.zoomX[laser] += int(args[0])
homographyp.newEDH(laser)
NewEDH(laser)
# /scale/Y/lasernumber value
if oscpath[1] == "scale" and oscpath[2] == "Y":
print "scale/Y laser ", laser, "modified : ", args[0]
print "scale/Y laser", laser, "modified to", args[0]
gstt.zoomY[laser] += int(args[0])
homographyp.newEDH(laser)
NewEDH(laser)
'''

View File

@ -2,32 +2,31 @@
set = 5
curve = 0
lasernumber = 1
debug = 0
debug = 1
ljayserverip = 127.0.0.1
nozoscip = 127.0.0.1
bhoroscip = 127.0.0.1
[laser0]
pl = 0
color = -1
ip = 192.168.1.4
kpps = 25000
centerx = 0
centery = 0
centery = -650
zoomx = 49.2
zoomy = 49.0
zoomy = 65.0
sizex = 31450
sizey = 32000
finangle = 0.0
swapx = 1
swapy = -1
swapy = 1
lsteps = [ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]
warpdest = [[-1500., 1500.],
[ 1500., 1500.],
[ 1500.,-1500.],
[-1500.,-1500.]]
[laser1]
pl = 1
color = -1
ip = 192.168.1.5
kpps = 25000
@ -40,13 +39,13 @@ sizey = 32000
finangle = 0.0
swapx = 1
swapy = 1
lsteps = [ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]
warpdest = [[-1500., 1500.],
[ 1500., 1500.],
[ 1500.,-1500.],
[-1500.,-1500.]]
[laser2]
pl = 2
color = -1
ip = 192.168.1.6
kpps = 25000
@ -59,13 +58,13 @@ sizey = 32000
finangle = -0.008
swapx = 1
swapy = 1
lsteps = [(1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]
warpdest = [[-1500., 1500.],
[ 1500., 1500.],
[ 1500.,-1500.],
[-1500.,-1500.]]
[laser3]
pl = 3
color = -1
ip = 192.168.1.3
kpps = 25000
@ -78,6 +77,7 @@ sizey = 32000
finangle = 0.0
swapx = -1
swapy = -1
lsteps = [(1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]
warpdest = [[-1500., 1500.],
[ 1500., 1500.],
[ 1500.,-1500.],

View File

@ -8,10 +8,6 @@ Laser server + webUI servers (ws + OSC)
todo :
r.set('/resampler/0', '[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]')
r.set('/resampler/1', '[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]')
r.set('/resampler/2', '[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]')
r.set('/resampler/3', '[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]')
'''
from __future__ import absolute_import
@ -45,6 +41,7 @@ from websocket_server import WebsocketServer
import types, thread, time
r = redis.StrictRedis(host=gstt.LjayServerIP , port=6379, db=0)
args =[0,0]
def dac_process(number, pl):
while True:
@ -93,7 +90,7 @@ wsPORT = 9001
# With Bhorosc
# OSC Server : relay OSC message from Bhorosc outport 8002 to UI
#oscIPin = "192.168.1.10"
#oscIPin = "192.168.1.10"s
bhoroscIPin = serverIP
bhoroscPORTin = 8002
@ -107,6 +104,8 @@ bhoroscPORTout = 8001
NozoscIPout = nozoscIP
NozoscPORTout = 8003
print bhoroscIPin
oscserver = OSCServer( (bhoroscIPin, bhoroscPORTin) )
oscserver.timeout = 0
OSCRunning = True
@ -162,7 +161,7 @@ def sendnozosc(oscaddress,oscargs=''):
pass
#time.sleep(0.001)
# NOT USED see las.py
# OSC default path handler : send OSC message from Bhorosc 8002 to UI via websocket 9001
def handler(path, tags, args, source):
@ -173,17 +172,7 @@ def handler(path, tags, args, source):
print "default handler"
print "Bhorosc said : ", path, oscpath, args
sendWSall(path + " " + str(args[0]))
las.handler(oscpath,args)
'''
# /lstt/number value
if oscpath[1] == "lstt":
sendWSall(path + " " + str(args[0]))
# /status string
if oscpath[1] == "status":
sendWSall(path + " " + str(args[0]))
'''
# RAW OSC Frame available ?
@ -213,9 +202,7 @@ def osc_thread():
time.sleep(1)
osc_frame()
for laserid in range(0,lasernumber): # Laser not used -> led is not lit
for laserid in range(0,gstt.LaserNumber): # Laser not used -> led is not lit
lstt = r.get('/lstt/'+ str(laserid))
#print "laserid", laserid,"lstt",lstt
@ -226,9 +213,9 @@ def osc_thread():
if lstt == "2": # Dac PLAYING (2) -> led is green (1)
sendWSall("/lstt/" + str(laserid) + " 1")
# This is used not working : lack never change. Todo : retest.
lack= r.get('/lack/'+str(laserid))
#print "laserid", laserid,"lack",lack
print "laserid", laserid,"lack",lack
if lack == 'a': # Dac sent ACK ("a") -> led is green (1)
sendWSall("/lack/" + str(laserid) +" 1")
if lack == 'F': # Dac sent FULL ("F") -> led is orange (5)
@ -247,7 +234,7 @@ def osc_thread():
# last number of points sent to etherdream buffer
sendWSall("/points/" + str(laserid) + " " + str(r.get('/cap/'+str(laserid))))
#sendWSall("/plframe/" + str(laserid) ) # + " " + str(r.get('/pl/'+str(laserid))))
sendWSall("/plframe/" + str(laserid) + " " + str(r.get('/pl/'+str(laserid))))
# WIP Too much packets -> flood webUI : Draw all PL point lists in JS canvas in WebUI
@ -276,6 +263,7 @@ def osc_thread():
# Called for every WS client connecting (after handshake)
def new_client(client, server):
print("New WS client connected and was given id %d" % client['id'])
sendWSall("/status Hello %d" % client['id'])
@ -284,14 +272,14 @@ def new_client(client, server):
sendWSall("/kpps/" + str(laserid)+ " " + str(gstt.kpps[laserid]))
if gstt.swapX[laserid] == 1:
sendWSall("swap/X/" + str(laserid)+ " 1")
sendWSall("/swap/X/" + str(laserid)+ " 1")
else:
sendWSall("swap/X/" + str(laserid)+ " 0")
sendWSall("/swap/X/" + str(laserid)+ " 0")
if gstt.swapY[laserid] == 1:
sendWSall("swap/Y/" + str(laserid)+ " 1")
sendWSall("/swap/Y/" + str(laserid)+ " 1")
else:
sendWSall("swap/Y/" + str(laserid)+ " 0")
sendWSall("/swap/Y/" + str(laserid)+ " 0")
# Called for every WS client disconnecting
def client_left(client, server):
@ -302,19 +290,24 @@ def client_left(client, server):
def message_received(client, server, message):
if len(message) > 200:
message = message[:200]+'..'
if gstt.debug >0:
print ("")
print("WS Client(%d) said: %s" % (client['id'], message))
oscpath = message.split(" ")
args[0] = float(oscpath[1])
#print oscpath[0].split("/"),oscpath[1]
las.handler(oscpath[0].split("/"),args)
# current UI has no dedicated off button so /on 0 trigs /off to bhorosc
if oscpath[0] == "/on":
if oscpath[1] == "1":
sendbhorosc("/on")
else:
sendbhorosc("/off")
else:
print "sending to bhorosc",oscpath[0],oscpath[1]
sendbhorosc(oscpath[0],oscpath[1])
@ -354,7 +347,7 @@ if r.set('/pl/3', str(random_points)) == True:
print "/pl/3 ", ast.literal_eval(r.get('/pl/3'))
# Order all lasers to show these random shapes at startup -> tell all 4 laser process to USER PLs
for laserid in range(0,lasernumber+1):
for laserid in range(0,gstt.LaserNumber):
r.set('/order/'+str(laserid), 0)
@ -429,7 +422,7 @@ finally:
for laserid in range(0,lasernumber+1):
print "Redis Etherdream",laserid,"feedback reset."
print "Laser",laserid,"feedbacks reset."
r.set('/lack/'+str(laserid),64)
r.set('/lstt/'+str(laserid),64)
r.set('/cap/'+str(laserid),0)

View File

@ -3,10 +3,10 @@
# -*- mode: Python -*-
'''
LJay v0.8.0
LJay/LJ v0.8.0
newdacp.py
Unhanced version (redis and process style) of the etherdream python library from j4cDAC.
Enhanced version (redis and process style) of the etherdream python library from j4cDAC.
LICENCE : CC
Sam Neurohack, pclf
@ -38,7 +38,7 @@ Geometric corrections :
import socket
import time
import struct
from gstt import debug, PL
#from gstt import debug
import gstt
import math
from itertools import cycle
@ -157,13 +157,13 @@ class DAC(object):
if math.hypot(delta_x, delta_y) < 4000:
# For glitch art : decrease lsteps
l_steps = [ (1.0, 8)]
#l_steps = gstt.stepshortline
#l_steps = [ (1.0, 8)]
l_steps = gstt.stepshortline
else:
# For glitch art : decrease lsteps
l_steps = [ (0.25, 3), (0.75, 3), (1.0, 10)]
#_steps = gstt.stepslongline
#l_steps = [ (0.25, 3), (0.75, 3), (1.0, 10)]
l_steps = gstt.stepslongline
for e in l_steps:
step = e[0]
@ -255,11 +255,11 @@ class DAC(object):
#print "pl :", self.pl
#print "EDH/"+str(self.mylaser),r.get('/EDH/'+str(self.mylaser))
if r.get('/EDH/'+str(self.mylaser)) == None:
#print "Laser",self.mylaser,"NO EDH !! Computing one..."
print "Laser",self.mylaser,"NO EDH !! Computing one..."
homographyp.newEDH(self.mylaser)
else:
gstt.EDH[self.mylaser] = np.array(ast.literal_eval(r.get('/EDH/'+str(self.mylaser))))
#print "Laser",self.mylaser,"found its EDH in redis"
print "Laser",self.mylaser,"found its EDH in redis"
#print gstt.EDH[self.mylaser]
'''
@ -358,7 +358,7 @@ class DAC(object):
self.pl = ast.literal_eval(r.get('/pl/'+str(self.mylaser)))
else:
# recompute EDH
# Get the new EDH
if order == 1:
print "Laser",self.mylaser,"new EDH ORDER in redis"
gstt.EDH[self.mylaser]= np.array(ast.literal_eval(r.get('/EDH/'+str(self.mylaser))))
@ -379,7 +379,7 @@ class DAC(object):
# Resampler Modification
if order == 4:
self.resampler = ast.literal_eval(r.get('/resampler/'+str(self.mylaser)))
print "resampler for", self.mylaser, ":",self.resampler
print "newdacp resetting lsteps for", self.mylaser, ":",self.resampler
gstt.stepshortline = self.resampler[0]
gstt.stepslongline[0] = self.resampler[1]
gstt.stepslongline[1] = self.resampler[2]
@ -445,6 +445,7 @@ class DAC(object):
# print "Took %f" % (t1 - t0, )
if not started:
print "starting laser", self.mylaser, "with", gstt.kpps[self.mylaser],"kpps"
self.begin(0, gstt.kpps[self.mylaser])
started = 1

View File

@ -58,7 +58,6 @@ def Read():
for i in range(4):
laser = 'laser' + str(i)
gstt.lasersIPS[i]= config.get(laser, 'ip')
gstt.lasersPLS[i] = config.getint(laser, 'PL')
gstt.kpps[i] = config.getint(laser, 'kpps')
#gstt.lasersPLcolor[i] = config.getint(laser, 'color')
gstt.centerX[i]= config.getint(laser, 'centerx')

View File

@ -42,6 +42,7 @@
},
onMessage: function (e) {
var res = e.data.split(" ");
var pl = ""
//console.log(e.data)
//console.log(res[0].substring(0,6))
switch (res[0].substring(0,6)) {
@ -49,12 +50,13 @@
_WS.showstatus(e.data.slice(8));
break;
case "/plfra":
console.log(e.data.slice(11));
pl = e.data.slice(11)
console.log(pl);
break;
case "/plpoi":
case "/plpoi":
//console.log("plpoint");
break;
default:
default:
console.log(res[0] + " " + res[1])
//console.log(res[1])
document.getElementById(res[0].slice(1)).value = res[1];