diff --git a/LJ.conf b/LJ.conf
index ee32cb2..69d6b6f 100644
--- a/LJ.conf
+++ b/LJ.conf
@@ -1,5 +1,5 @@
[General]
-lasernumber = 1
+lasernumber = 4
debug = 0
ljayserverip = 0.0.0.0
wwwip = 192.168.2.43
@@ -13,13 +13,13 @@ type = DS1000
ip = 192.168.2.4
kpps = 25000
centerx = 0
-centery = 0
+centery = 765
zoomx = 45.0
zoomy = 45.0
sizex = 32000
sizey = 32000
finangle = 0.0
-swapx = 1
+swapx = -1
swapy = -1
lsteps = [ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]
warpdest = [[-1500., 1500.],
@@ -32,20 +32,20 @@ color = -1
type = LOCAL
ip = 192.168.2.43
kpps = 25000
-centerx = 0
-centery = 0
-zoomx = 45.0
-zoomy = 45.0
+centerx = -11970
+centery = -6510
+zoomx = 30.0
+zoomy = 30.0
sizex = 32000
sizey = 32000
-finangle = -30.0
+finangle = 0.0
swapx = -1
swapy = -1
lsteps = [ (1.0, 2),(0.25, 1), (0.75, 1), (1.0, 5)]
warpdest = [[-1500., 1500.],
- [ 1500., 1500.],
- [ 1500.,-1500.],
- [-1500.,-1500.]]
+ [ 1500., 1500.],
+ [ 1500.,-1500.],
+ [-1500.,-1500.]]
[laser2]
color = -1
@@ -63,14 +63,14 @@ 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.]]
+ [ 1500., 1500.],
+ [ 1500.,-1500.],
+ [-1500.,-1500.]]
[laser3]
color = -1
type = LUKE400
-ip = 192.168.1.5
+ip = 192.168.2.3
kpps = 25000
centerx = 0
centery = 0
@@ -83,19 +83,13 @@ 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.]]
+ [ 1500., 1500.],
+ [ 1500.,-1500.],
+ [-1500.,-1500.]]
[plugins]
plugins = {
- "trckr": {"OSC": 8017, "command": "python3 plugins/VJing/trckr.py", "display": True},
"aurora": {"OSC": 8090, "command": "python3 plugins/aurora/aurora.py", "display": True},
- "maxw": {"OSC": 8012, "command": "python3 plugins/maxwell.py", "display": True},
- "square": {"OSC": 8013, "command": "python3 plugins/square.py", "display": True},
- "custom1": {"OSC": 8014, "command": "python3 plugins/custom1.py", "display": True},
- "mitraille": {"OSC": 8015, "command": "python3 plugins/audio/mitraille.py", "display": True},
- "livecode": {"OSC": 8016, "command": "python3 plugins/livecoding.py", "display": True},
"nozoid": {"OSC": 8003, "command": "python3 plugins/audio/nozoids3.py", "display": True},
"glyph": {"OSC": 8004, "command": "python3 plugins/laserglyph.py", "display": True},
"planet": {"OSC": 8005, "command": "python3 plugins/planetarium/main.py", "display": True},
@@ -103,6 +97,11 @@ plugins = {
"cycl": {"OSC": 8007, "command": "python3 plugins/textcycl.py", "display": True},
"simu": {"OSC": 8008, "command": "python plugins/pysimu.py", "display": False},
"artnet": {"OSC": 8009, "command": "python3 libs3/artnet.py", "display": False},
+ "trckr": {"OSC": 8017, "command": "python3 plugins/trckr.py", "display": False},
+ "maxw": {"OSC": 8012, "command": "python3 plugins/maxwell.py", "display": True},
+ "square": {"OSC": 8013, "command": "python3 plugins/square.py", "display": True},
+ "custom1": {"OSC": 8014, "command": "python3 plugins/custom1.py", "display": True},
+ "mitraille": {"OSC": 8015, "command": "python3 plugins/audio/mitraille.py", "display": True},
"livecode": {"OSC": 8016, "command": "python3 plugins/livecoding.py", "display": True},
"ljpong": {"OSC": 8020, "command": "python plugins/games/ljpong/main.py", "display": True},
"ljwars": {"OSC": 8021, "command": "python plugins/games/ljsw/main.py", "display": True},
diff --git a/LJ_template..conf b/LJ_template..conf
index 7e839ef..fa413f6 100644
--- a/LJ_template..conf
+++ b/LJ_template..conf
@@ -34,11 +34,11 @@ ip = 192.168.2.43
kpps = 25000
centerx = 0
centery = 0
-zoomx = 45.0
-zoomy = 45.0
+zoomx = 30.0
+zoomy = 30.0
sizex = 32000
sizey = 32000
-finangle = -30.0
+finangle = 0
swapx = -1
swapy = -1
lsteps = [ (1.0, 2),(0.25, 1), (0.75, 1), (1.0, 5)]
@@ -89,13 +89,7 @@ warpdest = [[-1500., 1500.],
[plugins]
plugins = {
- "trckr": {"OSC": 8017, "command": "python3 plugins/VJing/trckr.py", "display": True},
"aurora": {"OSC": 8090, "command": "python3 plugins/aurora/aurora.py", "display": True},
- "maxw": {"OSC": 8012, "command": "python3 plugins/maxwell.py", "display": True},
- "square": {"OSC": 8013, "command": "python3 plugins/square.py", "display": True},
- "custom1": {"OSC": 8014, "command": "python3 plugins/custom1.py", "display": True},
- "mitraille": {"OSC": 8015, "command": "python3 plugins/audio/mitraille.py", "display": True},
- "livecode": {"OSC": 8016, "command": "python3 plugins/livecoding.py", "display": True},
"nozoid": {"OSC": 8003, "command": "python3 plugins/audio/nozoids3.py", "display": True},
"glyph": {"OSC": 8004, "command": "python3 plugins/laserglyph.py", "display": True},
"planet": {"OSC": 8005, "command": "python3 plugins/planetarium/main.py", "display": True},
@@ -103,6 +97,11 @@ plugins = {
"cycl": {"OSC": 8007, "command": "python3 plugins/textcycl.py", "display": True},
"simu": {"OSC": 8008, "command": "python plugins/pysimu.py", "display": False},
"artnet": {"OSC": 8009, "command": "python3 libs3/artnet.py", "display": False},
+ "trckr": {"OSC": 8017, "command": "python3 plugins/trckr.py", "display": False},
+ "maxw": {"OSC": 8012, "command": "python3 plugins/maxwell.py", "display": True},
+ "square": {"OSC": 8013, "command": "python3 plugins/square.py", "display": True},
+ "custom1": {"OSC": 8014, "command": "python3 plugins/custom1.py", "display": True},
+ "mitraille": {"OSC": 8015, "command": "python3 plugins/audio/mitraille.py", "display": True},
"livecode": {"OSC": 8016, "command": "python3 plugins/livecoding.py", "display": True},
"ljpong": {"OSC": 8020, "command": "python plugins/games/ljpong/main.py", "display": True},
"ljwars": {"OSC": 8021, "command": "python plugins/games/ljsw/main.py", "display": True},
diff --git a/README.md b/README.md
index 95eca6f..ee8e4ff 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ Important : for best performance LJ is meant to run in a dedicated computer espe
- Some Lasermapping ('alignment') like in videomapping.
- OSC and websocket commands. Very cool : LJ can script or be scripted.
- Python3
-- Web User Interface in your browser : open www/index.html. Javascript is needed. By default it connect to localhost. If you want to control remotely, you need to change the uri line in LJ.js.
+- Web User Interface in your browser : open www/index.html. Javascript is needed. By default it connect to localhost. If you want to control remotely, you need edit webui choice : python3 configure.py
- Live WebUI extras : change debug level, restart plugin, rescan DACs,...
- Status update every 0.5 seconds : every etherdream DAC state, number of buffer points sent,...
- "Optimisation" points automatically added, can be changed live for glitch art. Search "resampler" commands.
@@ -260,10 +260,14 @@ DrawDests() will take care of all your declared drawn elements/"objects" and Des
# Nannou etherdeam simulator aka visualiser
#
-2 compiled nannou visualisers are included, one for Linux, one for macOS. It's pretty old version but much more compatible with "old" processors/computer.
+Nannou visualiser kind of emulate an etherdream and display in a window what a real laser draws.
+
+2 compiled nannou visualisers are included, one for Linux, one for macOS. It's pretty old versions but much more compatible with "old" processors/computer, as you may want to repurpose an old computer to run LJ.
To use this visualiser as one of LJ's lasers, in LJ.conf edit one of line ip = someipaddress with the IP of the computer running the visualiser. Relaunch LJ. One visualiser per computer.
+Nannou visualiser emulation is better and better but one can find a few known non-working situations. See it's github repository (https://github.com/nannou-org/ether-dream/tree/master/dac-emulator) for more recent versions.
+
#
# Todo
#
@@ -349,9 +353,9 @@ About hardware setup, especially if you have several lasers : ILDA cables are in
# Ethertools directory
#
-2 useful and always working tools from j4cdac github repository : sitter and talk
-- Sitter will display all real etherdreams available on the network and their state (playing, idle,...). python sitter.py or use the compiled version (for macOS).
-- Talk : will draw a 4 colors square. python3 talk3.py
+2 useful and *always working tools* from j4cdac github repository : sitter and talk.
+- Sitter will display all etherdreams available on the network and their state (playing, idle,...). python sitter.py or use the compiled version (for macOS). May need tkinter : pip3 install tk
+- Talk : will draw a 4 colors square. Try : python3 talk3.py -h
#
# Links
@@ -367,6 +371,8 @@ Generic :
![Laser Faq](https://www.repairfaq.org/sam/lasersam.htm)
+![Etherdream protocol](https://ether-dream.com/protocol.html)
+
There is a nice websocket debug tool : websocat.
#
diff --git a/clitools/README.md b/clitools/README.md
index 407050a..b69e4a5 100644
--- a/clitools/README.md
+++ b/clitools/README.md
@@ -9,7 +9,7 @@ BOOM | WIIIIIZ :: PHHHHHRACKRACKRACK ~~ WOOP ~~###~~ WIIT
## The basic loop
```
-python3 generators/dummy.py -f 2 | filters/kaleidoscope.py | exports/toRedis.py -v
+python3 generators/dummy.py -f 2 | python3 filters/kaleidoscope.py | python3 exports/toRedis.py -v
------------------------------ --------------------- -------------------
\/ \/ \/
Generator Filter Export
diff --git a/ethertools/dac3.py b/ethertools/dac3.py
index 325672b..3c50adc 100755
--- a/ethertools/dac3.py
+++ b/ethertools/dac3.py
@@ -165,7 +165,7 @@ class DAC(object):
return self.readresp("d")
def prepare(self):
- self.conn.sendall('p')
+ self.conn.sendall(b'p')
return self.readresp('p')
def stop(self):
diff --git a/ethertools/talk3.py b/ethertools/talk3.py
index 183e613..b841124 100755
--- a/ethertools/talk3.py
+++ b/ethertools/talk3.py
@@ -1,4 +1,17 @@
#!/usr/bin/env python
+
+'''
+
+Improved dac.py and talk.py (by Jacob Potter). Pimped by Sam Neurohack.
+
+- python3
+- works with nannou visualisers
+- can talk to a given etherdream knowing it's IP.
+
+v0.1.0
+
+'''
+
#
# j4cDAC test code
#
@@ -17,6 +30,19 @@
# along with this program. If not, see .
import dac3 as dac
+import argparse
+import sys
+
+argsparser = argparse.ArgumentParser(description="Draw a square on a laser via Etherdream DAC")
+
+argsparser.add_argument("-i","--ip",help="Etherdream IP (default : first etherdream broadcast received",default="True",type=str)
+
+
+
+args = argsparser.parse_args()
+etherIP = args.ip
+
+
class SquarePointStream(object):
'''
@@ -88,8 +114,14 @@ class NullPointStream(object):
return [(0, 0, 0, 0, 0)] * n
#dac.find_dac()
+if etherIP == "True":
+ print("Waiting for the first DAC broadcast...")
+ d = dac.DAC(dac.find_first_dac())
-d = dac.DAC(dac.find_first_dac())
-#d = dac.DAC("192.168.1.43")
+else:
+ print("Using Etherdream :", etherIP)
+ d = dac.DAC(etherIP)
+
+print("Sending points...")
d.play_stream(SquarePointStream())
diff --git a/plugins/custom1.py b/plugins/custom1.py
index 75506c3..3ee5e6f 100644
--- a/plugins/custom1.py
+++ b/plugins/custom1.py
@@ -25,15 +25,15 @@ ljpath = r'%s' % os.getcwd().replace('\\','/')
# import from shell
-sys.path.append(ljpath +'/../libs/')
+sys.path.append(ljpath +'/../libs3/')
#import from LJ
-sys.path.append(ljpath +'/libs/')
-print(ljpath+'/../libs/')
+sys.path.append(ljpath +'/libs3/')
+print(ljpath+'/../libs3/')
import lj23layers as lj
-sys.path.append('../libs')
+sys.path.append('../libs3')
from OSC3 import OSCServer, OSCClient, OSCMessage
import redis
import math
diff --git a/plugins/square.py b/plugins/square.py
index a9f6c34..9b48d3f 100644
--- a/plugins/square.py
+++ b/plugins/square.py
@@ -25,15 +25,15 @@ ljpath = r'%s' % os.getcwd().replace('\\','/')
# import from shell
-sys.path.append(ljpath +'/../libs/')
+sys.path.append(ljpath +'/../libs3/')
#import from LJ
-sys.path.append(ljpath +'/libs/')
-print(ljpath+'/../libs/')
+sys.path.append(ljpath +'/libs3/')
+print(ljpath+'/../libs3/')
import lj23layers as lj
-sys.path.append('../libs')
+sys.path.append('../libs3')
from OSC3 import OSCServer, OSCClient, OSCMessage
import redis
import math
diff --git a/plugins/trckr.py b/plugins/trckr.py
new file mode 100644
index 0000000..fa449cc
--- /dev/null
+++ b/plugins/trckr.py
@@ -0,0 +1,647 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+# -*- mode: Python -*-
+
+
+'''
+
+trckr
+Work with clmtrackr-dev and www/trckr/trckr.html
+v0.1.0
+
+
+LICENCE : CC
+by Sam Neurohack
+
+To test the examples locally, you need to run a local server.
+One easy way to do this is to install http-server, a small node.js utility:
+npm install -g http-server.
+
+Then run http-server in the root of clmtrackr and go to
+
+- read a video :
+http://localhost:8080/examples/trckr.html
+- webcam
+
+
+clmtrackr :
+https://github.com/auduno/clmtrackr/tree/dev/examples
+
+
+'''
+import sys
+import os
+print()
+ljpath = r'%s' % os.getcwd().replace('\\','/')
+
+# import from shell
+sys.path.append(ljpath +'/../libs3/')
+#import from LJ
+import log
+
+print ("")
+
+log.infog("Trckr Plugin v0.1")
+
+
+sys.path.append('../libs3')
+sys.path.append(ljpath +'/../../libs3')
+
+from OSC3 import OSCServer, OSCClient, OSCMessage
+import lj23layers as lj
+import redis
+import math
+import time
+import argparse
+
+OSCinPort = 8017
+
+print ("")
+print ("Arguments parsing if needed...")
+argsparser = argparse.ArgumentParser(description="trckr example for LJ")
+argsparser.add_argument("-r","--redisIP",help="IP of the Redis server used by LJ (127.0.0.1 by default) ",type=str)
+argsparser.add_argument("-s","--scene",help="LJ scene number (0 by default)",type=int)
+#argsparser.add_argument("-l","--laser",help="Laser number to be displayed (0 by default)",type=int)
+argsparser.add_argument("-v","--verbose",help="Verbosity level (0 by default)",type=int)
+argsparser.add_argument("-m","--myIP",help="Local IP (127.0.0.1 by default) ",type=str)
+
+args = argsparser.parse_args()
+
+if args.scene:
+ ljscene = args.scene
+else:
+ ljscene = 0
+'''
+if args.laser:
+ plnumber = args.laser
+else:
+ plnumber = 0
+'''
+
+# Redis Computer IP
+if args.redisIP != None:
+ redisIP = args.redisIP
+else:
+ redisIP = '127.0.0.1'
+
+print("redisIP",redisIP)
+
+# myIP
+if args.myIP != None:
+ myIP = args.myIP
+else:
+ myIP = '127.0.0.1'
+
+print("myIP",myIP)
+
+if args.verbose:
+ debug = args.verbose
+else:
+ debug = 0
+
+# Useful variables init.
+white = lj.rgb2int(255,255,255)
+red = lj.rgb2int(255,0,0)
+blue = lj.rgb2int(0,0,255)
+green = lj.rgb2int(0,255,0)
+
+# 3D to 2D projection parameters
+fov = 256
+viewer_distance = 2.2
+
+width = 800
+height = 600
+centerX = width / 2
+centerY = height / 2
+
+TrckrPts = [[0,0]] * 70
+
+
+
+#
+# LJ inits
+#
+
+layer = 0
+
+# Setup LJ library mandatory properties for this layerugin
+lj.Config(redisIP, ljscene, "trckr")
+
+# Define properties for each drawn "element" : name, intensity, active, xy, color, red, green, blue, layer , closed
+FaceForm = lj.FixedObject('Face', True, 255, [], red, 255, 0, 0, layer , False)
+
+# 'Destination' for given layer : name, number, active, layer , scene, laser
+Dest0 = lj.DestObject('0', 0, True, 0 , 0, 0) # Dest0 will send layer 0 points to scene 0, laser 0
+
+
+
+#
+# OSC
+#
+
+oscserver = OSCServer( (myIP, OSCinPort) )
+oscserver.timeout = 0
+
+
+# this method of reporting timeouts only works by convention
+# that before calling handle_request() field .timed_out is
+# set to False
+def handle_timeout(self):
+ self.timed_out = True
+
+# funny python's way to add a method to an instance of a class
+import types
+oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver)
+
+
+# OSC callbacks
+
+# /trckr/ljscene
+def OSCljscene(path, tags, args, source):
+
+ print("Got /trckr/ljscene with value", args[0])
+ lj.WebStatus("trckr to virtual "+ str(args[0]))
+ ljscene = args[0]
+ lj.Ljscene(ljscene)
+
+# /trckr/layer
+def OSClayer(path, tags, args, source):
+
+ print()
+ print()
+ print("Got /trckr/layer with value", args[0])
+ lj.WebStatus("trckr to layer "+ str(args[0]))
+ FaceForm.layer = int(args[0])
+ Dest0.layer = int(args[0])
+ Dest0.laser = int(args[0])
+
+# /trckr/frame
+def OSCtrckr(path, tags, args, source):
+ global TrckrPts
+
+ #print("trckr got frame", args[0])
+ if debug != 0:
+ print("trckr plugin got frame", args[0])
+ print(len(args),"args", args)
+ counter =0
+ TrckrPts = []
+
+ for dot in range(1,len(args)-1,2):
+
+ TrckrPts.append([float(args[dot]), float(args[dot+1])])
+ print(TrckrPts)
+
+# /trckr/frame layernumber framenumber points
+def OSCTrckrframe(path, tags, args, source):
+ global TrckrPts
+
+ if debug != 0:
+ print("trckr plugin got frame", args[1], "for layer", args[0], "with path", path)
+ print(len(args),"args", args)
+
+ TrckrPts[args[0]] = []
+
+ for dot in range(2,len(args)-1,2):
+ TrckrPts[args[0]].append([float(args[dot]), float(args[dot+1])])
+
+
+
+
+#/trckr/color/0 red ?
+def OSColor():
+ global FaceForm
+
+ if debug != 0:
+ print("trckr color got ", args[1], "for layer", args[0], "with path", path)
+ print(len(args),"args", args)
+ FaceForm.color = args[1]
+
+
+# default handler
+def OSChandler(path, tags, args, source):
+
+ oscaddress = ''.join(path.split("/"))
+ print()
+ print("trckr default OSC Handler :", path, "from Client :" + str(source[0]))
+
+
+#
+# Face Tracking
+#
+
+# get absolute face position points
+def getPART(pose_points):
+
+ dots = []
+ for dot in pose_points:
+
+ dots.append((TrckrPts[dot][0], TrckrPts[dot][1],0))
+
+ return dots
+
+
+# Face keypoints
+def face():
+ pose_points = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]
+ return getPART(pose_points)
+
+def browL():
+ pose_points = [15,16,17,18]
+ return getPART(pose_points)
+
+def browR():
+ pose_points = [22,21,20,19]
+ return getPART(pose_points)
+
+def eyeR():
+ pose_points = [25,64,24,63,23,66,26,65,25]
+ return getPART(pose_points)
+
+def eyeL():
+ pose_points = [28,67,29,68,30,69,31,28]
+ return getPART(pose_points)
+
+def pupR():
+ pose_points = [27]
+ return getPART(pose_points)
+
+def pupL():
+ pose_points = [32]
+ return getPART(pose_points)
+
+
+def nose1():
+ pose_points = [62,41,33]
+ return getPART(pose_points)
+
+def nose2():
+ pose_points = [40,39,38,43,37,42,36,35,34]
+ return getPART(pose_points)
+
+def mouth():
+ pose_points = [50,49,48,47,46,45,44,55,54,53,52,51,50]
+ return getPART(pose_points)
+
+def mouthfull():
+ pose_points = [50,49,48,47,46,45,44,55,54,53,52,51,50,59,60,61,44,56,57,58,50]
+ return getPART(pose_points)
+
+
+
+
+def Proj(x,y,z,angleX,angleY,angleZ):
+
+ rad = angleX * math.pi / 180
+ cosa = math.cos(rad)
+ sina = math.sin(rad)
+ y2 = y
+ y = y2 * cosa - z * sina
+ z = y2 * sina + z * cosa
+
+ rad = angleY * math.pi / 180
+ cosa = math.cos(rad)
+ sina = math.sin(rad)
+ z2 = z
+ z = z2 * cosa - x * sina
+ x = z2 * sina + x * cosa
+
+ rad = angleZ * math.pi / 180
+ cosa = math.cos(rad)
+ sina = math.sin(rad)
+ x2 = x
+ x = x2 * cosa - y * sina
+ y = x2 * sina + y * cosa
+
+
+ """ Transforms this 3D point to 2D using a perspective projection. """
+ factor = fov / (viewer_distance + z)
+ x = x * factor + centerX
+ y = - y * factor + centerY
+ return (x,y)
+
+
+#
+# Main
+#
+
+def Run():
+
+
+ Facepts = []
+ counter =0
+ lj.WebStatus("trckr")
+ lj.SendLJ("/trckr/start 1")
+
+ # OSC Server callbacks
+ print("Starting OSC server at",myIP," port",OSCinPort,"...")
+ oscserver.addMsgHandler( "/trckr/ljscene", OSCljscene)
+ oscserver.addMsgHandler( "/trckr/layer", OSClayer)
+ oscserver.addMsgHandler( "/trckr/frame", OSCtrckr)
+ oscserver.addMsgHandler( "/trckr/color", OSColor)
+
+
+ # Add OSC generic layerugins commands : 'default", /ping, /quit, /pluginame/obj, /pluginame/var, /pluginame/adddest, /pluginame/deldest
+ lj.addOSCdefaults(oscserver)
+ oscserver.addMsgHandler( "default", OSChandler )
+ try:
+
+ while lj.oscrun:
+
+ lj.OSCframe()
+
+ #print("browL", browL(), "browR", browR(), "nose1", nose1(), "mouth", mouth())
+ lj.rPolyLineOneColor(browL(), c = FaceForm.color, layer = FaceForm.layer, closed = FaceForm.closed, xpos = -300, ypos = -300, resize = 3.6, rotx = 0, roty = 0, rotz = 0)
+ lj.rPolyLineOneColor(eyeL(), c = FaceForm.color, layer = FaceForm.layer, closed = FaceForm.closed, xpos = -300, ypos = -300, resize = 3.6, rotx = 0, roty = 0, rotz = 0)
+ lj.rPolyLineOneColor(browR(), c = FaceForm.color, layer = FaceForm.layer, closed = FaceForm.closed, xpos = -300, ypos = -300, resize = 3.6, rotx = 0, roty = 0, rotz = 0)
+ lj.rPolyLineOneColor(eyeR(), c = FaceForm.color, layer = FaceForm.layer, closed = FaceForm.closed, xpos = -300, ypos = -300, resize = 3.6, rotx = 0, roty = 0, rotz = 0)
+ lj.rPolyLineOneColor(pupL(), c = FaceForm.color, layer = FaceForm.layer, closed = FaceForm.closed, xpos = -300, ypos = -300, resize = 3.6, rotx = 0, roty = 0, rotz = 0)
+ lj.rPolyLineOneColor(pupR(), c = FaceForm.color, layer = FaceForm.layer, closed = FaceForm.closed, xpos = -300, ypos = -300, resize = 3.6, rotx = 0, roty = 0, rotz = 0)
+ lj.rPolyLineOneColor(nose1(), c = FaceForm.color, layer = FaceForm.layer, closed = FaceForm.closed, xpos = -300, ypos = -300, resize = 3.6, rotx = 0, roty = 0, rotz = 0)
+ lj.rPolyLineOneColor(nose2(), c = FaceForm.color, layer = FaceForm.layer, closed = FaceForm.closed, xpos = -300, ypos = -300, resize = 3.6, rotx = 0, roty = 0, rotz = 0)
+ lj.rPolyLineOneColor(mouthfull(), c = FaceForm.color, layer = FaceForm.layer, closed = FaceForm.closed, xpos = -300, ypos = -300, resize = 3.6, rotx = 0, roty = 0, rotz = 0)
+
+ lj.DrawDests()
+
+ time.sleep(0.005)
+
+ counter += 1
+ if counter > 360:
+ counter = 0
+
+ except KeyboardInterrupt:
+ pass
+
+ # Gently stop on CTRL C
+
+ finally:
+
+ lj.ClosePlugin()
+
+
+Run()
+'''
+//
+// a template for receiving face tracking osc messages from
+// Kyle McDonald's trckr https://github.com/kylemcdonald/ofxFaceTracker
+//
+// 2012 Dan Wilcox danomatika.com
+// for the IACD Spring 2012 class at the CMU School of Art
+//
+// adapted from from Greg Borenstein's 2011 example
+// http://www.gregborenstein.com/
+// https://gist.github.com/1603230
+//
+
+//Xavier Apostol
+//Generative Faces: Plotter Project Concept
+
+import oscP5.*;
+OscP5 oscP5;
+
+// num faces found
+int found;
+
+// pose
+float poseScale;
+PVector posePosition = new PVector();
+PVector poseOrientation = new PVector();
+
+// gesture
+float mouthHeight;
+float mouthWidth;
+float eyeLeft;
+float eyeRight;
+float eyebrowLeft;
+float eyebrowRight;
+float jaw;
+float nostrils;
+
+float sz = 1;
+float spacing = 100;
+float genSz = spacing/4;
+float fcOff = genSz/2;
+
+//Initialization of Colors
+float R = random(255);
+float G = random(255);
+float B = random(255);
+
+//Initialization of Head
+float rotInt = 15;
+float hdX = cos(sz) + random(genSz, 3*genSz);
+float hdY = sin(sz) + random(genSz, 3*genSz);
+float rotAngle = random(-rotInt,rotInt);
+
+//Initialization of Eyes
+float lEyeX1 = sin(sz*0) + random(genSz);
+float lEyeY1 = cos(sz*0) + random(genSz);
+float rEyeX1 = sin(sz*0) + random(genSz);
+float rEyeY1 = cos(sz*0) + random(genSz);
+float lEyeX2 = sin(sz*1) + random(genSz);
+float lEyeY2 = cos(sz*1) + random(genSz);
+float rEyeX2 = sin(sz*1) + random(genSz);
+float rEyeY2 = cos(sz*1) + random(genSz);
+float ranREye = random(7, 9);
+float ranLEye = random(7, 9);
+
+//Initialization of Mouth
+float mthX = cos(sz) + random(genSz);
+float mthY = sin(sz) + random(genSz);
+float ranM = random(-0.1, 1.5);
+
+//Initialization of Spine
+float hdOffset = hdY/1.5;
+float spineSz = random(genSz/2);
+float spXOff1 = random(-8, 8);
+float spYOff1 = hdOffset + random(genSz/3);
+float spXOff2 = random(-8, 8)+spXOff1;
+float spYOff2 = random(genSz/3)+spYOff1;
+float spXOff3 = random(-8, 8)+spXOff2;
+float spYOff3 = random(genSz/3)+spYOff2;
+float spXOff4 = random(-8, 8)+spXOff3;
+float spYOff4 = random(genSz/3)+spYOff3;
+float spXOff5 = random(-8, 8)+spXOff4;
+float spYOff5 = random(genSz/3)+spYOff4;
+
+void setup() {
+ size(800, 600, OPENGL);
+ frameRate(30);
+
+ oscP5 = new OscP5(this, 8338);
+ oscP5.plug(this, "found", "/found");
+ oscP5.plug(this, "poseScale", "/pose/scale");
+ oscP5.plug(this, "posePosition", "/pose/position");
+ oscP5.plug(this, "poseOrientation", "/pose/orientation");
+ oscP5.plug(this, "mouthWidthReceived", "/gesture/mouth/width");
+ oscP5.plug(this, "mouthHeightReceived", "/gesture/mouth/height");
+ oscP5.plug(this, "eyeLeftReceived", "/gesture/eye/left");
+ oscP5.plug(this, "eyeRightReceived", "/gesture/eye/right");
+ oscP5.plug(this, "eyebrowLeftReceived", "/gesture/eyebrow/left");
+ oscP5.plug(this, "eyebrowRightReceived", "/gesture/eyebrow/right");
+ oscP5.plug(this, "jawReceived", "/gesture/jaw");
+ oscP5.plug(this, "nostrilsReceived", "/gesture/nostrils");
+}
+
+void keyPressed() {
+ if (key == CODED) {
+ if (keyCode == UP) {
+ //Create an entirely new character.
+
+ //For Eyes
+ lEyeX1 = sin(sz*0) + random(genSz);
+ lEyeY1 = cos(sz*0) + random(genSz);
+ rEyeX1 = sin(sz*0) + random(genSz);
+ rEyeY1 = cos(sz*0) + random(genSz);
+ lEyeX2 = sin(sz*1) + random(genSz);
+ lEyeY2 = cos(sz*1) + random(genSz);
+ rEyeX2 = sin(sz*1) + random(genSz);
+ rEyeY2 = cos(sz*1) + random(genSz);
+ ranREye = random(7, 9);
+ ranLEye = random(7, 9);
+
+ //For Mouth
+ mthX = cos(sz) + random(genSz);
+ mthY = sin(sz) + random(genSz);
+ ranM = random(-0.1, 1.5);
+
+ //For Spine
+ spineSz = random(genSz/2);
+ spXOff1 = random(-8, 8);
+ spYOff1 = hdOffset + random(genSz/3);
+ spXOff2 = random(-8, 8) + spXOff1;
+ spYOff2 = random(genSz/3) + spYOff1;
+ spXOff3 = random(-8, 8) + spXOff2;
+ spYOff3 = random(genSz/3) + spYOff2;
+ spXOff4 = random(-8, 8) + spXOff3;
+ spYOff4 = random(genSz/3) + spYOff3;
+ spXOff5 = random(-8, 8) + spXOff4;
+ spYOff5 = random(genSz/3) + spYOff4;
+
+ //For Head
+ hdX = cos(sz) + random(genSz, 3*genSz);
+ hdY = sin(sz) + random(genSz, 3*genSz);
+ rotAngle = random(-rotInt,rotInt);
+
+ //For Colors
+ R = random(255);
+ G = random(255);
+ B = random(255);
+ draw();
+ }
+ }
+}
+
+void draw() {
+ background(0);
+ strokeWeight(1);
+ noFill();
+
+ if(found != 0) {
+ pushMatrix();
+ translate(posePosition.x, posePosition.y);
+ //Scales head and allows for rotations
+ scale(poseScale*2);
+ rotateY(0 - poseOrientation.y);
+ rotateX(0 - poseOrientation.x);
+ rotateZ(poseOrientation.z);
+ rotate(radians(rotAngle));
+ ellipse(0,0, hdX,hdY);
+ popMatrix();
+
+ //FACE
+ translate(posePosition.x, posePosition.y);
+ scale(poseScale);
+ noFill();
+
+ //Eyes
+ float eyeFac = 1;
+ float eyeBL = eyebrowLeft * 2;
+ float eyeBR = eyebrowRight * 2;
+ ellipse(-20,eyeLeft * -ranLEye, lEyeX1*eyeFac + eyeBL,lEyeY1*eyeFac + eyeBL);
+ ellipse(20,eyeRight * -ranREye, rEyeX1*eyeFac + eyeBR,rEyeY1*eyeFac + eyeBR);
+ ellipse(-20,eyeLeft * -ranLEye, lEyeX2*eyeFac + eyeBL,lEyeY2*eyeFac + eyeBL);
+ ellipse(20,eyeRight * -ranREye, rEyeX2*eyeFac + eyeBR,rEyeY2*eyeFac + eyeBR);
+
+ //Mouth
+ ellipse(0, 20*ranM, mouthWidth* mthX/3, mouthHeight * mthY);
+
+ //BODY/BUBBLES
+ stroke(R,G,B);
+ ellipse(spXOff1,spYOff1, spineSz,spineSz);
+ ellipse(spXOff2,spYOff2, spineSz,spineSz);
+ ellipse(spXOff3,spYOff3, spineSz,spineSz);
+ ellipse(spXOff4,spYOff4, spineSz,spineSz);
+ ellipse(spXOff5,spYOff5, spineSz,spineSz);
+
+ }
+}
+
+// OSC CALLBACK FUNCTIONS
+
+public void found(int i) {
+ println("found: " + i);
+ found = i;
+}
+
+public void poseScale(float s) {
+ println("scale: " + s);
+ poseScale = s;
+}
+
+public void posePosition(float x, float y) {
+ println("pose position\tX: " + x + " Y: " + y );
+ posePosition.set(x, y, 0);
+}
+
+public void poseOrientation(float x, float y, float z) {
+ println("pose orientation\tX: " + x + " Y: " + y + " Z: " + z);
+ poseOrientation.set(x, y, z);
+}
+
+public void mouthWidthReceived(float w) {
+ println("mouth Width: " + w);
+ mouthWidth = w;
+}
+
+public void mouthHeightReceived(float h) {
+ println("mouth height: " + h);
+ mouthHeight = h;
+}
+
+public void eyeLeftReceived(float f) {
+ println("eye left: " + f);
+ eyeLeft = f;
+}
+
+public void eyeRightReceived(float f) {
+ println("eye right: " + f);
+ eyeRight = f;
+}
+
+public void eyebrowLeftReceived(float f) {
+ println("eyebrow left: " + f);
+ eyebrowLeft = f;
+}
+
+public void eyebrowRightReceived(float f) {
+ println("eyebrow right: " + f);
+ eyebrowRight = f;
+}
+
+public void jawReceived(float f) {
+ println("jaw: " + f);
+ jaw = f;
+}
+
+public void nostrilsReceived(float f) {
+ println("nostrils: " + f);
+ nostrils = f;
+}
+
+// all other OSC messages end up here
+void oscEvent(OscMessage m) {
+ if(m.isPlugged() == false) {
+ println("UNPLUGGED: " + m);
+ }
+}
+'''
diff --git a/server/install.sh b/server/install.sh
index 76e317b..3f2e34b 100755
--- a/server/install.sh
+++ b/server/install.sh
@@ -25,6 +25,7 @@ sudo apt install libjack-dev
pip3 install python-rtmidi
pip3 install mido
git clone https://github.com/ptone/pyosc --depth 1 /tmp/pyosc && cd /tmp/pyosc && sudo ./setup.py install
+pip3 install tk
cd ../
python3 configure.py
# todo : ask for computer ip and run updateUI.py
diff --git a/server/install.sh.darwin b/server/install.sh.darwin
index e0e3165..63edb84 100644
--- a/server/install.sh.darwin
+++ b/server/install.sh.darwin
@@ -21,7 +21,7 @@ brew install libasound2-dev
brew install libjack-dev
pip3 install python-rtmidi
pip3 install mido
-
+#pip3 install tk
cd ../
python3 configure.py
#sudo cp syncthing.conf to /etc/supervisor/conf.d/
diff --git a/updateUI.py b/updateUI.py
index e2f2a90..ee985dd 100644
--- a/updateUI.py
+++ b/updateUI.py
@@ -60,6 +60,7 @@ def www(wwwip):
print("Updating www files to use", wwwIP)
Updatepage(ljpath+"/www/LJ.js")
Updatepage(ljpath+"/www/trckr/trckrcam1.html")
+ Updatepage(ljpath+"/www/trckr/trckr.html")
Updatepage(ljpath+"/www/simu.html")
Updatepage(ljpath+"/www/align.html")
Updatepage(ljpath+"/www/auralls.html")
diff --git a/www/README.md b/www/README.md
index f3ed726..22d19eb 100644
--- a/www/README.md
+++ b/www/README.md
@@ -1,5 +1,21 @@
-clmtrackr
-======
+= Web Interface
+
+You can load index.html file from your browser or have a webserver of your choice pointing to this directory.
+
+Webserver is mandatory if you want :
+
+- to remotely control LJ : imagine LJ can be installed in a dedicated computer/container with no easy access.
+- to use the face tracking, say from a smartphone. That's Lasercam (a clmtrackr plugin).
+
+== Simu
+
+A laser simulator. Choose lasernumber and it will display redis points for current scene/lasernumber
+
+
+
+
+== clmtrackr
+
[![npm version](https://img.shields.io/npm/v/clmtrackr.svg)](https://www.npmjs.com/package/clmtrackr)
diff --git a/www/index.html b/www/index.html
index 3101372..3196027 100644
--- a/www/index.html
+++ b/www/index.html
@@ -300,16 +300,6 @@
console.log("/laser "+res[1])
newlaser(res[1])
break;
-
- case "/lack/":
- console.log("/lack "+res[1])
- document.getElementById(res[0].slice(1)).value = res[1];
- break;
-
- case "/lstt/":
- console.log("/lstt "+res[1])
- document.getElementById(res[0].slice(1)).value = res[1];
- break;
default:
diff --git a/www/simu.html b/www/simu.html
index e2d0c5c..95ae133 100644
--- a/www/simu.html
+++ b/www/simu.html
@@ -287,17 +287,6 @@
case "/plpoi":
//console.log("plpoint");
break;
-
- case "/lack/":
- console.log("/lack "+res[1])
- document.getElementById(res[0].slice(1)).value = res[1];
- break;
-
- case "/lstt/":
- console.log("/lstt "+res[1])
- document.getElementById(res[0].slice(1)).value = res[1];
- break;
-
default:
//console.log("test "+res[0].slice(1)+" "+res[1]);
document.getElementById(res[0].slice(1)).value = res[1];
diff --git a/www/trckr.png b/www/trckr.png
deleted file mode 100644
index a0a1443..0000000
Binary files a/www/trckr.png and /dev/null differ
diff --git a/www/trckr/trckr.html b/www/trckr/trckr.html
new file mode 100644
index 0000000..e630dcc
--- /dev/null
+++ b/www/trckr/trckr.html
@@ -0,0 +1,679 @@
+
+
+
+ LASERCam 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /TL RGY 1
+
+
+
+
+
+
+
+ LASERcam 1 : Allow to use your webcam + start
+
+
+ /team/laser
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Colors
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
To try it out:
+
+ - Allow the page to use your webcamera
+ - Make sure that your face is clearly visible in the video, and click start
+ - See the model fitted to your face
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+