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):
msg= [NOTE_ON, PadNoteXY(x,y), color]
#print msg
midi3.send(msg,"Launchpad")
PadLeds[BhorNoteXY(x,y)]=color
def PadNoteOffXY(x,y):
msg= [NOTE_OFF, PadNoteXY(x,y), 0]
midi3.send(msg,"Launchpad")
PadLeds[BhorNoteXY(x,y)]=0
def PadNoteXY(x,y):
note = LaunchLedMatrix[int(y-1)][int(x-1)]
return note
def PadIndex(note):
y=note/16
x=note%16
return int(x+1),int(y+1)
def BhorIndex(note):
y=note/8
x=note%8
#print "Note : ",note
#print "BhorIndex : ", x+1,y+1
return int(x+1),int(y+1)
def BhorNoteXY(x,y):
note = (x -1)+ (y-1) * 8
return note
# top raw and right column leds are numbered humanly 1-8. So -1 is for pythonic arrays position 0-7
def PadTopOn(number,color):
msg= [CONTROLLER_CHANGE, LaunchTop[number-1], color]
midi3.send(msg,"Launchpad")
PadTops[number-1]=color
def PadTopOff(number):
msg= [CONTROLLER_CHANGE, LaunchTop[number-1], 0]
midi3.send(msg,"Launchpad")
PadTops[number-1]=0
def PadRightOn(number,color):
msg= [NOTE_ON, LaunchRight[number-1], color]
midi3.send(msg,"Launchpad")
PadRights[number-1]=color
def PadRightOff(number):
msg= [NOTE_OFF, LaunchRight[number-1], 0]
midi3.send(msg,"Launchpad")
PadRights[number-1]=0
def TopUpdate(button,color):
#print(PadTop)
PadTop = [0,0,0,0,0,0,0,0]
PadTop[button] = color
for pad in range(7):
PadTopOn(pad+1,PadTop[pad])
def RightUpdate():
for pad in range(9):
PadRightOn(pad,PadRight[pad])
def MatrixUpdate():
for pad in range(64):
PadNoteOn(pad,PadMatrix[pad])
def MatrixSelect():
MatrixUpdate()
return
def ComputerUpdate(comput):
global computer
computer = comput
PadRightOn(computer+1,127)
# Client to export buttons actions from Launchpad or bhoreal
def SendOSC(ip,port,oscaddress,oscargs=''):
oscmsg = OSCMessage()
oscmsg.setAddress(oscaddress)
oscmsg.append(oscargs)
osclient = OSCClient()
osclient.connect((ip, port))
print("sending OSC message : ", oscmsg, "to", ip, ":", port)
try:
osclient.sendto(oscmsg, (ip, port))
oscmsg.clearData()
return True
except:
print ('Connection to', ip, 'refused : died ?')
return False
#
# LaunchPad start anim
#
# AllColor for bhoreal on given port
def AllColorPad(color):
for led in range(0,64,1):
PadNoteOn(led,color)
'''
for line in LaunchLedMatrix:
for led in line:
midiport[port].send_message([NOTE_ON, led, color])
'''
for rightled in range(8):
PadRightOn(rightled+1,color)
for topled in range(8):
PadTopOn(topled+1,color)
#midiport[port].send_message([CONTROLLER_CHANGE, topled, color])
def ClsMatrix():
for led in range(0,64,1):
PadNoteOff(led)
def ClsTop():
for topled in range(8):
PadTopOff(topled+1)
def ClsRight():
for rightled in range(8):
PadRightOff(rightled+1)
def Cls():
ClsMatrix()
ClsTop()
ClsRight()
ComputerUpdate(computer)
'''
for line in LaunchLedMatrix:
for led in line:
midiport[port].send_message([NOTE_OFF, led, 0])
'''
def StartLaunchPad(port):
#ClsPad(port)
#time.sleep(0.3)
AllColorPad(20)
time.sleep(0.6)
Cls()
time.sleep(0.3)
#
# Events from Launchpad Handling
#
# Process events coming from Launchpad in a separate thread.
def MidinProcess(launchqueue):
global computer
while True:
launchqueue_get = launchqueue.get
msg = launchqueue_get()
#print (msg)
if msg[0]==NOTE_ON:
(x,y) = PadIndex(msg[1])
# MATRIX = macros, notes, channels,...
if x < 9:
msg[1]= BhorNoteXY(x,y)
macroname = "m"+str(y)+str(x)
# Run Macro with matrix location and velocity
Run(macroname, macroargs = int(msg[2]))
# RIGHT = computer, this host or other computer
if x == 9:
print("Right Button : ", y)
macroname = "r"+str(y)
print(macroname)
ClsRight()
PadRightOn(y,127)
print("Destination computer",y)
computer = y
#time.sleep(0.1)
#PadRightOff(y)
# TOP = Mode Note, CC, Os, Monome,..
if msg[0]==CONTROLLER_CHANGE:
print("Pad Top Button : ", str(msg[1]-103), "value",msg[2])
TopUpdate(msg[1]-104,20)
macroname = "t"+str(msg[1]-103)
#print(macroname)
Run(macroname, macroargs = (msg[1]-103,msg[2]))
launchqueue = Queue()
ModeCallback = "ModeNo"
# LaunchPad Mini call back : new msg forwarded to Launchpad queue
class LaunchAddQueue(object):
def __init__(self, port):
self.port = port
#print("LaunchAddQueue", self.port)
self._wallclock = time.time()
def __call__(self, event, data=None):
message, deltatime = event
self._wallclock += deltatime
print()
print("[%s] @%0.6f %r" % (self.port, self._wallclock, message))
launchqueue.put(message)
#
# Modes : Top lines functions
#
# Load Matrix only macros (for the moment) in macros.json
def LoadMacros():
global macros
print()
print("Loading Launchpad Macros...")
f=open("macros.json","r")
s = f.read()
macros = json.loads(s)
print(len(macros['OS']),"Macros")
print("Loaded.")
# return macroname number for given type 'OS', 'Maxwell'
def findMacros(macroname,macrotype):
#print("searching", macroname,'...')
position = -1
for counter in range(len(macros[macrotype])):
#print (counter,macros[macrotype][counter]['name'],macros[macrotype][counter]['code'])
if macroname == macros[macrotype][counter]['name']:
#print(macroname, "is ", counter)
position = counter
return position
# Default top buttons : maxwell macros
def TopMacro(arg):
topbutton, value = arg
print ("topmacro", topbutton, "value", value)
if value == 127:
TopUpdate(topbutton-1,20)
Disp("Ma")
Disp('cr', 'bhoreal')
ModeCallback = TopCallback
def TopCallback(arg):
ClsMatrix()
x,y,velocity = arg
PadNoteOnXY(x,y,20)
#print ('Macros OS', BhorNoteXY(x,y), "velocity", velocity )
macroname = 'm'+str(y)+str(x)
macronumber = findMacros(macroname,'Maxwell')
if macronumber != -1:
#print("code : ",macros['OS'][macronumber]["code"])
eval(macros['Maxwell'][macronumber]["code"])
else:
print("no Code yet")
#
# Notes Macros
#
def ModeNote(arg):
global ModeCallback
topbutton, value = arg
if value == 127:
TopUpdate(topbutton-1,20)
Disp("No")
Disp('te', 'bhoreal')
print("ModeNote")
else:
ClsMatrix()
ModeCallback = "NoteCallback"
def NoteCallback(arg):
#ClsMatrix()
x,y,velocity = arg
notename = midi3.midi2note(BhorNoteXY(x,y))
print('computer',computer)
# todo : decide whether its 0 or 1 !!!
if computer == 0 or computer == 1:
midi3.NoteOn(BhorNoteXY(x,y),velocity,'AutoTonic MIDI In')
else:
SendOSC(computerIP[computer-1],maxwellatorPort,'/note',[BhorNoteXY(x,y),velocity])
if velocity == 127:
PadNoteOnXY(x,y,20)
#print ('NoteON', BhorNoteXY(x,y),notename , "velocity", velocity )
#Disp(notename)
else:
PadNoteOnXY(x,y,0)
#print ('NoteOFF', BhorNoteXY(x,y),notename , "velocity", velocity )
#
# CC Macros
#
def ModeCC(arg):
global ModeCallback
topbutton, value = arg
if value == 127:
TopUpdate(topbutton-1,20)
Disp('CC')
Disp(' ', 'bhoreal')
print("Mode CC")
ModeCallback = "CCSelect"
print("Please enter CC Channel")
#ClsMatrix()
Disp('Ch')
def CCSelect(arg):
global ModeCallback, CChannel
x,y, velocity = arg
PadNoteOnXY(x,y,20)
#print ('in CC channel callback x',x,'y',y)
if velocity == 127:
CChannel = BhorNoteXY(x,y)
print("CC Channel", CChannel)
print("Please enter CC Value")
ModeCallback = "CCValue"
Disp('Va')
def CCValue(arg):
#ClsMatrix()
x,y, velocity = arg
PadNoteOnXY(x,y,20)
#print ('in CC value callback x',x,'y',y)
if velocity == 127:
CCvalue = BhorNoteXY(x,y) * 2
print("CC Channel", CChannel,"CC Value", CCvalue)
#
# OS Macros
#
def ModeOS(arg):
global ModeCallback
topbutton, value = arg
if value == 127:
Disp('Os')
Disp('Ma', 'bhoreal')
TopUpdate(topbutton-1,20)
ModeCallback = "OSCallback"
else:
ClsMatrix()
def OSCallback(arg):
ClsMatrix()
x,y,velocity = arg
PadNoteOnXY(x,y,20)
#print ('Macros OS', BhorNoteXY(x,y), "velocity", velocity )
macroname = 'm'+str(y)+str(x)
macronumber = findMacros(macroname,'OS')
if macronumber != -1:
#print("code : ",macros['OS'][macronumber]["code"])
eval(macros['OS'][macronumber]["code"])
else:
print("no Code yet")
#
# Monome emulation
#
prefix = '/box'
def ModeMonome(arg):
global ModeCallback
topbutton, value = arg
if value == 127:
TopUpdate(topbutton-1,20)
Disp('Mo')
Disp('me', 'bhoreal')
ModeCallback = "MonomeCallback"
else:
ClsMatrix()
def MonomeCallback(arg):
ClsMatrix()
x,y,velocity = arg
#PadNoteOnXY(x,y,20)
SendOSC('127.0.0.1', monomePort, prefix+'/press', (x,y,1))
SendOSC('127.0.0.1', monomePort, prefix+'/grid/key', (x,y,1))
#
# StartMode
#
def ModeNo(arg):
x,y,velocity = arg
PadNoteOnXY(x,y,20)
print ('Mode No x',x,'y',y,"note", PadNoteXY(x,y))
'''
def Mode(mode):
global macros
if mode == "maxwell":
print("Launchpad in Maxwell mode")
macros = maxwellmacros.buttons
if mode == "generic":
print("Launchpad in generic mode")
macros = generic
'''
#
# Right column functions
#
def RightMacro(number):
print ("rightmacro",number)
#
# Default Pad macros
#
launchmacros = {
"t": {"command": TopMacro, "default": -1},
"t1": {"command": ModeNote, "default": ''},
"t2": {"command": ModeCC, "default": ''},
"t3": {"command": ModeOS, "default": ''},
"t4": {"command": ModeMonome, "default": ''},
"t5": {"command": TopMacro, "default": 5},
"t6": {"command": TopMacro, "default": 6},
"t7": {"command": TopMacro, "default": 7},
"t8": {"command": TopMacro, "default": 8},
"r1": {"command": RightMacro, "default": 1},
"r2": {"command": RightMacro, "default": 2},
"r3": {"command": RightMacro, "default": 3},
"r4": {"command": RightMacro, "default": 4},
"r5": {"command": RightMacro, "default": 5},
"r6": {"command": RightMacro, "default": 6},
"r7": {"command": RightMacro, "default": 7},
"r8": {"command": RightMacro, "default": 8}
}
#Mode("generic")
def Run(macroname, macroargs=''):
#print ("macroargs", macroargs)
# Matrix button -> parameters sent to current Function in ModeCallback
if macroname.find("m") == 0:
doit = eval(ModeCallback)
doit((int(macroname[2]),int(macroname[1]), macroargs))
#eval(ModeCallback)((int(macroname[2]),int(macroname[1]), macroargs),)
# Otherwise do the macro
else:
doit = launchmacros[macroname]["command"]
if macroargs=='':
macroargs = launchmacros[macroname]["default"]
#print("Running", doit, "with args", macroargs )
doit(macroargs)
#ComputerUpdate(computer)
LoadMacros()
'''
Docs Community About
monome
osc : opensound control / serialosc protocol
what is serialosc? how does it work?
discovering and connecting to serialosc devices
serialosc server listens on port 12002.
when devices are connected, serialosc spawns new ports for each device. querying the server allows you to discover the port number for each device. (this supersedes the zeroconf method, which is still in place for legacy compatibility).
messages sent to serialosc server
/serialosc/list si <host> <port>
request a list of the currently connected devices, sent to host:port
/serialosc/notify si <host> <port>
request that next device change (connect/disconnect) is sent to host:port. to keep receiving the notifications, send another message to /serialosc/notify from the notify handler.
messages received from serialosc server
/serialosc/device ssi <id> <type> <port>
currently connected device id and type, at this port
/serialosc/add s <id>
device added
/serialosc/remove s <id>
device removed
to serialosc device
sys
these messages can be sent to a serialosc device to change settings.
/sys/port i <port>
change computer port
/sys/host s <host>
change computer host
/sys/prefix s <prefix>
change message prefix (filtering)
/sys/rotation i <degrees>
rotate the monome by degrees, where degrees is one of 0, 90, 180, 270. this replaces /cable
/sys/info si <host> <port>
/sys/info i <port>
/sys/info
info
request information (settings) about this device
/info can take the following arguments:
/info si <host> <port> (send /sys/info messages to host:port)
/info i <port> (send to localhost:port)
/info (send to current computer application's host:port)
example:
to serialosc:
/sys/info localhost 9999
from serialosc to localhost:9999:
/sys/id m0000045
/sys/size 8 16
/sys/host localhost
/sys/port 23849
/sys/prefix /nubs
/sys/rotation 270
from serialosc
these messages are sent from serialosc to the computer port.
the messages below are sent after a /sys/info request is received.
sys
/sys/port i report computer port
/sys/host s report computer host
/sys/id s report device id
/sys/prefix s report prefix
/sys/rotation i report grid device rotation
/sys/size ii report grid device size
to device
grid
/grid/led/set x y s
set led at (x,y) to state s (0 or 1).
/grid/led/all s
set all leds to state s (0 or 1).
/grid/led/map x_offset y_offset s[8]
Set a quad (8×8, 64 buttons) in a single message.
Each number in the list is a bitmask of the buttons in a row, one number in the list for each row. The message will fail if the list doesnt have 8 entries plus offsets.
taken apart:
(/grid/led/map) <- the message/route
(8 8) <- the offsets
(1 2 4 8 16 32 64 128) <- the bitmasks for each row
examples
/grid/led/map 0 0 4 4 4 4 8 8 8 8
/grid/led/map 0 0 254 253 125 247 239 36 191 4
Offsets must be mutliples of 8.
/grid/led/row x_offset y s[..]
Set a row in a quad in a single message.
Each number in the list is a bitmask of the buttons in a row, one number in the list for each row being updated.
examples (for 256)
/grid/led/row 0 0 255 255
/grid/led/row 8 5 255
examples (for 64)
/grid/led/row 0 0 232
/grid/led/row 0 3 129
Offsets must be mutliples of 8. Offsets for monome64 should always be zero.
/grid/led/col x y_offset s[..]
Set a column in a quad in a single message.
Each number in the list is a bitmask of the buttons in a column, one number in the list for each row being updated.
examples (for 256)
/grid/led/col 0 0 255 255 (updates quads 1 and 3)
/grid/led/col 13 8 255 (updates quad 4 due to offset.)
examples (for 64)
/grid/led/col 0 0 232
/grid/led/col 6 0 155
Offsets must be mutliples of 8. Offsets for monome64 should always be zero.
/grid/led/intensity i
variable brightness:
Valid values for l below are in the range [0, 15].
January 2011 devices only support four intensity levels (off + 3 brightness levels). The value passed in /level/ messages will be rounded down to the lowest available intensity as below:
[0, 3] - off
[4, 7] - low intensity
[8, 11] - medium intensity
[12, 15] - high intensity
June 2012 devices allow the full 16 intensity levels.
/grid/led/level/set x y l
/grid/led/level/all l
/grid/led/level/map x_off y_off l[64]
/grid/led/level/row x_off y l[..]
/grid/led/level/col x y_off l[..]
tilt
/tilt/set n s
set active state of tilt sensor n to s (0 or 1, 1 = active, 0 = inactive).
arc
led 0 is north. clockwise increases led number. These can be viewed and tested in the browser at http://nomeist.com/osc/arc/
/ring/set n x l
set led x (0-63) on encoder n (0-1 or 0-3) to level l (0-15)
/ring/all n l
set all leds on encoder n (0-1 or 0-3) to level l (0-15)
/ring/map n l[64]
set all leds on encoder n (0-1 or 0-3) to 64 member array l[64]
/ring/range n x1 x2 l
set leds on encoder n (0-1 or 0-3) between (inclusive) x1 and x3 to level l (0-15). direction of set is always clockwise, with wrapping.
from device
grid
/grid/key x y s
key state change at (x,y) to s (0 or 1, 1 = key down, 0 = key up).
tilt
/tilt n x y z
position change on tilt sensor n, integer (8-bit) values (x, y, z)
arc
/enc/delta n d
position change on encoder n by value d (signed). clockwise is positive.
/enc/key n s
key state change on encoder n to s (0 or 1, 1 = key down, 0 = key up)
Info@monome.org
'''

