newUI, python3,...

This commit is contained in:
sam 2020-09-19 14:28:56 +02:00
parent 0bb0049f02
commit e9d3009ffb
551 changed files with 22992 additions and 787437 deletions

180
LJ.conf
View File

@ -1,103 +1,113 @@
[General]
lasernumber = 4
lasernumber = -1
debug = 0
ljayserverip = 127.0.0.1
ljayserverip = 0.0.0.0
wwwip = 192.168.2.43
nozoscip = 127.0.0.1
bhoroscip = 127.0.0.1
autostart = artnet
[laser0]
color = -1
ip = 192.168.1.4
kpps = 25000
centerx = -10485
centery = -1985
zoomx = 12.0
zoomy = 7.0
sizex = 31450
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.]]
[laser1]
color = -1
ip = 192.168.1.3
kpps = 25000
centerx = 1554
centery = 3573
zoomx = 42.0
zoomy = 40.0
sizex = 32000
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]
color = -1
ip = 192.168.1.5
kpps = 25000
centerx = -31084
centery = -4837
zoomx = 37.8
zoomy = 13.3
sizex = 30600
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.]]
[laser3]
color = -1
ip = 192.168.1.6
kpps = 25000
centerx = -15930
centery = -4434
zoomx = 36.0
zoomy = 54.0
type = DS1000
ip = 192.168.2.43
kpps = 30156
centerx = 46500
centery = 0
zoomx = 294.0
zoomy = 50.0
sizex = 32000
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]
color = -1
type = LOCAL
ip = 192.168.2.5
kpps = 0
centerx = -5707
centery = -838
zoomx = 20.0
zoomy = 20.0
sizex = 32000
sizey = 32000
finangle = -30.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.]]
[laser2]
color = -1
type = LUKE400
ip = 192.168.2.4
kpps = 25000
centerx = 0
centery = 0
zoomx = 37.8
zoomy = 13.3
sizex = 30600
sizey = 32000
finangle = -4.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.]]
[ 1500., 1500.],
[ 1500.,-1500.],
[-1500.,-1500.]]
[laser3]
color = -1
type = LUKE400
ip = 192.168.1.5
kpps = 25000
centerx = 0
centery = 0
zoomx = 57.0
zoomy = 63.0
sizex = 32000
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.]]
[plugins]
plugins = {
"nozoid": {"OSC": 8003, "command": "python3 plugins/audio/nozoids3.py"},
"glyph": {"OSC": 8004, "command": "python3 plugins/laserglyph.py"},
"planet": {"OSC": 8005, "command": "python3 plugins/planetarium/main.py"},
"words": {"OSC": 8006, "command": "python3 plugins/livewords3.py"},
"cycl": {"OSC": 8007, "command": "python3 plugins/textcycl.py"},
"simu": {"OSC": 8008, "command": "python plugins/pysimu.py"},
"artnet": {"OSC": 8009, "command": "python3 libs/artnet.py"},
"bank0": {"OSC": 8010, "command": "python3 plugins/VJing/bank0.py"},
"pose": {"OSC": 8011, "command": "python plugins/VJing/idiotia.py"},
"maxw": {"OSC": 8012, "command": "python3 plugins/maxwell.py"},
"square": {"OSC": 8013, "command": "python3 plugins/square.py"},
"ljpong": {"OSC": 8020, "command": "python plugins/games/ljpong/main.py"},
"ljwars": {"OSC": 8021, "command": "python plugins/games/ljsw/main.py"},
"audiogen": {"OSC": 8030, "command": "python3 plugins/audio/audiogen.py"},
"midigen": {"OSC": 8031, "command": "python3 plugins/audio/midigen.py"},
"viewgen": {"OSC": 8032, "command": "python3 plugins/audio/viewgen.py"}
"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},
"words": {"OSC": 8006, "command": "python3 plugins/livewords3.py", "display": True},
"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},
"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},
"audiogen": {"OSC": 8030, "command": "python3 plugins/audio/audiogen.py", "display": False},
"midigen": {"OSC": 8031, "command": "python3 plugins/audio/midigen.py", "display": False},
"viewgen": {"OSC": 8032, "command": "python3 plugins/audio/viewgen.py", "display": True}
}

1
LJ.py
View File

@ -1 +0,0 @@
main.py

5
LJ.py Normal file
View File

@ -0,0 +1,5 @@
XSym
0007
5bc02cefb3ea9e27f1a6776eabd1935d
main.py

0
libs/OSC3.py → OSC3.py Executable file → Normal file
View File

195
README.md
View File

