From 9ecee93b430525a4dc7c22ebbfb81357fa757bff Mon Sep 17 00:00:00 2001 From: nrhck Date: Tue, 26 Feb 2019 11:10:57 +0100 Subject: [PATCH] UI upgrades --- LJ.conf | 24 +- clients/lj.py | 9 +- clients/planetarium/hipnames | 96 ++++++ clients/planetarium/lj3.py | 15 +- clients/planetarium/main.py | 112 ++++--- commands.py | 243 +++++++------- gstt.py | 10 +- main.py | 157 ++++++--- webui/LJ.js | 338 +++++++++++++------- webui/LJgrid.css | 33 +- webui/index.html | 599 +++++++++++++++++++++++++++++------ webui/knobs/align.png | Bin 0 -> 4386 bytes webui/knobs/blackout.png | Bin 4555 -> 5887 bytes webui/knobs/faster.png | Bin 0 -> 3906 bytes webui/knobs/grid.png | Bin 1720 -> 3192 bytes webui/knobs/live.png | Bin 0 -> 4230 bytes webui/knobs/ljaylogo.png | Bin 8168 -> 7458 bytes webui/knobs/mmo3.png | Bin 0 -> 4667 bytes webui/knobs/mouse.png | Bin 4866 -> 5124 bytes webui/knobs/nozoid.png | Bin 0 -> 4581 bytes webui/knobs/nozoids.png | Bin 0 -> 4802 bytes webui/knobs/ocs2.png | Bin 0 -> 4499 bytes webui/knobs/planet.png | Bin 0 -> 4385 bytes webui/knobs/power.png | Bin 0 -> 4613 bytes webui/knobs/run.png | Bin 0 -> 4178 bytes webui/knobs/simu.png | Bin 0 -> 4288 bytes webui/knobs/slower.png | Bin 0 -> 3911 bytes 27 files changed, 1168 insertions(+), 468 deletions(-) create mode 100644 clients/planetarium/hipnames mode change 100644 => 100755 main.py create mode 100644 webui/knobs/align.png create mode 100644 webui/knobs/faster.png create mode 100644 webui/knobs/live.png create mode 100644 webui/knobs/mmo3.png create mode 100644 webui/knobs/nozoid.png create mode 100644 webui/knobs/nozoids.png create mode 100644 webui/knobs/ocs2.png create mode 100644 webui/knobs/planet.png create mode 100644 webui/knobs/power.png create mode 100644 webui/knobs/run.png create mode 100644 webui/knobs/simu.png create mode 100644 webui/knobs/slower.png diff --git a/LJ.conf b/LJ.conf index a842d13..b7e6daa 100644 --- a/LJ.conf +++ b/LJ.conf @@ -1,5 +1,5 @@ [General] -lasernumber = 4 +lasernumber = 1 debug = 0 ljayserverip = 127.0.0.1 nozoscip = 127.0.0.1 @@ -26,7 +26,7 @@ warpdest = [[-1500., 1500.], [laser1] color = -1 -ip = 192.168.1.5 +ip = 192.168.1.3 kpps = 25000 centerx = 506 centery = 413 @@ -39,9 +39,9 @@ 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.]] [laser2] color = -1 @@ -58,15 +58,15 @@ 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 ip = 192.168.1.4 kpps = 25000 -centerx = 0 +centerx = -12 centery = 0 zoomx = 38.0 zoomy = 26.0 @@ -77,7 +77,7 @@ 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.]] diff --git a/clients/lj.py b/clients/lj.py index 37c8900..d8505d4 100644 --- a/clients/lj.py +++ b/clients/lj.py @@ -20,7 +20,7 @@ Sam Neurohack import math import redis -from OSC import OSCServer, OSCClient, OSCMessage +#from OSC import OSCServer, OSCClient, OSCMessage redisIP = '127.0.0.1' r = redis.StrictRedis(host=redisIP, port=6379, db=0) @@ -39,6 +39,7 @@ oscmsg = OSCMessage() osclientlj.connect((redisIP, 8002)) ''' +''' def Send(oscaddress,oscargs=''): oscmsg = OSCMessage() @@ -53,7 +54,7 @@ def Send(oscaddress,oscargs=''): print ('Connection to LJ refused : died ?') pass #time.sleep(0.001 - +''' def WebStatus(message): Send("/status",message) @@ -249,7 +250,7 @@ def rPolyLineOneColor(xy_list, c, PL , closed, xpos = 0, ypos =0, resize =0.7, r def LinesPL(PL): - print "Stupido !! your code is to old : use DrawPL() instead of LinesPL()" + print ("Stupido !! your code is to old : use DrawPL() instead of LinesPL()") DrawPL(PL) def DrawPL(PL): @@ -311,4 +312,4 @@ def Text(message,c, PL, xpos, ypos, resize, rotx, roty, rotz): - \ No newline at end of file + diff --git a/clients/planetarium/hipnames b/clients/planetarium/hipnames new file mode 100644 index 0000000..5b56e86 --- /dev/null +++ b/clients/planetarium/hipnames @@ -0,0 +1,96 @@ +Acamar, 13847 +Groombridge 1830, 57939 +Achernar, 7588 +Hadar, 68702 +Acrux, 60718 +Hamal, 9884 +Adhara, 33579 +Izar, 72105 +Agena, 68702 +Kapteyn's star, 24186 +Albireo, 95947 +Kaus Australis, 90185 +Alcor, 65477 +Kocab, 72607 +Alcyone, 17702 +Kruger,60, 110893 +Aldebaran, 21421 +Luyten's star, 36208 +Alderamin, 105199 +Markab, 113963 +Algenib, 1067 +Megrez, 59774 +Algieba, 50583 +Menkar, 14135 +Algol, 14576 +Merak, 53910 +Alhena, 31681 +Mintaka, 25930 +Alioth, 62956 +Mira, 10826 +Alkaid, 67301 +Mirach, 5447 +Almaak, 9640 +Mirphak, 15863 +Alnair, 109268 +Mizar, 65378 +Alnath, 25428 +Nihal, 25606 +Alnilam, 26311 +Nunki, 92855 +Alnitak, 26727 +Phad, 58001 +Alphard, 46390 +Pleione, 17851 +Alphekka, 76267 +Polaris, 11767 +Alpheratz, 677 +Pollux, 37826 +Alshain, 98036 +Procyon, 37279 +Altair, 97649 +Proxima, 70890 +Ankaa, 2081 +Rasalgethi, 84345 +Antares, 80763 +Rasalhague, 86032 +Arcturus, 69673 +Red,Rectangle, 30089 +Arneb, 25985, +Regulus, 49669 +Babcock's star, 112247 +Rigel, 24436 +Barnard's,star, 87937 +Rigil Kent, 71683 +Bellatrix, 25336 +Sadalmelik, 109074 +Betelgeuse, 27989 +Saiph, 27366 +Campbell's star, 96295 +Scheat, 113881 +Canopus, 30438 +Shaula, 85927 +Capella, 24608 +Shedir, 3179 +Caph, 746 +Sheliak, 92420 +Castor, 36850 +Sirius, 32349 +Cor Caroli, 63125 +Spica, 65474 +Cyg X-1, 98298 +Tarazed, 97278 +Deneb, 102098 +Thuban, 68756 +Denebola, 57632 +Unukalhai, 77070 +Diphda, 3419 +Van,Maanen 2, 3829 +Dubhe, 54061 +Vega, 91262 +Enif, 107315 +Vindemiatrix, 63608 +Etamin, 87833 +Zaurak, 18543 +Fomalhaut, 113368 +3C 273, 60936 \ No newline at end of file diff --git a/clients/planetarium/lj3.py b/clients/planetarium/lj3.py index 7f47e5f..6791c54 100644 --- a/clients/planetarium/lj3.py +++ b/clients/planetarium/lj3.py @@ -46,6 +46,7 @@ def OSCstart(): #osc_udp_client(redisIP, 8002, "LJ 8002") def OSCframe(): + #print("OSCprocess") osc_process() # Properly close the system. Todo @@ -55,14 +56,11 @@ def OSCstop(): def Send(oscaddress,oscargs=''): - oscmsg = OSCMessage() - oscmsg.setAddress(oscaddress) - oscmsg.append(oscargs) - - #print ("sending to bhorosc : ",oscmsg) try: msg = oscbuildparse.OSCMessage(oscaddress, None, [oscargs]) osc_send(msg, "LJ 8002") + OSCframe() + except: print ('Connection to LJ refused : died ?') pass @@ -82,11 +80,6 @@ osc_udp_server("0.0.0.0", 3724, "anotherserver") - - - - - ASCII_GRAPHICS = [ # caracteres corrects @@ -341,4 +334,4 @@ def Text(message,c, PL, xpos, ypos, resize, rotx, roty, rotz): - \ No newline at end of file + diff --git a/clients/planetarium/main.py b/clients/planetarium/main.py index c6bfae6..ab3f946 100755 --- a/clients/planetarium/main.py +++ b/clients/planetarium/main.py @@ -1,3 +1,4 @@ +#!/usr/bin/python3 # coding=UTF-8 ''' @@ -5,7 +6,7 @@ Multi Laser planetarium in python3 for LJ. v0.01 Sam Neurohack -Accuracy tested against apparent data and starchart at https://www.calsky.com/cs.cgi?cha=7&sec=3&sub=2 +Accuracy could be tested against apparent data and starchart at https://www.calsky.com/cs.cgi?cha=7&sec=3&sub=2 Remember to set the same observer position and time. See Readme for more information @@ -13,8 +14,10 @@ See Readme for more information Todo: +- use debug mode and check altaz calculated values against online sites. - Validate aa2radec() with online calculator. Rewrite it to remove need for Astropy. - Findout how to use OSC in python 3. +- - Code WebUI page. - UpdateStars() in each laser sky. Get magnitude. See UpdateSolar for example. - All Draw operations should also check visibility in the given laser altitude range. @@ -39,7 +42,11 @@ from skyfield.data import hipparcos from osc4py3.as_eventloop import * from osc4py3 import oscbuildparse -from osc4py3 import oscmethod as osm +#from osc4py3 import oscmethod as osm +from osc4py3.oscmethod import * + + + import json @@ -65,8 +72,8 @@ print ("Arguments parsing if needed...") argsparser = argparse.ArgumentParser(description="Planetarium 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("-c","--client",help="LJ client 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("-d","--debug",help="Verbosity level (0 by default)",type=int) +argsparser.add_argument("-L","--Lasers",help="Number of lasers connected (1 by default).",type=int) +argsparser.add_argument("-v","--verbose",help="Verbosity level (0 by default)",type=int) argsparser.add_argument("-i","--input",help="inputs OSC Port (8005 by default)",type=int) #argsparser.add_argument("-n","--name",help="City Name of the observer",type=str) #argsparser.add_argument("-r","--redisIP",help="Country code of the observer ",type=str) @@ -79,13 +86,13 @@ if args.client: else: ljclient = 0 -if args.laser: - lasernumber = args.laser +if args.Lasers: + lasernumber = args.Lasers else: - lasernumber = 0 + lasernumber = 1 -if args.debug: - debug = args.laser +if args.verbose: + debug = args.verbose else: debug = 0 @@ -322,7 +329,7 @@ def DrawSolar(laser): # Stars # -StarsObjectShape = [(-50,30), (-30,-30), (30,-30), (10,30), (-50,30)] +StarsObjectShape = [(-10,10), (-10,-10), (10,-10), (10,10), (-10,10)] def LoadHipparcos(ts): global hipdata @@ -543,6 +550,26 @@ def InitObserver(SkyCity, SkyCountryCode, time,ts): RadecSkies(LaserSkies, AstroSkyTime) +# Change Observer position by adding deltas (Gpslong, gpslat, elevation in decimal degree/meters) +def UpdateObserver(gpslatdelta, gpslongdelta, elevationdelta,time,ts): + global LaserSkies, Skylat, Skylong, SkyfieldTime, AstrObserver, SkyObserver + + Skylat += gpslatdelta + Skylong += gpslongdelta + Skyelevation += elevationdelta + AstroSkyTime = time + print ("AstroPy time", AstroSkyTime) + SkyfieldTime = ts.from_astropy(AstroSkyTime) + print("SkyfieldTime from AstropyUTC",SkyfieldTime.utc_iso()) + + AstrObserver = EarthLocation(lat = Skylat * u.deg, lon = Skylong * u.deg, height = Skyelevation * u.m,) + SkyObserver = earth + Topos(Skylat, Skylong) + RadecSkies(LaserSkies, AstroSkyTime) + + UpdateSolar() + UpdateStars() + UpdateAnything() + def NewTime(timeshift): SkyfieldTime += timeshift @@ -555,60 +582,60 @@ def NewTime(timeshift): UpdateAnything() -#def handlerfunction(s, x, y): - # Will receive message data unpacked in s, x, y -# pass - -def OSChandler(address, s, x, y): +def OSCstart(value): # Will receive message address, and message data flattened in s, x, y - print("Planetarium OSC server got address", address,"s",s,"x",x,"y",y) - pass - + print("Planetarium OSC server got /planet/start with value", value) + +def OSCUI(value): + # Will receive message address, and message data flattened in s, x, y + print("Planetarium OSC server got /planet/planetUI with value", value) def WebStatus(message): lj3.Send("/status",message) - # # Main part # try: - lj3.OSCstart() - # Make server channels to receive packets. - #osc_udp_server("127.0.0.1", 3721, "localhost") - osc_udp_server("0.0.0.0", OSCinPort, "InPort") - - # Associate Python functions with message address patterns, using default - # argument scheme OSCARG_DATAUNPACK. - #osc_method("/planet/*", handlerfunction) - # Too, but request the message address pattern before in argscheme - osc_method("/planet/*", OSChandler, argscheme=osm.OSCARG_ADDRESS + osm.OSCARG_DATAUNPACK) + WebStatus("Planetarium") + # OSC Server callbacks + print("Starting OSC at 127.0.0.1 port",OSCinPort,"...") + osc_startup() + osc_udp_server("127.0.0.1", OSCinPort, "InPort") + osc_method("/planet/start*", OSCstart) + osc_method("/planet/planetUI*", OSCUI) + + WebStatus("Load Cities.") ts = load.timescale() LoadCities() + SkyCity = 'Paris' SkyCountryCode = 'FR' + WebStatus(SkyCity) + + WebStatus("Solar System..") LoadSolar() + + WebStatus("Observer..") InitObserver(SkyCity, SkyCountryCode, Time.now(),ts) - + WebStatus("Load Stars..") LoadHipparcos(ts) - - StarSelect() - #print() - #print ("Updating Sky Objects for current observer...") - #print() + WebStatus("Updating...") print("Updating solar system (de421) objects position for observer at", Skylat, Skylong, "time", SkyfieldTime.utc_iso()) UpdateSolar() - #print ("Done.") - #print() + print("Updating stars for observer at", Skylat, Skylong, "time", SkyfieldTime.utc_iso()) UpdateStars(ts) + + WebStatus("Ready") + lj3.Send("/planet/start",1) print ("Done.") # UpdateStars() Todo @@ -617,19 +644,28 @@ try: DisplaySolar = False DisplayOrientation = True DisplayAnything = False + print("Start displaying on",lasernumber,"lasers") while 1: for laser in range(lasernumber): + #print ("Drawing laser",lasernumber) if DisplayOrientation: DrawOrientation(laser) + lj3.OSCframe() + if DisplaySolar: DrawSolar(laser) + lj3.OSCframe() + if DisplayStars: DrawStars(laser) + lj3.OSCframe() + if DisplayAnything: DrawAnything() + lj3.OSCframe() lj3.DrawPL(laser) lj3.OSCframe() @@ -644,6 +680,8 @@ except KeyboardInterrupt: finally: + WebStatus("Planet Exit") + print("Stopping OSC...") lj3.OSCstop() print ("Fin du planetarium.") diff --git a/commands.py b/commands.py index fce97a2..ae489c0 100644 --- a/commands.py +++ b/commands.py @@ -73,7 +73,7 @@ Bob could use /pl/2/0 and /pl/2/1 and Lisa could use /pl/2/2 and /pl/2/3. """ - +from __future__ import absolute_import import types, time import gstt import homographyp @@ -159,144 +159,153 @@ def Mouse(x1,y1,x2,y2): def handler(oscpath, args): print "" - print "Handler" + print "OSC handler in commands.py got oscpath[1] :",oscpath[1], "with args :",args - if oscpath[1] == "client" or oscpath[1] =="noteon" or oscpath[1]=="mouse": + # 2 incoming cases : generic or specific for a given lasernumber + # Need better programming + if oscpath[1] == "client" or oscpath[1] =="noteon" or oscpath[1]=="mouse" or oscpath[1]=="emergency" or oscpath[1]=="simu" or oscpath[1]=="status" or oscpath[1]=="run" or oscpath[1]=="nozoid" or oscpath[1]=="planet" or oscpath[1]=="live" or oscpath[1]=="planet" : + if oscpath[1] == "client": LasClientChange(int(args[0])) + elif oscpath[1] == "noteon": NoteOn(int(args[0])) + elif oscpath[1] == "mouse": Mouse(int(args[0]),int(args[1]),int(args[2]),int(args[3])) + + # /emergency value (0 or 1) + if oscpath[1] == "emergency": + + if args[0] == "1": + print "EMERGENCY MODE" + for laser in range(gstt.lasernumber): + print "Black requested for laser ", laser + BlackOn(laser) + else: + for laser in range(gstt.lasernumber): + print "Back to normal for laser ", laser + UserOn(laser) + else: pathlength = len(oscpath) + if pathlength == 3: laser = int(oscpath[2]) else: laser = int(oscpath[3]) - - print "args[0] :",args[0]," ", type(args[0]) - # /grid/lasernumber value (0 or 1) - if oscpath[1] == "grid": - - if args[0] == "1": - print "Grid requested for laser ", laser - GridOn(laser) - else: - print "No grid for laser ", laser - UserOn(laser) - - - # /black/lasernumber value (0 or 1) - if oscpath[1] == "black": - - if args[0] == "1": - print "Black requested for laser ", laser - BlackOn(laser) - else: - print "No black for laser ", laser - UserOn(laser) - - - # /ip/lasernumber value - if oscpath[1] == "ip": - print "New IP for laser ", laser - gstt.lasersIPS[laser]= args[0] - 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", int(args[0]) - gstt.kpps[laser]= int(args[0]) - settings.Write() - - # /angle/lasernumber value - if oscpath[1] == "angle": - print "New Angle modification for laser ", oscpath[2], ":", float(args[0]) - gstt.finANGLE[laser] += float(args[0]) - NewEDH(laser) - "New angle", gstt.finANGLE[laser] + print "args[0] :",args[0]," ", type(args[0]) - # /intens/lasernumber value - if oscpath[1] == "intens": - print "New intensity requested for laser ", laser, ":", int(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]) + # /grid/lasernumber value (0 or 1) + if oscpath[1] == "grid": - - # /mouse/lasernumber value (0 or 1) - if oscpath[1] == "mouse": + if args[0] == "1": + print "Grid requested for laser ", laser + GridOn(laser) + else: + print "No grid for laser ", laser + UserOn(laser) + + + # /ip/lasernumber value + if oscpath[1] == "ip": + print "New IP for laser ", laser + gstt.lasersIPS[laser]= args[0] + settings.Write() - if args[0] == "1": - print "Mouse requested for laser ", oscpath[2] - gstt.Laser = oscpath[2] - else: - print "No mouse for laser ", oscpath[2] - - - # /swap/X/lasernumber value (0 or 1) - if oscpath[1] == "swap" and oscpath[2] == "X": - print "swapX was", gstt.swapX[laser] - if args[0] == "0": - print "swap X -1 for laser ", laser - gstt.swapX[laser]= -1 - NewEDH(laser) - - else: - print "swap X 1 for laser ", laser - gstt.swapX[laser]= 1 - NewEDH(laser) - - # /swap/Y/lasernumber value (0 or 1) - if oscpath[1] == "swap" and oscpath[2] == "Y": - - print "swapY was", gstt.swapX[laser] - if args[0] == "0": - print "swap Y -1 for laser ", laser - gstt.swapY[laser]= -1 - NewEDH(laser) - else: - print "swap Y 1 for laser ", laser - gstt.swapY[laser]= 1 - NewEDH(laser) - - # /loffset/X/lasernumber value - if oscpath[1] == "loffset" and oscpath[2] == "X": - print "offset/X laser", laser, "modified to", args[0] - gstt.centerX[laser] -= int(args[0]) - NewEDH(laser) + # /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", int(args[0]) + gstt.kpps[laser]= int(args[0]) + settings.Write() - # /loffset/Y/lasernumber value - if oscpath[1] == "loffset" and oscpath[2] == "Y": - print "offset/Y laser", laser, "modified to", args[0] - gstt.centerY[laser] -= int(args[0]) - NewEDH(laser) - - - # /scale/X/lasernumber value - if oscpath[1] == "scale" and oscpath[2] == "X": - if gstt.zoomX[laser] + int(args[0]) > 0: - gstt.zoomX[laser] += int(args[0]) - print "scale/X laser", laser , "modified to", gstt.zoomX[laser] + # /angle/lasernumber value + if oscpath[1] == "angle": + print "New Angle modification for laser ", oscpath[2], ":", float(args[0]) + gstt.finANGLE[laser] += float(args[0]) NewEDH(laser) - - # /scale/Y/lasernumber value - if oscpath[1] == "scale" and oscpath[2] == "Y": - if gstt.zoomY[laser] + int(args[0]) > 0: - gstt.zoomY[laser] += int(args[0]) - print "scale/Y laser", laser, "modified to", gstt.zoomY[laser] + "New angle", gstt.finANGLE[laser] + + # /intens/lasernumber value + if oscpath[1] == "intens": + print "New intensity requested for laser ", laser, ":", int(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": + + if args[0] == "1": + print "Mouse requested for laser ", oscpath[2] + gstt.Laser = oscpath[2] + else: + print "No mouse for laser ", oscpath[2] + + + # /swap/X/lasernumber value (0 or 1) + if oscpath[1] == "swap" and oscpath[2] == "X": + + print "swapX was", gstt.swapX[laser] + if args[0] == "0": + print "swap X -1 for laser ", laser + gstt.swapX[laser]= -1 + NewEDH(laser) + + else: + print "swap X 1 for laser ", laser + gstt.swapX[laser]= 1 + NewEDH(laser) + + # /swap/Y/lasernumber value (0 or 1) + if oscpath[1] == "swap" and oscpath[2] == "Y": + + print "swapY was", gstt.swapX[laser] + if args[0] == "0": + print "swap Y -1 for laser ", laser + gstt.swapY[laser]= -1 + NewEDH(laser) + else: + print "swap Y 1 for laser ", laser + gstt.swapY[laser]= 1 + NewEDH(laser) + + # /loffset/X/lasernumber value + if oscpath[1] == "loffset" and oscpath[2] == "X": + print "offset/X laser", laser, "modified to", args[0] + gstt.centerX[laser] -= int(args[0]) NewEDH(laser) + + # /loffset/Y/lasernumber value + if oscpath[1] == "loffset" and oscpath[2] == "Y": + print "offset/Y laser", laser, "modified to", args[0] + gstt.centerY[laser] -= int(args[0]) + NewEDH(laser) + + + # /scale/X/lasernumber value + if oscpath[1] == "scale" and oscpath[2] == "X": + if gstt.zoomX[laser] + int(args[0]) > 0: + gstt.zoomX[laser] += int(args[0]) + print "scale/X laser", laser , "modified to", gstt.zoomX[laser] + NewEDH(laser) + + # /scale/Y/lasernumber value + if oscpath[1] == "scale" and oscpath[2] == "Y": + if gstt.zoomY[laser] + int(args[0]) > 0: + gstt.zoomY[laser] += int(args[0]) + print "scale/Y laser", laser, "modified to", gstt.zoomY[laser] + NewEDH(laser) ''' For reference values of EDH modifier if assign to keyboard keys (was alignp) diff --git a/gstt.py b/gstt.py index 541b1c9..f8982d1 100644 --- a/gstt.py +++ b/gstt.py @@ -74,11 +74,13 @@ swapY = [1,1,1,-1] # For glitch art : change position and number of points added by tracer.py # shortline is for distance with next point, 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)] + +#stepslongline = [(0.25,1), (0.75, 1), (1.0, 1)] #stepshortline = [(1.0, 8)] -#stepslongline = [(0.25, 3), (0.75, 3), (1.0, 10)] -stepslongline = [(0.25,1), (0.75, 1), (1.0, 1)] -#stepshortline = [(1.0, 8)] -stepslongline = [(1.0, 1)] +#stepslongline = [(1.0, 1)] +#stepshortline = [(1.0, 1)] point = [0,0,0] diff --git a/main.py b/main.py old mode 100644 new mode 100755 index 33eba79..7885de2 --- a/main.py +++ b/main.py @@ -14,7 +14,7 @@ todo : ''' -from __future__ import absolute_import + import time import gstt import redis @@ -78,8 +78,8 @@ print "Laser client number :",gstt.LasClientNumber serverIP = gstt.LjayServerIP print "Redis IP :", serverIP -bhoroscIP = gstt.oscIPin -print "Bhorosc IP :", bhoroscIP +extoscIP = gstt.oscIPin +print "extosc IP :", extoscIP nozoscIP = gstt.nozoscip print "Nozosc IP :", nozoscIP @@ -94,15 +94,15 @@ print "Lasers requested :", gstt.LaserNumber # Websocket listening port wsPORT = 9001 -# With Bhorosc +# With extosc # OSC Server : accept OSC message on port 8002 #oscIPin = "192.168.1.10"s -bhoroscIPin = serverIP -bhoroscPORTin = 8002 +extoscIPin = serverIP +extoscPORTin = 8002 # OSC Client : to send OSC message to an IP port 8001 -bhoroscIPout = bhoroscIP -bhoroscPORTout = 8001 +extoscIPout = extoscIP +extoscPORTout = 8001 # With Nozoid @@ -110,9 +110,14 @@ bhoroscPORTout = 8001 NozoscIPout = nozoscIP NozoscPORTout = 8003 -#print bhoroscIPin -oscserver = OSCServer( (bhoroscIPin, bhoroscPORTin) ) +# With Planetarium +# OSC Client : to send OSC message to planetarium inport 8005 +planetIPout = nozoscIP +planetPORTout = 8005 + + +oscserver = OSCServer( (extoscIPin, extoscPORTin) ) oscserver.timeout = 0 OSCRunning = True @@ -122,64 +127,90 @@ def handle_timeout(self): oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver) -osclientbhorosc = OSCClient() +osclientext = OSCClient() oscmsg = OSCMessage() -osclientbhorosc.connect((bhoroscIPout, bhoroscPORTout)) +osclientext.connect((extoscIPout, extoscPORTout)) -# send UI string as OSC message to Bhorosc 8001 -# sendbhorosc(oscaddress, [arg1, arg2,...]) +# send UI string as OSC message to extosc 8001 +# sendextosc(oscaddress, [arg1, arg2,...]) -def sendbhorosc(oscaddress,oscargs=''): +def sendextosc(oscaddress,oscargs=''): oscmsg = OSCMessage() oscmsg.setAddress(oscaddress) oscmsg.append(oscargs) - #print ("sending to bhorosc : ",oscmsg) + #print ("sending to extosc : ",oscmsg) try: - osclientbhorosc.sendto(oscmsg, (bhoroscIPout, bhoroscPORTout)) + osclientext.sendto(oscmsg, (extoscIPout, extoscPORTout)) oscmsg.clearData() except: - print ('Connection to bhorosc refused : died ?') + print ('Connection to extosc IP', extoscIPout, 'port', extoscPORTout,'refused : died ?') sendWSall("/on 0") sendWSall("/status NoLJay") - pass + #time.sleep(0.001) # send UI string as OSC message to Nozosc 8003 # sendnozosc(oscaddress, [arg1, arg2,...]) +osclientnozoid = OSCClient() +osclientnozoid.connect((NozoscIPout, NozoscPORTout)) + def sendnozosc(oscaddress,oscargs=''): oscmsg = OSCMessage() oscmsg.setAddress(oscaddress) oscmsg.append(oscargs) - #print ("sending to nozosc : ",oscmsg) + print "Sending OSC to Nozosc server :", oscaddress,'with args', oscargs try: - osclientnozosc.sendto(oscmsg, (NozoscIPout, NozoscPORTout)) + osclientnozoid.sendto(oscmsg, (NozoscIPout, NozoscPORTout)) oscmsg.clearData() except: - print ('Connection to nozosc refused : died ?') + print 'Connection to nozosc IP', NozoscIPout,'port', NozoscPORTout,' refused : died ?' sendWSall("/on 0") sendWSall("/status No Nozosc ") - pass + #time.sleep(0.001) +# send UI string as OSC message to Planet 8005 +# sendplanet(oscaddress, [arg1, arg2,...]) + +osclientplanet = OSCClient() +osclientplanet.connect((planetIPout, planetPORTout)) + +def sendplanet(oscaddress,oscargs=''): + + oscmsg = OSCMessage() + oscmsg.setAddress(oscaddress) + oscmsg.append(oscargs) + + print "Sending OSC to Planet server :", oscaddress,'with args :', oscargs + try: + osclientplanet.sendto(oscmsg, (planetIPout, planetPORTout)) + oscmsg.clearData() + except: + print 'OSC send to planet IP', planetIPout, 'port', planetPORTout, "refused : died ?" + sendWSall("/planet/start 0") + sendWSall("/status No Planet") + + #time.sleep(0.001) # OSC default path handler : send incoming OSC message to UI via websocket 9001 def handler(path, tags, args, source): oscpath = path.split("/") print "" - print "OSC said : ", path, oscpath, args + print "OSC default handler in main said : path", path," oscpath ", oscpath," args", args #print "debug", gstt.debug - if gstt.debug >0: - print "" - print "default handler" - print "OSC said : ", path, oscpath, args + #if gstt.debug >0: + # print "default handler" + # print "OSC said path", path," oscpath ", oscpath," args", args + sendWSall(path + " " + str(args[0])) + commands.handler(oscpath,args) @@ -216,8 +247,8 @@ def osc_thread(): lack= r.get('/lack/'+str(laserid)) - if gstt.debug >0: - print "laserid", laserid,"lack",lack + if gstt.debug >1: + 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) @@ -280,27 +311,61 @@ def client_left(client, server): print("WS Client(%d) disconnected" % client['id']) -# Called when a WS client sends a message +# Called for each ws received message. 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)) + #if gstt.debug >0: + # print ("") + # print("WS Client(%d) said: %s" % (client['id'], message)) - print("WS Client(%d) said: %s" % (client['id'], message)) + print("") + oscpath = message.split(" ") - args[0] = str(oscpath[1]) - #print oscpath[0].split("/"),oscpath[1] - commands.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") + print "WS Client", client['id'], "said :", message, "splitted in an oscpath :", oscpath + + # If message included "planet" forward the message as OSC to planet IP port 8005 + if oscpath[0].find("planet") != -1: + if len(oscpath) == 1: + sendplanet(oscpath[0], oscargs='noargs') else: - sendbhorosc("/off") + sendplanet(oscpath[0], oscargs=oscpath[1]) + + # If message included "nozoid" forward the message as OSC to nozoid IP port 8003 + elif oscpath[0].find("nozoid") != -1: + if len(oscpath) == 1: + sendnozosc(oscpath[0], oscargs='noargs') + else: + sendnozosc(oscpath[0], oscargs=oscpath[1]) + + # If message included "ai" do something + elif oscpath[0].find("ai") != -1: + print "ai order ", oscpath + + # If message included "lissa" do something + elif oscpath[0].find("lissa") != -1: + print "lissa order ", oscpath + + # If message included "vj" do something + elif oscpath[0].find("vj") != -1: + print "VJ order ", oscpath + + elif len(oscpath) > 1: + args[0] = str(oscpath[1]) + #print oscpath[0].split("/"),oscpath[1] + + # current UI has no dedicated off button so /on 0 trigs /off to extosc + elif oscpath[0] == "/on": + if oscpath[1] == "1": + sendextosc("/on") + else: + sendextosc("/off") + + else: + args[0] = "noargs" + commands.handler(oscpath[0].split("/"),args) + # if needed a loop back : WS Client -> server -> WS Client #sendWSall("ws"+message) @@ -367,10 +432,10 @@ try: # Websocket startup server = WebsocketServer(wsPORT,host=serverIP) - # Launch OSC thread listening to Bhorosc + # Launch OSC thread listening to extosc print "" print "Launching OSC server..." - print "at", bhoroscIPin, "port",str(bhoroscPORTin) + print "at", extoscIPin, "port",str(extoscPORTin) print "Will update webUI dac status every second" oscserver.addMsgHandler( "/noteon", commands.NoteOn ) # Default OSC handler for all OSC incoming message diff --git a/webui/LJ.js b/webui/LJ.js index a86b44a..2769bba 100644 --- a/webui/LJ.js +++ b/webui/LJ.js @@ -1,23 +1,25 @@ // -// LJ.js v0.7.0 +// LJ.js v0.7.1 // - +// +// Central horizontal menu +// function noMenu() { - // Set all menu button with normal button style - var x = document.getElementById("showalign"); - x.className = "button"; - var x = document.getElementById("showrun"); - x.className = "button"; - var x = document.getElementById("showcanvas"); - x.className = "button"; - var x = document.getElementById("showlive"); - x.className = "button"; - var x = document.getElementById("shownozoid"); - x.className = "button"; - var x = document.getElementById("showplanet"); - x.className = "button"; + // Set all central menu buttons with normal button style + var x = document.getElementById("align"); + x.value = 0 ; + var x = document.getElementById("run"); + x.value = 0 ; + var x = document.getElementById("simu"); + x.value = 0 ; + var x = document.getElementById("live"); + x.value = 0 ; + var x = document.getElementById("nozoid"); + x.value = 0 ; + var x = document.getElementById("planet"); + x.value = 0 ; // Hide all possible main central grids. var x = document.getElementById("mgalign"); @@ -37,103 +39,188 @@ } function showAlign() { - noMenu(); + noMenu(); var x = document.getElementById("mgalign"); x.style.display = "grid"; - var x = document.getElementById("showalign"); - x.className = "button:checked"; + var x = document.getElementById("align"); + x.value = 1 ; } - function showRun() { - noMenu(); - var x = document.getElementById("mgrun"); - x.style.display = "grid"; - var x = document.getElementById("showrun"); - x.className = "button:checked"; - } + function showRun() { + noMenu(); + var x = document.getElementById("mgrun"); + x.style.display = "grid"; + var x = document.getElementById("run"); + x.value = 1 ; + } - function showCanvas() { - noMenu(); - var x = document.getElementById("mgsimu"); - x.style.display = "grid"; - var x = document.getElementById("cnvbuttons"); - x.style.display = "grid"; - var x = document.getElementById("showcanvas"); - x.className = "button:checked"; - } + function showCanvas() { + noMenu(); + var x = document.getElementById("mgsimu"); + x.style.display = "grid"; + var x = document.getElementById("cnvbuttons"); + x.style.display = "grid"; + var x = document.getElementById("simu"); + x.value = 1 ; + } - function showLive() { - noMenu(); - var x = document.getElementById("mglive"); - x.style.display = "grid"; - var x = document.getElementById("showlive"); - x.className = "button:checked"; - } + function showLive() { + noMenu(); + var x = document.getElementById("mglive"); + x.style.display = "grid"; + var x = document.getElementById("live"); + x.value = 1 ; + } - function showNozoid() { + function showNozoid() { noMenu(); var x = document.getElementById("mgnozoid"); x.style.display = "grid"; - var x = document.getElementById("shownozoid"); - x.className = "button:checked"; - } + var x = document.getElementById("nozoid"); + x.value = 1 ; + } - function showPlanet() { + function showPlanet() { noMenu(); var x = document.getElementById("mgplanet"); - x.style.display = "grid"; + x.style.display = "grid"; var x = document.getElementById("cnvbuttons"); x.style.display = "grid"; - var x = document.getElementById("showplanet"); - x.className = "button:checked"; - } + var x = document.getElementById("planet"); + x.value = 1 ; + } - function buttonClicked(clicked_id) { - _WS.send("/" + clicked_id); - } + function buttonClicked(clicked_id) { - function onSubmit(clicked_id) { - var input = document.getElementById(clicked_id); - console.log("/" + clicked_id + " " + input.value); - _WS.send("/" + clicked_id + " " + input.value); - _WS.showout("/" + clicked_id + " " + input.value); + _WS.send("/" + clicked_id); + + // update Canvas right part of maingrid + if (clicked_id === "planet/planetUI") { + showplanetUI(); + } + if (clicked_id === "nozoid/nozoidUI") { + shownozoidUI(); + } + if (clicked_id === "ai/aiUI") { + showaiUI(); + } + if (clicked_id === "lissa/lissaUI") { + showlissaUI(); + } + if (clicked_id === "vj/vjUI") { + showlissaUI(); + } + if (clicked_id === "nozoid/down 50") { + var x = document.getElementById("nozoid/down 50"); + x.value = 0 ; + } + } + + +// +// SimuUIs +// + + function nosimuUI() { + // Hide all possible main central grids. + var x = document.getElementById("planetUI"); + x.style.display = "none"; + var x = document.getElementById("nozoidUI"); + x.style.display = "none"; + var x = document.getElementById("aiUI"); + x.style.display = "none"; + var x = document.getElementById("lissaUI"); + x.style.display = "none"; + var x = document.getElementById("vjUI"); + x.style.display = "none"; + } + + function showplanetUI() { + nosimuUI(); + var x = document.getElementById("planetUI"); + x.style.display = "grid"; + } + + function shownozoidUI() { + nosimuUI(); + var x = document.getElementById("nozoidUI"); + x.style.display = "grid"; + } + + function showaiUI() { + nosimuUI(); + var x = document.getElementById("aiUI"); + x.style.display = "grid"; + } + + function showlissaUI() { + nosimuUI(); + var x = document.getElementById("lissaUI"); + x.style.display = "grid"; + } + + function showvjUI() { + nosimuUI(); + var x = document.getElementById("vjUI"); + x.style.display = "grid"; + } + + + +// +// Forms submits +// + + function onSubmit(clicked_id) { + var input = document.getElementById(clicked_id); + console.log("/" + clicked_id + " " + input.value); + _WS.send("/" + clicked_id + " " + input.value); + _WS.showout("/" + clicked_id + " " + input.value); } +// +// Websocket handler +// var pl = ""; var pl2 = new Array(); - var _WS = { - uri: 'ws://127.0.0.1:9001/', - ws: null, - init : function (e) { - _WS.s = new WebSocket(_WS.uri); - _WS.s.onopen = function (e) { _WS.onOpen(e); }; - _WS.s.onclose = function (e) { _WS.onClose(e); }; - _WS.s.onmessage = function (e) { _WS.onMessage(e); }; - _WS.s.onerror = function (e) { _WS.onError(e); }; - }, - onOpen: function () { - _WS.showout(_WS.uri); - _WS.showout('CONNECTED'); - document.getElementById("on").value = 1; - }, - onClose: function () { - _WS.showout('DISCONNECTED'); - document.getElementById("on").value = 0; - document.getElementById("lstt/0").value = 0; - document.getElementById("lstt/1").value = 0; - document.getElementById("lstt/2").value = 0; - document.getElementById("lstt/3").value = 0; - document.getElementById("lack/0").value = 0; - document.getElementById("lack/1").value = 0; - document.getElementById("lack/2").value = 0; - document.getElementById("lack/3").value = 0; - }, - onMessage: function (e) { - var res = e.data.split(" "); - //console.log(e.data) - //console.log(res[0].substring(0,6)) + var _WS = { + uri: 'ws://127.0.0.1:9001/', + ws: null, + + init : function (e) { + _WS.s = new WebSocket(_WS.uri); + _WS.s.onopen = function (e) { _WS.onOpen(e); }; + _WS.s.onclose = function (e) { _WS.onClose(e); }; + _WS.s.onmessage = function (e) { _WS.onMessage(e); }; + _WS.s.onerror = function (e) { _WS.onError(e); }; + }, + + onOpen: function () { + _WS.showout(_WS.uri); + _WS.showout('CONNECTED'); + document.getElementById("on").value = 1; + }, + + onClose: function () { + _WS.showout('DISCONNECTED'); + document.getElementById("on").value = 0; + document.getElementById("lstt/0").value = 0; + document.getElementById("lstt/1").value = 0; + document.getElementById("lstt/2").value = 0; + document.getElementById("lstt/3").value = 0; + document.getElementById("lack/0").value = 0; + document.getElementById("lack/1").value = 0; + document.getElementById("lack/2").value = 0; + document.getElementById("lack/3").value = 0; + }, + + onMessage: function (e) { + var res = e.data.split(" "); + //console.log(e.data) + //console.log(res[0].substring(0,6)) + switch (res[0].substring(0,6)) { case "/statu": _WS.showstatus(e.data.slice(8)); @@ -149,39 +236,44 @@ document.getElementById(res[0].slice(1)).value = res[1]; _WS.showin(e.data); } - - }, - onError: function (e) { - _WS.showin('ERROR: ' + e.data); - }, - showin: function (message) { - var divtext = document.getElementById('showin'); - divtext.innerHTML=""; - divtext.innerHTML= message.toString(); - }, - showout: function (message) { - var divtext = document.getElementById('showout'); - divtext.innerHTML=""; - divtext.innerHTML= message.toString(); - }, - showstatus: function (message) { - var divtext = document.getElementById('showstatus'); - divtext.innerHTML=""; - divtext.innerHTML= message.toString(); - }, - send: function (message) { - if (!message.length) { - alert('Empty message not allowed !'); - } else { - _WS.showout(message); - _WS.s.send(message); - } - }, - close: function () { - _WS.showout('GOODBYE !'); - _WS.s.close(); - } - }; + }, - window.addEventListener('load', _WS.init, false); + onError: function (e) { + _WS.showin('ERROR: ' + e.data); + }, + + showin: function (message) { + var divtext = document.getElementById('showin'); + divtext.innerHTML=""; + divtext.innerHTML= message.toString(); + }, + + showout: function (message) { + var divtext = document.getElementById('showout'); + divtext.innerHTML=""; + divtext.innerHTML= message.toString(); + }, + + showstatus: function (message) { + var divtext = document.getElementById('showstatus'); + divtext.innerHTML=""; + divtext.innerHTML= message.toString(); + }, + + send: function (message) { + if (!message.length) { + alert('Empty message not allowed !'); + } else { + _WS.showout(message); + _WS.s.send(message); + } + }, + + close: function () { + _WS.showout('GOODBYE !'); + _WS.s.close(); + } + }; + + window.addEventListener('load', _WS.init, false); diff --git a/webui/LJgrid.css b/webui/LJgrid.css index c8550f2..2f45c9e 100644 --- a/webui/LJgrid.css +++ b/webui/LJgrid.css @@ -11,7 +11,7 @@ .mgtitle { display: grid; height: 90px; - grid-template-columns: 130px 70px 80px 600px; + grid-template-columns: 130px 70px 80px 70px 530px; background-color: #111; transition: all .3s ease; padding-top: 10px; @@ -21,13 +21,13 @@ } .mgstatus { display: grid; - grid-template-columns: 300px 150px 1fr; + grid-template-columns: 470px 80px 1fr; grid-template-raw: 30px; grid-column-gap: 1px; grid-row-gap: 1px; border-color: #334; border-style: groove; - border-width: 1px; + border-width: 0px; background-color: #111; font-size: small; color:#444; @@ -37,7 +37,7 @@ font-family: 'hobeaux-rococeaux-background', Helvetica; } .mgalign { - display: grid; + display: none; height: 400px; grid-template-columns: 144px 144px 138px 138px 10px 326px; grid-template-rows: 1Fr; @@ -47,13 +47,12 @@ border-width: 1px; } .mgsimu { - display: none; + display: grid; height: 400px; width: 900px; grid-template-columns: 500px 400px; grid-template-rows: 400px; background-color: #151515; - } .cnvbuttons { display: none; @@ -133,7 +132,7 @@ display: grid; height: 80px; grid-template-columns: 60px 75px 40px 60px 75px 60px 75px 60px 75px; - background-color: #111; + background-color: #000; justify-items: center; align-items: center; grid-gap: 1px; @@ -303,10 +302,7 @@ vertical-align: middle; padding: 8px 5px; border: 1px solid #404040; - background: #141414; - background: -webkit-gradient(linear, left top, left bottom, from(#141414), to(#141414)); - background: -moz-linear-gradient(top, #141414, #141414); - background: linear-gradient(to bottom, #141414, #141414); + background: #000; font: normal normal normal 11px arial; color: #ffffff; text-decoration: none; @@ -343,15 +339,22 @@ text-decoration: none; } .submit { - background: #0c0c0c; + background: #000; color: #c0c0c0; width: 90px; text-align: center; vertical-align: middle; height: 15px; - background: -webkit-gradient(linear, left top, left bottom, from(#0c0c0c), to(#141414)); - background: -moz-linear-gradient(top, #0c0c0c, #141414); - background: linear-gradient(to bottom, #0c0c0c, #141414); + border: 1px solid #445; +} +.submitsmall { + background: #000; + color: #c0c0c0; + width: 45px; + text-align: center; + vertical-align: middle; + height: 15px; border: 1px solid #445; } + diff --git a/webui/index.html b/webui/index.html index 075ee21..4dc23fa 100644 --- a/webui/index.html +++ b/webui/index.html @@ -1,5 +1,10 @@ + + + @@ -50,6 +55,8 @@
+ +
@@ -80,19 +87,48 @@
+ +
+
Emergy Black
+
+
- + + +
@@ -109,15 +145,57 @@ --> - - - - + + + + + + + + +
+
+ +
+ Client + + + PL + + + Laser + + + + +
+ +
@@ -146,7 +224,7 @@ -
+
@@ -200,7 +278,7 @@
-
+
kPPS
@@ -253,7 +331,7 @@
-
+
kPPS
@@ -309,7 +387,7 @@
-
+
kPPS
@@ -441,33 +519,330 @@
+
- + +
+ + + +
+ +
+
+
+ +
+ Country (FR) + + City + +
+
+ Date/Time (2012-7-12 23:00:00) + +
+
+ Laser 0 : Alt + + Az + + Angle + +
+
+ Laser 1 : Alt + + Az + + Angle + +
+
+ Laser 2 : Alt + + Az + + Angle + +
+
+ Laser 3 : Alt + + Az + + Angle + +
+
+ + + + + + + + + + + + + + + + + + + + +
+
@@ -589,64 +964,64 @@
XCURVE LineIN XCURVE
Automodulation X ? Automodulation Y ?
@@ -707,13 +1082,13 @@ var log=[]; var knobs = document.getElementsByTagName('webaudio-knob'); for(var i = 0; i < knobs.length; i++){ - knobs[i].addEventListener("input",Dump,false); - knobs[i].addEventListener("change",Dump,false); + knobs[i].addEventListener("input",Dump,false); + knobs[i].addEventListener("change",Dump,false); } var sliders = document.getElementsByTagName('webaudio-slider'); for(var i = 0; i < sliders.length; i++){ - sliders[i].addEventListener("input",Dump,false); - sliders[i].addEventListener("change",Dump,false); + sliders[i].addEventListener("input",Dump,false); + sliders[i].addEventListener("change",Dump,false); } var switches = document.getElementsByTagName('webaudio-switch'); for(var i = 0; i < switches.length; i++) { @@ -722,7 +1097,7 @@ function Dump(e) { var str=""; str=e.type + " : " + e.target.id + " : " + e.target.value + " "; - //console.log(str); + console.log(str); log.unshift(str); log.length=1; str=""; @@ -734,27 +1109,52 @@ evview.innerHTML=str; //console.log( e.type + "/" + e.target.id + "/" + e.target.value); - if (e.target.id === "noteon" && e.type ==="input") - console.log("only noteon change are sent not input"); + if (e.target.id === "align" && e.type === "change") { + showAlign(); + } + if (e.target.id === "simu" && e.type === "change") { + showCanvas(); + } + if (e.target.id === "live" && e.type === "change") { + showLive(); + } + if (e.target.id === "nozoid" && e.type === "change") { + showNozoid(); + } + if (e.target.id === "planet" && e.type === "change") { + showPlanet(); + } + if (e.target.id === "run" && e.type === "change") { + showRun(); + } + if (e.target.id === "on" && e.type === "change") { + window.location.reload(); + } - else - _WS.send("/" + e.target.id + " " + e.target.value); - - // for /scale : after a change (knob is released) reset knob value to 0 - if (e.target.id.substring(0,5) === "scale" && e.type === "change") { - e.target.value = 0; - //console.log(e.target.id + "set to 0") - } - // for /loffset : after a change (knob is released) reset knob value to 0 - if (e.target.id.substring(0,7) === "loffset" && e.type === "change") { - e.target.value = 0; - console.log(e.target.id + "set to 0") - } - // for /angle : after a change (knob is released) reset knob value to 0 - if (e.target.id.substring(0,5) === "angle" && e.type === "change") { - e.target.value = 0; - //console.log(e.target.id + "set to 0") - } + if (e.target.id === "nozoid/down 50" && e.type === "input") { + e.target.value = 1 ; + } + + if (e.target.id === "noteon" && e.type ==="input") + console.log("only noteon change are sent not input"); + else + _WS.send("/" + e.target.id + " " + e.target.value); + + // for /scale : after a change (knob is released) reset knob value to 0 + if (e.target.id.substring(0,5) === "scale" && e.type === "change") { + e.target.value = 0; + //console.log(e.target.id + "set to 0") + } + // for /loffset : after a change (knob is released) reset knob value to 0 + if (e.target.id.substring(0,7) === "loffset" && e.type === "change") { + e.target.value = 0; + console.log(e.target.id + "set to 0") + } + // for /angle : after a change (knob is released) reset knob value to 0 + if (e.target.id.substring(0,5) === "angle" && e.type === "change") { + e.target.value = 0; + //console.log(e.target.id + "set to 0") + } } @@ -783,7 +1183,8 @@ return { x: evt.clientX - rect.left, y: evt.clientY - rect.top }; } - function MouseDown(evt) + + function MouseDown(evt) { mousePosDown = getMousePos(aligncanvas, evt); mouseMsgDown = mousePosDown.x + ' ' + mousePosDown.y; diff --git a/webui/knobs/align.png b/webui/knobs/align.png new file mode 100644 index 0000000000000000000000000000000000000000..8a6aa487eee7f48b6a27f61a0887cc5d8d0e54e7 GIT binary patch literal 4386 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 M77nOVGr#!%1N6n!s{jB1 literal 0 HcmV?d00001 diff --git a/webui/knobs/blackout.png b/webui/knobs/blackout.png index 9c66b38c701dc1349ff0f294b6d065654420ac44..98c79598b267b8811528aef606f880fd2d952e16 100644 GIT binary patch delta 5867 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 B8SVf8 delta 4525 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 D>>1IN literal 0 HcmV?d00001 diff --git a/webui/knobs/grid.png b/webui/knobs/grid.png index da415a28bf41549def8d3c09e34681f518c25245..84c6ec28a0e08f5bbe117bf22361aed797f20eb7 100644 GIT binary patch delta 3163 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 B1|a|d delta 1679 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 WUY9hYPULR>8L%?5!QIDroc}*R?sOyo literal 0 HcmV?d00001 diff --git a/webui/knobs/ljaylogo.png b/webui/knobs/ljaylogo.png index 233cb6229633e30ba5ac864a31a480732a2db192..fdf094ac04cd048bed45de69e386c9b6fe8c4585 100644 GIT binary patch delta 7451 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

w}20<>2p1YR-(CUDAQ2P_Id2UCo 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 C9`Yvu diff --git a/webui/knobs/mmo3.png b/webui/knobs/mmo3.png new file mode 100644 index 0000000000000000000000000000000000000000..978b76d96a9a96e469929960a3c019a7018f6bff GIT binary patch literal 4667 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 literal 0 HcmV?d00001 diff --git a/webui/knobs/mouse.png b/webui/knobs/mouse.png index 5000744bad54f8d0fc892654490a67a3c746047e..13c19f34a0ad0778ff473eddf514416fbb50f468 100644 GIT binary patch delta 5098 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 M07*qoM6N<$f^vf=@c;k- diff --git a/webui/knobs/nozoid.png b/webui/knobs/nozoid.png new file mode 100644 index 0000000000000000000000000000000000000000..d88f3e332faa5bb9c586752f5aa09e0b061abcde GIT binary patch literal 4581 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 CeHTRl literal 0 HcmV?d00001 diff --git a/webui/knobs/nozoids.png b/webui/knobs/nozoids.png new file mode 100644 index 0000000000000000000000000000000000000000..4f9d10b78b3c42bb0e7c5f20eed46c6ec8809529 GIT binary patch literal 4802 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 NGBL0~mFPK!{2zwVkVyal literal 0 HcmV?d00001 diff --git a/webui/knobs/ocs2.png b/webui/knobs/ocs2.png new file mode 100644 index 0000000000000000000000000000000000000000..55c71342993423be83258ccd6e523b2cac3dad7a GIT binary patch literal 4499 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 TWP>vYfBELdR@fRN&)EL}SItjN literal 0 HcmV?d00001 diff --git a/webui/knobs/simu.png b/webui/knobs/simu.png new file mode 100644 index 0000000000000000000000000000000000000000..56fedd0437228a75c679de9eb58c4fd5bb24e191 GIT binary patch literal 4288 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 literal 0 HcmV?d00001 diff --git a/webui/knobs/slower.png b/webui/knobs/slower.png new file mode 100644 index 0000000000000000000000000000000000000000..19ffc086e541c82223acca7d2f1bc3394ea67aad GIT binary patch literal 3911 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 Yb7bLcHY-s!a{Irw=2&Y?71}-G-^RAkHUIzs literal 0 HcmV?d00001