Binary file not shown.

View File

@ -1,359 +0,0 @@
# coding=UTF-8
'''
lj v0.7.5 for LJ v0.8+
Some LJ functions useful for python 2.7 clients
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 from libs..."
#redisIP = '127.0.0.1'
#r = redis.StrictRedis(host=redisIP, port=6379, db=0)
ClientNumber = 0
name = "noname"
oscrun = True
point_list = []
pl = [[],[],[],[]]
def SendLJ(oscaddress,oscargs=''):
oscmsg = OSCMessage()
oscmsg.setAddress(oscaddress)
oscmsg.append(oscargs)
osclientlj = OSCClient()
osclientlj.connect((redisIP, 8002))
print "lj is sending OSC message : ",oscmsg, "to",redisIP,":8002"
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(redIP,client,myname):
global ClientNumber, name, redisIP
redisIP = redIP
r = redis.StrictRedis(host=redisIP, port=6379, db=0)
ClientNumber = client
#print "client configured",ClientNumber
name = myname
print "Plugin declare its name",name
def LjClient(client):
global ClientNumber
ClientNumber = client
def LjPl(pl):
global PL
PL = pl
# Answer to LJ pings with /pong value
def OSCping(path, tags, args, source):
print name,"got /ping from LJ -> reply /pong", name
SendLJ("/pong",name)
# Closing plugin messages to LJ
def ClosePlugin():
WebStatus(name+" Exiting")
SendLJ("/"+name+"/start",0)
# /quit
def OSCquit(path, tags, args, source):
global oscrun
oscrun = False
print('lj got /quit for',name)
#WebStatus(name + " quit.")
#SendLJ("/"+name+"/start",0)
#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,669 +0,0 @@
{
"ccs": [
{
"_comment": "Oscillator LEFT X Functions",
"Function": "/osc/left/X/curvetype",
"init": "sin"
},
{
"Function": "/osc/left/X/freq",
"init": "1"
},
{
"Function": "/osc/left/X/freqlimit",
"init": "127"
},
{
"Function": "/osc/left/X/amp",
"init": "100"
},
{
"Function": "/osc/left/X/amplimit",
"init": "constant"
},
{
"Function": "/osc/left/X/phasemod",
"init": "64"
},
{
"Function": "/osc/left/X/phasemodlimit",
"init": "linear"
},
{
"Function": "/osc/left/X/phaseoffset",
"init": "64"
},
{
"Function": "/osc/left/X/phaseoffsetlimit",
"init": "manual"
},
{
"Function": "/osc/left/X/ampoffset",
"init": "64"
},
{
"Function": "/osc/left/X/ampoffsetlimit",
"init": "manual"
},
{
"Function": "/osc/left/X/inversion",
"init": "off"
},
{
"_comment": "Oscillator LEFT Y Functions",
"Function": "/osc/left/Y/curvetype",
"init": "sin"
},
{
"Function": "/osc/left/Y/freq",
"init": "1"
},
{
"Function": "/osc/left/Y/freqlimit",
"init": "127"
},
{
"Function": "/osc/left/Y/amp",
"init": "100"
},
{
"Function": "/osc/left/Y/amplimit",
"init": "constant"
},
{
"Function": "/osc/left/Y/phasemod",
"init": "64"
},
{
"Function": "/osc/left/Y/phasemodlimit",
"init": "linear"
},
{
"Function": "/osc/left/Y/phaseoffset",
"init": "64"
},
{
"Function": "/osc/left/Y/phaseoffsetlimit",
"init": "manual"
},
{
"Function": "/osc/left/Y/ampoffset",
"init": "64"
},
{
"Function": "/osc/left/Y/ampoffsetlimit",
"init": "manual"
},
{
"Function": "/osc/left/Y/inversion",
"init": "off"
},
{
"_comment": "Oscillator LEFT Z Functions",
"Function": "/osc/left/Z/curvetype",
"init": "sin"
},
{
"Function": "/osc/left/Z/freq",
"init": "1"
},
{
"Function": "/osc/left/Z/freqlimit",
"init": "127"
},
{
"Function": "/osc/left/Z/amp",
"init": "100"
},
{
"Function": "/osc/left/Z/amplimit",
"init": "constant"
},
{
"Function": "/osc/left/Z/phasemod",
"init": "64"
},
{
"Function": "/osc/left/Z/phasemodlimit",
"init": "linear"
},
{
"Function": "/osc/left/Z/phaseoffset",
"init": "64"
},
{
"Function": "/osc/left/Z/phaseoffsetlimit",
"init": "manual"
},
{
"Function": "/osc/left/Z/ampoffset",
"init": "64"
},
{
"Function": "/osc/left/Z/ampoffsetlimit",
"init": "manual"
},
{
"Function": "/osc/left/Z/inversion",
"init": "off"
},
{
"_comment": "Oscillator RIGHT X Functions",
"Function": "/osc/right/X/curvetype",
"init": "sin"
},
{
"Function": "/osc/right/X/freq",
"init": "1"
},
{
"Function": "/osc/right/X/freqlimit",
"init": "127"
},
{
"Function": "/osc/right/X/amp",
"init": "100"
},
{
"Function": "/osc/right/X/amplimit",
"init": "constant"
},
{
"Function": "/osc/right/X/phasemod",
"init": "64"
},
{
"Function": "/osc/right/X/phasemodlimit",
"init": "linear"
},
{
"Function": "/osc/right/X/phaseoffset",
"init": "64"
},
{
"Function": "/osc/right/X/phaseoffsetlimit",
"init": "manual"
},
{
"Function": "/osc/right/X/ampoffset",
"init": "64"
},
{
"Function": "/osc/right/X/ampoffsetlimit",
"init": "manual"
},
{
"Function": "/osc/right/X/inversion",
"init": "off"
},
{
"_comment": "Oscillator RIGHT Y Functions",
"Function": "/osc/right/Y/curvetype",
"init": "sin"
},
{
"Function": "/osc/right/Y/freq",
"init": "1"
},
{
"Function": "/osc/right/Y/freqlimit",
"init": "127"
},
{
"Function": "/osc/right/Y/amp",
"init": "100"
},
{
"Function": "/osc/right/Y/amplimit",
"init": "constant"
},
{
"Function": "/osc/right/Y/phasemod",
"init": "64"
},
{
"Function": "/osc/right/Y/phasemodlimit",
"init": "linear"
},
{
"Function": "/osc/right/Y/phaseoffset",
"init": "64"
},
{
"Function": "/osc/right/Y/phaseoffsetlimit",
"init": "manual"
},
{
"Function": "/osc/right/Y/ampoffset",
"init": "64"
},
{
"Function": "/osc/right/Y/ampoffsetlimit",
"init": "manual"
},
{
"Function": "/osc/right/Y/inversion",
"init": "off"
},
{
"_comment": "Oscillator RIGHT Z Functions",
"Function": "/osc/right/Z/curvetype",
"init": "sin"
},
{
"Function": "/osc/right/Z/freq",
"init": "1"
},
{
"Function": "/osc/right/Z/freqlimit",
"init": "127"
},
{
"Function": "/osc/right/Z/amp",
"init": "100"
},
{
"Function": "/osc/right/Z/amplimit",
"init": "constant"
},
{
"Function": "/osc/right/Z/phasemod",
"init": "64"
},
{
"Function": "/osc/right/Z/phasemodlimit",
"init": "linear"
},
{
"Function": "/osc/right/Z/phaseoffset",
"init": "64"
},
{
"Function": "/osc/right/Z/phaseoffsetlimit",
"init": "manual"
},
{
"Function": "/osc/right/Z/ampoffset",
"init": "64"
},
{
"Function": "/osc/right/Z/ampoffsetlimit",
"init": "manual"
},
{
"Function": "/osc/right/Z/inversion",
"init": "off"
},
{
"_comment": "LFO 1 Functions",
"Function": "/lfo/1/curvetype",
"init": "sin"
},
{
"Function": "/lfo/1/freq",
"init": "64"
},
{
"Function": "/lfo/1/freqlimit",
"init": "127"
},
{
"Function": "/lfo/1/phase",
"init": "64"
},
{
"Function": "/lfo/1/inversion",
"init": "off"
},
{
"_comment": "LFO 2 Functions",
"Function": "/lfo/2/curvetype",
"init": "sin"
},
{
"Function": "/lfo/2/freq",
"init": "64"
},
{
"Function": "/lfo/2/freqlimit",
"init": "127"
},
{
"Function": "/lfo/2/phase",
"init": "64"
},
{
"Function": "/lfo/2/inversion",
"init": "off"
},
{
"_comment": "LFO 3 Functions",
"Function": "/lfo/3/curvetype",
"init": "sin"
},
{
"Function": "/lfo/3/freq",
"init": "64"
},
{
"Function": "/lfo/3/freqlimit",
"init": "127"
},
{
"Function": "/lfo/3/phase",
"init": "64"
},
{
"Function": "/lfo/3/inversion",
"init": "off"
},
{
"_comment": "Duplicator Functions",
"Function": "/duplicator/num",
"init": "0"
},
{
"Function": "/duplicator/offset",
"init": "0"
},
{
"_comment": "Mixer Functions",
"Function": "/mixer/operation",
"init": "+"
},
{
"Function": "/mixer/value",
"init": "0"
},
{
"_comment": "Intensity Functions",
"Function": "/intensity/mod",
"init": "0"
},
{
"Function": "/intensity/freq",
"init": "0"
},
{
"_comment": "Scaler Functions",
"Function": "/scaler/curvetype",
"init": "sin"
},
{
"Function": "/scaler/speed",
"init": "64"
},
{
"Function": "/scaler/switch",
"init": "off"
},
{
"Function": "/scaler/width",
"init": "64"
},
{
"Function": "/scaler/amt",
"init": "64"
},
{
"Function": "/scaler/scale",
"init": "64"
},
{
"_comment": "Rotator X Functions",
"Function": "/rotator/X/curvetype",
"init": "sin"
},
{
"Function": "/rotator/X/speed",
"init": "64"
},
{
"Function": "/rotator/X/lfo/switch",
"init": "off"
},
{
"Function": "/rotator/X/direct",
"init": "64"
},
{
"_comment": "Rotator Y Functions",
"Function": "/rotator/Y/curvetype",
"init": "sin"
},
{
"Function": "/rotator/Y/speed",
"init": "64"
},
{
"Function": "/rotator/Y/lfo/switch",
"init": "off"
},
{
"Function": "/rotator/Y/direct",
"init": "64"
},
{
"_comment": "Rotator Z Functions",
"Function": "/rotator/Z/curvetype",
"init": "sin"
},
{
"Function": "/rotator/Z/speed",
"init": "64"
},
{
"Function": "/rotator/Z/lfo/switch",
"init": "off"
},
{
"Function": "/rotator/Z/direct",
"init": "64"
},
{
"_comment": "Translator X Functions",
"Function": "/translator/X/curvetype",
"init": "sin"
},
{
"Function": "/translator/X/speed",
"init": "64"
},
{
"Function": "/translator/X/lfo/switch",
"init": "off"
},
{
"Function": "/translator/X/amt",
"init": "64"
},
{
"_comment": "Translator Y Functions",
"Function": "/translator/Y/curvetype",
"init": "sin"
},
{
"Function": "/translator/Y/speed",
"init": "64"
},
{
"Function": "/translator/Y/lfo/switch",
"init": "off"
},
{
"Function": "/translator/Y/amt",
"init": "64"
},
{
"_comment": "Translator Z Functions",
"Function": "/translator/Z/curvetype",
"init": "sin"
},
{
"Function": "/translator/Z/speed",
"init": "64"
},
{
"Function": "/translator/Z/lfo/switch",
"init": "off"
},
{
"Function": "/translator/Z/amt",
"init": "64"
},
{
"_comment": "Colors Functions",
"Function": "/color/colortype",
"init": "solid"
},
{
"Function": "/color/huewidth",
"init": "0"
},
{
"Function": "/color/hueoff",
"init": "0"
},
{
"Function": "/color/huemod",
"init": "0"
},
{
"Function": "/color/huerot",
"init": "0"
},
{
"Function": "/color/intwidth",
"init": "0"
},
{
"Function": "/color/intoff",
"init": "0"
},
{
"Function": "/color/intmod",
"init": "0"
},
{
"Function": "/color/intfreq",
"init": "0"
},
{
"Function": "/color/satwidth",
"init": "0"
},
{
"Function": "/color/satmod",
"init": "0"
},
{
"Function": "/color/saturation",
"init": "127"
},
{
"Function": "/color/modtype",
"init": "sin"
}
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -36,25 +36,30 @@ from rtmidi.midiconstants import (CHANNEL_PRESSURE, CONTROLLER_CHANGE, NOTE_ON,
from mido import MidiFile
import mido
import sys
import midi3, launchpad
import os
ljpath = r'%s' % os.getcwd().replace('\\','/')
from . import midi3, launchpad
#import midimacros, maxwellmacros
import traceback
from queue import Queue
#from libs import macros
import json, subprocess
from OSC3 import OSCServer, OSCClient, OSCMessage
from .OSC3 import OSCServer, OSCClient, OSCMessage
import socket
print('LPD8 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)
print('LPD8 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)))
print(('Used IP', myIP))
OSCinPort = 8080
maxwellatorPort = 8090
@ -104,14 +109,14 @@ def SendOSC(ip,port,oscaddress,oscargs=''):
osclient = OSCClient()
osclient.connect((ip, port))
print("sending OSC message : ", oscmsg, "to", ip, ":", port)
print(("sending OSC message : ", oscmsg, "to", ip, ":", port))
try:
osclient.sendto(oscmsg, (ip, port))
oscmsg.clearData()
return True
except:
print ('Connection to', ip, 'refused : died ?')
print(('Connection to', ip, 'refused : died ?'))
return False
@ -146,16 +151,16 @@ def MidinProcess(LPD8queue):
# Program Change button selected : change destination computer
if msg[0]==PROGRAM_CHANGE:
print("Program change : ", str(msg[1]))
print(("Program change : ", str(msg[1])))
# Change destination computer mode
print("Destination computer",int(msg[1]))
print(("Destination computer",int(msg[1])))
computer = int(msg[1])
# CC rotary -> midi CC.
if msg[0] == CONTROLLER_CHANGE:
print("CC :", msg[1], msg[2])
print(("CC :", msg[1], msg[2]))
if computer == 0 or computer == 1:
cc(int(msg[1]), int(msg[2]))
@ -170,7 +175,7 @@ def MidinProcess(LPD8queue):
def ModeNote(note, velocity, mididest):
print('computer',computer)
print(('computer',computer))
# todo : decide whether its 0 or 1 !!!
if computer == 0 or computer == 1:
@ -218,7 +223,7 @@ class LPD8AddQueue(object):
message, deltatime = event
self._wallclock += deltatime
print()
print("[%s] @%0.6f %r" % (self.port, self._wallclock, message))
print(("[%s] @%0.6f %r" % (self.port, self._wallclock, message)))
LPD8queue.put(message)
#
@ -231,10 +236,18 @@ def LoadMacros():
print()
print("Loading LPD8 Macros...")
f=open("macros.json","r")
if os.path.exists('libs/matrix.json'):
#print('File libs/matrix.json exits')
f=open("libs/matrix.json","r")
elif os.path.exists(ljpath+'/../../libs/matrix.json'):
#print('File '+ljpath+'/../../libs/matrix.json exits')
f=open(ljpath+"/../../libs/matrix.json","r")
s = f.read()
macros = json.loads(s)
print(len(macros['OS']),"Macros")
print((len(macros['OS']),"Macros"))
print("Loaded.")
@ -255,7 +268,7 @@ def findMacros(macroname,macrotype):
# Not assigned buttons
def DefaultMacro(arg):
print ("DefaultMacro", arg)
print(("DefaultMacro", arg))

2873
libs3/OSC3.py Normal file

File diff suppressed because it is too large Load Diff

212
libs3/OSCom.py Normal file
View File

@ -0,0 +1,212 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
OSCcom for jamidi v0.1b
OSCom.Start(serverIP, OSCPORT)
default handler : handler(path, tags, args, source)
register particular OSC command in Start(): i.e oscserver.addMsgHandler( "/n", Note)
Launch
print("Launching OSC Server", serverIP,':', OSCPORT)
OSCom.Start(serverIP, OSCPORT)
'''
from . import midi3
#import socket
import types, json
from .OSC3 import OSCServer, OSCClient, OSCMessage
import _thread, time
from . import gstt
import WScom, UDPcom
from . import midi3
#base36 = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
def GetTime():
return time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())
# this method of reporting timeouts only works by convention
# that before calling handle_request() field .timed_out is
# set to False
def handle_timeout(self):
self.timed_out = True
def Start(serverIP, OSCPORT):
global oscserver
#print(GetTime(),gstt.oscname, gstt.Confs[gstt.oscname][0]["midichan"])
#print(gstt.Confs)
#print(gstt.Confs[gstt.oscname])
for i in range(len(gstt.Confs[gstt.oscname])):
print((GetTime(),gstt.oscname, gstt.Confs[gstt.oscname][i]["midichan"]))
oscserver = OSCServer( (serverIP, OSCPORT) )
oscserver.timeout = 0
# funny python's way to add a method to an instance of a class
import types
oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver)
oscserver.addMsgHandler( "default", handler )
oscserver.addMsgHandler( "/n", Note)
oscserver.addMsgHandler( "/c", CC)
oscserver.addMsgHandler( "/p", PB)
_thread.start_new_thread(osc_thread, ())
# RAW OSC Frame available ?
def OSCframe():
# clear timed_out flag
oscserver.timed_out = False
# handle all pending requests then return
while not oscserver.timed_out:
oscserver.handle_request()
# OSC server Thread : handler, dacs reports and simulator points sender to UI.
def osc_thread():
#print("osc Thread launched")
try:
while True:
time.sleep(0.005)
OSCframe()
except Exception as e:
import sys, traceback
print('\n---------------------')
print(('Exception: %s' % e))
print('- - - - - - - - - - -')
traceback.print_tb(sys.exc_info()[2])
print("\n")
# Properly close the system. Todo
def Stop():
oscserver.close()
# default handler
def handler(path, tags, args, source):
oscaddress = ''.join(path.split("/"))
print()
print(("Jamidi Default OSC Handler got from " + str(source[0]),"OSC msg", path, "args", args))
#print("OSC address", path)
#print("find.. /bhoreal ?", path.find('/bhoreal'))
if len(args) > 0:
#print("with args", args)
pass
'''
# for example
if path == '/truc':
arg1 = args[0]
arg2 = args[1])
'''
'''
MIDI NOTES
=n in ORCA
/n in OSC
ORCA OSC
=nmonv /n m o n v
m : midi channel (0-15 / ORCA 0-F)
o : octave (0-8 / ORCA 0-7)
n : Note A to G
v : velocity 0-Z will output (v/36)*127
'''
def Note(path, tags, args, source):
#print('Note from ORCA received',args)
midichannel = int(args[0],36)
octave = int(args[1],36)
note = args[2]
velocity = int((int(args[3],36)/36)*127)
if note.istitle() == True:
notename = str(note)+ str(octave)
else:
notename = str(note)+ "#"+ str(octave)
if gstt.debug > 0:
print(("incoming note", note, octave, notename, midi3.note2midi(notename) ))
for mididevice in midi3.findJamDevices(gstt.oscname):
midi3.NoteOn(midi3.note2midi(notename), velocity, mididevice)
#midi3.NoteOn(int(wspath[1]), int(wspath[2]), gstt.Confs[wscommand[1]][0]["mididevice"])
'''
CC
=c in ORCA
/c in OSC
ORCA OSC
=cmcd /c m n d
m : midi channel
n : number (0-35 / ORCA 0-Z)
d : data 0-Z will output (d/36)*127
'''
def CC(path, tags, args, source):
midichannel = int(args[0],36)
ccvr = int(args[1],36)
ccvl = int((int(args[2],36)/36)*127)
if gstt.debug > 0:
print(("ccvr=%d/ccvl=%d"%(ccvr,ccvl)))
if gstt.oscname == "ocs2":
gstt.crtvalueOCS2[ccvr]=ccvl
else:
gstt.crtvalueMMO3[ccvr]=ccvl
for mididevice in midi3.findJamDevices(gstt.oscname):
midi3.cc(gstt.Confs[gstt.oscname][0]["midichan"], ccvr, ccvl, mididevice)
def PB(path, tags, args, source):
#print("Pitch number",ccnumber, value)
midichannel = int(args[0])
ccnumber = int(args[1])
ccdata = int(args[3])
'''
# If needed to send some OSC
def SendOSC(ip,port,oscaddress,oscargs=''):
oscmsg = OSCMessage()
oscmsg.setAddress(oscaddress)
oscmsg.append(oscargs)
osclient = OSCClient()
osclient.connect((ip, port))
if gstt.debug == True :
print("sending OSC message : ", oscmsg, "to", ip, ":", port)
try:
osclient.sendto(oscmsg, (ip, port))
oscmsg.clearData()
return True
except:
print ('Connection to', ip, 'refused : died ?')
return False
'''