@ -1,13 +1,13 @@
LJ v0.8.1
LJ v0.8.2
By Sam Neurohack, Loloster, Cocoa
LICENCE : CC BY
![LJ](http://www.teamlaser.fr/thsf/images/fulls/THSF9-33.jpg)
![LJ](http://www.teamlaser.tk/lj/images/calig.png)
A software laser server with GUI for up to 4 lasers live actions. Think creative like Laser "battles", planetarium, sharing available lasers in demoparties for competition, ...
A software laser framework with GUI, for up to 4 lasers live actions with ethedreams DACs. Think creative like Laser "battles", planetarium, sharing available lasers in demoparties for competition, ...
@ -16,13 +16,15 @@ LJ has 5 main components :
- "Plugins" are points generators (to one or more lasers). Lot examples comes with LJ : planetarium, 3D anaglyph animations,... See plugins directory.
- A "tracer" per etherdream/laser that take its given point list, correct geometry, recompute in laser controller coordinates, send it to its controller and report its status to the "manager".
- A "manager" that talk to all tracers (which client number point lists to draw, new geometry correction,...), handle IOs (webui functions, OSC commands,...) and plugins.
- A web GUI in html, css, and vanilla js. No html server or js framework here : it's complex enough. This GUI has a (currently slow) simulator, but one can used a builtin python simulator (pysimu) or an etherdream/laser emulator (from nannou) to work without physical lasers !!
- A network available database (redis). "Plugins" send directly their pointlists to redis and each "tracer" is instructed to get one of the avalaible pointlist in redis. See details right below...
- A web GUI in html, css, and vanilla js. No html server or js framework here : it's complex enough. This GUI has a (currently slow) simulator, but one can used an etherdream/laser emulator (from nannou) to work without physical lasers !!
- A network available database (redis). "Plugins" can send directly their pointlists to redis and each "tracer" is instructed to get one of the avalaible pointlist in redis.
More details :
LJ server accept up to 4 groups = virtual "scenes" of 4 "pointlists" so up to 16 pointlists can be sent to redis at anytime from anywhere in the network. You select in WebUI (Simu/plugins matrix) wich "scene" should be used by tracers/lasers. The all point is to easily share actual lasers. Imagine in demo party :
![Scenes](http://www.teamlaser.tk/lj/images/scenes.png)
LJ accept up to 4 groups = virtual "scenes" of 4 "pointlists" each, so up to 16 pointlists can be sent to redis at anytime from anywhere in the network. You select in WebUI (Simu/plugins matrix) wich "scene" should be used by tracers/lasers. The all point is to easily share actual lasers. Imagine in demo party :
Erica needs 4 lasers, that's the 4 pointlists of a "scene".
Paula and Jennifer use only 2 lasers each, so they can share a "scene".
@ -34,7 +36,7 @@ It's obviously overkill for one laser in a garage, but for several laserS games
Registering the plugin in LJ.conf is absolutely not mandatory.
Needs at least : an etherdream DAC connected to an ILDA laser, RJ 45 IP network (gigabits only !! wifi and wired 100 mpbs doesn't work well with several lasers). Seriously : if you experience frame drops you need to upgrade your network.
Needs at least : an etherdream DAC connected to an ILDA laser, RJ 45 IP network (gigabits only !! wifi and wired 100 mpbs doesn't work well with several lasers). Seriously : if you experience frame drops you need to upgrade your network and use a dedicated computer to run seperately main program from plugins, youtube,...
LJ is tested with Firefox, supports Linux and OS X. Windows is unkown but welcome, if someone want to jump in.
@ -48,30 +50,39 @@ LJ is in dev : versions in this repository will always be core functionnal : acc
(Doc in progress)
- Laser alignment like in videomapping.
- Intensity and kpps live modification.
- Some Lasermapping ('alignment') like in videomapping.
- OSC and websocket commands. Very cool : LJ can script or be scripted.
- Web ui : In your browser open webui/index.html. Javascript is needed. By default it connect to localhost. If you want to control a remote server, you need to change the uri line in LJ.js.
- 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.
- 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.
- A compiled version for os x and linux of nannou.org etherdream+laser emulator is included. For more informations, like license see https://github.com/nannou-org/ether-dream
- Some fancy examples are available : 3D anaglyph, Laser Pong,...
- Midi and audio reactive, look midigen.py and fft3.py
- Openpose skeletons animations laser player.
- Webcam live face display (trckr). Openpose skeletons animations laser player.
- Resolume OSC client.
- Another project (bhorpad) has been merged in LJ : so if you a led matrix, like Launchpad mini or bhoreal, plug it you may define, launch macros as pushing on one led or use them to display informations.
- Artnet plugin.
- Maxwell laser synth emulation plugin.
- Another project (bhorpad) has been merged in LJ : so if you have a led matrix, like Launchpad mini or bhoreal, plug it and you may define, launch macros as pushing on leds or use them to display informations.
- Artnet receiver plugin, another possibity to script LJ.
- Ableton link time synchro support.
- Maxwell laser synth emulation plugin. Work in progress
- Plugins list auto start, see line in LJ.conf : autostart = artnet
- user.py plugin code example
#
# Install
#
With Linux, type in a terminal window :
With Linux, in LJ directory, type in a terminal window :
cd server
./install.sh
Server directory also contains config files for optionnal nginx, supervisorctl and syncthing.
For OS X, you need brew already installed, then :
brew update
@ -83,7 +94,7 @@ For Linux and OS X :
You probably want redis bound to all network interfaces : comment the bind line in /etc/redis/redis.conf and restart it.
In webui/index.html change the websocket (ws) ip adress to the server IP if needed.
In www/index.html change the websocket (ws) ip adress to the server IP if needed.
Using the same idea check all ip address in LJ.conf.
@ -98,41 +109,45 @@ There is a nice websocket debug tool : websocat.
Correct launch order is :
- Switch on Dac/Laser (emulator or IRL)
- Redis server once : i.e redis-server &
- This server. see below.
- Load/reload webUI page from disk in a browser (webui/index.html). Javascript must be enabled.
- Redis server, usually automatically start at boot if redis is a service or you launched manually : redis-server &
- This program. see below.
- Load/reload webUI page from disk in a browser (www/index.html). Javascript must be enabled.
- Run a builtin plugin or your generator, to send pointlists in redis. See in clients/plugins folder for examples.
A typical LJ server start is python main.py -L numberoflasers.
Use also -h to display all possible arguments, like -v for debug informations.
A typical LJ start is :
python3 main.py -L numberoflasers.
Use also -h to display all possible arguments, like -v for debug informations.
CASE 1 : the laser server computer is the same that the computer running a generator/plugin :
CASE 1 : the laser server computer, where LJ runs, is the same that the computer running a generator/plugin :
1/ Run LJ
python main.py -L 1
python3 main.py -L 1
2/ Check in your client code if the laser server IP is the good one
Run your client
3/ to monitor redis server, there is an app for that (redis-manager/medis/...) or :
redis-cli monitor
redis-cli monitor
redis-cli --stat
redis-cli then ask for the key you want like : get /pl/0/0
CASE 2 : Server and Client computers are different :
1/ Say the laser server computer (running LJ) IP is 192.138.1.13, the client computer is 192.168.1.52, First remember to check on the server computer if the redis server is listening to the right IP :
1/ Say the laser server computer (running LJ) IP is 192.138.1.13, the client computer is 192.168.1.52, First remember to check on the server computer, if the redis server is listening to the right IP :
edit /etc/redis/redis.conf
2/ Launch LJ with -r argument :
python main.py -r 192.168.1.13 -L 1
python3 main.py -r 192.168.1.13 -L 1
3/ If the webUI is launched on "client" computer, update uri line in LJ.js
@ -154,38 +169,34 @@ A "plugin" is a software that send any number of pointlist(s). LJ comes with dif
- LiveWords : Fill the input form and it's displayed. One word / laser.
- Textcycl : Cycle some words with adjustable length on one laser.
- Anaglyph : A green/red rotating cube. Try it with green/red 3D glasses !
- Planetarium : A 4 lasers planetarium.
- pySimu : A full speed laser simulator (pygame, python 2.7)
- LaserPong : Our laser Pong is back ! (python 2.7)
- Pose : Display json openpose skeleton animations ans starfields
- fft3 : Example how to make LJ audio reactive
- maxwell : A laser synth inspired by bluefang great work.
- square : The basic plugin.
- custom1 : A copy of square.py for your experiments. Start here.
#
# Client Side : Program your own "plugin"
#
The server approach is based on redis, so you write and run your laser client software in any redis capable programming langage (50+ : https://redis.io/clients). An external program that just send pointlists is a "client". If you want some interactions from the webUI, like text status area support, crash detection, launch,... it's a "plugin" and some default code is needed see square.py as example and :
The server approach is based on redis, so you can write and run your laser client software in any redis capable programming langage (50+ : https://redis.io/clients). An external program that just send pointlists is a "client". If you want some interactions from the webUI, like text status area support, crash detection, launch,... it's a "plugin" and some default code is needed. See custom1.py, a basic plugin you can modiffy. LJ and plugins signaling is mainly over OSC.
- Read all this readme ;-)
- There is a client and plugin folders with examples in different languages. If you want to do game, especially with pygame, see ljpong in plugins/games directory.
- Generate at least one point list array (say a square) with *enough points*, one point is likely to fail for buffering reason.
- Feed your point list array in string format to redis server. i.e use "/pl/0/1" redis key to feed scene 0, pointlist 1.
- Generate at least one pointlist array (say a square) with *enough points*, one point is likely to fail for buffering reason. See command reference below for more.
- Feed your point list array in string format to redis server. i.e use "/pl/0/1" redis key to feed scene 0, laser 1.
- Tell LJ.conf your plugin configuration : OSC port and command line to start it.
Currently the WebUI (webui/index.html) is static so it has to be modified 'manually' and build : run python build.py in webui directory.
Currently the WebUI (www/index.html) is static.
#
# Client side dope mode : How to use lj23
# Client side dope mode : How to use lj23 (python3)
#
lj23 have many very useful functions to not reinvent the wheel for advanced point generation "client" side : layers, built in rotations,..
lj23 have many very useful functions to not reinvent the wheel for advanced points generation "client" side : layers, sprites, built in rotations,..
4 Great TRICKS with lj23.
First open square.py and learn how to declare different objects. square.py is a 2D shape example in 3D rotation (red/green anaglyph rendering) that use 2 layers : one left eye and one for right eye.
4 Great TRICKS with lj23 :
First open square.py and learn how to declare different objects. square.py is a 2D shape example in 3D rotation (red/green anaglyph rendering) that use 2 layers : one for left eye and one for right eye.
1/ How to have another laser drawing the same thing ?
@ -195,6 +206,7 @@ That's a destination problem : just add another destination !
Dest1 = lj.DestObject('1', 1, True, 0 , 1, 1) # Dest1 will also send layer 0 points to scene 1, laser 1
![Layers](http://www.teamlaser.tk/lj/images/layer.png)
2/ Different layers to different lasers ?
@ -222,14 +234,18 @@ Dest1 = lj.DestObject('1', 1, True, 1 , 0, 0) # Dest1 will also send layer 1 poi
4/ I want to animate/modify anything on the fly : I'm doing a game and suddenly my hero change color.
It's a declared object problem : say Hero is a Fixed Object, you can directly change value of
It's a drawn object problem : there is two kind of drawn ojects :
- "Fixed" objects : you generate points in 2D from 0,0 top left and 500,500 is bottom right. Say Hero is a Fixed Object, you can directly change value of
Hero.name, Hero.active, Hero.intensity, Hero.xy, Hero.color, Hero.red, Hero.green, Hero.blue, Hero.layer, Hero.closed
For a character vanishing in one point use a relativeObject so you can decrease resize parameter,...
- "Relative" Object : is a kind of laser sprite : your points in 'objectname.xy' has to be around 0,0,0. The other properties let you describe the actual position (xpos, ypos), resize,..
i.e for a character "PNC" vanishing in one point declared as a "Relative" Object, you can decrease resize parameter : PNC.resize
PNC.name, PNC.active, PNC.intensity, PNC.xy, PNC.color, PNC.red, PNC.green, PNC.blue, PNC.layer, PNC.closed, PNC.xpos, PNC.ypos, PNC.resize, PNC.rotx, PNC.roty, PNC.rotz
Remember RelativeObject points 'objectname.xy' has to be around 0,0,0. The other properties let you change the actual position (xpos, ypos), resize,..
Same for Dest0 if it's a destObject, properties are :
@ -252,10 +268,9 @@ DrawDests() will take care of all your declared drawn elements/"objects" and Des
(Doc in Progress)
- kpps live modification for glitch art.
- A grid style warp correction process in webUI.
- IP change should not need a LJ relaunch
- Way faster WebUI simulator. Use pysimu plugin for full speed.
- Way faster WebUI simulator.
#
@ -269,7 +284,7 @@ Our "always working solution", as we regularly move our gear for different venue
- We use static network configuration. 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 (laser server and clients) are *gigabits wired* with 192.168.1.10 and after. Don't trust end user gear marketing on wifi. We have a big gigabits switch for the *laser only lan*. We provide Internet through wifi on a different network like 192.168.2.x if really needed.
- Because wifi will always finally sucks for many reasons, our computers (LJ server and plugins) are *gigabits wired* with IP 192.168.1.10 and after. Don't trust end user gear marketing on wifi. We have a big gigabits switch for the *laser only lan*. We provide Internet through wifi on a different network like 192.168.2.x if really needed.
- Again, even if etherdreams are 100 Mbits, we use *gigabits* gear.
@ -277,12 +292,12 @@ Our "always working solution", as we regularly move our gear for different venue
By default LJ uses on 127.0.0.1 (localhost) :
- A websocket on port 9001 for WebUI interaction.
- The redis server on port 6379 ('ljayserverip')
- The redis server on port 6379 ('ljayserverip').
- An OSC server on port 8002 for remote control via OSC and plugins.
- Some OSC clients defined in LJ.conf to forward commands to defined plugins
- Some OSC clients defined in LJ.conf to forward commands to defined plugins.
You need to update LJ.conf to your network/etherdreams IPs and be sure to check command arguments : python main.py --help
You need to update LJ.conf to your network/etherdreams IPs and be sure to check command arguments : python3 main.py --help
The need for a dedicated computer to act as "laser server" usually depends on how many lasers you want to control and your main computer load. If you seen flickering with small point lists, try the dedicated computer idea and/or stop process interfering like redis monitoring,...
@ -307,3 +322,81 @@ This program suppose that the ether dream is configured in a certain way especia
/ilda/fps 25
About hardware setup, especially if you have several lasers : ILDA cables are insanely expensive. You may consider the Power Over Ethernet 'POE' option. Buy a very small ILDA cable, a POE splitter and connect everything to the ether dream fixed near your laser. You can have then a simple and very long network cable and use a Power Over Ethernet injector or switch close to the driving computer. Beware some vendors use 24V POE Injector : POE injectors and splitters must match.
#
# LJ commands reference
#
8002 OSC incoming
9001 Websocket
redis key
/pl/scenenumber/lasernumber value : value is the pointlist to draw as string type :
"[(150.0, 230.0, 65280), (170.0, 170.0, 65280), (230.0, 170.0, 65280), (210.0, 230.0, 65280), (150.0, 230.0, 65280)]"
/scale/X/lasernumber value
/scale/Y/lasernumber value
/swap/X/lasernumber value (0 or 1)
/swap/Y/lasernumber value (0 or 1)
/angle/lasernumber value : increase/decrease angle correction for given laser by value
/loffset/X/lasernumber value : change X offset of given laser by value
/loffset/Y/lasernumber value : change Y offset of given laser by value
/kpps/lasernumber value : Live change of kpps is not implemented in newdac.py. Change will effect next startup.
/intens/lasernumber value : increase/decrease intensity for given laser by value
/client or note on < 8 : change client displayed for Current Laser
23 < /noteon < 32 : PL number displayed on webUI simulator
/grid/lasernumber value (0 or 1) : switch given laser with grid display on or off
/black/lasernumber value (0 or 1) : set given laser to black on or off
/ip/lasernumber value : change given laser IP i.e '192.168.1.1'
/resampler/lasernumber lsteps : change resampling strategy (glitch art) for given laser
lsteps is a string like "[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]"
/planet will be forwarded to planetarium client.
/nozoid will be forwarded to nozoid client.
/scene/scenenumber/start 0 or 1
/regen : regen webui index html page.
/scim
/forwardui "uicommand arg" : display *one* word on webui. There is 2 lines, first line (/status or /redstatus)
and second line (/line1 or /redline1). Examples of "uicommand arg" :
/status hello
/redline1 Error
/laser 0
![LJ Display](https://www.teamlaser.tk/images/display.png)
Leds colors for each DACs
DAC state "stt" :
Laser not requested -> led is not lit
IDLE -> blue
PREPARE -> cyan
PLAYING -> green
DAC answers (ack) :
replied ACK -> green
replied FULL -> orange
replied INVALID -> yellow
no connection to dac -> leds are red (6)

View File

@ -1,182 +0,0 @@
# coding=UTF-8
'''
Anaglyphed cube
LICENCE : CC
'''
import redis
import lj
import math
import time
import numpy as np
# IP defined in /etd/redis/redis.conf
redisIP = '127.0.0.1'
r = redis.StrictRedis(host=redisIP, port=6379, db=0)
width = 800
height = 600
centerX = width / 2
centerY = height / 2
fov = 256
viewer_distance = 2.2
eye_spacing = 100
nadir = 0.5
observer_altitude = 30000
# elevation = z coordinate
# 0.0 or -2000 pop out)
map_plane_altitude = 0.0
samparray = [0] * 100
def LeftShift(elevation):
diff = elevation - map_plane_altitude
return nadir * eye_spacing * diff / (observer_altitude - elevation)
def RightShift(elevation):
diff = map_plane_altitude - elevation
return (1 - nadir) * eye_spacing * diff / (observer_altitude - elevation)
# If you want to use rgb for color :
def rgb2int(r,g,b):
return int('0x%02x%02x%02x' % (r,g,b),0)
def ssawtooth(samples,freq,phase):
t = np.linspace(0+phase, 1+phase, samples)
for ww in range(samples):
samparray[ww] = signal.sawtooth(2 * np.pi * freq * t[ww])
return samparray
def ssquare(samples,freq,phase):
t = np.linspace(0+phase, 1+phase, samples)
for ww in range(samples):
samparray[ww] = signal.square(2 * np.pi * freq * t[ww])
return samparray
def ssine(samples,freq,phase):
t = np.linspace(0+phase, 1+phase, samples)
for ww in range(samples):
samparray[ww] = np.sin(2 * np.pi * freq * t[ww])
return samparray
def shader2scrX(s):
a1, a2 = -1,1
b1, b2 = -width/2, width/2
return b1 + ((s - a1) * (b2 - b1) / (a2 - a1))
def shader2scrY(s):
a1, a2 = -1,1
b1, b2 = -heigth/2, heigth/2
return b1 + ((s - a1) * (b2 - b1) / (a2 - a1))
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)
def DrawPL():
Shape = []
Left = []
Right = []
counter =0
while 1:
yfactor = 10
Left = []
Right = []
x = -1
z = -0.1
for step in y0:
Left.append( Proj(x+LeftShift(z*25),step/yfactor,z,0,0,0))
Right.append(Proj(x+RightShift(z*25),step/yfactor,z,0,0,0))
x += 0.02
lj.rPolyLineOneColor(Left, c = red, PL = 0, closed = False, xpos = 0, ypos = 10, resize = 1.5, rotx =0, roty =0 , rotz=0)
lj.rPolyLineOneColor(Right, c = green, PL = 0, closed = False, xpos = 0, ypos = 10, resize = 1.5, rotx =0, roty =0 , rotz=0)
Left = []
Right = []
x = -1
z = 0
for step in y1:
Left.append( Proj(x+LeftShift(z*25),step/yfactor,z,0,0,0))
Right.append(Proj(x+RightShift(z*25),step/yfactor,z,0,0,0))
x += 0.02
lj.rPolyLineOneColor(Left, c = red, PL = 0, closed = False, xpos = 0, ypos = 25, resize = 1.5, rotx =0, roty =0 , rotz=0)
lj.rPolyLineOneColor(Right, c = green, PL = 0, closed = False, xpos = 0, ypos = 25, resize = 1.5, rotx =0, roty =0 , rotz=0)
Left = []
Right = []
x = -1
z = 0.1
for step in y2:
Left.append( Proj(x+LeftShift(z*25),step/yfactor,z,0,0,0))
Right.append(Proj(x+RightShift(z*25),step/yfactor,z,0,0,0))
x += 0.02
lj.rPolyLineOneColor(Left, c = red, PL = 0, closed = False, xpos = 0, ypos = 50, resize = 1.5, rotx =0, roty =0 , rotz=0)
lj.rPolyLineOneColor(Right, c = green, PL = 0, closed = False, xpos = 0, ypos = 50, resize = 1.5, rotx =0, roty =0 , rotz=0)
lj.DrawPL(0)
time.sleep(0.005)
white = rgb2int(255,255,255)
red = rgb2int(255,0,0)
blue = rgb2int(0,0,255)
green = rgb2int(0,255,0)
y0 = ssine(100,5,-0.5)
y1 = ssine(100,5,0)
y2 = ssine(100,5,0.5)
DrawPL()

View File

@ -1,352 +0,0 @@
# coding=UTF-8
'''
LJ v0.8.2
Some LJ functions useful for python 2.7 clients (was framy.py)
Functions and documentation here is low priority as python 2 support will stop soon.
Better code your plugin with python 3 and lj3.py.
Config
PolyLineOneColor
rPolyLineOneColor
Text
SendLJ : remote control
LjClient :
LjPl :
DrawPL
WebStatus
LICENCE : CC
Sam Neurohack
'''
import math
import redis
from OSC import OSCServer, OSCClient, OSCMessage
print "Importing lj..."
#redisIP = '127.0.0.1'
#r = redis.StrictRedis(host=redisIP, port=6379, db=0)
ClientNumber = 0
point_list = []
pl = [[],[],[],[]]
def SendLJ(oscaddress,oscargs=''):
oscmsg = OSCMessage()
oscmsg.setAddress(oscaddress)
oscmsg.append(oscargs)
print ("sending OSC message : ",oscmsg)
try:
osclientlj.sendto(oscmsg, (redisIP, 8002))
oscmsg.clearData()
except:
print ('Connection to LJ refused : died ?')
pass
#time.sleep(0.001
def WebStatus(message):
SendLJ("/status", message)
ASCII_GRAPHICS = [
#implementé
[(-50,30), (-30,-30), (30,-30), (10,30), (-50,30)], #0
[(-20,30), (0,-30), (-20,30)], #1
[(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], #2
[(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], #3
[(30,10), (-30,10), (0,-30), (0,30)], #4
[(30,-30), (-30,-30), (-30,0), (0,0), (30,10), (0,30), (-30,30)], #5
[(30,-30), (0,-30), (-30,-10), (-30,30), (0,30), (30,10), (30,0), (-30,0)], #6
[(-30,-30), (30,-30), (-30,30)], #7
[(-30,30), (-30,-30), (30,-30), (30,30), (-30,30), (-30,0), (30,0)], #8
[(30,0), (-30,0), (-30,-10), (0,-30), (30,-30), (30,10), (0,30), (-30,30)], #9
# A implementer
[(-30,10), (30,-10), (30,10), (0,30), (-30,10), (-30,-10), (0,-30), (30,-10)], #:
[(-30,-10), (0,-30), (0,30)], [(-30,30), (30,30)], #;
[(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], #<
[(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], #=
[(30,10), (-30,10), (0,-30), (0,30)], #>
[(30,-30), (-30,-30), (-30,0), (0,0), (30,10), (0,30), (-30,30)], #?
[(30,-30), (0,-30), (-30,-10), (-30,30), (0,30), (30,10), (30,0), (-30,0)], #@
# Implementé
[(-30,30), (-30,-30), (30,-30), (30,30), (30,0), (-30,0)], #A
[(-30,30), (-30,-30), (30,-30), (30,30), (30,0), (-30,0)], #A
[(-30,30), (-30,-30), (30,-30), (30,30), (-30,30), (-30,0), (30,0)], #B
[(30,30), (-30,30), (-30,-30), (30,-30)], #C
[(-30,30), (-30,-30), (30,-30), (30,30), (-30,30)], #D
[(30,30), (-30,30), (-30,-0), (30,0), (-30,0), (-30,-30), (30,-30)], #E
[(-30,30), (-30,-0), (30,0), (-30,0), (-30,-30), (30,-30)], #F
[(0,0), (30,0), (30,30), (-30,30), (-30,-30),(30,-30)], #G
[(-30,-30), (-30,30), (-30,0), (30,0), (30,30), (30,-30)], #H
[(0,30), (0,-30)], #I
[(-30,30), (0,-30), (0,-30), (-30,-30), (30,-30)], #J
[(-30,-30), (-30,30), (-30,0), (30,-30), (-30,0), (30,30)], #K
[(30,30), (-30,30), (-30,-30)], #L
[(-30,30), (-30,-30), (0,0), (30,-30), (30,30)], #M
[(-30,30), (-30,-30), (30,30), (30,-30)], #N
[(-30,30), (-30,-30), (30,-30), (30,30), (-30,30)], #O
[(-30,0), (30,0), (30,-30), (-30,-30), (-30,30)], #P
[(30,30), (30,-30), (-30,-30), (-30,30), (30,30),(35,35)], #Q
[(-30,30), (-30,-30), (30,-30), (30,0), (-30,0), (30,30)], #R
[(30,-30), (-30,-30), (-30,0), (30,0), (30,30), (-30,30)], #S
[(0,30), (0,-30), (-30,-30), (30,-30)], #T
[(-30,-30), (-30,30), (30,30), (30,-30)], #U
[(-30,-30), (0,30), (30,-30)], #V
[(-30,-30), (-30,30), (0,0), (30,30), (30,-30)], #W
[(-30,30), (30,-30)], [(-30,-30), (30,30)], #X
[(0,30), (0,0), (30,-30), (0,0), (-30,-30)], #Y
[(30,30), (-30,30), (30,-30), (-30,-30)], #Z
# A implementer
[(-30,-10), (0,-30), (0,30)], [(-30,30), (30,30)], #[
[(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], #\
[(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], #]
[(30,10), (-30,10), (0,-30), (0,30)], #^
[(30,-30), (-30,-30), (-30,0), (0,0), (30,10), (0,30), (-30,30)], #_
[(30,-30), (0,-30), (-30,-10), (-30,30), (0,30), (30,10), (30,0), (-30,0)], #`
# Implementé
[(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], #a
[(-20,20), (-20,-20), (20,-20), (20,20), (-20,20), (-20,0), (20,0)], #b
[(20,20), (-20,20), (-20,-20), (20,-20)], #c
[(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], #d
[(20,20), (-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], #e
[(-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], #f
[(0,0), (20,0), (20,20), (-20,20), (-20,-20),(20,-20)], #g
[(-20,-20), (-20,20), (-20,0), (20,0), (20,20), (20,-20)], #H
[(0,20), (0,-20)], #I
[(-20,20), (0,-20), (0,-20), (-20,-20), (20,-20)], #J
[(-20,-20), (-20,20), (-20,0), (20,-20), (-20,0), (20,20)], #K
[(20,20), (-20,20), (-20,-20)], #L
[(-20,20), (-20,-20), (0,0), (20,-20), (20,20)], #M
[(-20,20), (-20,-20), (20,20), (20,-20)], #N
[(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], #O
[(-20,0), (20,0), (20,-20), (-20,-20), (-20,20)], #P
[(20,20), (20,-20), (-20,-20), (-20,20), (20,20),(25,25)], #Q
[(-20,20), (-20,-20), (20,-20), (20,0), (-20,0), (20,20)], #R
[(20,-20), (-20,-20), (-20,0), (20,0), (20,20), (-20,20)], #S
[(0,20), (0,-20), (-20,-20), (20,-20)], #T
[(-20,-20), (-20,20), (20,20), (20,-20)], #U
[(-20,-20), (0,20), (20,-20)], #V
[(-20,-20), (-20,20), (0,0), (20,20), (20,-20)], #W
[(-20,20), (20,-20)], [(-20,-20), (20,20)], #X
[(0,20), (0,0), (20,-20), (0,0), (-20,-20)], #Y
[(20,20), (-20,20), (20,-20), (-20,-20)], #Z
[(-2,15), (2,15)] # Point a la place de {
]
def Config(redisIP,client):
global ClientNumber
r = redis.StrictRedis(host=redisIP, port=6379, db=0)
ClientNumber = client
#print "client configured",ClientNumber
def LjClient(client):
global ClientNumber
ClientNumber = client
def LjPl(pl):
global PL
PL = pl
# Properly close the system. Todo
def OSCstop():
osc_terminate()
# Answer to LJ pings with /pong value
def OSCping(name):
SendLJ("/pong",name)
# Closing plugin messages to LJ
def ClosePlugin(name):
WebStatus(name+" Exit")
SendLJ("/"+name+"/start",0)
# /quit
def OSCquit(name):
WebStatus(name + " quit.")
print("Stopping OSC...")
OSCstop()
sys.exit()
def LineTo(xy, c, PL):
pl[PL].append((xy + (c,)))
def Line(xy1, xy2, c, PL):
LineTo(xy1, 0, PL)
LineTo(xy2, c , PL)
def PolyLineOneColor(xy_list, c, PL , closed ):
#print "--"
#print "c",c
#print "xy_list",xy_list
#print "--"
xy0 = None
for xy in xy_list:
if xy0 is None:
xy0 = xy
#print "xy0:",xy0
LineTo(xy0,0, PL)
LineTo(xy0,c, PL)
else:
#print "xy:",xy
LineTo(xy,c, PL)
if closed:
LineTo(xy0,c, PL)
# Computing points coordinates for rPolyline function from 3D and around 0,0 to pygame coordinates
def Pointransf(xy, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0):
x = xy[0] * resize
y = xy[1] * resize
z = 0
rad = math.radians(rotx)
cosaX = math.cos(rad)
sinaX = math.sin(rad)
y2 = y
y = y2 * cosaX - z * sinaX
z = y2 * sinaX + z * cosaX
rad = math.radians(roty)
cosaY = math.cos(rad)
sinaY = math.sin(rad)
z2 = z
z = z2 * cosaY - x * sinaY
x = z2 * sinaY + x * cosaY
rad = math.radians(rotz)
cosZ = math.cos(rad)
sinZ = math.sin(rad)
x2 = x
x = x2 * cosZ - y * sinZ
y = x2 * sinZ + y * cosZ
#print xy, (x + xpos,y+ ypos)
return (x + xpos,y+ ypos)
'''
to understand why it get negative Y
# 3D to 2D projection
factor = 4 * gstt.cc[22] / ((gstt.cc[21] * 8) + z)
print xy, (x * factor + xpos, - y * factor + ypos )
return (x * factor + xpos, - y * factor + ypos )
'''
# Send 2D point list around 0,0 with 3D rotation resizing and reposition around xpos ypos
#def rPolyLineOneColor(self, xy_list, c, PL , closed, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0):
def rPolyLineOneColor(xy_list, c, PL , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
xy0 = None
for xy in xy_list:
if xy0 is None:
xy0 = xy
LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),0, PL)
LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),c, PL)
else:
LineTo(Pointransf(xy, xpos, ypos, resize, rotx, roty, rotz),c, PL)
if closed:
LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),c, PL)
def LinesPL(PL):
print "Stupido !! your code is to old : use DrawPL() instead of LinesPL()"
DrawPL(PL)
def DrawPL(PL):
#print '/pl/0/'+str(PL), str(pl[PL])
if r.set('/pl/'+str(ClientNumber)+'/'+str(PL), str(pl[PL])) == True:
#print '/pl/'+str(ClientNumber)+'/'+str(PL), str(pl[PL])
pl[PL] = []
return True
else:
return False
def ResetPL(self, PL):
pl[PL] = []
def DigitsDots(number,color):
dots =[]
for dot in ASCII_GRAPHICS[number]:
#print dot
dots.append((gstt.xy_center[0]+dot[0],gstt.xy_center[1]+dot[1],color))
#self.point_list.append((xy + (c,)))
return dots
def CharDots(char,color):
dots =[]
for dot in ASCII_GRAPHICS[ord(char)-46]:
dots.append((dot[0],dot[1],color))
return dots
def Text(message,c, PL, xpos, ypos, resize, rotx, roty, rotz):
dots =[]
l = len(message)
i= 0
#print message
for ch in message:
#print ""
# texte centre en x automatiquement selon le nombre de lettres l
x_offset = 26 * (- (0.9*l) + 3*i)
# Digits
if ord(ch)<58:
char_pl_list = ASCII_GRAPHICS[ord(ch) - 48]
else:
char_pl_list = ASCII_GRAPHICS[ord(ch) - 46]
char_draw = []
#dots.append((char_pl_list[0][0] + x_offset,char_pl_list[0][1],0))
for xy in char_pl_list:
char_draw.append((xy[0] + x_offset,xy[1],c))
i +=1
#print ch,char_pl_list,char_draw
rPolyLineOneColor(char_draw, c, PL , False, xpos, ypos, resize, rotx, roty, rotz)
#dots.append(char_draw)

View File

@ -1,94 +0,0 @@
// Send points lists to redis server
// In compatible LJay string format (pythonic lists)
var redis = require("redis"),
client = redis.createClient(6379,'127.0.0.1');
function rgb2int(r,g,b) {
// Generate color from r g b components
var color = hex(r) + hex(g) + hex(b);
return parseInt(color, 16)
}
function hex(v) {
// Get hexadecimal numbers.
var hex = v.toString(16);
if (v < 16) {
hex = "0" + hex;
}
return hex;
}
// add one dot to Laser 0 point list
function adddot0(dotdata){
var dotstring = "(" + dotdata + "),";
pl0 += dotstring;
}
// add one dot to Laser 1 point list
function adddot1(dotdata){
var dotstring = "(" + dotdata + "),";
pl1 += dotstring;
}
// Generate same square to laser 0 and laser 1
function GenPoints()
{
var pt = {};
// direct colors, i.e white
pt.r = 255;
pt.g = 255;
pt.b = 255;
// named colors
var white = rgb2int(255, 255, 255);
pt.x = 100;
pt.y = 200;
adddot0([pt.x, pt.y, rgb2int(pt.r, pt.g, pt.b)]);
adddot1([pt.x, pt.y, rgb2int(pt.r, pt.g, pt.b)]);
pt.x = 100;
pt.y = 300;
adddot0([pt.x, pt.y, white]);
adddot1([pt.x, pt.y, white]);
pt.x = 200;
pt.y = 300;
adddot0([pt.x, pt.y, white]);
adddot1([pt.x, pt.y, white]);
pt.x = 200;
pt.y = 200;
adddot0([pt.x, pt.y, white]);
adddot1([pt.x, pt.y, white]);
pt.x = 100;
pt.y = 200;
adddot0([pt.x, pt.y, white]);
adddot1([pt.x, pt.y, white]);
}
// Point lists strings
var pl0 = "[";
var pl1 = "[";
GenPoints();
pl0 = pl0.slice(0,-1) + "]"
pl1 = pl1.slice(0,-1) + "]"
console.log(pl0);
console.log(pl1);
// Send points lists to redis server
// /pl/clientnumber/lasernumber pointlist
// you're client 0 and want to send points to laser 0 and 1
client.set("/pl/0/0",pl0);
client.set("/pl/0/1",pl1);
// Quit
client.quit()

View File

@ -1,41 +0,0 @@
# coding=UTF-8
'''
Multi Laser client example with direct send of point lists to redis server.
Remember : LJ will automatically warp geometry according to alignement data. See webUI.
LICENCE : CC
'''
import redis
# IP defined in /etd/redis/redis.conf
redisIP = '127.0.0.1'
r = redis.StrictRedis(host=redisIP, port=6379, db=0)
# (x,y,color in integer) 65280 is color #00FF00
# Green rectangular shape :
pl0 = [(100,300,65280),(200,300,65280),(200,200,65280),(100,200,65280),(100,300,65280)]
# If you want to use rgb for color :
def rgb2int(r,g,b):
return int('0x%02x%02x%02x' % (r,g,b),0)
# White rectangular shape
pl1 = [(100,300,rgb2int(255,255,255)),(200,300,rgb2int(255,255,255)),(200,200,rgb2int(255,255,255)),(100,200,rgb2int(255,255,255)),(100,300,rgb2int(255,255,255))]
# /pl/clientnumber/lasernumber pointlist
# Consider you're client 0
# Send to laser 0 (see LJ.conf)
r.set('/pl/0/0', str(pl0))
# Send to laser 1 (see LJ.conf)
r.set('/pl/0/1', str(pl1))
# Send to laser 2 (see LJ.conf)
r.set('/pl/0/2', str(pl1))

View File

@ -1,11 +0,0 @@
#!/bin/bash
sudo apt install python-pip
sudo apt install git
sudo apt install redis
pip install numpy
pip install scipy
git clone https://github.com/ptone/pyosc --depth 1 /tmp/pyosc && cd /tmp/pyosc && sudo ./setup.py install
pip install redis

BIN
libs/.DS_Store vendored

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,883 +0,0 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
Launchpad
v0.7.0
Maunchpad mini Handler.
Start a dedicated thread to handle incoming events from launchpad.
Cls()
AllColorPad(color)
StartLaunchPad(port) : Start animation
Led Matrix can be access with X and Y coordinates and as midi note (0-63)
PadNoteOn(note,color)
PadNoteOff(note)
PadNoteOnXY(x,y,color):
PadNoteOffXY(x,y):
PadNoteXY(x,y):
PadLeds[], PadTops[] and PadRights arrays stores matrix current state
Top raw and right column leds are numbered humanly 1-8. So -1 is for pythonic arrays position 0-7
PadTopOn(number,color)
PadTopOff(number)
PadRightOn(number)
PadRightOff(number):
by Sam Neurohack
from /team/laser
for python 2 & 3
"""
import time
import rtmidi
from rtmidi.midiutil import open_midiinput
from threading import Thread
from rtmidi.midiconstants import (CHANNEL_PRESSURE, CONTROLLER_CHANGE, NOTE_ON, NOTE_OFF,
PITCH_BEND, POLY_PRESSURE, PROGRAM_CHANGE)
from mido import MidiFile
import mido
import sys
import midi3
#import midimacros, maxwellmacros
import traceback
from queue import Queue
import scrolldisp
#from libs import macros
import json, subprocess
from OSC3 import OSCServer, OSCClient, OSCMessage
import socket
print('Launchpad Startup..')
myHostName = socket.gethostname()
print("Name of the localhost is {}".format(myHostName))
myIP = socket.gethostbyname(myHostName)
print("IP address of the localhost is {}".format(myIP))
myIP = "127.0.0.1"
print('Used IP', myIP)
OSCinPort = 8080
monomePort = 8000
maxwellatorPort = 8090
launchqueue = Queue()
mode = "maxwell"
mididest = 'Session 1'
midichannel = 1
CChannel = 0
CCvalue = 0
PadLeds = [0] * 64
PadTops= [0] * 8
PadRights= [0] * 8
Here = -1
ModeCallback = ''
# midi notes
LaunchLedMatrix = [(0,1,2,3,4,5,6,7),(16,17,18,19,20,21,22,23),(32,33,34,35,36,37,38,39),(48,49,50,51,52,53,54,55),(64,65,66,67,68,69,70,71),(80,81,82,83,84,85,86,87),(96,97,98,99,100,101,102,103),(112,113,114,115,116,117,118,119)]
# Notes
LaunchRight = (8,24,40,56,72,88,104,120)
# CC
LaunchTop = (104,105,106,107,108,109,110,111)
PadTop = [0,0,0,0,0,0,0,0]
PadRight = [0,0,0,0,0,0,0,0]
PadMatrix = [0] * 64
TopSelection = [0] *8
computerIP = ['127.0.0.1','192.168.2.95','192.168.2.52','127.0.0.1',
'127.0.0.1','127.0.0.1','127.0.0.1','127.0.0.1']
computer = 0
# /cc cc number value
def cc(ccnumber, value, dest=mididest):
midi3.MidiMsg([CONTROLLER_CHANGE+midichannel-1,ccnumber,value], dest)
def Disp(text,device = 'Launchpad Mini'):
print(device,midi3.FindInDevice(device))
if (device == "Launchpad Mini" or device =='launchpad') and midi3.FindInDevice(device) != -1:
scrolldisp.Display(text, color=(255,255,255), delay=0.2, mididest = 'launchpad')
if device == 'bhoreal' and midi3.FindInDevice('Bhoreal'):
scrolldisp.Display(text, color=(255,255,255), delay=0.2, mididest = device)
def PadNoteOn(note,color):
(x,y) = BhorIndex(note)
#print(note,x,y)
PadNoteOnXY(x,y,color)
def PadNoteOff(note):
(x,y) = BhorIndex(note)
PadNoteOffXY(x,y)
def PadNoteOnXY(x,y,color):