107
libs3/alink.py Normal file
View File

@ -0,0 +1,107 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
Ableton Link
LICENCE : CC
Sam Neurohack
Get:
git clone --recursive https://github.com/gonzaloflirt/link-python.git
Build:
Make sure python 3 is installed on your system.
mkdir build
cd build
cmake ..
cmake --build .
'''
import midix
import sys
prevphase = 0
bpm = 120
def Start():
global lnk
import link
print("Link ENABLED")
lnk = link.Link(120)
lnk.enabled = True
lnk.startStopSyncEnabled = True
linked = True
def BeatEvent():
global lnk, prevphase
lnkstr = lnk.captureSessionState()
link_time = lnk.clock().micros();
tempo_str = '{0:.2f}'.format(lnkstr.tempo())
bpm = float(tempo_str)
#beatstep.SendOSCUI('/bpm', [bpm])
beats_str = '{0:.2f}'.format(lnkstr.beatAtTime(link_time, 0))
playing_str = str(lnkstr.isPlaying()) # always False ???
phase = lnkstr.phaseAtTime(link_time, 4)
# new beat ?
if int(phase) != prevphase:
prevphase = int(phase)
#print("LINK BPM:",bpm)
sys.stdout.write("Beat "+str(beats_str) + ' \r')
sys.stdout.flush()
midix.SendUI('/beats', [beats_str])
#alink.SendOSCUI('/states/cc/'+str(ccnumber), [value])
currentbeat = float(beats_str)
#midix.SendAU('/aurora/beats', beats_str)
#AllStatus("Beat "+str(beats_str))
# Change current Link Tempo.
def newtempo(tempo):
global lnk
#print("val2", val2, "tempo", tempo)
if linked == True:
lnk.enabled = False
lnk.startStopSyncEnabled = False
lnk = link.Link(tempo)
lnk.enabled = True
lnk.startStopSyncEnabled = True
bpm = tempo
print(("New BPM", bpm))
midix.SendUI('/bpm', [bpm])
else:
print("Link is disabled")
#
def BPMAdj(val1, keyname):
print((gstt.currentbpm))
# + 1
if val1 == 1:
newtempo(gstt.currentbpm+1)
# -1
if val1 == 127 and gstt.currentbpm > 0:
newtempo(gstt.currentbpm-1)

View File

@ -20,6 +20,7 @@ banck change/scene/
"""
import random
import pysimpledmx
from serial.tools import list_ports
@ -32,8 +33,10 @@ from sys import platform, version
import sys
import argparse, traceback
import os
import log
is_py2 = version[0] == '2'
if is_py2:
from OSC import OSCServer, OSCClient, OSCMessage
else:
@ -48,8 +51,7 @@ ljpath = r'%s' % os.getcwd().replace('\\','/')
#import from LJ
sys.path.append(ljpath +'/libs/')
import lj23 as lj
import lj23layers as lj
#
# Init
@ -73,7 +75,7 @@ for i in range(1,514):
print ("")
print ("Artnet v0.1")
log.infog("Artnet v0.1")
print ("Arguments parsing if needed...")
argsparser = argparse.ArgumentParser(description="Artnet & DMX for LJ")
argsparser.add_argument("-u","--universe",help="Universe, not implemented (0 by default)",type=int)
@ -146,7 +148,7 @@ def updateDmxValue(channel, val):
# DMX UPDATE!!! WOW!!!
if dmxstates[channel] != val:
dmxstates[channel] = val
print("updating channel", channel, "with ", val )
print("updating channel", channel, "with ", val)
if mydmx != False:
senddmx(channel, ord(val))
@ -155,7 +157,7 @@ def updateDmxValue(channel, val):
#ljnozoids.WebStatus("Available serial devices")
print("")
print("Available serial devices...")
ports = list(list_ports.comports())
@ -219,10 +221,10 @@ oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver)
def OSChandler(path, tags, args, source):
oscaddress = ''.join(path.split("/"))
print("Default OSC Handler : msg from Client : " + str(source[0]),)
print("OSC address", path, "with",)
print(("Default OSC Handler : msg from Client : " + str(source[0]),))
print(("OSC address", path, "with",))
if len(args) > 0:
print("args", args)
print(("args", args))
else:
print("noargs")
#oscIPout = str(source[0])
@ -259,15 +261,19 @@ lj.addOSCdefaults(oscserver)
lj.SendLJ("/pong", "artnet")
lj.WebStatus("Artnet Running...")
log.infog("Artnet running...")
print()
oscserver.addMsgHandler( "/sendmx", OSCsendmx )
#
# Running...
#
'''
print ("Starting, use Ctrl+C to stop")
print (lj.oscrun)
'''
try:
@ -287,7 +293,7 @@ try:
print("OpDmx")
continue
print ("oscrun", lj.oscrun)
print(("oscrun", lj.oscrun))
protverhi = ord(data[10])
protverlo = ord(data[11])
sequence = ord(data[12])
@ -298,9 +304,9 @@ try:
length = ord(data[17])
dmx = data[18:]
print (data[0:7], "version :",lhex(data[10])+lhex(data[11]), "sequence :", sequence, "physical", physical, "subuni",subuni,"net", net)
print((data[0:7], "version :",lhex(data[10])+lhex(data[11]), "sequence :", sequence, "physical", physical, "subuni",subuni,"net", net))
for i in xrange(0,510):
for i in range(0,510):
updateDmxValue(i+1,dmx[i])

6
libs/audio.py → libs3/audio.py Executable file → Normal file
View File

@ -63,11 +63,11 @@ def list_devices():
p = pyaudio.PyAudio()
i = 0
n = p.get_device_count()
print (n,"devices found")
print((n,"devices found"))
while i < n:
dev = p.get_device_info_by_index(i)
if dev['maxInputChannels'] > 0:
print (str(i)+'. '+dev['name'])
print((str(i)+'. '+dev['name']))
i += 1
@ -83,7 +83,7 @@ def valid_input_devices(self):
if len(mics)==0:
print("no microphone devices found!")
else:
print("found %d microphone devices: %s"%(len(mics),mics))
print(("found %d microphone devices: %s"%(len(mics),mics)))
return mics

View File

@ -28,7 +28,7 @@ from /team/laser
import time
from rtmidi.midiconstants import (CHANNEL_PRESSURE, CONTROLLER_CHANGE, NOTE_ON, NOTE_OFF,
PITCH_BEND, POLY_PRESSURE, PROGRAM_CHANGE)
import gstt, midi3
from . import gstt, midi3
import sys
gstt.BhorLeds = [0]*65
@ -39,7 +39,7 @@ from queue import Queue
def NoteOn(note,color):
print ("bhoreal noteon", note, color)
print(("bhoreal noteon", note, color))
msg = [NOTE_ON, note, color]
midi3.send(msg,"Bhoreal")
gstt.BhorLeds[note]=color
@ -201,7 +201,7 @@ def MidinProcess(bhorqueue):
msg = bhorqueue_get()
# Bhoreal Led pressed
print ("Bhoreal Matrix : ", str(msg[1]), gstt.BhorLeds[msg[1]])
print(("Bhoreal Matrix : ", str(msg[1]), gstt.BhorLeds[msg[1]]))
if msg[0] == NOTE_ON and msg[2] == 64:
# led
@ -253,7 +253,7 @@ class AddQueue(object):
def __call__(self, event, data=None):
message, deltatime = event
self._wallclock += deltatime
print("[%s] @%0.6f %r" % (self.portname, self._wallclock, message))
print(("[%s] @%0.6f %r" % (self.portname, self._wallclock, message)))
bhorqueue.put(message)
'''

View File

@ -12,11 +12,9 @@ from /team/laser
"""
import gstt
from libs3 import gstt
import argparse
print "-h will display help"
print ""
import subprocess
def handle():
@ -24,7 +22,7 @@ def handle():
#have to be done before importing bhorosc.py to get correct port assignment
argsparser = argparse.ArgumentParser(description="LJ v0.8")
argsparser.add_argument("-r","--redisIP",help="IP address to bind builtin servers (OSC and websocket) also must be the Redis server IP ",type=str)
argsparser.add_argument("-L","--Lasers",help="Number of lasers connected (4 by default).",type=int)
argsparser.add_argument("-L","--Lasers",help="Number of lasers requested (Autodetected by default).",type=int)
argsparser.add_argument("-v","--verbose",help="Debug mode 0,1 or 2 (0 by default)",type=int)
argsparser.add_argument("-x","--invx",help="Invert laser 0 X axis again",action="store_true")
argsparser.add_argument("-y","--invy",help="Invert laser 0 Y axis again",action="store_true")
@ -34,6 +32,7 @@ def handle():
argsparser.add_argument("-n","--nozoidIP",help="IP for llstr' Nozoid OSC server port 8003 ('127.0.0.1' by default)",type=str)
argsparser.add_argument("-b","--bhoroscIP",help="IP for OSC output ('127.0.0.1' by default)",type=str)
argsparser.add_argument("-o","--oport",help="OSC output port number (8001 by default)",type=int)
argsparser.add_argument("-w","--webui",help="Regen the webui",action="store_true")
@ -50,6 +49,10 @@ def handle():
else:
gstt.debug = 0
# Webui regen
if args.webui == True:
subprocess.call(['python','webui/build.py'])
# Ports arguments
if args.iport:
iport = args.iport
@ -64,8 +67,8 @@ def handle():
oport = gstt.oport
if gstt.debug > 0:
print "Accept OSC on port",gstt.oport
print "gstt.iport:",gstt.iport
print("Accept OSC on port",gstt.oport)
print("gstt.iport:",gstt.iport)
# X Y inversion arguments
@ -102,15 +105,15 @@ def handle():
# Point list number used by simulator
if args.display != None:
gstt.simuPL = args.display
print "Display : " + str(gstt.simuPL)
print("Display : " + str(gstt.simuPL))
# Lasers = number of laser connected
# Lasers = number of laser connected otherwise will be autodetected with one minimum
if args.Lasers != None:
gstt.LaserNumber = args.Lasers
else:
gstt.LaserNumber = 4
gstt.LaserNumber = -1
if args.bhoroscIP != None:
@ -154,4 +157,4 @@ def handle():
gstt.swapy[0] = 1
#Settings.Write()
handle()
handle()

View File

@ -6,11 +6,16 @@ v0.7.0
LICENCE : CC
by Sam Neurohack, Loloster,
by Sam Neurohack, Loloster
from /team/laser
Commands reference. Use commands from websocket (webUI) or OSC, do not set values in redis directly except for /pl.
DAChecks()
UpdateAllwww()
/forwardui "htmlid args"
/scale/X/lasernumber value
/scale/Y/lasernumber value
@ -38,22 +43,27 @@ lsteps is a string like "[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]"
/swap/X/lasernumber value (0 or 1)
/swap/Y/lasernumber value (0 or 1)
/loffset/X/lasernumber value : change X offset of 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
/order value : instruct tracer what to do.
/planet will be forwarded to planetarium client.
/nozoid will be forwarded to nozoid client.
/scene/scenenumber/start 0 or 1
0 : display user pointlist with current client key. See below for client key.
1 : pull in redis a new correction matrix (EDH)
2 : display black
3 : display grid
4 : resampler
5 : pull in redis a new client key
6 : Max Intensity Change = reread redis key /intensity
7 : kpps change = reread redis key /kpps
8 : color balance change = reread redis keys /red /green /blue
/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.
/pl/clientnumber/lasernumber value : value is the pointlist to draw as string type. For string format see code in clients directory.
@ -78,56 +88,57 @@ 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
from libs import gstt
import redis
from libs import settings, plugins, homographyp
import types, time, socket
from libs3 import gstt
import redis
from libs3 import settings, plugins, homographyp
r = redis.StrictRedis(host=gstt.LjayServerIP , port=6379, db=0)
#r = redis.StrictRedis(host=gstt.LjayServerIP , port=6379, db=0, password='-+F816Y+-')
GenericCommands = ["start","align","ljclient","scene","addest","deldest","clientnumber","vcvrack","fft","midigen","viewgen","audiogen","noteon","cc","ljpong","ljwars","mouse","emergency","simu","status","run","nozoid","planet","live","words","ai","bank0","pose","lj","cycl","glyph","pong"]
GenericCommands = ["start","align","ljclient","scene","addest","deldest","dest","clientnumber","vcvrack","fft","mitraille","faceosc","midigen","viewgen","audiogen","noteon","cc","ljpong","ljwars","mouse","emergency","simu","status","run","nozoid","planet","live","words","ai","bank0","pose","lj","cycl","glyph","pong","maxw","custom1","square","regen","trckr","aurora","line1","ForwardUI","settings","debug","pl"]
def UserOn(laser):
print "User for laser ", laser
print("User for laser ", laser)
plugins.sendWSall("/status User on laser " + str(laser))
r.set('/order/'+str(laser), 0)
def NewEDH(laser):
print "New EDH requested for laser ", laser
print("New EDH requested for laser ", laser)
plugins.sendWSall("/status New EDH on laser " + str(laser))
settings.Write()
print "Settings saving swapX ", gstt.swapX[laser]
print "Settings saving swapY ", gstt.swapY[laser]
print("Settings saving swapX ", gstt.swapX[laser])
print("Settings saving swapY ", gstt.swapY[laser])
homographyp.newEDH(laser)
def BlackOn(laser):
print "Black for laser ", laser
print("Black for laser ", laser)
plugins.sendWSall("/status Black on laser " + str(laser))
r.set('/order/'+str(laser), 2)
def GridOn(laser):
print "Grid for laser ", laser
print("Grid for laser ", laser)
plugins.sendWSall("/status Grid on laser " + str(laser))
r.set('/order/'+str(laser), 3)
def Resampler(laser,lsteps):
def Resampler(laser,args):
# lsteps is a string like : "[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]"
print "Resampler change for laser ", laser
r.set('/resampler/' + str(laser), lsteps)
print("Resampler change for laser", laser, "[("+str(args[0])+","+str(args[1])+"),("+str(args[2])+","+str(args[3])+"),("+str(args[4])+","+str(args[5])+"),("+str(args[6])+","+str(args[7])+")]")
#r.set('/resampler/' + str(laser), lsteps)
r.set('/resampler/' + str(laser), "[("+str(args[0])+","+str(args[1])+"),("+str(args[2])+","+str(args[3])+"),("+str(args[4])+","+str(args[5])+"),("+str(args[6])+","+str(args[7])+")]")
r.set('/order/'+str(laser), 4)
@ -135,37 +146,37 @@ def LasClientChange(clientnumber):
if r.get("/pl/"+str(clientnumber)+"/0") != None:
print "Switching to laser client", clientnumber
print("Switching to laser client", clientnumber)
gstt.SceneNumber = clientnumber
plugins.sendWSall("/status Client " + str(gstt.SceneNumber) + " laser " + str(gstt.Laser))
r.set('/clientkey', "/pl/"+str(clientnumber)+"/")
print "clientkey set to", "/pl/"+str(clientnumber)+"/"
for laserid in xrange(0,gstt.LaserNumber):
print("clientkey set to", "/pl/"+str(clientnumber)+"/")
for laserid in range(0,gstt.LaserNumber):
r.set('/order/'+str(laserid), 5)
else:
print "ERROR : Maximum number of scenes is set to ", gstt.MaxScenes
print("ERROR : Maximum number of scenes is set to ", gstt.MaxScenes)
def SceneChange(newscene):
print "Switching to scene", newscene
print("Switching to scene", newscene)
gstt.SceneNumber = int(newscene)
plugins.sendWSall("/status Scene " + newscene)
r.set('/clientkey', "/pl/"+ newscene +"/")
print "clientkey set to", "/pl/" + newscene + "/"
print("clientkey set to", "/pl/" + newscene + "/")
for laserid in xrange(0,gstt.LaserNumber):
for laserid in range(0,gstt.LaserNumber):
r.set('/order/'+str(laserid), 5)
plugins.sendWSall("/scene/" + str(laserid) + "/start 0")
plugins.sendWSall("/scene/" + newscene + "/start 1")
# Change current laser and send "/scim lasernumber to each plugin"
def NoteOn(note):
print "NoteOn", note
print("NoteOn", note)
# Change laser client
if note < 8:
@ -174,36 +185,78 @@ def NoteOn(note):
# Change PL displayed on webui
if note > 23 and note < 32:
if note - 24 > gstt.LaserNumber -1:
print "Only",gstt.LaserNumber,"lasers asked, you dum ass !"
plugins.sendWSall("/status Not Enough Lasers")
print("Only",gstt.LaserNumber,"lasers asked, you dum ass !")
plugins.sendWSall("/redstatus No Laser"+str(note-24))
plugins.sendWSall("/laser "+str(gstt.LaserNumber-1))
else:
gstt.Laser = note -24
plugins.sendWSall("/status Scene " + str(gstt.SceneNumber) + " laser " + str(gstt.Laser))
print "Current Laser switched to", gstt.Laser
plugins.sendWSall("/status Laser " + str(gstt.Laser))
plugins.SendAll("/scim "+str(gstt.Laser))
print("Current Laser switched to", gstt.Laser)
def Scim(path, tags, args, source):
laser = int(args[0])
print("OSC /scim", laser)
# Change PL displayed on webui
if laser > 23 and laser < 32:
if laser - 24 > gstt.LaserNumber -1:
print("Only",gstt.LaserNumber,"lasers asked, you dum ass !")
plugins.sendWSall("/redstatus No Laser"+str(note-24))
plugins.sendWSall("/laser "+str(gstt.LaserNumber-1))
else:
gstt.Laser = laser -24
plugins.sendWSall("/status Laser " + str(gstt.Laser))
print("Current Laser switched to", gstt.Laser)
def Line1(path, tags, args, source):
line1 = args[0]
print("OSC /line1", line1)
plugins.sendWSall("/line1 " +"Fx "+line1)
# forward
def ForwardUI(path, tags, args, source):
line = args[0]
print("OSC /forwardui to WebUI :", line)
print('from path', path, 'args', args)
plugins.sendWSall(line)
def CC(number, value):
print "CC", note, value
print("CC", note, value)
def Mouse(x1,y1,x2,y2):
print "Mouse", x1,y1,x2,y2
print("Mouse", x1,y1,x2,y2)
def handler(oscpath, args):
#print ""
print("OSC handler in commands.py got /"+ str(oscpath)+ " with args :",args)
if gstt.debug > 0:
print "OSC handler in commands.py got /"+ str(oscpath)+ " with args :",args
print("OSC handler in commands.py got /"+ str(oscpath)+ " with args :",args)
# 2 incoming cases : generic or specific for a given lasernumber :
# Generic : Commands without a laser number
#
# Generic : Commands without a laser number
#
if oscpath[1] in GenericCommands:
if gstt.debug > 0:
print "GenericCommand :",oscpath[1],"with args",args
print("GenericCommand :", oscpath[1], "with args", args)
if oscpath[1] == "ljclient":
@ -211,30 +264,42 @@ def handler(oscpath, args):
SceneChange(args[0])
if oscpath[1] == "pl":
r.set(oscpath, args[0])
#/scene/scenenumber/start 0 or 1
if oscpath[1] == "scene":
print oscpath[1], oscpath[2], args[0]
print(oscpath[1], oscpath[2], args[0])
if args[0] == '1' and r.get("/pl/" + oscpath[2] + "/0") != None:
SceneChange(oscpath[2])
else:
print "ERROR : Maximum number of scenes is set to ", gstt.MaxScenes
print("ERROR : Maximum number of scenes is set to ", gstt.MaxScenes)
elif oscpath[1] == "noteon":
NoteOn(int(args[0]))
# regen index.html (python build.py)
elif oscpath[1] == "regen":
subprocess.Popen(["python", plugins.ljpath + "/webui/build.py"])
# todo
elif oscpath[1] == "CC":
CC(int(args[0]), int(args[1]))
elif oscpath[1] == "pong":
#print "LJ commands got pong from", args
print("/" + args[0] + "/start 1")
if gstt.debug >0:
print(("/" + args[0] + "/start 1"))
print(("/status got pong from "+ args[0] +"."))
plugins.sendWSall("/" + args[0] + "/start 1")
print("/status got pong from "+ args[0] +".")
plugins.sendWSall("/status got pong from "+ args[0] +".")
#plugins.sendWSall("/status got pong from "+ args[0] +".")
elif oscpath[1] == "vcvrack":
@ -259,23 +324,71 @@ def handler(oscpath, args):
if args[0] == "1":
for laser in range(gstt.lasernumber):
print "Black requested for laser ", laser
print("Black requested for laser ", laser)
BlackOn(laser)
print "EMERGENCY MODE"
print("EMERGENCY MODE")
plugins.sendWSall("/status EMERGENCY MODE")
else:
for laser in range(gstt.lasernumber):
print "Back to normal for laser ", laser
print("Back to normal for laser ", laser)
UserOn(laser)
# Settings commands :
elif oscpath[1] == "settings":
if oscpath[2] == "lasers":
print()
print("new laser number",args[0])
print()
if oscpath[2] == "regen":
print()
print("Regen www pages...")
UpdateAllwww()
if oscpath[2] == "IP":
print()
print("new server IP for www regen",args[0])
gstt.wwwIP = args[0]
if oscpath[2] == "debug":
print()
print("Debug level",args[0])
print()
gstt.debug = int(args[0])
plugins.SendAll("/debug "+str(gstt.debug))
if oscpath[2] == "rescan":
print()
print("Rescanning DACs...")
DAChecks()
print("Done.")
if oscpath[2] == "rstrt":
print()
print("Restarting", args[0], "...")
if args[0] == "lj":
raise Restart(time.asctime())
else:
plugins.Restart(args[0])
print()
#
# Commands with a laser number
else:
pathlength = len(oscpath)
print("oscpath", oscpath)
#
print("pathlength", pathlength)
else:
pathlength = len(oscpath)
if gstt.debug > 0:
print("Non Generic Command :", oscpath[1], "with args", args)
#print "oscpath", oscpath
#print "pathlength", pathlength
#print "args", args
if pathlength == 3:
laser = int(oscpath[2])
@ -283,22 +396,22 @@ def handler(oscpath, args):
else:
laser = int(oscpath[3])
print "args[0] :",args[0]," ", type(args[0])
#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
print("Grid requested for laser ", laser)
GridOn(laser)
else:
print "No grid for laser ", laser
print("No grid for laser ", laser)
UserOn(laser)
# /ip/lasernumber value
if oscpath[1] == "ip":
print "New IP for laser ", laser
print("New IP for laser ", laser)
gstt.lasersIPS[laser]= args[0]
settings.Write()
@ -306,76 +419,81 @@ def handler(oscpath, args):
# /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])
print("New kpps for laser ", laser, " next startup", int(args[0]))
gstt.kpps[laser]= int(args[0])
settings.Write()
r.set('/kpps/' + str(laser), str(args[0]))
r.set('/order/'+str(laser), 7)
# /angle/lasernumber value
if oscpath[1] == "angle":
print "New Angle modification for laser ", oscpath[2], ":", float(args[0])
print("New Angle modification for laser ", oscpath[2], ":", float(args[0]))
gstt.finANGLE[laser] += float(args[0])
NewEDH(laser)
print "New angle", gstt.finANGLE[laser]
print("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"
print("LJ2 : New intensity requested for laser ", laser, ":", int(args[0]))
plugins.sendWSall("/status Intensity " + str(args[0]))
r.set('/intensity/' + str(laser), str(args[0]))
r.set('/order/'+str(laser), 6)
# /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])
#print"resampler with args", args
Resampler(laser,args)
# /mouse/lasernumber value (0 or 1)
if oscpath[1] == "mouse":
if args[0] == "1":
print "Mouse requested for laser ", oscpath[2]
print("Mouse requested for laser ", oscpath[2])
gstt.Laser = oscpath[2]
else:
print "No mouse for laser ", oscpath[2]
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]
print("swapX was", gstt.swapX[laser])
if args[0] == "0":
print "swap X -1 for laser ", laser
print("swap X -1 for laser ", laser)
gstt.swapX[laser]= -1
NewEDH(laser)
else:
print "swap X 1 for laser ", laser
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]
print("swapY was", gstt.swapX[laser])
if args[0] == "0":
print "swap Y -1 for laser ", laser
print("swap Y -1 for laser ", laser)
gstt.swapY[laser]= -1
NewEDH(laser)
else:
print "swap Y 1 for laser ", laser
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]
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]
print("offset/Y laser", laser, "modified to", args[0])
gstt.centerY[laser] -= int(args[0])
NewEDH(laser)
@ -384,16 +502,119 @@ def handler(oscpath, args):
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]
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]
print("scale/Y laser", laser, "modified to", gstt.zoomY[laser])
NewEDH(laser)
#
# Different useful codes for some commands
#
def Updatewww(file_name):
print("updating", file_name)
f=open(file_name,"r+")
a=f.readlines()
for line in a:
if "var LJ = " in line == True:
p=a.index(line)
#so now we have the position of the line which to be modified
a[p]=" var LJ = 'ws://"+gstt.wwwIP+":9001/'\n"
#print(p, line, a[p])
f.seek(0)
f.truncate() #ersing all data from the file
f.close()
#so now we have an empty file and we will write the modified content now in the file
o=open(file_name,"w")
for i in a:
o.write(i)
o.close()
#now the modification is done in the file
# Change
def UpdateAllwww():
print("Updating all www pages...")
Updatewww(gstt.ljpath+"/www/LJ.js")
Updatewww(gstt.ljpath+"/www/trckr/trckrcam1.html")
Updatewww(gstt.ljpath+"/www/simu.html")
Updatewww(gstt.ljpath+"/www/align.html")
Updatewww(gstt.ljpath+"/www/gen0.html")
Updatewww(gstt.ljpath+"/www/aur0.html")
Updatewww(gstt.ljpath+"/www/aur0s.html")
Updatewww(gstt.ljpath+"/www/aur1.html")
Updatewww(gstt.ljpath+"/www/auralls.html")
Updatewww(gstt.ljpath+"/www/index.html")
def isOpen(ip):
dacksock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
dacksock.settimeout(1)
istate = False
try:
dacksock.connect((ip, 7765))
#s.shutdown(2)
istate = True
dacksock.shutdown(socket.SHUT_RDWR)
except:
time.sleep(1)
finally:
dacksock.close()
return istate
'''
def isconnected(IP):
ipup = False
for i in range(retry):
if isOpen(IP, 7765):
ipup = True
break
else:
time.sleep(delay)
return ipup
'''
# autodetect connected DACs. Will change gstt.LaserNumber. One at least
def DAChecks():
gstt.dacs = [-1, -1, -1, -1]
gstt.dacnumber = 0
print("Searching DACs...")
for dac in range(gstt.maxdacs):
if isOpen(gstt.lasersIPS[dac]):
print("DAC", dac, "at", gstt.lasersIPS[dac], ": UP")
gstt.dacs[gstt.dacnumber] = dac
gstt.dacnumber +=1
else:
print("DAC", dac, "at", gstt.lasersIPS[dac], ": DOWN")
# At least one.
if gstt.dacnumber == 0:
gstt.dacs = [0, -1, -1, -1]
gstt.dacnumber = 1
gstt.LaserNumber = gstt.dacnumber
'''
For reference values of EDH modifier if assign to keyboard keys (was alignp)

2
libs/font1.py → libs3/font1.py Executable file → Normal file
View File

@ -11,7 +11,7 @@ from /team/laser
"""
import gstt
from libs3 import gstt
def DigitsDots(number,color):
dots =[]

View File

@ -5,10 +5,10 @@ LJ Global state
v0.8.0
**
Almost all values here Will be overriden by LJ.conf file data
Almost all values here Will be overriden by data in LJ.conf at startup
**
LICENCE : CC
LICENCE : CC BY
by Sam Neurohack, Loloster, pclf
from /team/laser
@ -18,11 +18,12 @@ from /team/laser
ConfigName = "LJ.conf"
debug = 0
ljpath=''
anims= [[],[],[],[]]
# How many lasers are connected. Different that "currentlaser".
LaserNumber = 2
# How many lasers are connected. Different that "currentlaser" and "dacnumber" (=autodetected)
LaserNumber = -1
# What laser client to listen at launch
SceneNumber = 0
@ -34,6 +35,7 @@ xy_center = [screen_size[0]/2,screen_size[1]/2]
LjayServerIP = '192.168.1.13'
oscIPin = '192.168.1.15'
nozoscip = '192.168.1.15'
wwwIP = '192.168.1.15'
# gstt.Laser select to what laser modifcation will occur.
# Can be changed with /noteon 16-23
@ -46,11 +48,20 @@ simuPL = 1
# gstt.laserIPS.
lasersIPS = ['192.168.1.5','192.168.1.6','192.168.1.3','192.168.1.4']
maxdacs = 4
# Autodetected by DAChecks() in main3 :
# Store connected dacs. Maybe laser 1 in LJ.conf is not connected but Laser 2 is.
dacs = [-1, -1, -1, -1]
# Actual number of connected DACs
dacnumber = 0
# gstt.kpps stores kpps for each laser.
# ** Will be overridden by LJ.conf file values **
kpps = [25000,25000,25000,25000]
lasertype = ["LOCAL","LOCAL","LOCAL","LOCAL"]
intensity = [-1,-1,-1,-1]
# gstt.GridDisplay : if = 1 Curve points actually sent to PL are replaced by a grid
GridDisplay = [0,0,0,0]
@ -71,6 +82,8 @@ lstt_points = [[0], [0], [0], [0]]
swapX = [1,1,1,-1]
swapY = [1,1,1,-1]
lsteps = [[],[],[],[]]
# 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.
@ -128,3 +141,12 @@ warpdest = [[[ 1. , 0. , 0.],[ 0. , 1. , 0.],[ 0. , 0. , 1.]],
[[ 1. , 0. , 0.],[ 0. , 1. , 0.],[ 0. , 0. , 1.]]
]
BeatstepLayer = 1
BeatstepLayers = ['XY','Live',"Align","Zregulators"]
TouchOSCPort = 8101
TouchOSCIP = '192.168.2.67' # iPad 1
#TouchOSCIP = '192.168.2.156' # iPad mini
#TouchOSCIP = '192.168.43.146' # iPad mini @ fuzz
#TouchOSCIP = '192.168.151.213' # CCN
#TouchOSCIP = '127.0.0.1' # Localhost

40
libs/homographyp.py → libs3/homographyp.py Executable file → Normal file
View File

@ -1,5 +1,4 @@
#!/usr/bin/python2.7
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
@ -67,7 +66,7 @@ import numpy as np
import math
from scipy.linalg import svd,lstsq
import ast
import gstt
from libs3 import gstt
#from globalVars import xy_center
import redis
@ -92,7 +91,7 @@ def find(points1,points2):
A = np.zeros((3*npoints,9),'float64')
for i in xrange(npoints):
for i in range(npoints):
p1i = p1[i]
x2i,y2i,w2i = p2[i]
xpi = x2i*p1i
@ -130,7 +129,7 @@ def find_affine(points1,points2):
A = np.zeros((3*npoints,6),'float64')
b = np.zeros((3*npoints,1),'float64')
for i in xrange(npoints):
for i in range(npoints):
p1i = p1[i]
x2i,y2i,w2i = p2[i]
xpi = x2i*p1i
@ -163,9 +162,10 @@ def apply(H,points):
# Reference points
pointsref = np.array([(300.0, 400.0), (500.0, 400.0), (500.0, 200.0), (300.0, 200.0)])
def EDpoint(mylaser,(pygamex,pygamey)):
def EDpoint(mylaser, xxx_todo_changeme):
#print "current point : ", pygamex, pygamey
(pygamex,pygamey) = xxx_todo_changeme
XX = pygamex - gstt.xy_center[0]
YY = pygamey - gstt.xy_center[1]
CosANGLE = math.cos(gstt.finANGLE[mylaser])
@ -177,15 +177,15 @@ def EDpoint(mylaser,(pygamex,pygamey)):
if gstt.debug >1:
#print "global center :", xy_center
print "EDpoint computing..."
print "Laser :", mylaser, "center at : ", gstt.centerX[mylaser], gstt.centerY[mylaser]
print "Pygame point",pygamex,",",pygamey
print("EDpoint computing...")
print("Laser :", mylaser, "center at : ", gstt.centerX[mylaser], gstt.centerY[mylaser])
print("Pygame point",pygamex,",",pygamey)
'''
print "swaps : ", (gstt.swapX[mylaser]), str(gstt.swapY[mylaser])
print "zooms : ", gstt.zoomX[mylaser], gstt.zoomY[mylaser]
print "angles : ", gstt.finANGLE[mylaser]
'''
print "Result point : ", x * gstt.swapX[mylaser] , y * gstt.swapY[mylaser]
print("Result point : ", x * gstt.swapX[mylaser] , y * gstt.swapY[mylaser])
return [x * gstt.swapX[mylaser] , y * gstt.swapY[mylaser]]
'''
@ -208,7 +208,7 @@ def EDpoint((pygamex,pygamey)):
def newEDH(mylaser):
EDpoints = []
for point in xrange(4):
for point in range(4):
EDpoints.append(EDpoint(mylaser,pointsref[point]))
# H matrix tansform pygame points in Etherdream system with align and swap correction,
@ -222,12 +222,12 @@ def newEDH(mylaser):
# EDH matrix is H x Hwarp
#gstt.EDH[mylaser] = np.dot(H,Hwarp)
print "Laser",mylaser,"New EDH computed, sending to redis..."
print("Tracer", mylaser, ": new EDH computed, sending to redis...")
if r.set('/EDH/'+str(mylaser), np.array2string(gstt.EDH[mylaser], separator=',')) == True:
r.set('/order/'+str(mylaser), 1)
print "New EDH sent."
print("New EDH sent.")
else:
print "New EDH not sent."
print("New EDH not sent.")
'''
# Laser bit 0 = 0 and bit 1 = 1 : New EDH
order = r.get('/order')
@ -238,15 +238,15 @@ def newEDH(mylaser):
'''
if gstt.debug >1:
print ""
print "laser ", mylaser
print "reference points", pointsref
print "laser EDpoints :", EDpoints
print "-> Computed H :",H
print("")
print("laser ", mylaser)
print("reference points", pointsref)
print("laser EDpoints :", EDpoints)
print("-> Computed H :",H)
#print "warped points coordinates ", gstt.warpdest[mylaser]
#print "-> Computed Hwarp", Hwarp
#print "laser ", mylaser, "warpd ",ast.literal_eval(gstt.warpdest[gstt.Laser])
#print "laser ", mylaser, "Hwarp ", Hwarp
#print ""
print "-> new EDH :", gstt.EDH[mylaser]
print("-> new EDH :", gstt.EDH[mylaser])

72
libs3/kb.py Normal file
View File

@ -0,0 +1,72 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
typetext('hello')
tap(key)
Loosely found and reuse in LPHK from nimaid
https://github.com/nimaid/LPHK
mouse functions commented yet
"""
import keyboard
# import ms
media_keys = {"vol_up" : 57392, "vol_down" : 57390, "mute" : 57376, "play_pause" : 57378, "prev_track" : 57360, "next_track" : 57369}
#with mouse
#media_keys = {"vol_up" : 57392, "vol_down" : 57390, "mute" : 57376, "play_pause" : 57378, "prev_track" : 57360, "next_track" : 57369, "mouse_left" : "mouse_left","mouse_middle" : "mouse_middle", "mouse_right" : "mouse_right"}
pressed = set()
def sp(name):
try:
return keyboard.key_to_scan_codes(str(name))[0]
except:
try:
return media_keys[str(name)]
except:
return None
def press(key):
pressed.add(key)
if type(key) == str:
'''
if "mouse_" in key:
ms.press(key[6:])
return
'''
keyboard.press(key)
def release(key):
pressed.discard(key)
if type(key) == str:
'''
if "mouse_" in key:
ms.release(key[6:])
return
'''
keyboard.release(key)
def release_all():
for key in pressed.copy():
release(key)
def tap(key):
if type(key) == str:
'''
if "mouse_" in key:
ms.click(key[6:])
return
'''
press(key)
release(key)
def typetext(name):
#print(name)
for letter in name:
#print (letter)
tap(letter)

1417
libs3/launchpad.py Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

BIN
libs3/link.cpython-38-darwin.so Executable file

Binary file not shown.

BIN
libs3/link.so Executable file

Binary file not shown.

View File

@ -1,34 +1,33 @@
# coding=UTF-8
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
lj23 v0.7.6 for LJ v0.8+
lj23layers v0.7.6 for LJ v0.8+
Some LJ functions useful for python clients
LJ functions (API) for python plugins/clients
"layers" version :
- "PL" has been replaced by "layer"
- "Client"
Each program using this API to manage complexity, should declare itself by calling Config, but it's not mandatory
Class management :
Config(redisIP, client number, name)
https://stackoverflow.com/questions/739882/iterating-over-object-instances-of-a-given-class-in-python
https://stackoverflow.com/questions/8628123/counting-instances-of-a-class
http://effbot.org/pyfaq/how-do-i-get-a-list-of-all-instances-of-a-given-class.htm
Config(redisIP, client number,name)
Basic Draw :
- PolyLineOneColor, rPolyLineOneColor, LineTo, Line
- PolyLineRGB, rPolyLineRGB, LineRGBTo, LineRGB
- rgb2int(r,g,b)
- DrawPL(point list number) : once you stacked all wanted elements, like 2 polylines, send them to lasers.
- DrawDests(): Draw all requested destinations for each PL.
- Drawlayer (point list number) : once you stacked all wanted elements, like 2 polylines, send them to lasers.
- DrawDests(): Draw all requested destinations for each layer .
High level draw :
- Text(word, integercolor, PL, xpos, ypos, resize, rotx, roty, rotz) : Display a word
- Text(word, integercolor, layer , xpos, ypos, resize, rotx, roty, rotz) : Display a word
- TextRGB(word, red, green, blue, ...)
- Embeded font1
@ -38,37 +37,51 @@ Laser objects (name and convenient group of parameters for one or several point
- RelativeObject
- FixedObject
PL "Destinations" : tells Live what PL to draw and to what scene/Laser ("destination") to send it.
"Destinations" : Tell for given Layer a scene/Laser ("destination").
Each Layer can have different destination (i.e to display same stuff on different laser)
OSC and plugins functions :
SendLJ(adress,message) : LJ remote control. See commands.py
SendResol(address,message): Send OSC message to Resolume.
WebStatus(message) : display message on webui
SendLJ(adress,message) LJ remote control. See commands.py
SendResol(address,message) Send OSC message to Resolume.
WebStatus(message) display message on webui
SendIntensity(laser, intensity)
Sendkpps(laser, kpps)
LjClient(client): Change Client number in redis keys
LjPl(pl): Change pl number in redis keys = laser target.
ClosePlugin(name): Send UI closing info of given plugin
Ljscene(client) Change scene number in redis keys
Ljlayer(layer) Change layer number in redis keys = laser target.
ClosePlugin(name) Send UI closing info of given plugin
OSCstart(): Start the OSC system.
OSCframe(): Handle incoming OSC message. Calling the right callback
OSCstop(): Properly close the OSC system
OSCping(): /ping Answer to LJ pings by sending /pong name
OSCquit(): /quit Exit calling script using name in terminal
OSCadddest(): PL, scene, laser Add a destination
OSCdeldest(): PL, scene, lasers delete a destination
OSCobj(): /name/obj objectname attribute value for automation
OSCvar(): /name/var variablename value for automation
OSCstart() Start the OSC system.
OSCframe() Handle incoming OSC message. Calling the right callback
OSCstop() Properly close the OSC system
OSCping() /ping Answer to LJ pings by sending /pong name
OSCquit() /quit Exit calling script using name in terminal
OSCadddest(layer, scene, laser) Add a destination
OSCdeldest(layer , scene, laser) Delete a destination
OSCobj() /name/obj objectname attribute value for automation
OSCvar() /name/var variablename value for automation
OSCdebug()
** Joystick management is removed. Get it back in todolist **
setup_controls(joystick)
XboxController : getLeftHori, getLeftVert, getRightHori, getRightVert, getLeftTrigger, getRightTrigger
Ps3Controller : getLeftHori, getLeftVert, getRightHori, getRightVert, getLeftTrigger, getRightTrigger, getUp, getDown, getLeft, getRight, getFire1, getFire2(self):
MySaitekController : getLeftHori,getLeftVert, getRightHori,getRightVert, getLeftTrigger,getRightTrigger
MyThrustController : getLeftHori, getLeftVert, getRightHori, getRightVert, getLeftTrigger, getRightTrigger
CSLController : getLeftHori,getLeftVert,getRightHori, getRightVert,getLeftTrigger,getRightTrigger,getFire1,getFire2
my USB Joystick : getUp,getDown,getLeft,getRight,etLeftTrigger, getRightTrigger,getFire1, getFire2
XboxController getLeftHori, getLeftVert, getRightHori, getRightVert, getLeftTrigger, getRightTrigger
Ps3Controller getLeftHori, getLeftVert, getRightHori, getRightVert, getLeftTrigger, getRightTrigger, getUp, getDown, getLeft, getRight, getFire1, getFire2(self):
MySaitekController getLeftHori,getLeftVert, getRightHori,getRightVert, getLeftTrigger,getRightTrigger
MyThrustController getLeftHori, getLeftVert, getRightHori, getRightVert, getLeftTrigger, getRightTrigger
CSLController getLeftHori,getLeftVert,getRightHori, getRightVert,getLeftTrigger,getRightTrigger,getFire1,getFire2
my USB Joystick getUp,getDown,getLeft,getRight,etLeftTrigger, getRightTrigger,getFire1, getFire2
Class management manuals:
https://stackoverflow.com/questions/739882/iterating-over-object-instances-of-a-given-class-in-python
https://stackoverflow.com/questions/8628123/counting-instances-of-a-class
http://effbot.org/pyfaq/how-do-i-get-a-list-of-all-instances-of-a-given-class.htm
LICENCE : CC
@ -82,6 +95,7 @@ import sys
import weakref
import struct
import numpy as np
import gstt
from multiprocessing import Process, Queue, TimeoutError
is_py2 = sys.version[0] == '2'
@ -100,7 +114,7 @@ ClientNumber = 0
name = "noname"
oscrun = True
point_list = []
pl = [[],[],[],[]]
layers = [[],[],[],[],[],[],[],[],[],[]]
fft3Groups = [-1,-1,-1,-1]
@ -109,6 +123,10 @@ Dests = dict()
oscIPresol = "127.0.0.1"
oscPORTresol = 7000
# 3D to 2D projection parameters
fov = 256
viewer_distance = 100
'''
@ -134,7 +152,7 @@ class RelativeObject:
kind = 'relative'
counter = 0
def __init__(self, name, active, intensity, xy, color, red, green, blue, PL , closed, xpos , ypos , resize , rotx , roty , rotz):
def __init__(self, name, active, intensity, xy, color, red, green, blue, layer , closed, xpos , ypos , resize , rotx , roty , rotz):
self.name = name
self.active = active # True/False
self.intensity = intensity
@ -143,7 +161,7 @@ class RelativeObject:
self.red = red
self.green = green
self.blue = blue
self.PL = PL
self.layer = layer
self.closed = closed
self.xpos = xpos
self.ypos = ypos
@ -165,7 +183,7 @@ class FixedObject:
kind = 'fixed'
counter = 0
def __init__(self, name, intensity, active, xy, color, red, green, blue, PL , closed):
def __init__(self, name, intensity, active, xy, color, red, green, blue, layer , closed):
self.name = name
self.active = active # True/False
self.intensity = intensity
@ -174,7 +192,7 @@ class FixedObject:
self.red = red
self.green = green
self.blue = blue
self.PL = PL
self.layer = layer
self.closed = closed
FixedObject.counter += 1
@ -202,11 +220,11 @@ class DestObject():
# class Destinations(metaclass=IterDest):
__metaclass__ = IterDest
counter = 0
def __init__(self, name, number, active, PL , scene, laser):
def __init__(self, name, number, active, layer , scene, laser):
self.name = name
self.number = number
self.active = active
self.PL = PL
self.layer = layer
self.scene = scene
self.laser = laser
@ -221,11 +239,11 @@ class DestObject():
_instances = set()
counter = 0
def __init__(self, name, number, active, PL , scene, laser):
def __init__(self, name, number, active, layer , scene, laser):
self.name = name
self.number = number
self.active = active
self.PL = PL
self.layer = layer
self.scene = scene
self.laser = laser
self._instances.add(weakref.ref(self))
@ -258,8 +276,8 @@ def Config(redIP,client,myname):
ClientNumber = client
#print ("client configured",ClientNumber)
name = myname
print ("Plugin declare its name",name)
#print pl
print ("lj23layers : Plugin declare its name :",name)
#print layer
return r
@ -270,10 +288,10 @@ def LjClient(client):
def LjPl(pl):
global PL
def Ljlayer(somelayer):
global layer
PL = pl
layer = somelayer
def fromRedis(n):
@ -322,11 +340,15 @@ def SendLJ(oscaddress,oscargs=''):
osclientlj = OSCClient()
osclientlj.connect((redisIP, 8002))
#print("lj23layers for", name, "sending OSC message :", oscmsg, "to", redisIP, ":8002")
if gstt.debug >0:
print("lj23layers for", name, "sending OSC message :", oscmsg, "to", redisIP, ":8002")
print("lj23 in",name," sending OSC message : ", oscmsg, "to", redisIP, ":8002")
try:
osclientlj.sendto(oscmsg, (redisIP, 8002))
oscmsg.clearData()
except:
print ('Connection to LJ refused : died ?')
pass
@ -347,7 +369,7 @@ def SendResol(oscaddress,oscargs):
osclientresol = OSCClient()
osclientresol.connect((oscIPresol, oscPORTresol))
print("lj sending OSC message : ", oscmsg, "to Resolume", oscIPresol, ":", oscPORTresol)
print("lj23layers sending OSC message : ", oscmsg, "to Resolume", oscIPresol, ":", oscPORTresol)
try:
osclientresol.sendto(oscmsg, (oscIPresol, oscPORTresol))
oscmsg.clearData()
@ -356,6 +378,15 @@ def SendResol(oscaddress,oscargs):
pass
def SendIntensity(laser, intensity):
r.set('/intensity/' + str(laser), str(intensity))
r.set('/order/'+str(laser), 6)
SendLJ("/kpps/" + str(layer)+ " " + str(int(args[1])))
def Sendkpps(laser, kpps):
r.set('/kpps/' + str(laser), str(kpps))
r.set('/order/'+str(laser), 7)
def WebStatus(message):
@ -364,8 +395,8 @@ def WebStatus(message):
# Closing plugin messages to LJ
def ClosePlugin():
WebStatus(name+" Exiting")
SendLJ("/"+name+"/start",0)
WebStatus(name+" Exiting")
SendLJ("/"+name+"/start",0)
@ -382,20 +413,26 @@ def OSCframe():
# Answer to LJ pings with /pong value
def OSCping(path, tags, args, source):
#def OSCping():
print(name, "got /ping from LJ -> reply /pong", name)
if gstt.debug >0:
print(name, "lj23layers got /ping from LJ -> reply /pong", name)
SendLJ("/pong",name)
# Properly close the system. Todo
# Properly close the system.
def OSCstop():
oscserver.close()
# change debug level (0-2)
def OSCdebug(path, tags, args, source):
print("new debug level", args[0] )
gstt.debug = int(args[0])
# /quit
def OSCquit(path, tags, args, source):
global oscrun
oscrun = False
print('lj23 got /quit for',name)
print('lj23layers got /quit for',name)
#WebStatus(name + " quit.")
#SendLJ("/"+name+"/start",0)
#print("Stopping OSC...")
@ -407,7 +444,7 @@ def OSCquit(path, tags, args, source):
def OSChandler(path, tags, args, source):
oscaddress = ''.join(path.split("/"))
print("Default OSC Handler in",name,": msg from Client : " + str(source[0]),)
print("lj23layers Default OSC Handler for",name,": msg from Client :" + str(source[0]),)
print("OSC address", path)
if len(args) > 0:
print("with args", args)
@ -418,7 +455,7 @@ def OSChandler(path, tags, args, source):
# for any laser object : /pluginame/obj objectname attribute value
# like : /pluginname/obj 'fft' 'xpos' 100
# attributes for all lj Objects: name, xy_list, c, PL
# attributes for all lj Objects: name, xy_list, c, layer
# + for RelativeObjects : closed, xpos , ypos , resize , rotx , roty , rotz
def OSCobj(path, tags, args, source):
@ -439,40 +476,82 @@ def addOSCdefaults(server):
oscserver.addMsgHandler( "default", OSChandler )
oscserver.addMsgHandler( "/ping", OSCping)
oscserver.addMsgHandler( "/quit", OSCquit)
oscserver.addMsgHandler( "/debug", OSCdebug)
oscserver.addMsgHandler( "/"+ name + "/adddest", OSCadddest)
oscserver.addMsgHandler( "/"+ name + "/deldest", OSCdeldest)
oscserver.addMsgHandler( "/"+ name + "/dest", OSCdest)
oscserver.addMsgHandler( "/"+ name + "/obj", OSCobj)
oscserver.addMsgHandler( "/"+ name + "/var", OSCvar)
#
# Color functions
#
# input hexcode = '0xff00ff'
def hex2rgb(hexcode):
hexcode = hexcode[2:]
return tuple(int(hexcode[i:i+2], 16) for i in (0, 2, 4))
#return tuple(map(ord,hexcode[1:].decode('hex')))
# input rgb=(255,0,255) output '0xff00ff'
#def rgb2hex(rgb):
# return '0x%02x%02x%02x' % tuple(rgb)
def rgb2hex(r, g, b):
return hex((r << 16) + (g << 8) + b)
#def rgb2int(rgb):
# return int('0x%02x%02x%02x' % tuple(rgb),0)
def rgb2int(r,g,b):
return int('0x%02x%02x%02x' % (r,g,b),0)
def int2rgb(intcode):
#hexcode = '0x{0:06X}'.format(intcode)
hexcode = '{0:06X}'.format(intcode)
return tuple(int(hexcode[i:i+2], 16) for i in (0, 2, 4))
#
# Drawing basic functions
#
def rgb2int(r,g,b):
return int('0x%02x%02x%02x' % (r,g,b),0)
# Lines
def Line(xy1, xy2, c, layer ):
LineTo(xy1, 0, layer )
LineTo(xy2, c , layer )
def rLine(xy1, xy2, c, layer , xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
rLineTo(xy1, 0, layer )
rLineTo(xy2, c , layer )
def LineRGB(xy1, xy2, red,green,blue, layer ):
LineTo(xy1, 0, layer )
LineTo(xy2, int('0x%02x%02x%02x' % (red,green,blue),0) , layer )
def LineTo(xy, c, PL):
# Lineto
def LineTo(xy, c, layer ):
pl[PL].append((xy + (c,)))
layers[layer].append((xy + (c,)))
def rLineTo(xy, c, PL, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
def LineRGBTo(xy, red, green, blue, layer ):
LineTo(xy, int('0x%02x%02x%02x' % (red,green,blue),0), layer )
pl[PL].append((Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz) + (c,)))
def rLineTo(xy, c, layer , xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
layers[layer ].append((Pointransf(xy, xpos, ypos, resize, rotx, roty, rotz) + (c,)))
def Line(xy1, xy2, c, PL):
LineTo(xy1, 0, PL)
LineTo(xy2, c , PL)
def rLine(xy1, xy2, c, PL, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
rLineTo(xy1, 0, PL)
rLineTo(xy2, c , PL)
def PolyLineOneColor(xy_list, c, PL , closed ):
# Polylines
def PolyLineOneColor(xy_list, c, layer , closed ):
#print "--"
#print "c",c
#print "xy_list",xy_list
@ -482,14 +561,38 @@ def PolyLineOneColor(xy_list, c, PL , closed ):
if xy0 is None:
xy0 = xy
#print "xy0:",xy0
LineTo(xy0,0, PL)
LineTo(xy0,c, PL)
LineTo(xy0,0, layer )
LineTo(xy0,c, layer )
else:
#print "xy:",xy
LineTo(xy,c, PL)
LineTo(xy,c, layer )
if closed:
LineTo(xy0,c, PL)
LineTo(xy0,c, layer )
def PolyLineRGB(xy_list, red, green, blue, layer , closed ):
PolyLineOneColor(xy_list, int('0x%02x%02x%02x' % (red,green,blue),0), layer , closed )
# rPolylines
# Send 2D point list around 0,0 with 3D rotation resizing and reposition around xpos ypos
#def rPolyLineOneColor(self, xy_list, c, layer , closed, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0):
def rPolyLineOneColor(xy_list, c, layer , 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, layer )
LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz), c, layer )
else:
LineTo(Pointransf(xy, xpos, ypos, resize, rotx, roty, rotz), c, layer )
if closed:
LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz), c, layer )
def rPolyLineRGB(xy_list, red, green, blue, layer , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
rPolyLineOneColor(xy_list, int('0x%02x%02x%02x' % (red,green,blue),0), layer , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0)
# Computing points coordinates for rPolyline function from 3D and around 0,0 to pygame coordinates
@ -497,7 +600,7 @@ 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
z = xy[2] * resize
rad = math.radians(rotx)
cosaX = math.cos(rad)
@ -523,113 +626,75 @@ def Pointransf(xy, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0):
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 )
'''
#print("transf",xy, (x + xpos,y+ ypos))
factor = resize / (10*(viewer_distance + z))
#print("resize", resize, "z", z, "factor", factor)
#print("perspec", xy, (x * factor) + xpos, (- y * factor)+ ypos)
#print()
return ((x * factor) + xpos, (y * factor)+ ypos)
#return (x + xpos, y + ypos)
def rLineTo(xy, c, PL, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
pl[PL].append((Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz) + (c,)))
#to understand why it get negative Y
""" Transforms this 3D point to 2D using a perspective projection. """
factor = fov / (viewer_distance + z)
print("z", z, "factor", factor)
#x = (x * factor)
#y = (- y * factor)
print("perspec", xy, (x * factor) + xpos, (- y * factor)+ ypos)
print()
return (x + xpos, y + ypos)
#return (x, y)
def rLine(xy1, xy2, c, PL, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
LineTo(Pointransf(xy1, xpos, ypos, resize, rotx, roty, rotz),0, PL)
LineTo(Pointransf(xy2, xpos, ypos, resize, rotx, roty, rotz),c, PL)
def Lineslayer(layer):
print("Stupido !! your code is to old : use Drawlayer() instead of LinesPL()")
Drawlayer(layer )
# 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 LineRGBTo(xy, red, green, blue, PL):
LineTo(xy, int('0x%02x%02x%02x' % (red,green,blue),0), PL)
def LineRGB(xy1, xy2, red,green,blue, PL):
LineTo(xy1, 0, PL)
LineTo(xy2, int('0x%02x%02x%02x' % (red,green,blue),0) , PL)
def PolyLineRGB(xy_list, red, green, blue, PL , closed ):
PolyLineOneColor(xy_list, int('0x%02x%02x%02x' % (red,green,blue),0), PL , closed )
def rPolyLineRGB(xy_list, red, green, blue, PL , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
rPolyLineOneColor(xy_list, int('0x%02x%02x%02x' % (red,green,blue),0), PL , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0)
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] = []
def Draw(layer):
#print '/pl/0/'+str(layer), str(layers[layer])
if r.set('/pl/'+str(ClientNumber)+'/'+str(layer), str(layers[layer])) == True:
#print '/pl/'+str(ClientNumber)+'/'+str(layer), str(layers[layer])
layers[layer] = []
return True
else:
return False
def ResetPL(self, PL):
pl[PL] = []
def Resetlayer(self, layer):
layers[layer] = []
#
# "Destinations" management for PLs
# "Destinations" management for layers
#
# Add a destination for a given PL
def Addest(PL, scene, laser):
# Add a destination for a given layer
def Addest(layer, scene, laser):
print (name,'adding',PL,scene,laser,'?')
if Findest(PL, scene, laser) == -1:
print (name,'adding',layer,scene,laser,'?')
if Findest(layer, scene, laser) == -1:
newdest = DestsObjects.counter + 1
Dest0 = lj.DestObject(str(newdest), newdest, True, PL , scene, laser)
Dest0 = lj.DestObject(str(newdest), newdest, True, layer , scene, laser)
print("New destination added with number", newdest)
else:
print("Destination already existed")
# OSC add a destination for a given PL
# /pluginame/dest PL, scene, laser
# OSC add a destination for a given layer
# /pluginame/dest layer, scene, laser
def OSCadddest(path, tags, args, source):
Addests(int(args[0]),int(args[1]),int(args[2]))
# Find PL destination with its parameters in destinations dictionnary
def Findest(PL, scene, laser):
# Find layer destination with its parameters in destinations dictionnary
def Findest(layer, scene, laser):
print(name, 'searching PL,scene,laser',PL,scene,laser)
print(name, 'searching layer,scene,laser',layer,scene,laser)
for item in DestObjects.getinstances():
#print(item)
if item.PL == PL and item.scene == scene and item.laser == laser:
if item.layer == layer and item.scene == scene and item.laser == laser:
#Dests.append(item[0])
print('found number',item.number)
return item.number
@ -641,18 +706,18 @@ def Findest(PL, scene, laser):
allDests = Dests.items()
for item in allDests:
print(item)
if item[1] == PL and item[2] == scene and item[3] == laser:
if item[1] == layer and item[2] == scene and item[3] == laser:
#Dests.append(item[0])
return Dests[item[0]]
else:
return -1
'''
# Find and remove a PL destination with its parameters in destinations dictionnary
def Deldest(PL, scene, laser):
# Find and remove a layer destination with its parameters in destinations dictionnary
def Deldest(layer, scene, laser):
Destnumber = Findest(PL, scene, laser)
print(name,'deleting Destination PL, scene, laser', PL,scene, laser)
Destnumber = Findest(layer, scene, laser)
print(name,'deleting Destination layer, scene, laser', layer,scene, laser)
if Destnumber != -1:
print('found DestObject', Destnumber)
@ -662,14 +727,25 @@ def Deldest(PL, scene, laser):
print("Destination was not found")
# OSC Delete a destination for a given PL
# /pluginame/deldests PL, scene, laser
# OSC Delete a destination for a given layer
# /pluginame/deldests layer, scene, laser
def OSCdeldest(path, tags, args, source):
Deldests(args[0],args[1],args[2])
Deldests(args[0], args[1], args[2])
# Replace DrawPL if Destinations paradigm is implemented in plugin code
# pluginame/dest layer, scene, laser
def OSCdest(path, tags, args, source):
# For single layer plugin : add a new destination
Addest(0, args[0], args[1])
# For single layer plugin : remove a destination
# For multiple layers plugin : add or remove
# Replace Drawlayer if Destinations paradigm is implemented in plugin code
def DrawDests():
# Objects style
@ -677,22 +753,21 @@ def DrawDests():
#print("DrawDest")
for destination in DestObject.getinstances():
#print (destination.name, destination.number, destination.active, destination.PL, destination.scene, destination.laser, pl[destination.PL] )
#print(Dests[str(destination)])
#print('/pl/'+str(Dests[str(destination)]["scene"])+'/'+str(Dests[str(destination)]["laser"]), ":", str(pl[Dests[str(destination)]["PL"]]))
#print(len(pl[destination.PL]))
#print('/pl/'+str(Dests[str(destination)]["scene"])+'/'+str(Dests[str(destination)]["laser"]), ":", str(layers[Dests[str(destination)]["PL"]]))
#print(len(layers[destination.layer]))
if destination.active == True:
if r.set('/pl/'+str(destination.scene)+'/'+str(destination.laser), str(pl[destination.PL])) == True:
#print ('pl', destination.PL, '/pl/'+str(destination.scene)+'/'+str(destination.laser), str(pl[destination.PL]))
if r.set('/pl/'+str(destination.scene)+'/'+str(destination.laser), str(layers[destination.layer])) == True:
#print ('layer', destination.layer, '/pl/'+str(destination.scene)+'/'+str(destination.laser), str(layers[destination.layer]))
pass
else:
print('Redis key modification failed')
# Maybe one PL can be sent to multiple destination so they are all reset *after* all sending.
for pls in range(4):
# Maybe one layer can be sent to multiple destination so they are all reset *after* all sending.
for layerss in range(4):
pl[pls] = []
layers[layerss] = []
'''
# Dictionnary style
@ -700,30 +775,30 @@ def DrawDests():
#print(Dests)
for destination in range(len(Dests)):
#print(Dests[str(destination)])
#print('/pl/'+str(Dests[str(destination)]["scene"])+'/'+str(Dests[str(destination)]["laser"]), ":", str(pl[Dests[str(destination)]["PL"]]))
if r.set('/pl/'+str(Dests[str(destination)]["scene"])+'/'+str(Dests[str(destination)]["laser"]), str(pl[Dests[str(destination)]["PL"]])) == True:
#print '/pl/'+str(ClientNumber)+'/'+str(PL), str(pl[PL])
#print('/pl/'+str(Dests[str(destination)]["scene"])+'/'+str(Dests[str(destination)]["laser"]), ":", str(layers[Dests[str(destination)]["layer"]]))
if r.set('/pl/'+str(Dests[str(destination)]["scene"])+'/'+str(Dests[str(destination)]["laser"]), str(layers[Dests[str(destination)]["layer"]])) == True:
#print '/pl/'+str(ClientNumber)+'/'+str(layer), str(layers[layer])
pass
else:
print('Redis key modification failed')
# Maybe one PL can be sent to multiple destination so they are all reset *after* all sending.
# Maybe one layer can be sent to multiple destination so they are all reset *after* all sending.
for destination in range(len(Dests)):
pl[Dests[str(destination)]["PL"]] = []
layers[Dests[str(destination)]["layer"]] = []
'''
'''
scenes = 4
def DrawDestsPL(PL):
def DrawDestslayer(layer):
for scene in range(scenes):
if Dests[laser]["scene"] != -1:
if r.set('/pl/'+str(Dests[laser]["scene"])+'/'+str(Dests[laser]["laser"]), str(pl[Dests[laser]["laser"]])) == True:
if r.set('/pl/'+str(ClientNumber)+'/'+str(PL), str(pl[PL])) == True:
#print '/pl/'+str(ClientNumber)+'/'+str(PL), str(pl[PL])
pl[Dests[laser]["laser"]] = []
if r.set('/pl/'+str(Dests[laser]["scene"])+'/'+str(Dests[laser]["laser"]), str(layers[Dests[laser]["laser"]])) == True:
if r.set('/pl/'+str(ClientNumber)+'/'+str(layer), str(layers[layer])) == True:
#print '/pl/'+str(ClientNumber)+'/'+str(layer), str(layers[layer])
layers[Dests[laser]["laser"]] = []
return True
else:
return False
@ -762,8 +837,7 @@ ASCII_GRAPHICS = [
[(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é
# Implementé 65-90
[(-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
@ -793,7 +867,7 @@ ASCII_GRAPHICS = [
[(0,30), (0,0), (30,-30), (0,0), (-30,-30)], # Y
[(30,30), (-30,30), (30,-30), (-30,-30)], # Z
# A implementer
# A implementer
[(-30,-10), (0,-30), (0,30)], [(-30,30), (30,30)], # [
[(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], # \
@ -802,7 +876,7 @@ ASCII_GRAPHICS = [
[(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é
# Implementé 97-122
[(-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
@ -831,7 +905,38 @@ ASCII_GRAPHICS = [
[(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 {
# A implementer
[(-2,15), (2,15)], # Point a la place de {
[(-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)], # DEL
# Accents 128-151 a implementer
[(30,30), (-30,30), (-30,-30), (30,-30)], # C
[(-20,-20), (-20,20), (20,20), (20,-20)], # û
[(20,20), (-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], # é
[(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], # â
[(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], # ä
[(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], # a
[(20,20), (-20,20), (-20,-20), (20,-20)], # c
[(20,20), (-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], # é
[(20,20), (-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], # é
[(20,20), (-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], # é
[(0,20), (0,-20)], # i
[(0,20), (0,-20)], # i
[(0,20), (0,-20)], # i
[(-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,-0), (30,0), (-30,0), (-30,-30), (30,-30)], # E
[(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], # a
[(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], # a
[(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], # o
[(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], # o
[(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], # o
[(-20,-20), (-20,20), (20,20), (20,-20)], # u
[(-20,-20), (-20,20), (20,20), (20,-20)] # u
]
@ -850,7 +955,7 @@ def CharDots(char,color):
dots.append((dot[0],dot[1],color))
return dots
def Text(message,c, PL, xpos, ypos, resize, rotx, roty, rotz):
def Text(message, c, layer, xpos, ypos, resize, rotx, roty, rotz):
dots =[]
@ -866,23 +971,29 @@ def Text(message,c, PL, xpos, ypos, resize, rotx, roty, rotz):
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_layer_list = ASCII_GRAPHICS[ord(ch) - 48]
# Uppercase
elif 64 < ord(ch) < 91 :
char_layer_list = ASCII_GRAPHICS[ord(ch) - 46]
# Lowercase
elif 96 < ord(ch) < 123 :
char_layer_list = ASCII_GRAPHICS[ord(ch) - 45]
char_draw = []
#dots.append((char_pl_list[0][0] + x_offset,char_pl_list[0][1],0))
#dots.append((char_layer_list[0][0] + x_offset,char_layer_list[0][1],0))
for xy in char_pl_list:
for xy in char_layer_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)
#print ch,char_layer_list,char_draw
rPolyLineOneColor(char_draw, c, layer , False, xpos, ypos, resize, rotx, roty, rotz)
#dots.append(char_draw)
def TextRGB(message,c, PL, xpos, ypos, resize, rotx, roty, rotz):
def TextRGB(message,c, layer, xpos, ypos, resize, rotx, roty, rotz):
Text(message,int('0x%02x%02x%02x' % (red,green,blue),0), PL, xpos, ypos, resize, rotx, roty, rotz)
Text(message,int('0x%02x%02x%02x' % (red,green,blue),0), layer, xpos, ypos, resize, rotx, roty, rotz)

View File

@ -1,20 +1,21 @@
# coding=UTF-8
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
lj23layers v0.7.6 for LJ v0.8+
Some LJ functions useful for python clients
LJ functions (API) for python plugins/clients
"layers" version : "PL" has been replaced by layer
"layers" version :
- "PL" has been replaced by "layer"
- "Client"
Each program using LJ should declare itself by call lj23layers Config :
Class management :
Config(redisIP, client number, name)
https://stackoverflow.com/questions/739882/iterating-over-object-instances-of-a-given-class-in-python
https://stackoverflow.com/questions/8628123/counting-instances-of-a-class
http://effbot.org/pyfaq/how-do-i-get-a-list-of-all-instances-of-a-given-class.htm
Config(redisIP, client number,name)
Basic Draw :
@ -36,7 +37,8 @@ Laser objects (name and convenient group of parameters for one or several point
- RelativeObject
- FixedObject
layer "Destinations" : tells Live what layer to draw and to what scene/Laser ("destination") to send it.
"Destinations" : Tell for given Layer a scene/Laser ("destination").
Each Layer can have different destination (i.e to display same stuff on different laser)
OSC and plugins functions :
@ -59,6 +61,9 @@ OSCdeldest(): layer , scene, lasers delete a destination
OSCobj(): /name/obj objectname attribute value for automation
OSCvar(): /name/var variablename value for automation
Joystick management is removed. Get it back in todolist
setup_controls(joystick)
XboxController : getLeftHori, getLeftVert, getRightHori, getRightVert, getLeftTrigger, getRightTrigger
@ -69,6 +74,14 @@ CSLController : getLeftHori,getLeftVert,getRightHori, getRightVert,getLeftT
my USB Joystick : getUp,getDown,getLeft,getRight,etLeftTrigger, getRightTrigger,getFire1, getFire2
Class management manuals:
https://stackoverflow.com/questions/739882/iterating-over-object-instances-of-a-given-class-in-python
https://stackoverflow.com/questions/8628123/counting-instances-of-a-class
http://effbot.org/pyfaq/how-do-i-get-a-list-of-all-instances-of-a-given-class.htm
LICENCE : CC
Sam Neurohack
@ -80,6 +93,7 @@ import sys
import weakref
import struct
import numpy as np
import gstt
from multiprocessing import Process, Queue, TimeoutError
is_py2 = sys.version[0] == '2'
@ -98,7 +112,7 @@ ClientNumber = 0
name = "noname"
oscrun = True
point_list = []
layers = [[],[],[],[]]
layers = [[],[],[],[],[],[],[],[],[],[]]
fft3Groups = [-1,-1,-1,-1]
@ -107,6 +121,10 @@ Dests = dict()
oscIPresol = "127.0.0.1"
oscPORTresol = 7000
# 3D to 2D projection parameters
fov = 256
viewer_distance = 2.2
'''
@ -256,7 +274,7 @@ def Config(redIP,client,myname):
ClientNumber = client
#print ("client configured",ClientNumber)
name = myname
print ("Plugin declare its name",name)
print ("lj23layers : Plugin declare its name :",name)
#print layer
return r
@ -321,7 +339,9 @@ def SendLJ(oscaddress,oscargs=''):
osclientlj = OSCClient()
osclientlj.connect((redisIP, 8002))
print("lj23 in",name," sending OSC message : ", oscmsg, "to", redisIP, ":8002")
print("lj23layers for",name,"sending OSC message :", oscmsg, "to", redisIP, ":8002")
if gstt.debug >0:
print("lj23layers for",name,"sending OSC message :", oscmsg, "to", redisIP, ":8002")
try:
osclientlj.sendto(oscmsg, (redisIP, 8002))
oscmsg.clearData()
@ -345,7 +365,7 @@ def SendResol(oscaddress,oscargs):
osclientresol = OSCClient()
osclientresol.connect((oscIPresol, oscPORTresol))
print("lj sending OSC message : ", oscmsg, "to Resolume", oscIPresol, ":", oscPORTresol)
print("lj23layers sending OSC message : ", oscmsg, "to Resolume", oscIPresol, ":", oscPORTresol)
try:
osclientresol.sendto(oscmsg, (oscIPresol, oscPORTresol))
oscmsg.clearData()
@ -354,6 +374,15 @@ def SendResol(oscaddress,oscargs):
pass
def SendIntensity(laser, intensity):
r.set('/intensity/' + str(laser), str(intensity))
r.set('/order/'+str(laser), 6)
SendLJ("/kpps/" + str(layer)+ " " + str(int(args[1])))
def Sendkpps(laser, kpps):
r.set('/kpps/' + str(laser), str(kpps))
r.set('/order/'+str(laser), 7)
def WebStatus(message):
@ -362,8 +391,8 @@ def WebStatus(message):
# Closing plugin messages to LJ
def ClosePlugin():
WebStatus(name+" Exiting")
SendLJ("/"+name+"/start",0)
WebStatus(name+" Exiting")
SendLJ("/"+name+"/start",0)
@ -380,7 +409,8 @@ def OSCframe():
# Answer to LJ pings with /pong value
def OSCping(path, tags, args, source):
#def OSCping():
print(name, "got /ping from LJ -> reply /pong", name)
if gstt.debug >0:
print(name, "lj23layers got /ping from LJ -> reply /pong", name)
SendLJ("/pong",name)
# Properly close the system. Todo
@ -393,7 +423,7 @@ def OSCquit(path, tags, args, source):
global oscrun
oscrun = False
print('lj23 got /quit for',name)
print('lj23layers got /quit for',name)
#WebStatus(name + " quit.")
#SendLJ("/"+name+"/start",0)
#print("Stopping OSC...")
@ -405,7 +435,7 @@ def OSCquit(path, tags, args, source):
def OSChandler(path, tags, args, source):
oscaddress = ''.join(path.split("/"))
print("Default OSC Handler in",name,": msg from Client : " + str(source[0]),)
print("lj23layers Default OSC Handler for",name,": msg from Client :" + str(source[0]),)
print("OSC address", path)
if len(args) > 0:
print("with args", args)
@ -439,28 +469,49 @@ def addOSCdefaults(server):
oscserver.addMsgHandler( "/quit", OSCquit)
oscserver.addMsgHandler( "/"+ name + "/adddest", OSCadddest)
oscserver.addMsgHandler( "/"+ name + "/deldest", OSCdeldest)
oscserver.addMsgHandler( "/"+ name + "/dest", OSCdest)
oscserver.addMsgHandler( "/"+ name + "/obj", OSCobj)
oscserver.addMsgHandler( "/"+ name + "/var", OSCvar)
#
# Color functions
#
# input hexcode = '0xff00ff'
def hex2rgb(hexcode):
hexcode = hexcode[2:]
return tuple(int(hexcode[i:i+2], 16) for i in (0, 2, 4))
#return tuple(map(ord,hexcode[1:].decode('hex')))
# input rgb=(255,0,255) output '0xff00ff'
#def rgb2hex(rgb):
# return '0x%02x%02x%02x' % tuple(rgb)
def rgb2hex(r, g, b):
return hex((r << 16) + (g << 8) + b)
#def rgb2int(rgb):
# return int('0x%02x%02x%02x' % tuple(rgb),0)
def rgb2int(r,g,b):
return int('0x%02x%02x%02x' % (r,g,b),0)
def int2rgb(intcode):
#hexcode = '0x{0:06X}'.format(intcode)
hexcode = '{0:06X}'.format(intcode)
return tuple(int(hexcode[i:i+2], 16) for i in (0, 2, 4))
#
# Drawing basic functions
#
def rgb2int(r,g,b):
return int('0x%02x%02x%02x' % (r,g,b),0)
def LineTo(xy, c, layer ):
layers[layer].append((xy + (c,)))
def rLineTo(xy, c, layer , xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
layers[layer ].append((Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz) + (c,)))
# Lines
def Line(xy1, xy2, c, layer ):
LineTo(xy1, 0, layer )
LineTo(xy2, c , layer )
@ -469,7 +520,27 @@ def rLine(xy1, xy2, c, layer , xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0
rLineTo(xy1, 0, layer )
rLineTo(xy2, c , layer )
def LineRGB(xy1, xy2, red,green,blue, layer ):
LineTo(xy1, 0, layer )
LineTo(xy2, int('0x%02x%02x%02x' % (red,green,blue),0) , layer )
# Lineto
def LineTo(xy, c, layer ):
layers[layer].append((xy + (c,)))
def LineRGBTo(xy, red, green, blue, layer ):
LineTo(xy, int('0x%02x%02x%02x' % (red,green,blue),0), layer )
def rLineTo(xy, c, layer , xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
layers[layer ].append((Pointransf(xy, xpos, ypos, resize, rotx, roty, rotz) + (c,)))
# Polylines
def PolyLineOneColor(xy_list, c, layer , closed ):
#print "--"
#print "c",c
@ -488,6 +559,31 @@ def PolyLineOneColor(xy_list, c, layer , closed ):
if closed:
LineTo(xy0,c, layer )
def PolyLineRGB(xy_list, red, green, blue, layer , closed ):
PolyLineOneColor(xy_list, int('0x%02x%02x%02x' % (red,green,blue),0), layer , closed )
# rPolylines
# Send 2D point list around 0,0 with 3D rotation resizing and reposition around xpos ypos
#def rPolyLineOneColor(self, xy_list, c, layer , closed, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0):
def rPolyLineOneColor(xy_list, c, layer , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
xy0 = None
for xy in xy_list:
print(xy,xy0)
if xy0 is None:
xy0 = xy
LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz), 0, layer )
LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz), c, layer )
else:
LineTo(Pointransf(xy, xpos, ypos, resize, rotx, roty, rotz), c, layer )
if closed:
LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz), c, layer )
def rPolyLineRGB(xy_list, red, green, blue, layer , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
rPolyLineOneColor(xy_list, int('0x%02x%02x%02x' % (red,green,blue),0), layer , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0)
# Computing points coordinates for rPolyline function from 3D and around 0,0 to pygame coordinates
@ -495,7 +591,7 @@ 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
z = xy[2] * resize
rad = math.radians(rotx)
cosaX = math.cos(rad)
@ -522,61 +618,15 @@ def Pointransf(xy, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0):
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 )
'''
#return (x + xpos, y + ypos)
def rLineTo(xy, c, layer , xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
layers[layer ].append((Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz) + (c,)))
def rLine(xy1, xy2, c, layer , xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
LineTo(Pointransf(xy1, xpos, ypos, resize, rotx, roty, rotz),0, layer )
LineTo(Pointransf(xy2, xpos, ypos, resize, rotx, roty, rotz),c, layer )
# Send 2D point list around 0,0 with 3D rotation resizing and reposition around xpos ypos
#def rPolyLineOneColor(self, xy_list, c, layer , closed, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0):
def rPolyLineOneColor(xy_list, c, layer , 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, layer )
LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),c, layer )
else:
LineTo(Pointransf(xy, xpos, ypos, resize, rotx, roty, rotz),c, layer )
if closed:
LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz),c, layer )
def LineRGBTo(xy, red, green, blue, layer ):
LineTo(xy, int('0x%02x%02x%02x' % (red,green,blue),0), layer )
def LineRGB(xy1, xy2, red,green,blue, layer ):
LineTo(xy1, 0, layer )
LineTo(xy2, int('0x%02x%02x%02x' % (red,green,blue),0) , layer )
def PolyLineRGB(xy_list, red, green, blue, layer , closed ):
PolyLineOneColor(xy_list, int('0x%02x%02x%02x' % (red,green,blue),0), layer , closed )
def rPolyLineRGB(xy_list, red, green, blue, layer , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
rPolyLineOneColor(xy_list, int('0x%02x%02x%02x' % (red,green,blue),0), layer , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0)
#to understand why it get negative Y
""" Transforms this 3D point to 2D using a perspective projection. """
factor = fov / (viewer_distance + z)
x = x * factor + xpos
y = y * factor + ypos
#y = - y * factor + ypos
return (x, y)
def Lineslayer(layer):
@ -584,7 +634,7 @@ def Lineslayer(layer):
Drawlayer(layer )
def Draw(layer ):
def Draw(layer):
#print '/pl/0/'+str(layer), str(layers[layer])
if r.set('/pl/'+str(ClientNumber)+'/'+str(layer), str(layers[layer])) == True:
#print '/pl/'+str(ClientNumber)+'/'+str(layer), str(layers[layer])
@ -664,7 +714,18 @@ def Deldest(layer, scene, laser):
# /pluginame/deldests layer, scene, laser
def OSCdeldest(path, tags, args, source):
Deldests(args[0],args[1],args[2])
Deldests(args[0], args[1], args[2])
# pluginame/dest layer, scene, laser
def OSCdest(path, tags, args, source):
# For single layer plugin : add a new destination
Addest(0, args[0], args[1])
# For single layer plugin : remove a destination
# For multiple layers plugin : add or remove
# Replace Drawlayer if Destinations paradigm is implemented in plugin code
@ -675,7 +736,6 @@ def DrawDests():
#print("DrawDest")
for destination in DestObject.getinstances():
#print (destination.name, destination.number, destination.active, destination.layer, destination.scene, destination.laser, layers[destination.layer] )
#print(Dests[str(destination)])
#print('/pl/'+str(Dests[str(destination)]["scene"])+'/'+str(Dests[str(destination)]["laser"]), ":", str(layers[Dests[str(destination)]["PL"]]))
@ -760,8 +820,7 @@ ASCII_GRAPHICS = [
[(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é
# Implementé 65-90
[(-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
@ -791,7 +850,7 @@ ASCII_GRAPHICS = [
[(0,30), (0,0), (30,-30), (0,0), (-30,-30)], # Y
[(30,30), (-30,30), (30,-30), (-30,-30)], # Z
# A implementer
# A implementer
[(-30,-10), (0,-30), (0,30)], [(-30,30), (30,30)], # [
[(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], # \
@ -800,7 +859,7 @@ ASCII_GRAPHICS = [
[(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é
# Implementé 97-122
[(-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
@ -829,7 +888,38 @@ ASCII_GRAPHICS = [
[(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 {
# A implementer
[(-2,15), (2,15)], # Point a la place de {
[(-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)], # DEL
# Accents 128-151 a implementer
[(30,30), (-30,30), (-30,-30), (30,-30)], # C
[(-20,-20), (-20,20), (20,20), (20,-20)], # û
[(20,20), (-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], # é
[(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], # â
[(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], # ä
[(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], # a
[(20,20), (-20,20), (-20,-20), (20,-20)], # c
[(20,20), (-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], # é
[(20,20), (-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], # é
[(20,20), (-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], # é
[(0,20), (0,-20)], # i
[(0,20), (0,-20)], # i
[(0,20), (0,-20)], # i
[(-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,-0), (30,0), (-30,0), (-30,-30), (30,-30)], # E
[(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], # a
[(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], # a
[(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], # o
[(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], # o
[(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], # o
[(-20,-20), (-20,20), (20,20), (20,-20)], # u
[(-20,-20), (-20,20), (20,20), (20,-20)] # u
]
@ -848,7 +938,7 @@ def CharDots(char,color):
dots.append((dot[0],dot[1],color))
return dots
def Text(message,c, layer, xpos, ypos, resize, rotx, roty, rotz):
def Text(message, c, layer, xpos, ypos, resize, rotx, roty, rotz):
dots =[]
@ -865,9 +955,15 @@ def Text(message,c, layer, xpos, ypos, resize, rotx, roty, rotz):
# Digits
if ord(ch)<58:
char_layer_list = ASCII_GRAPHICS[ord(ch) - 48]
else:
# Uppercase
elif 64 < ord(ch) < 91 :
char_layer_list = ASCII_GRAPHICS[ord(ch) - 46]
# Lowercase
elif 96 < ord(ch) < 123 :
char_layer_list = ASCII_GRAPHICS[ord(ch) - 45]
char_draw = []
#dots.append((char_layer_list[0][0] + x_offset,char_layer_list[0][1],0))

View File

@ -5,6 +5,8 @@ lj3 v0.7.5 for LJ v0.8+
Some LJ functions useful for python clients
lj3 is deprecated use lj23
OSC functions commented, waiting working on OSC in python3
Config(redisIP, client number,name)

43
libs3/log.py Normal file
View File

@ -0,0 +1,43 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
Log in color from
https://stackoverflow.com/questions/287871/how-to-print-colored-text-in-terminal-in-python
usage :
import log
log.info("Hello World")
log.err("System Error")
'''
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = "\033[1m"
def disable():
HEADER = ''
OKBLUE = ''
OKGREEN = ''
WARNING = ''
FAIL = ''
ENDC = ''
def infog( msg):
print(OKGREEN + msg + ENDC)
def info( msg):
print(OKBLUE + msg + ENDC)
def warn( msg):
print(WARNING + msg + ENDC)
def err( msg):
print(FAIL + msg + ENDC)

404
libs3/maxwellccs.py Normal file
View File

@ -0,0 +1,404 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
Maxwell Macros
v0.7.0
by Sam Neurohack
from /team/laser
Launchpad set a "current path"
"""
from OSC3 import OSCServer, OSCClient, OSCMessage
import time
import numpy as np
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)
import os, json
import midi3
if os.uname()[1]=='raspberrypi':
pass
port = 8090
ip = "127.0.0.1"
mididest = 'Session 1'
djdest = 'Port'
midichannel = 1
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
# store current value for computer 1
cc1 =[0]*140
current = {
"patch": 0,
"prefixLeft": "/osc/left/X",
"prefixRight": "/osc/right/X",
"suffix": "/amp",
"path": "/osc/left/X/curvetype",
"pathLeft": "/osc/left/X/curvetype",
"pathRight": "/osc/left/X/curvetype",
"previousmacro": -1,
"LeftCurveType": 0,
"lfo": 1,
"rotator": 1,
"translator": 1
}
specificvalues = {
# Sine: 0-32, Tri: 33-64, Square: 65-96, Line: 96-127
"curvetype": {"sin": 0, "saw": 33, "squ": 95, "lin": 127},
"freqlimit": {"1": 0, "4": 26, "16": 52, "32": 80, "127": 127},
"amptype": {"constant": 0, "lfo1": 33, "lfo2": 95, "lfo3": 127},
"phasemodtype": {"linear": 0,"sin": 90},
"phaseoffsettype": {"manual": 0, "lfo1": 33, "lfo2": 95, "lfo3": 127},
"ampoffsettype": { "manual": 0, "lfo1": 33, "lfo2": 95, "lfo3": 127},
"inversion": {"off": 0, "on": 127},
"colortype": {"solid": 0, "lfo": 127},
"modtype": {"sin": 0,"linear": 127},
"switch": {"off": 0,"on": 127},
"operation": {"+": 0, "-": 50, "*": 127}
}
#
# Maxwell CCs
#
def FindCC(FunctionName):
for Maxfunction in range(len(maxwell['ccs'])):
if FunctionName == maxwell['ccs'][Maxfunction]['Function']:
#print(FunctionName, "is CC", Maxfunction)
return Maxfunction
def LoadCC():
global maxwell
print("Loading Maxwell CCs Functions...")
if os.path.exists('maxwell.json'):
#print('File maxwell.json exits')
f=open("maxwell.json","r")
else:
if os.path.exists('../maxwell.json'):
#print('File ../maxwell.json exits')
f=open("../maxwell.json","r")
s = f.read()
maxwell = json.loads(s)
print(len(maxwell['ccs']),"Functions")
print("Loaded.")
# /cc cc number value
def cc(ccnumber, value, dest=mididest):
#print('Output CC',[CONTROLLER_CHANGE+midichannel-1, ccnumber, value], dest)
midi3.MidiMsg([CONTROLLER_CHANGE+midichannel-1,ccnumber,value], dest)
def NoteOn(note,velocity, dest=mididest):
midi3.NoteOn(note,velocity, mididest)
def NoteOff(note, dest=mididest):
midi3.NoteOn(note, mididest)
def Send(oscaddress,oscargs=''):
oscmsg = OSCMessage()
oscmsg.setAddress(oscaddress)
oscmsg.append(oscargs)
osclient = OSCClient()
osclient.connect((ip, port))
print("sending OSC message : ", oscmsg, "to", ip, ":",port)
try:
osclient.sendto(oscmsg, (ip, port))
oscmsg.clearData()
return True
except:
print ('Connection to', ip, 'refused : died ?')
return False
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 MixerLeft(value):
if value == 127:
Send("/mixer/value", 0)
def MixerRight(value):
if value == 127:
Send("/mixer/value", 127)
def MixerTempo(tempo):
for counter in range(127):
Send("/mixer/value", counter)
# Jog send 127 to left and 1 to right
# increase or decrease current CC defined in current path
def jogLeft(value):
path = current["pathLeft"]
print("jog : path =",path, "CC :", FindCC(path), "value", value)
MaxwellCC = FindCC(current["pathLeft"])
if value == 127:
# decrease CC
if cc1[MaxwellCC] > 0:
cc1[MaxwellCC] -= 1
else:
if cc1[MaxwellCC] < 127:
cc1[MaxwellCC] += 1
#print("sending", cc1[MaxwellCC], "to CC", MaxwellCC )
cc(MaxwellCC, cc1[MaxwellCC] , dest ='to Maxwell 1')
#RotarySpecifics(MaxwellCC, path[path.rfind("/")+1:len(path)], value)
# Jog send 127 to left and 1 to right
# increase or decrease current CC defined in current path
def jogRight(value):
path = current["pathRight"]
print("jog : path =",path, "CC :", FindCC(path), "value", value)
MaxwellCC = FindCC(current["pathRight"])
if value == 127:
# decrease CC
if cc1[MaxwellCC] > 0:
cc1[MaxwellCC] -= 1
else:
if cc1[MaxwellCC] < 127:
cc1[MaxwellCC] += 1
#print("sending", cc1[MaxwellCC], "to CC", MaxwellCC )
cc(MaxwellCC, cc1[MaxwellCC] , dest ='to Maxwell 1')
#RotarySpecifics(MaxwellCC, path[path.rfind("/")+1:len(path)], value)
# Parameter change : to left 127 / to right 0 or 1
def RotarySpecifics( MaxwellCC, specificsname, value):
global maxwell
print("Maxwell CC :",MaxwellCC)
print("Current :",maxwell['ccs'][MaxwellCC]['init'])
print("Specifics :",specificvalues[specificsname])
print("midi value :", value)
elements = list(enumerate(specificvalues[specificsname]))
print(elements)
nextype = maxwell['ccs'][MaxwellCC]['init']
for count,ele in elements:
if ele == maxwell['ccs'][MaxwellCC]['init']:
if count > 0 and value == 127:
nextype = elements[count-1][1]
if count < len(elements)-1 and value < 2:
#print("next is :",elements[count+1][1])
nextype = elements[count+1][1]
print("result :", nextype, "new value :", specificvalues[specificsname][nextype], "Maxwell CC", MaxwellCC)
maxwell['ccs'][MaxwellCC]['init'] = nextype
cc(MaxwellCC, specificvalues[specificsname][nextype], dest ='to Maxwell 1')
# Change type : trig with only with midi value 127 on a CC event
def ButtonSpecifics127( MaxwellCC, specificsname, value):
global maxwell
print("Maxwell CC :",MaxwellCC)
print("Current :",maxwell['ccs'][MaxwellCC]['init'])
print("Specifics :",specificvalues[specificsname])
print("midi value :", value)
elements = list(enumerate(specificvalues[specificsname]))
print(elements)
nextype = maxwell['ccs'][MaxwellCC]['init']
for count,ele in elements:
if ele == maxwell['ccs'][MaxwellCC]['init']:
if count >0 and value == 127:
nextype = elements[count-1][1]
if count < len(elements)-1 and value < 2:
#print("next is :",elements[count+1][1])
nextype = elements[count+1][1]
print("result :", nextype, "new value :", specificvalues[specificsname][nextype], "Maxwell CC", MaxwellCC)
maxwell['ccs'][MaxwellCC]['init'] = nextype
cc(MaxwellCC, specificvalues[specificsname][nextype], dest ='to Maxwell 1')
# Left cue button 127 = on 0 = off
def PrevPatch(value):
global current
print('PrevPatch function')
if value == 127 and current['patch'] - 1 > -1:
cc(9, 127, dest=djdest)
time.sleep(0.1)
current['patch'] -= 1
print("Current patch is now :",current['patch'])
midi3.NoteOn(current['patch'], 127, 'to Maxwell 1')
cc(9, 0, dest=djdest)
# Right cue button 127 = on 0 = off
def NextPatch(value):
global current
print('NextPatch function', current["patch"])
if value == 127 and current["patch"] + 1 < 41:
cc(3, 127, dest = djdest)
current["patch"] += 1
#ModeNote(current["patch"], 127, 'to Maxwell 1')
midi3.NoteOn(current["patch"], 127, 'to Maxwell 1')
print("Current patch is now :",current["patch"])
time.sleep(0.1)
cc(3, 0, dest = djdest)
# increase/decrease a CC
def changeCC(value, path):
global current
#path = current["pathLeft"]
MaxwellCC = FindCC(path)
cc1[MaxwellCC] += value
print("Change Left CC : path =",path, "CC :", FindCC(path), "is now ", cc1[MaxwellCC])
cc(MaxwellCC, cc1[MaxwellCC] , dest ='to Maxwell 1')
def PlusTenLeft(value):
value = 10
changeCC(value, current["pathLeft"])
def MinusTenLeft(value):
value = -10
changeCC(value, current["pathLeft"])
def PlusOneLeft(value):
value = 1
changeCC(value, current["pathLeft"])
def MinusOneLeft(value):
value = -1
changeCC(value, current["pathLeft"])
def PlusTenRight(value):
value = 10
changeCC(value, current["pathRight"])
def MinusTenRight(value):
value = -10
changeCC(value, current["pathRight"])
def PlusOneRight(value):
value = 1
changeCC(value, current["pathRight"])
def MinusOneRight(value):
value = -1
changeCC(value, current["pathRight"])
def ChangeCurveLeft(value):
MaxwellCC = FindCC(current["prefixLeft"] + '/curvetype')
RotarySpecifics(MaxwellCC, "curvetype", value)
def ChangeFreqLimitLeft(value):
MaxwellCC = FindCC(current["prefixLeft"] + '/freqlimit')
RotarySpecifics(MaxwellCC, "curvetype", value)
def ChangeATypeLeft(value):
MaxwellCC = FindCC(current["prefixLeft"] + '/freqlimit')
RotarySpecifics(MaxwellCC, "curvetype", value)
def ChangePMTypeLeft(value):
MaxwellCC = FindCC(current["prefixLeft"] + '/phasemodtype')
RotarySpecifics(MaxwellCC, "curvetype", value)
def ChangePOTypeLeft(value):
MaxwellCC = FindCC(current["prefixLeft"] + '/phaseoffsettype')
RotarySpecifics(MaxwellCC, "curvetype", value)
def ChangeAOTypeLeft(value):
MaxwellCC = FindCC(current["prefixLeft"] + '/ampoffsettype')
RotarySpecifics(MaxwellCC, "curvetype", value)
def ChangeCurveRight(value):
MaxwellCC = FindCC(current["prefixRight"] + '/curvetype')
RotarySpecifics(MaxwellCC, "curvetype", value)
def ChangeCurveLFO(value):
MaxwellCC = FindCC('/lfo/'+ current["lfo"] +'/curvetype')
RotarySpecifics(MaxwellCC, "curvetype", value)
def ChangeCurveRot(value):
MaxwellCC = FindCC('/rotator/'+ current["rotator"] +'/curvetype')
RotarySpecifics(MaxwellCC, "curvetype", value)
def ChangeCurveTrans(value):
MaxwellCC = FindCC('/translator/'+ current["translator"] +'/curvetype')
RotarySpecifics(MaxwellCC, "curvetype", value)

View File

@ -55,7 +55,7 @@ print('Midi startup...')
import gstt, bhoreal, launchpad, LPD8
from queue import Queue
#from OSC3 import OSCServer, OSCClient, OSCMessage
from OSC3 import OSCServer, OSCClient, OSCMessage
midiname = ["Name"] * 16
@ -153,7 +153,7 @@ def send(msg,device):
# mididest : all, launchpad, bhoreal, specificname
def NoteOn(note,color, mididest):
global MidInsNumber
gstt.note = note
gstt.velocity = color
@ -219,24 +219,31 @@ def NoteOff(note, mididest):
# mididest : all or specifiname, won't be sent to launchpad or Bhoreal.
def MidiMsg(midimsg, mididest):
#print("MidiMsg", midimsg, "Dest", mididest)
#print("midi3 got MidiMsg", midimsg, "Dest", mididest)
desterror = -1
for port in range(MidInsNumber):
##print("port",port,"midiname", midiname[port])
#print("port",port,"midiname", midiname[port])
# To mididest
if midiname[port].find(mididest) != -1:
#print("sending to name", midiname[port],midimsg)
#print("midi 3 sending to name", midiname[port], "port", port, ":", midimsg)
midiport[port].send_message(midimsg)
desterror = 0
# To All
elif mididest == "all" and midiname[port].find(mididest) == -1 and midiname[port].find(BhorealMidiName) == -1 and midiname[port].find(LaunchMidiName) == -1:
elif mididest == "all" and midiname[port].find(mididest) == -1 and midiname[port].find(BhorealMidiName) == -1 and midiname[port].find(LaunchMidiName) == -1 and midiname[port].find(DJName) == -1:
#print("all sending to port",port,"name", midiname[port])
midiport[port].send_message(midimsg)
desterror = 0
for OSCtarget in midi2OSC:
if (OSCtarget == mididest or mididest == 'all') and midi2OSC[OSCtarget]["msgs"]:
OSCsend(OSCtarget, "/cc", [midimsg[1], midimsg[2]])
desterror = 0
if desterror == -1:
print ("** This midi or OSC destination doesn't exists **")
def OSCsend(name, oscaddress, oscargs =''):
@ -303,25 +310,18 @@ def MidinProcess(inqueue, portname):
# Note On
if msg[0]==NOTE_ON:
print ("from", portname, "noteon", msg[1])
NoteOn(msg[1],msg[2],mididest)
# Webstatus(''.join(("note ",msg[1]," to ",msg[2])))
# NoteOn(msg[1],msg[2],mididest)
# Note Off
if msg[0]==NOTE_OFF:
print("from", portname,"noteoff")
NoteOff(msg[1],msg[2], mididest)
# Webstatus(''.join(("note ",msg[1]," to ",msg[2])))
# NoteOff(msg[1],msg[2], mididest)
# Midi CC message
if msg[0] == CONTROLLER_CHANGE:
print("from", portname,"CC :", msg[1], msg[2])
'''
Webstatus("CC :" + str(msg[1]) + " " + str(msg[2]))
for OSCtarget in midi2OSC:
if OSCtarget["notes"]:
pass
#OSCsend(OSCtarget, "/CC", note)
'''
# other midi message
if msg[0] != NOTE_OFF and msg[0] != NOTE_ON and msg[0] != CONTROLLER_CHANGE:
print("from", portname,"other midi message")

View File

@ -1,4 +1,4 @@
#!/usr/bin/python2.7
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
@ -9,9 +9,9 @@ Plugins Handler.
'''
from OSC import OSCServer, OSCClient, OSCMessage
from OSC3 import OSCServer, OSCClient, OSCMessage
from websocket_server import WebsocketServer
import gstt
from libs3 import gstt
import os
import subprocess
import sys
@ -34,6 +34,14 @@ def Port(name):
data = gstt.plugins.get(name)
return data.get("OSC")
def Ping(name):
sendWSall("/"+ name + "/start 0")
return OSCsend(name,"/ping",1)
#return True
# How to start the plugin ?
def Command(name):
@ -45,6 +53,34 @@ def Data(name):
return gstt.plugins.get(name)
def Kill(name):
#data = Data(name)
print("Killing", name, "...")
OSCsend(name,"/quit")
'''
if data["process"] != None:
print name, "plugin is owned by LJ."
print "Killing plugin", name
OSCsend(name,"/quit")
#data["process"].terminate()
sendWSall("/status Killing "+ name +".")
else:
print "Killing asked but plugin is not owned by LJ"
sendWSall("/status Not own plugin")
'''
def Restart(name):
Kill(name)
Start(name)
# See LJ.conf data
def Start(name):
@ -53,20 +89,30 @@ def Start(name):
sendWSall("/status Starting "+name+"...")
# Get LJ path
ljpath = r'%s' % os.getcwd().replace('\\','/')
#ljpath = r'%s' % os.getcwd().replace('\\','/')
print("")
print("LJ is starting plugin :", name)
print ""
print "LJ is starting plugin :", name
# Construct the command with absolute path.
PluginPath = command.split(" ")
# Launch as a subprocess
PluginProcess = subprocess.Popen([PluginPath[0], ljpath + "/" + PluginPath[1]])
print("launch :", PluginPath[0], gstt.ljpath + "/" + PluginPath[1])
# without argument
if len(PluginPath) < 3:
PluginProcess = subprocess.Popen( [PluginPath[0], gstt.ljpath + "/" + PluginPath[1] ], env=os.environ)
# with 1 argument
else:
PluginProcess = subprocess.Popen( [PluginPath[0], gstt.ljpath + "/" + PluginPath[1] + " " + PluginPath[2]], env=os.environ)
#PluginProcess = os.execv([PluginPath[0], ljpath + "/" + PluginPath[1]])
if gstt.debug >0:
print "LJ path :", ljpath
print "New process pid for ", name, ":", PluginProcess.pid
print("LJ path :", ljpath)
print("New process pid for ", name, ":", PluginProcess.pid)
'''
# Maybe it's not fully started
@ -114,17 +160,17 @@ def OSCsend(name, oscaddress, oscargs =''):
try:
if gstt.debug > 0:
print "Plugins manager : OSCsending", oscmsg,"to plugin", name, "at", gstt.LjayServerIP, ":", PluginPort
print("Plugins manager : OSCsending", oscmsg,"to plugin", name, "at", gstt.LjayServerIP, ":", PluginPort)
osclientplugin.sendto(oscmsg, (gstt.LjayServerIP, PluginPort))
oscmsg.clearData()
if gstt.debug >0:
print oscaddress, oscargs, "was sent to",name
print(oscaddress, oscargs, "was sent to",name)
return True
except:
if gstt.debug > 0:
print 'OSCSend : Connection to plugin IP', gstt.LjayServerIP ,':', PluginPort,'refused : died ?'
print('OSCSend : Connection to plugin IP', gstt.LjayServerIP ,':', PluginPort,'refused : died ?')
#sendWSall("/status No plugin.")
#sendWSall("/status " + name + " is offline")
#sendWSall("/" + name + "/start 0")
@ -132,33 +178,19 @@ def OSCsend(name, oscaddress, oscargs =''):
return False
def Ping(name):
sendWSall("/"+ name + "/start 0")
return OSCsend(name,"/ping",1)
#return True
# for each plugin will automatically add /pluginame before oscpath to send like /aurora/scim 1, if oscpath = "/scim 1"
def SendAll(oscpath):
if gstt.debug > 0:
print("Sending to all plugins ", oscpath)
def Kill(name):
for plugin in list(gstt.plugins.keys()):
if gstt.debug > 0:
print("sending ",oscpath,"to", plugin)
#sendWSall("/"+ plugin + "/start 0")
Send(plugin, "/"+plugin+oscpath)
#data = Data(name)
print "Killing",name
OSCsend(name,"/quit")
'''
if data["process"] != None:
print name, "plugin is owned by LJ."
print "Killing plugin", name
OSCsend(name,"/quit")
#data["process"].terminate()
sendWSall("/status Killing "+ name +".")
else:
print "Killing asked but plugin is not owned by LJ"
sendWSall("/status Not own plugin")
'''
# Send a command to given plugin. Will also start it if command contain /start 1
def Send(name, oscpath):
@ -173,15 +205,15 @@ def Send(name, oscpath):
#sendWSall("/" + name + "/start 1")
#sendWSall("/status " + name + " online")