newUI, python3,...
This commit is contained in:
parent
0bb0049f02
commit
e9d3009ffb
551 changed files with 22992 additions and 787437 deletions
302
libs3/LPD8.py
Normal file
302
libs3/LPD8.py
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
LPD8
|
||||
v0.7.0
|
||||
|
||||
LPD8 Handler.
|
||||
Start a dedicated thread to handle incoming events from LPD8 midi controller.
|
||||
|
||||
Depending on selected destination computer (Prog Chg + Pad number) actions will be done
|
||||
locally or forwarded via OSC to given computer. Remote computer must run bhorpad or
|
||||
maxwellator.
|
||||
|
||||
# Note
|
||||
|
||||
# Program Change button selected : change destination computer
|
||||
|
||||
# CC rotary -> midi CC.
|
||||
|
||||
|
||||
by Sam Neurohack
|
||||
from /team/laser
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
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 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
|
||||
import socket
|
||||
|
||||
|
||||
myIP = "127.0.0.1"
|
||||
|
||||
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
|
||||
|
||||
LPD8queue = Queue()
|
||||
|
||||
mode = "maxwell"
|
||||
mididest = 'Session 1'
|
||||
|
||||
midichannel = 1
|
||||
CChannel = 0
|
||||
CCvalue = 0
|
||||
Here = -1
|
||||
|
||||
ModeCallback = ''
|
||||
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 NoteOn(note,velocity, dest=mididest):
|
||||
midi3.NoteOn(note,velocity, mididest)
|
||||
|
||||
def NoteOff(note, dest=mididest):
|
||||
midi3.NoteOn(note, mididest)
|
||||
|
||||
|
||||
def ComputerUpdate(comput):
|
||||
global computer
|
||||
|
||||
computer = comput
|
||||
|
||||
|
||||
|
||||
# Client to export buttons actions from LPD8 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
|
||||
|
||||
|
||||
#
|
||||
# Events from LPD8 buttons
|
||||
#
|
||||
|
||||
# Process events coming from LPD8 in a separate thread.
|
||||
|
||||
def MidinProcess(LPD8queue):
|
||||
global computer
|
||||
|
||||
|
||||
while True:
|
||||
LPD8queue_get = LPD8queue.get
|
||||
msg = LPD8queue_get()
|
||||
#print (msg)
|
||||
|
||||
# Note
|
||||
if msg[0]==NOTE_ON:
|
||||
|
||||
# note mode
|
||||
ModeNote(msg[1], msg[2], mididest)
|
||||
|
||||
'''
|
||||
# ModeOS
|
||||
if msg[2] > 0:
|
||||
ModeOS(msg[0])
|
||||
'''
|
||||
|
||||
|
||||
# Program Change button selected : change destination computer
|
||||
if msg[0]==PROGRAM_CHANGE:
|
||||
|
||||
print(("Program change : ", str(msg[1])))
|
||||
# Change destination computer mode
|
||||
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]))
|
||||
|
||||
if computer == 0 or computer == 1:
|
||||
cc(int(msg[1]), int(msg[2]))
|
||||
|
||||
else:
|
||||
SendOSC(computerIP[computer-1], maxwellatorPort, '/cc', [int(msg[1]), int(msg[2])])
|
||||
|
||||
#
|
||||
# Notes = midi notes
|
||||
#
|
||||
|
||||
def ModeNote(note, velocity, mididest):
|
||||
|
||||
|
||||
print(('computer',computer))
|
||||
|
||||
# todo : decide whether its 0 or 1 !!!
|
||||
if computer == 0 or computer == 1:
|
||||
midi3.NoteOn(arg, velocity, mididest)
|
||||
|
||||
|
||||
if velocity == 127:
|
||||
pass
|
||||
#print ('NoteON', BhorNoteXY(x,y),notename , "velocity", velocity )
|
||||
#Disp(notename)
|
||||
else:
|
||||
midi3.NoteOff(arg)
|
||||
#print ('NoteOFF', BhorNoteXY(x,y),notename , "velocity", velocity )
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Notes = OS Macros
|
||||
#
|
||||
|
||||
def ModeOS(arg):
|
||||
|
||||
|
||||
macroname = 'n'+arg
|
||||
macronumber = findMacros(macroname,'OS')
|
||||
if macronumber != -1:
|
||||
|
||||
eval(macros['OS'][macronumber]["code"])
|
||||
else:
|
||||
print("no Code yet")
|
||||
|
||||
|
||||
|
||||
LPD8queue = Queue()
|
||||
|
||||
|
||||
# LPD8 Mini call back : new msg forwarded to LPD8 queue
|
||||
class LPD8AddQueue(object):
|
||||
def __init__(self, port):
|
||||
self.port = port
|
||||
#print("LPD8AddQueue", 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)))
|
||||
LPD8queue.put(message)
|
||||
|
||||
#
|
||||
# Modes :
|
||||
#
|
||||
|
||||
# Load Matrix only macros (for the moment) in macros.json
|
||||
def LoadMacros():
|
||||
global macros
|
||||
|
||||
print()
|
||||
print("Loading LPD8 Macros...")
|
||||
|
||||
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("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
|
||||
|
||||
|
||||
|
||||
# Not assigned buttons
|
||||
def DefaultMacro(arg):
|
||||
|
||||
print(("DefaultMacro", arg))
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Default macros
|
||||
#
|
||||
|
||||
|
||||
LPD8macros = {
|
||||
|
||||
"n1": {"command": DefaultMacro, "default": 1},
|
||||
"n2": {"command": DefaultMacro, "default": 2},
|
||||
"n3": {"command": DefaultMacro, "default": 3},
|
||||
"n4": {"command": DefaultMacro, "default": 4},
|
||||
"n5": {"command": DefaultMacro, "default": 5},
|
||||
"n6": {"command": DefaultMacro, "default": 6},
|
||||
"n7": {"command": DefaultMacro, "default": 7},
|
||||
"n8": {"command": DefaultMacro, "default": 8}
|
||||
}
|
||||
|
||||
|
||||
def Run(macroname, macroargs=''):
|
||||
|
||||
doit = LPD8macros[macroname]["command"]
|
||||
if macroargs=='':
|
||||
macroargs = LPD8macros[macroname]["default"]
|
||||
#print("Running", doit, "with args", macroargs )
|
||||
doit(macroargs)
|
||||
|
||||
LoadMacros()
|
||||
2873
libs3/OSC3.py
Normal file
2873
libs3/OSC3.py
Normal file
File diff suppressed because it is too large
Load diff
212
libs3/OSCom.py
Normal file
212
libs3/OSCom.py
Normal 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
|
||||
'''
|
||||
0
libs3/__init__.py
Normal file
0
libs3/__init__.py
Normal file
107
libs3/alink.py
Normal file
107
libs3/alink.py
Normal 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)
|
||||
|
||||
|
||||
|
||||
370
libs3/artnet.py
Normal file
370
libs3/artnet.py
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
"""
|
||||
|
||||
ArtNet/DMX Handler :
|
||||
v0.7.0
|
||||
|
||||
|
||||
by Sam Neurohack
|
||||
from /team/laser
|
||||
|
||||
Artnet receving code from https://github.com/kongr45gpen/simply-artnet
|
||||
Laser selection
|
||||
one universe / laser
|
||||
|
||||
Plugin selection
|
||||
banck change/scene/
|
||||
|
||||
"""
|
||||
|
||||
|
||||
import random
|
||||
import pysimpledmx
|
||||
from serial.tools import list_ports
|
||||
import serial,time
|
||||
from threading import Thread
|
||||
import socket
|
||||
import struct
|
||||
import types
|
||||
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:
|
||||
from OSC3 import OSCServer, OSCClient, OSCMessage
|
||||
|
||||
ljpath = r'%s' % os.getcwd().replace('\\','/')
|
||||
|
||||
# import from shell
|
||||
|
||||
#sys.path.append('../../libs')
|
||||
|
||||
#import from LJ
|
||||
sys.path.append(ljpath +'/libs/')
|
||||
|
||||
import lj23layers as lj
|
||||
|
||||
#
|
||||
# Init
|
||||
#
|
||||
|
||||
OSCinPort = 8032
|
||||
|
||||
|
||||
sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
|
||||
sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
|
||||
sock.bind(('',6454))
|
||||
|
||||
dmxeq = {}
|
||||
dmxstates = []
|
||||
dmxinit = False
|
||||
universe = []
|
||||
|
||||
|
||||
for i in range(1,514):
|
||||
dmxstates.append(-1)
|
||||
|
||||
|
||||
print ("")
|
||||
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)
|
||||
argsparser.add_argument("-s","--subuniverse",help="Subniverse, not implemented (0 by default)",type=int)
|
||||
argsparser.add_argument("-r","--redisIP",help="IP of the Redis server used by LJ (127.0.0.1 by default) ",type=str)
|
||||
argsparser.add_argument("-m","--myIP",help="Local IP (127.0.0.1 by default) ",type=str)
|
||||
argsparser.add_argument("-v","--verbose",help="Verbosity level (0 by default)",type=int)
|
||||
|
||||
args = argsparser.parse_args()
|
||||
|
||||
|
||||
# Universe
|
||||
if args.universe:
|
||||
universenb = args.universe
|
||||
else:
|
||||
universenb = 0
|
||||
|
||||
# Universe
|
||||
if args.subuniverse:
|
||||
subuniversenb = args.subuniverse
|
||||
else:
|
||||
subuniversenb = 0
|
||||
|
||||
# Debug level
|
||||
if args.verbose:
|
||||
debug = args.verbose
|
||||
else:
|
||||
debug = 0
|
||||
|
||||
# Redis Computer IP
|
||||
if args.redisIP != None:
|
||||
redisIP = args.redisIP
|
||||
else:
|
||||
redisIP = '127.0.0.1'
|
||||
|
||||
# myIP
|
||||
if args.myIP != None:
|
||||
myIP = args.myIP
|
||||
else:
|
||||
myIP = '127.0.0.1'
|
||||
|
||||
r = lj.Config(redisIP, 255, "artnet")
|
||||
|
||||
lj.WebStatus("Artnet init...")
|
||||
|
||||
def lhex(h):
|
||||
return ':'.join(x.encode('hex') for x in h)
|
||||
|
||||
|
||||
def senddmx0():
|
||||
for channel in range (1,512):
|
||||
senddmx(channel,0)
|
||||
|
||||
def senddmx(channel, value):
|
||||
|
||||
print("Setting channel %d to %d" % (i,value))
|
||||
#mydmx.setChannel((channel + 1 ), value, autorender=True)
|
||||
# calling render() is better more reliable to actually sending data
|
||||
# Some strange bug. Need to add one to required dmx channel is done automatically
|
||||
mydmx.setChannel((channel ), value)
|
||||
mydmx.render()
|
||||
print("Sending DMX Channel : ", str(channel), " value : ", str(value))
|
||||
|
||||
def updateDmxValue(channel, val):
|
||||
|
||||
#
|
||||
if dmxstates[channel] == -1:
|
||||
dmxstates[channel] = val
|
||||
|
||||
# DMX UPDATE!!! WOW!!!
|
||||
if dmxstates[channel] != val:
|
||||
dmxstates[channel] = val
|
||||
print("updating channel", channel, "with ", val)
|
||||
if mydmx != False:
|
||||
senddmx(channel, ord(val))
|
||||
|
||||
|
||||
# Search for DMX devices
|
||||
|
||||
#ljnozoids.WebStatus("Available serial devices")
|
||||
|
||||
|
||||
print("Available serial devices...")
|
||||
ports = list(list_ports.comports())
|
||||
|
||||
portnumber = 0
|
||||
|
||||
# Get all serial ports names
|
||||
for i, p in enumerate(ports):
|
||||
|
||||
print(i, ":", p)
|
||||
|
||||
if p[0]== "/dev/ttyUSB0":
|
||||
portname[portnumber] = p[0]
|
||||
portnumber += 1
|
||||
|
||||
|
||||
if platform == 'darwin' and p[1].find("DMX USB PRO") != -1:
|
||||
portname[portnumber] = p[0]
|
||||
portnumber += 1
|
||||
|
||||
|
||||
# ljnozoids.WebStatus("Found " + str(portnumber) +" Nozoids.")
|
||||
|
||||
print("Found", portnumber, "DMX devices")
|
||||
|
||||
|
||||
if portnumber > 0:
|
||||
|
||||
print("with serial names", portname)
|
||||
mydmx = pysimpledmx.DMXConnection(gstt.serdmx[0])
|
||||
senddmx0()
|
||||
time.sleep(1)
|
||||
|
||||
# Send a random value to channel 1
|
||||
vrand=random.randint(0,255)
|
||||
senddmx(1,vrand)
|
||||
|
||||
else:
|
||||
mydmx = False
|
||||
print("No DMX found, Art-Net receiver only.")
|
||||
|
||||
|
||||
#
|
||||
# OSC
|
||||
#
|
||||
|
||||
oscserver = OSCServer( (myIP, OSCinPort) )
|
||||
oscserver.timeout = 0
|
||||
#oscrun = True
|
||||
|
||||
# this method of reporting timeouts only works by convention
|
||||
# that before calling handle_request() field .timed_out is
|
||||
# set to False
|
||||
def handle_timeout(self):
|
||||
self.timed_out = True
|
||||
|
||||
# funny python's way to add a method to an instance of a class
|
||||
oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver)
|
||||
|
||||
|
||||
# default handler
|
||||
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",))
|
||||
if len(args) > 0:
|
||||
print(("args", args))
|
||||
else:
|
||||
print("noargs")
|
||||
#oscIPout = str(source[0])
|
||||
#osclient.connect((oscIPout, oscPORTout))
|
||||
|
||||
|
||||
# RAW OSC Frame available ?
|
||||
def OSCframe():
|
||||
|
||||
# clear timed_out flag
|
||||
print ("oscframe")
|
||||
oscserver.timed_out = False
|
||||
# handle all pending requests then return
|
||||
while not oscserver.timed_out:
|
||||
oscserver.handle_request()
|
||||
|
||||
|
||||
# Stop osc server
|
||||
def OSCstop():
|
||||
|
||||
oscrun = False
|
||||
oscserver.close()
|
||||
|
||||
|
||||
# /sendmx channel value
|
||||
def OSCsendmx(path, tags, args, source):
|
||||
|
||||
channel = args[0]
|
||||
val = args[1]
|
||||
updateDmxValue(channel, val)
|
||||
|
||||
|
||||
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:
|
||||
|
||||
while lj.oscrun:
|
||||
|
||||
data = sock.recv(10240)
|
||||
if len(data) < 20:
|
||||
continue
|
||||
|
||||
if data[0:7] != "Art-Net" or data[7] != "\0":
|
||||
print("artnet package")
|
||||
#lj.WebStatus("Artnet package")
|
||||
continue
|
||||
OSCframe()
|
||||
|
||||
if ord(data[8]) != 0x00 or ord(data[9]) != 0x50:
|
||||
print("OpDmx")
|
||||
continue
|
||||
|
||||
print(("oscrun", lj.oscrun))
|
||||
protverhi = ord(data[10])
|
||||
protverlo = ord(data[11])
|
||||
sequence = ord(data[12])
|
||||
physical = ord(data[13])
|
||||
subuni = ord(data[14])
|
||||
net = ord(data[15])
|
||||
lengthhi = ord(data[16])
|
||||
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))
|
||||
|
||||
for i in range(0,510):
|
||||
updateDmxValue(i+1,dmx[i])
|
||||
|
||||
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
|
||||
finally:
|
||||
|
||||
lj.ClosePlugin()
|
||||
sock.close()
|
||||
OSCstop()
|
||||
'''
|
||||
import sys, socket, math, time
|
||||
from ctypes import *
|
||||
|
||||
class Artnet:
|
||||
class ArtNetDMXOut(LittleEndianStructure):
|
||||
PORT = 0x1936
|
||||
_fields_ = [("id", c_char * 8),
|
||||
("opcode", c_ushort),
|
||||
("protverh", c_ubyte),
|
||||
("protver", c_ubyte),
|
||||
("sequence", c_ubyte),
|
||||
("physical", c_ubyte),
|
||||
("universe", c_ushort),
|
||||
("lengthhi", c_ubyte),
|
||||
("length", c_ubyte),
|
||||
("payload", c_ubyte * 512)]
|
||||
|
||||
def __init__(self):
|
||||
self.id = b"Art-Net"
|
||||
self.opcode = 0x5000
|
||||
self.protver = 14
|
||||
self.universe = 0
|
||||
self.lengthhi = 2
|
||||
|
||||
def __init__(self):
|
||||
self.artnet = Artnet.ArtNetDMXOut()
|
||||
self.S = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
|
||||
for i in range(512):
|
||||
self.artnet.payload[i] = 0
|
||||
|
||||
def send(self,data,IP,port):
|
||||
# send(送るデータ,IPアドレス,ポート番号)
|
||||
self.artnet.universe = port
|
||||
for i in range(512):
|
||||
if(i < len(data)):
|
||||
self.artnet.payload[i] = data[i]
|
||||
else:
|
||||
break
|
||||
self.S.sendto(self.artnet,(IP,Artnet.ArtNetDMXOut.PORT))
|
||||
|
||||
if __name__ == '__main__':
|
||||
artnet = Artnet()
|
||||
data = [0] * 512
|
||||
for i in range(150):
|
||||
data[i*3+0] = 0
|
||||
data[i*3+1] = 0
|
||||
data[i*3+2] = 0
|
||||
artnet.send(data,"133.15.42.111",5)
|
||||
'''
|
||||
292
libs3/audio.py
Normal file
292
libs3/audio.py
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Audio Spectrum analyser
|
||||
v0.7.0
|
||||
|
||||
- summed given fft in n bands, but re normalized between 0 - 70?
|
||||
- Peaks L and R
|
||||
- amplitude for given target frequency and PEAK frequency
|
||||
- "music note" to given frequency
|
||||
- Real FFT, Imaginary FFT, Real + imaginary FFT
|
||||
- threshold detection
|
||||
|
||||
todo :
|
||||
|
||||
|
||||
by Sam Neurohack
|
||||
from /team/laser
|
||||
|
||||
for python 2 & 3
|
||||
|
||||
Stereo : CHANNELS = 2
|
||||
mono : CHANNELS = 1
|
||||
|
||||
"""
|
||||
|
||||
|
||||
import numpy as np
|
||||
import pyaudio
|
||||
from math import log, pow
|
||||
|
||||
#import matplotlib.pyplot as plt
|
||||
|
||||
#from scipy.interpolate import Akima1DInterpolator
|
||||
#import matplotlib.pyplot as plt
|
||||
|
||||
DEVICE = 3
|
||||
CHANNELS = 2
|
||||
START = 0
|
||||
RATE = 44100 # time resolution of the recording device (Hz)
|
||||
CHUNK = 4096 # number of data points to read at a time. Almost 10 update/second
|
||||
TARGET = 2100 # show only this one frequency
|
||||
|
||||
|
||||
A4 = 440
|
||||
C0 = A4*pow(2, -4.75)
|
||||
name = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
|
||||
data = []
|
||||
|
||||
p = pyaudio.PyAudio() # start the PyAudio class
|
||||
stream = p.open(format = pyaudio.paInt16, channels = CHANNELS, input_device_index = DEVICE, rate=RATE, input=True,
|
||||
frames_per_buffer=CHUNK) #uses default input device
|
||||
|
||||
|
||||
#
|
||||
# Audio devices & audiogen functions
|
||||
#
|
||||
|
||||
def list_devices():
|
||||
# List all audio input devices
|
||||
p = pyaudio.PyAudio()
|
||||
i = 0
|
||||
n = p.get_device_count()
|
||||
print((n,"devices found"))
|
||||
while i < n:
|
||||
dev = p.get_device_info_by_index(i)
|
||||
if dev['maxInputChannels'] > 0:
|
||||
print((str(i)+'. '+dev['name']))
|
||||
i += 1
|
||||
|
||||
|
||||
def valid_input_devices(self):
|
||||
"""
|
||||
See which devices can be opened for microphone input.
|
||||
call this when no PyAudio object is loaded.
|
||||
"""
|
||||
mics=[]
|
||||
for device in range(self.p.get_device_count()):
|
||||
if self.valid_test(device):
|
||||
mics.append(device)
|
||||
if len(mics)==0:
|
||||
print("no microphone devices found!")
|
||||
else:
|
||||
print(("found %d microphone devices: %s"%(len(mics),mics)))
|
||||
return mics
|
||||
|
||||
|
||||
|
||||
def loop():
|
||||
try:
|
||||
|
||||
#plt.ion()
|
||||
|
||||
#plt.axis([x[0], x[-1], -0.1, max_f])
|
||||
fftbands = [0,1,2,3,4,5,6,7,8,9]
|
||||
plt.xlabel('frequencies')
|
||||
plt.ylabel('amplitude')
|
||||
data = audioinput()
|
||||
drawfreq, fft = allfft(data)
|
||||
#lines = plt.plot(drawfreq, fft)
|
||||
|
||||
#plt.axis([drawfreq[0], drawfreq[-1], 0, np.max(fft)])
|
||||
#plt.plot(drawfreq, fft)
|
||||
#plt.show()
|
||||
#line, = plt.plot(fftbands, levels(fft,10))
|
||||
line, = plt.plot(drawfreq, fft)
|
||||
#while True :
|
||||
for i in range(50):
|
||||
|
||||
data = audioinput()
|
||||
|
||||
# smooth the FFT by windowing data
|
||||
#data = data * np.hanning(len(data))
|
||||
|
||||
# conversion to -1 to +1
|
||||
# normed_samples = (data / float(np.iinfo(np.int16).max))
|
||||
|
||||
# Left is channel 0
|
||||
dataL = data[0::2]
|
||||
# Right is channel 1
|
||||
dataR = data[1::2]
|
||||
|
||||
# Peaks L and R
|
||||
peakL = np.abs(np.max(dataL)-np.min(dataL))/CHUNK
|
||||
peakR = np.abs(np.max(dataR)-np.min(dataR))/CHUNK
|
||||
# print(peakL, peakR)
|
||||
|
||||
drawfreq, fft = allfft(data)
|
||||
#fft, fftr, ffti, fftb, drawfreq = allfft(data)
|
||||
|
||||
#line.set_ydata(levels(fft,10))
|
||||
line.set_ydata(fft)
|
||||
plt.pause(0.01)
|
||||
#print(drawfreq)
|
||||
#print(fft)
|
||||
#print (levels(fft,10))
|
||||
|
||||
#line.set_ydata(fft)
|
||||
#plt.pause(0.01) # pause avec duree en secondes
|
||||
|
||||
# lines = plt.plot(x, y)
|
||||
#lines[0].set_ydata(fft)
|
||||
#plt.legend(['s=%4.2f' % s])
|
||||
#plt.draw()
|
||||
#plt.show()
|
||||
|
||||
|
||||
|
||||
'''
|
||||
targetpower,freqPeak = basicfft(audioinput(stream))
|
||||
print("amplitude", targetpower, "@", TARGET, "Hz")
|
||||
if freqPeak > 0.0:
|
||||
print("peak frequency: %d Hz"%freqPeak, pitch(freqPeak))
|
||||
'''
|
||||
plt.show()
|
||||
|
||||
except KeyboardInterrupt:
|
||||
stream.stop_stream()
|
||||
stream.close()
|
||||
p.terminate()
|
||||
|
||||
print("End...")
|
||||
|
||||
# Close properly
|
||||
def close():
|
||||
stream.stop_stream()
|
||||
stream.close()
|
||||
p.terminate()
|
||||
|
||||
|
||||
# Return "music note" to given frequency
|
||||
def pitch(freq):
|
||||
h = round(12*(log(freq/C0)/log(2)))
|
||||
octave = h // 12
|
||||
n = h % 12
|
||||
return name[n] + str(octave)
|
||||
|
||||
|
||||
# Return summed given fft in n bands, but re normalized 0 - 70
|
||||
def levels(fourier, bands):
|
||||
|
||||
size = int(len(fourier))
|
||||
levels = [0.0] * bands
|
||||
|
||||
# Add up for n bands
|
||||
# remove normalizer if you want raw added data in all bands
|
||||
normalizer = size/bands
|
||||
#print (size,bands,size/bands)
|
||||
levels = [sum(fourier[I:int(I+size/bands)])/normalizer for I in range(0, size, int(size/bands))][:bands]
|
||||
|
||||
for band in range(bands):
|
||||
if levels[band] == np.NINF:
|
||||
levels[band] =0
|
||||
|
||||
|
||||
return levels
|
||||
|
||||
|
||||
# read CHUNK size in audio buffer
|
||||
def audioinput():
|
||||
|
||||
# When reading from our 16-bit stereo stream, we receive 4 characters (0-255) per
|
||||
# sample. To get them in a more convenient form, numpy provides
|
||||
# fromstring() which will for each 16 bits convert it into a nicer form and
|
||||
# turn the string into an array.
|
||||
return np.fromstring(stream.read(CHUNK),dtype=np.int16)
|
||||
|
||||
# power for given TARGET frequency and PEAK frequency
|
||||
# do fft first. No conversion in 'powers'
|
||||
def basicfft(data):
|
||||
|
||||
#data = data * np.hanning(len(data)) # smooth the FFT by windowing data
|
||||
fft = abs(np.fft.fft(data).real)
|
||||
#fft = 10*np.log10(fft)
|
||||
fft = fft[:int(len(fft)/2)] # first half of fft
|
||||
|
||||
freq = np.fft.fftfreq(CHUNK,1.0/RATE)
|
||||
freq = freq[:int(len(freq)/2)] # first half of FFTfreq
|
||||
|
||||
assert freq[-1]>TARGET, "ERROR: increase chunk size"
|
||||
|
||||
# return power for given TARGET frequency and peak frequency
|
||||
return fft[np.where(freq > TARGET)[0][0]], freq[np.where(fft == np.max(fft))[0][0]]+1
|
||||
|
||||
|
||||
# todo : Try if data = 1024 ?
|
||||
# in "power' (0-70?) get Real FFT, Imaginary FFT, Real + imaginary FFT
|
||||
def allfft(data):
|
||||
|
||||
#print ("allfft", len(data))
|
||||
fft = np.fft.fft(data)
|
||||
#print("fft",len(fft))
|
||||
fftr = 10*np.log10(abs(fft.real))[:int(len(data)/2)]
|
||||
ffti = 10*np.log10(abs(fft.imag))[:int(len(data)/2)]
|
||||
fftb = 10*np.log10(np.sqrt(fft.imag**2+fft.real**2))[:int(len(data)/2)]
|
||||
#print("fftb",len(fftb))
|
||||
drawfreq = np.fft.fftfreq(np.arange(len(data)).shape[-1])[:int(len(data)/2)]
|
||||
drawfreq = drawfreq*RATE/1000 #make the frequency scale
|
||||
#return fft, fftr, ffti, fftb, drawfreq
|
||||
return drawfreq, fftb
|
||||
|
||||
# Draw Original datas
|
||||
# X : np.arange(len(data))/float(rate)*1000
|
||||
# Y : data
|
||||
|
||||
# Draw real FFT
|
||||
# X : drawfreq
|
||||
# Y : fftr
|
||||
|
||||
# Draw imaginary
|
||||
# X : drawfreq
|
||||
# Y : ffti
|
||||
|
||||
# Draw Real + imaginary
|
||||
# X : drawfreq
|
||||
# Y : fftb
|
||||
|
||||
|
||||
# True if any value in the data is greater than threshold and after a certain delay
|
||||
def ding(right,threshold):
|
||||
if max(right) > threshold and time.time() - last_run > min_delay:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
last_run = time.time()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
|
||||
loop()
|
||||
'''
|
||||
x = np.linspace(0, 3, 100)
|
||||
k = 2*np.pi
|
||||
w = 2*np.pi
|
||||
dt = 0.01
|
||||
|
||||
t = 0
|
||||
for i in range(50):
|
||||
y = np.cos(k*x - w*t)
|
||||
if i == 0:
|
||||
line, = plt.plot(x, y)
|
||||
else:
|
||||
line.set_ydata(y)
|
||||
plt.pause(0.01) # pause avec duree en secondes
|
||||
t = t + dt
|
||||
|
||||
plt.show()
|
||||
'''
|
||||
|
||||
271
libs3/bhoreal.py
Normal file
271
libs3/bhoreal.py
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
# coding=UTF-8
|
||||
"""
|
||||
Bhoreal
|
||||
v0.7.0
|
||||
Bhoreal Led matrix Handler
|
||||
|
||||
Start a dedicated thread to handle incoming events from launchpad.
|
||||
|
||||
Cls()
|
||||
AllColor(color)
|
||||
StarttBhoreal(port) : Start animation
|
||||
|
||||
Led Matrix can be access with X and Y coordinates and as midi note (0-63)
|
||||
|
||||
NoteOn(note,color)
|
||||
NoteOff(note)
|
||||
NoteOnXY(x,y,color):
|
||||
NoteOffXY(x,y):
|
||||
NoteXY(x,y):
|
||||
|
||||
gstt.BhorLeds[] array stores matrix current state
|
||||
|
||||
by Sam Neurohack
|
||||
from /team/laser
|
||||
|
||||
"""
|
||||
|
||||
import time
|
||||
from rtmidi.midiconstants import (CHANNEL_PRESSURE, CONTROLLER_CHANGE, NOTE_ON, NOTE_OFF,
|
||||
PITCH_BEND, POLY_PRESSURE, PROGRAM_CHANGE)
|
||||
from . import gstt, midi3
|
||||
import sys
|
||||
|
||||
gstt.BhorLeds = [0]*65
|
||||
|
||||
|
||||
Here = -1
|
||||
from queue import Queue
|
||||
|
||||
def NoteOn(note,color):
|
||||
|
||||
print(("bhoreal noteon", note, color))
|
||||
msg = [NOTE_ON, note, color]
|
||||
midi3.send(msg,"Bhoreal")
|
||||
gstt.BhorLeds[note]=color
|
||||
|
||||
def NoteOff(note):
|
||||
msg = [NOTE_OFF, note, 0]
|
||||
midi3.send(msg,"Bhoreal")
|
||||
gstt.BhorLeds[note]=0
|
||||
|
||||
|
||||
def NoteOnXY(x,y,color):
|
||||
#print x,y
|
||||
msg = [NOTE_ON, NoteXY(x,y), color]
|
||||
midi3.send(msg,"Bhoreal")
|
||||
gstt.BhorLeds[NoteXY(x,y)]=color
|
||||
|
||||
def NoteOffXY(x,y):
|
||||
msg = [NOTE_OFF, NoteXY(x,y), 0]
|
||||
midi3.send(msg,"Bhoreal")
|
||||
gstt.BhorLeds[NoteXY(x,y)]=0
|
||||
|
||||
|
||||
# Leds position are humans numbers 1-8. So -1 for pythonic array position 0-7
|
||||
def NoteXY(x,y):
|
||||
note = (x -1)+ (y-1) * 8
|
||||
return note
|
||||
|
||||
def Index(note):
|
||||
y=note/8
|
||||
x=note%8
|
||||
#print "Note : ",note
|
||||
#print "BhorIndex : ", x+1,y+1
|
||||
return int(x+1),int(y+1)
|
||||
|
||||
#
|
||||
# Bhoreal Start anim
|
||||
#
|
||||
|
||||
# AllColor for bhoreal on given port
|
||||
|
||||
def AllColor(port,color):
|
||||
for led in range(0,64,1):
|
||||
msg = [NOTE_ON, led, color]
|
||||
midi3.send(msg,"Bhoreal")
|
||||
|
||||
# Cls for bhoreal on given port
|
||||
|
||||
def Cls(port):
|
||||
for led in range(0,64,1):
|
||||
msg = [NOTE_OFF, led, 0]
|
||||
midi3.send(msg,"Bhoreal")
|
||||
|
||||
|
||||
|
||||
def StartBhoreal(port):
|
||||
|
||||
Cls(port)
|
||||
time.sleep(0.2)
|
||||
for color in range(0,126,1):
|
||||
AllColor(port,color)
|
||||
time.sleep(0.02)
|
||||
time.sleep(0.2)
|
||||
Cls(port)
|
||||
|
||||
|
||||
|
||||
def UpdateLine(line,newval):
|
||||
if gstt.BhorealHere != -1:
|
||||
for led in range(8):
|
||||
NoteOffXY(led,line)
|
||||
|
||||
NoteOnXY(newval,line,64)
|
||||
|
||||
|
||||
|
||||
# Update Laser
|
||||
def Noteon_Update(note):
|
||||
|
||||
'''
|
||||
# forward new instruction ?
|
||||
if gstt.MyLaser != gstt.Laser:
|
||||
doit = jumplaser.get(gstt.Laser)
|
||||
doit("/noteon",note)
|
||||
'''
|
||||
#
|
||||
|
||||
|
||||
if note < 8:
|
||||
pass
|
||||
|
||||
#
|
||||
if note > 7 and note < 16:
|
||||
pass
|
||||
|
||||
#
|
||||
if note > 15 and note < 24:
|
||||
pass
|
||||
|
||||
# change current simulator PL
|
||||
if note > 23 and note < 32:
|
||||
pass
|
||||
|
||||
if note == 57 or note == 58:
|
||||
pass
|
||||
|
||||
if note > 58:
|
||||
pass
|
||||
|
||||
'''
|
||||
# todo 57 Color mode : Rainbow
|
||||
# 58 Color mode : RGB
|
||||
|
||||
# Notes for Curve : 0-7
|
||||
def UpdateCurve():
|
||||
print ("New Curve :", gstt.Curve)
|
||||
if gstt.BhorealHere != -1:
|
||||
for led in range(0,8):
|
||||
NoteOff(led)
|
||||
NoteOn(gstt.Curve,20)
|
||||
|
||||
# Notes for set : 8-15
|
||||
def UpdateSet():
|
||||
print ("New Set :", gstt.Set)
|
||||
if gstt.BhorealHere != -1:
|
||||
for led in range(9,17):
|
||||
NoteOff(led)
|
||||
NoteOn(gstt.Set+8,10)
|
||||
|
||||
# Note for current laser : 16-23
|
||||
def UpdateLaser():
|
||||
print ("New Laser :", gstt.Laser)
|
||||
if gstt.BhorealHere != -1:
|
||||
for led in range(16,24):
|
||||
NoteOff(led)
|
||||
NoteOn(gstt.Laser+16,30)
|
||||
|
||||
# Note for PL displayed in pygame window : 24-31
|
||||
def UpdateSimu():
|
||||
print ("New simuPL :", gstt.simuPL)
|
||||
if gstt.BhorealHere != -1:
|
||||
for led in range(24,32):
|
||||
NoteOff(led)
|
||||
NoteOn(gstt.simuPL+24,40)
|
||||
'''
|
||||
|
||||
#
|
||||
# Events from Bhoreal handling
|
||||
#
|
||||
|
||||
# Process events coming from Bhoreal in a separate thread.
|
||||
def MidinProcess(bhorqueue):
|
||||
|
||||
#print()
|
||||
#print("bhoreal midi in process started with queue", bhorqueue)
|
||||
#print()
|
||||
bhorqueue_get = bhorqueue.get
|
||||
while True:
|
||||
|
||||
msg = bhorqueue_get()
|
||||
|
||||
# Bhoreal Led pressed
|
||||
print(("Bhoreal Matrix : ", str(msg[1]), gstt.BhorLeds[msg[1]]))
|
||||
|
||||
if msg[0] == NOTE_ON and msg[2] == 64:
|
||||
# led
|
||||
NoteOn(msg[1],64)
|
||||
|
||||
# Bhoreal Led depressed
|
||||
elif msg[0] == NOTE_ON and msg[2] == 0:
|
||||
NoteOn(msg[1],0)
|
||||
|
||||
'''
|
||||
|
||||
print "Bhoreal Matrix : ", str(msg[1]), str(gstt.BhorLeds[msg[1]])
|
||||
|
||||
if msg[1]< 8:
|
||||
gstt.Curve = msg[1]
|
||||
UpdateCurve()
|
||||
|
||||
if msg[1]> 7 and msg[1] < 16:
|
||||
gstt.Set = msg[1]-8
|
||||
UpdateSet()
|
||||
|
||||
if msg[1]> 15 and msg[1] < 24:
|
||||
gstt.Laser = msg[1]-16
|
||||
UpdateLaser()
|
||||
|
||||
if msg[1]> 23 and msg[1] < 31:
|
||||
gstt.simuPL = msg[1]-24
|
||||
UpdateSimu()
|
||||
|
||||
#Bhoreal send back note on and off to light up the led.
|
||||
if msg[1]> 56:
|
||||
if gstt.BhorLeds[msg[1]] < 115:
|
||||
gstt.BhorLeds[msg[1]] += 10
|
||||
#midi3.NoteOn(msg[1],gstt.BhorLeds[msg[1]])
|
||||
|
||||
#time.sleep(0.1)
|
||||
#midi3.NoteOff(msg[1])
|
||||
'''
|
||||
bhorqueue = Queue()
|
||||
|
||||
|
||||
# New Bhoreal call back : new msg forwarded to Bhoreal queue
|
||||
class AddQueue(object):
|
||||
def __init__(self, portname):
|
||||
self.portname = portname
|
||||
self._wallclock = time.time()
|
||||
|
||||
|
||||
def __call__(self, event, data=None):
|
||||
message, deltatime = event
|
||||
self._wallclock += deltatime
|
||||
print(("[%s] @%0.6f %r" % (self.portname, self._wallclock, message)))
|
||||
bhorqueue.put(message)
|
||||
|
||||
'''
|
||||
# Old Bhoreal call back : new msg forwarded to Bhoreal queue
|
||||
class AddQueue(object):
|
||||
def __init__(self, port):
|
||||
self.port = port
|
||||
self._wallclock = time.time()
|
||||
|
||||
def __call__(self, event, data=None):
|
||||
message, deltatime = event
|
||||
self._wallclock += deltatime
|
||||
print("[%s] @%0.6f %r" % (self.port, self._wallclock, message))
|
||||
bhorqueue.put(message)
|
||||
'''
|
||||
164
libs3/bhorunicornhat.py
Normal file
164
libs3/bhorunicornhat.py
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''
|
||||
Bhorunicornhat
|
||||
v0.7.0
|
||||
|
||||
A library to replace unicornhat and unicorn_hat_sim to use
|
||||
any unicorn hat python script with a bhoreal or a Launchpad mini.
|
||||
|
||||
2 things to do :
|
||||
|
||||
1/ Change import in a unicorn target python program
|
||||
|
||||
import unicornhat as unicorn
|
||||
|
||||
by :
|
||||
|
||||
import bhorunicornhat as unicorn
|
||||
|
||||
2/ Set target (bhoreal or launchpad) by calling unicornhat.dest(device,rotation)
|
||||
or modify destination and rotation manually : see a few lines down.
|
||||
|
||||
|
||||
|
||||
by Sam Neurohack
|
||||
from /team/laser
|
||||
|
||||
CC NC BY
|
||||
|
||||
'''
|
||||
import colorsys,time
|
||||
import midi3,bhoreal,launchpad
|
||||
|
||||
# For Launchpad mini
|
||||
mididest = "launchpad"
|
||||
rotangle = 270
|
||||
|
||||
# For Bhoreal
|
||||
#mididest = "bhoreal"
|
||||
#rotangle = 180
|
||||
|
||||
BhorLeds = [0] * 64
|
||||
Bhuffer = [0] * 64
|
||||
HAT = (8,8)
|
||||
AUTO = (8,8)
|
||||
|
||||
# 'launchpad' with rotation 270
|
||||
# 'bhoreal' with rotation 180
|
||||
def dest(dest,rot):
|
||||
global mididest, rotangle
|
||||
|
||||
mididest = dest
|
||||
rotangle = rot
|
||||
|
||||
def set_layout(x):
|
||||
pass
|
||||
|
||||
|
||||
def rot90():
|
||||
|
||||
for notes in range(0,64):
|
||||
Bhuffer[notes] = BhorLeds[notes]
|
||||
|
||||
for y in range(1,9):
|
||||
for x in range(1,9):
|
||||
#print x,y,9-y,x,bhoreal.NoteXY(9-y,x),bhoreal.NoteXY(x,y),BhorLeds[bhoreal.NoteXY(9-y,x)],Bhuffer[bhoreal.NoteXY(x,y)]
|
||||
BhorLeds[bhoreal.NoteXY(9-y,x)]=Bhuffer[bhoreal.NoteXY(x,y)]
|
||||
|
||||
def rot180():
|
||||
|
||||
for notes in range(0,64):
|
||||
Bhuffer[notes] = BhorLeds[notes]
|
||||
|
||||
for y in range(8,0,-1):
|
||||
#print ""
|
||||
for x in range(1,9):
|
||||
#print x,y,9-y,bhoreal.NoteXY(x,9-y),bhoreal.NoteXY(x,y),BhorLeds[bhoreal.NoteXY(x,9-y)],Bhuffer[bhoreal.NoteXY(x,y)]
|
||||
BhorLeds[bhoreal.NoteXY(x,9-y)]=Bhuffer[bhoreal.NoteXY(x,y)]
|
||||
|
||||
def rotation(angle):
|
||||
if angle == 90:
|
||||
rot90()
|
||||
if angle == 180:
|
||||
rot180()
|
||||
if angle == 270:
|
||||
rot180()
|
||||
rot90()
|
||||
|
||||
def brightness(brightness):
|
||||
#like 0.5
|
||||
pass
|
||||
|
||||
def get_shape():
|
||||
return 8,8
|
||||
|
||||
def clear():
|
||||
off()
|
||||
|
||||
def hue(r,g,b):
|
||||
|
||||
h = int(127*colorsys.rgb_to_hsv(r,g,b)[0])
|
||||
v = int(127*colorsys.rgb_to_hsv(r,g,b)[2])
|
||||
if h == 0 and v != 0:
|
||||
h=127
|
||||
#should be variation of grey (v,v,v)
|
||||
#v = int(127*colorsys.rgb_to_hsv(r,g,b)[2])
|
||||
#print r,g,b,h
|
||||
return h
|
||||
|
||||
def off():
|
||||
for note in range(1,64):
|
||||
BhorLeds[note] = 0
|
||||
show()
|
||||
|
||||
def set_all(r,g,b):
|
||||
|
||||
for led in range(0,64):
|
||||
BhorLeds[led] = hue(r,g,b)
|
||||
|
||||
def set_pixel(x,y,r,g,b):
|
||||
|
||||
#print x,y,r,g,b,colorsys.rgb_to_hsv(r,g,b)
|
||||
note = (x-1)+ (y-1) * 8
|
||||
#print int(127*colorsys.rgb_to_hsv(r,g,b)[0])
|
||||
BhorLeds[note] = hue(r,g,b)
|
||||
|
||||
def set_pixels(pixels):
|
||||
led = 0
|
||||
for line in pixels:
|
||||
#print line
|
||||
for ledline in range(0,8):
|
||||
#print line[ledline]
|
||||
r,g,b = line[ledline][0],line[ledline][1],line[ledline][2]
|
||||
BhorLeds[led] = hue(r,g,b)
|
||||
led += 1
|
||||
|
||||
def clean_shutdown():
|
||||
pass
|
||||
|
||||
def show():
|
||||
|
||||
# How turn off all leds
|
||||
'''
|
||||
if bhoreal.Here != -1:
|
||||
bhoreal.Cls(0)
|
||||
|
||||
if launchpad.Here != -1:
|
||||
launchpad.Cls()
|
||||
'''
|
||||
|
||||
# Check if midi3 has been previously initiated
|
||||
if len(midi3.OutDevice) == 0:
|
||||
midi3.OutConfig()
|
||||
|
||||
|
||||
if (mididest == 'launchpad' and launchpad.Here != -1) or (mididest == 'bhoreal' and bhoreal.Here != -1):
|
||||
|
||||
rotation(rotangle)
|
||||
for note in range(1,65):
|
||||
midi3.NoteOn(note-1,BhorLeds[note-1],mididest)
|
||||
time.sleep(0.0001)
|
||||
else:
|
||||
print(mididest,'is connected ?')
|
||||
160
libs3/cli.py
Normal file
160
libs3/cli.py
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
# coding=UTF-8
|
||||
"""
|
||||
LJay/LJ
|
||||
|
||||
v0.8
|
||||
|
||||
Command line arguments parser
|
||||
|
||||
by Sam Neurohack
|
||||
from /team/laser
|
||||
|
||||
"""
|
||||
|
||||
|
||||
from libs3 import gstt
|
||||
import argparse
|
||||
import subprocess
|
||||
|
||||
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 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")
|
||||
argsparser.add_argument("-d","--display",help="Point List number displayed in simulator",type=int)
|
||||
argsparser.add_argument("-a","--align",help="Reset laser 0 alignement values",action="store_true")
|
||||
argsparser.add_argument("-i","--iport",help="port number for builtin LJ OSC server (8002 by default)",type=int)
|
||||
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")
|
||||
|
||||
|
||||
|
||||
# Keep it ! if new features of cli.py is used in a monolaser program
|
||||
# argsparser.add_argument("-l","--laser",help="Last digit of etherdream ip address 192.168.1.0/24 (4 by default). Localhost if digit provided is 0.",type=int)
|
||||
|
||||
|
||||
args = argsparser.parse_args()
|
||||
|
||||
# Verbose = debug
|
||||
if args.verbose != None:
|
||||
#print "setting gstt.debug to", args.verbose
|
||||
gstt.debug = args.verbose
|
||||
else:
|
||||
gstt.debug = 0
|
||||
|
||||
# Webui regen
|
||||
if args.webui == True:
|
||||
subprocess.call(['python','webui/build.py'])
|
||||
|
||||
# Ports arguments
|
||||
if args.iport:
|
||||
iport = args.iport
|
||||
gstt.iport = iport
|
||||
else:
|
||||
iport = gstt.iport
|
||||
|
||||
if args.oport:
|
||||
oport = args.oport
|
||||
gstt.oport = oport
|
||||
else:
|
||||
oport = gstt.oport
|
||||
|
||||
if gstt.debug > 0:
|
||||
print("Accept OSC on port",gstt.oport)
|
||||
print("gstt.iport:",gstt.iport)
|
||||
|
||||
|
||||
# X Y inversion arguments
|
||||
if args.invx == True:
|
||||
|
||||
gstt.swapX[0] = -1 * gstt.swapX[0]
|
||||
gstt.centerx[0] = 0
|
||||
gstt.centery[0] = 0
|
||||
#WriteSettings()
|
||||
print("laser 0 X new invertion Asked")
|
||||
if gstt.swapX[0] == 1:
|
||||
print ("X not Inverted")
|
||||
else:
|
||||
print ("X Inverted")
|
||||
|
||||
if args.invy == True:
|
||||
|
||||
gstt.swapY[0] = -1 * gstt.swapY[0]
|
||||
gstt.centerx[0] = 0
|
||||
gstt.centery[0] = 0
|
||||
#WriteSettings()
|
||||
print("laser 0 Y new invertion Asked")
|
||||
if gstt.swapY[0] == 1:
|
||||
print ("Y not Inverted")
|
||||
else:
|
||||
print("Y inverted")
|
||||
|
||||
# Redis Computer IP
|
||||
if args.redisIP != None:
|
||||
gstt.LjayServerIP = args.redisIP
|
||||
|
||||
|
||||
|
||||
# Point list number used by simulator
|
||||
if args.display != None:
|
||||
gstt.simuPL = args.display
|
||||
print("Display : " + str(gstt.simuPL))
|
||||
|
||||
|
||||
|
||||
# Lasers = number of laser connected otherwise will be autodetected with one minimum
|
||||
if args.Lasers != None:
|
||||
gstt.LaserNumber = args.Lasers
|
||||
else:
|
||||
gstt.LaserNumber = -1
|
||||
|
||||
|
||||
if args.bhoroscIP != None:
|
||||
gstt.oscIPin = args.bhoroscIP
|
||||
else:
|
||||
gstt.oscIPin = '127.0.0.1'
|
||||
|
||||
|
||||
if args.nozoidIP != None:
|
||||
gstt.nozoscIP = args.nozoidIP
|
||||
else:
|
||||
gstt.nozoscIP = '127.0.0.1'
|
||||
|
||||
# Etherdream target for mono laser program
|
||||
'''
|
||||
if args.laser != None:
|
||||
lstdgtlaser = args.laser
|
||||
|
||||
if lstdgtlaser == 0:
|
||||
etherIP = "127.0.0.1"
|
||||
else:
|
||||
etherIP = "192.168.1."+str(lstdgtlaser)
|
||||
|
||||
else:
|
||||
etherIP = "192.168.1.4"
|
||||
|
||||
#print ("Laser 1 etherIP:",etherIP)
|
||||
'''
|
||||
|
||||
# Reset alignment values
|
||||
if args.align == True:
|
||||
|
||||
gstt.centerx[0] = 0
|
||||
gstt.centery[0] = 0
|
||||
gstt.zoomx[0] = 15
|
||||
gstt.zoomy[0] = 15
|
||||
gstt.sizex[0] = 32000
|
||||
gstt.sizey[0] = 32000
|
||||
gstt.finangle[0] = 0.0
|
||||
gstt.swapx[0] = 1
|
||||
gstt.swapy[0] = 1
|
||||
#Settings.Write()
|
||||
|
||||
handle()
|
||||
669
libs3/commands.py
Normal file
669
libs3/commands.py
Normal file
|
|
@ -0,0 +1,669 @@
|
|||
# coding=UTF-8
|
||||
"""
|
||||
|
||||
LJ OSC and Websockets laser commands
|
||||
v0.7.0
|
||||
|
||||
|
||||
LICENCE : CC
|
||||
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
|
||||
|
||||
/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'
|
||||
|
||||
/kpps/lasernumber value
|
||||
Live change of kpps is not implemented in newdac.py. Change will effect next startup.
|
||||
|
||||
/angle/lasernumber value : increase/decrease angle correction for given laser by value
|
||||
|
||||
/intens/lasernumber value : increase/decrease intensity for given laser by value
|
||||
|
||||
/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)]"
|
||||
|
||||
/mouse/lasernumber value (0 or 1)
|
||||
|
||||
/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/Y/lasernumber value : change Y offset of given laser by value
|
||||
|
||||
/order value : instruct tracer what to do.
|
||||
|
||||
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.
|
||||
|
||||
Example : client 0 send 2 point lists one for laser 0 and one for laser 1 by sending in redis :
|
||||
/pl/0/0 and /pl/0/1
|
||||
The "client key" when client 0 is selected to be displayed by lasers is "/pl/0/".
|
||||
Each tracer pull its pointlist by using the current client key "/pl/0/"
|
||||
and add its laser number at startup : /pl0/0 ant /pl/0/1
|
||||
|
||||
"Client" is a concept. Imagine in a demoparty there is 4 lasers.
|
||||
John and Paul want to draw on all lasers.
|
||||
Let's give John client 0, he will send points to /pl/0/0, /pl/0/1, /pl/0/2 and /pl/0/3.
|
||||
|
||||
Paul is client 1, so he will use /pl/1/0, /pl/1/1, /pl/1/2 and /pl/1/3.
|
||||
|
||||
Both can send their pointlists to redis server.
|
||||
When John get the lasers switch to client 0, when it's Paul turn switch to client 1.
|
||||
|
||||
But say Bob and Lisa needs only 2 lasers each. Give them client 2.
|
||||
Bob could use /pl/2/0 and /pl/2/1 and Lisa could use /pl/2/2 and /pl/2/3.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
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","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)
|
||||
plugins.sendWSall("/status User on laser " + str(laser))
|
||||
r.set('/order/'+str(laser), 0)
|
||||
|
||||
|
||||
def NewEDH(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])
|
||||
|
||||
homographyp.newEDH(laser)
|
||||
|
||||
def BlackOn(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)
|
||||
plugins.sendWSall("/status Grid on laser " + str(laser))
|
||||
r.set('/order/'+str(laser), 3)
|
||||
|
||||
|
||||
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, "[("+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)
|
||||
|
||||
|
||||
def LasClientChange(clientnumber):
|
||||
|
||||
if r.get("/pl/"+str(clientnumber)+"/0") != None:
|
||||
|
||||
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 range(0,gstt.LaserNumber):
|
||||
r.set('/order/'+str(laserid), 5)
|
||||
else:
|
||||
print("ERROR : Maximum number of scenes is set to ", gstt.MaxScenes)
|
||||
|
||||
|
||||
def SceneChange(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 + "/")
|
||||
|
||||
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)
|
||||
|
||||
# Change laser client
|
||||
if note < 8:
|
||||
LasClientChange(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("/redstatus No Laser"+str(note-24))
|
||||
plugins.sendWSall("/laser "+str(gstt.LaserNumber-1))
|
||||
|
||||
|
||||
else:
|
||||
gstt.Laser = note -24
|
||||
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)
|
||||
|
||||
|
||||
def Mouse(x1,y1,x2,y2):
|
||||
print("Mouse", x1,y1,x2,y2)
|
||||
|
||||
|
||||
|
||||
def handler(oscpath, args):
|
||||
|
||||
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)
|
||||
|
||||
# 2 incoming cases : generic or specific for a given lasernumber :
|
||||
|
||||
|
||||
#
|
||||
# Generic : Commands without a laser number
|
||||
#
|
||||
|
||||
if oscpath[1] in GenericCommands:
|
||||
|
||||
if gstt.debug > 0:
|
||||
print("GenericCommand :", oscpath[1], "with args", args)
|
||||
|
||||
|
||||
if oscpath[1] == "ljclient":
|
||||
#LasClientChange(int(args[0]))
|
||||
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])
|
||||
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)
|
||||
|
||||
|
||||
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
|
||||
if gstt.debug >0:
|
||||
print(("/" + args[0] + "/start 1"))
|
||||
print(("/status got pong from "+ args[0] +"."))
|
||||
|
||||
plugins.sendWSall("/" + args[0] + "/start 1")
|
||||
#plugins.sendWSall("/status got pong from "+ args[0] +".")
|
||||
|
||||
|
||||
elif oscpath[1] == "vcvrack":
|
||||
pass
|
||||
'''
|
||||
#print "LJ commands got /vcvrack from", args
|
||||
if oscpath[2] == "1" :
|
||||
r.set('/vcvrack/1', args[0])
|
||||
#print('/vcvrack/1', args[0])
|
||||
if oscpath[2] == "2" :
|
||||
r.set('/vcvrack/2', args[0])
|
||||
#print('/vcvrack/2', args[0])
|
||||
'''
|
||||
|
||||
elif oscpath[1] == "mouse":
|
||||
Mouse(int(args[0]),int(args[1]),int(args[2]),int(args[3]))
|
||||
|
||||
|
||||
# /emergency value (0 or 1)
|
||||
elif oscpath[1] == "emergency":
|
||||
|
||||
if args[0] == "1":
|
||||
|
||||
for laser in range(gstt.lasernumber):
|
||||
print("Black requested for laser ", laser)
|
||||
BlackOn(laser)
|
||||
print("EMERGENCY MODE")
|
||||
plugins.sendWSall("/status EMERGENCY MODE")
|
||||
else:
|
||||
for laser in range(gstt.lasernumber):
|
||||
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)
|
||||
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])
|
||||
|
||||
else:
|
||||
laser = int(oscpath[3])
|
||||
|
||||
#print "args[0] :",args[0]," ", type(args[0])
|
||||
|
||||
# /grid/lasernumber value (0 or 1)
|
||||
if oscpath[1] == "grid":
|
||||
|
||||
if args[0] == "1":
|
||||
print("Grid requested for laser ", laser)
|
||||
GridOn(laser)
|
||||
else:
|
||||
print("No grid for laser ", laser)
|
||||
UserOn(laser)
|
||||
|
||||
|
||||
# /ip/lasernumber value
|
||||
if oscpath[1] == "ip":
|
||||
print("New IP for laser ", laser)
|
||||
gstt.lasersIPS[laser]= args[0]
|
||||
settings.Write()
|
||||
|
||||
|
||||
# /kpps/lasernumber value
|
||||
# Live change of kpps is not implemented in newdac.py. Change will effect next startup.
|
||||
if oscpath[1] == "kpps":
|
||||
print("New kpps for laser ", laser, " next startup", int(args[0]))
|
||||
gstt.kpps[laser]= int(args[0])
|
||||
settings.Write()
|
||||
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]))
|
||||
gstt.finANGLE[laser] += float(args[0])
|
||||
NewEDH(laser)
|
||||
print("New angle", gstt.finANGLE[laser])
|
||||
|
||||
# /intens/lasernumber value
|
||||
if oscpath[1] == "intens":
|
||||
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":
|
||||
#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])
|
||||
gstt.Laser = oscpath[2]
|
||||
else:
|
||||
print("No mouse for laser ", oscpath[2])
|
||||
|
||||
|
||||
# /swap/X/lasernumber value (0 or 1)
|
||||
if oscpath[1] == "swap" and oscpath[2] == "X":
|
||||
|
||||
print("swapX was", gstt.swapX[laser])
|
||||
if args[0] == "0":
|
||||
print("swap X -1 for laser ", laser)
|
||||
gstt.swapX[laser]= -1
|
||||
NewEDH(laser)
|
||||
|
||||
else:
|
||||
print("swap X 1 for laser ", laser)
|
||||
gstt.swapX[laser]= 1
|
||||
NewEDH(laser)
|
||||
|
||||
# /swap/Y/lasernumber value (0 or 1)
|
||||
if oscpath[1] == "swap" and oscpath[2] == "Y":
|
||||
|
||||
print("swapY was", gstt.swapX[laser])
|
||||
if args[0] == "0":
|
||||
print("swap Y -1 for laser ", laser)
|
||||
gstt.swapY[laser]= -1
|
||||
NewEDH(laser)
|
||||
else:
|
||||
print("swap Y 1 for laser ", laser)
|
||||
gstt.swapY[laser]= 1
|
||||
NewEDH(laser)
|
||||
|
||||
# /loffset/X/lasernumber value
|
||||
if oscpath[1] == "loffset" and oscpath[2] == "X":
|
||||
print("offset/X laser", laser, "modified to", args[0])
|
||||
gstt.centerX[laser] -= int(args[0])
|
||||
NewEDH(laser)
|
||||
|
||||
# /loffset/Y/lasernumber value
|
||||
if oscpath[1] == "loffset" and oscpath[2] == "Y":
|
||||
print("offset/Y laser", laser, "modified to", args[0])
|
||||
gstt.centerY[laser] -= int(args[0])
|
||||
NewEDH(laser)
|
||||
|
||||
|
||||
# /scale/X/lasernumber value
|
||||
if oscpath[1] == "scale" and oscpath[2] == "X":
|
||||
if gstt.zoomX[laser] + int(args[0]) > 0:
|
||||
gstt.zoomX[laser] += int(args[0])
|
||||
print("scale/X laser", laser , "modified to", gstt.zoomX[laser])
|
||||
NewEDH(laser)
|
||||
|
||||
# /scale/Y/lasernumber value
|
||||
if oscpath[1] == "scale" and oscpath[2] == "Y":
|
||||
if gstt.zoomY[laser] + int(args[0]) > 0:
|
||||
gstt.zoomY[laser] += int(args[0])
|
||||
print("scale/Y laser", laser, "modified to", gstt.zoomY[laser])
|
||||
NewEDH(laser)
|
||||
|
||||
|
||||
|
||||
#
|
||||
# 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)
|
||||
|
||||
gstt.centerY[gstt.Laser] -= 20
|
||||
|
||||
gstt.centerY[gstt.Laser] += 20
|
||||
|
||||
gstt.zoomX[gstt.Laser]-= 0.1
|
||||
|
||||
gstt.zoomX[gstt.Laser] += 0.1
|
||||
gstt.zoomY[gstt.Laser] -= 0.1
|
||||
|
||||
gstt.zoomY[gstt.Laser] += 0.1
|
||||
|
||||
gstt.sizeX[gstt.Laser] -= 50
|
||||
|
||||
gstt.sizeX[gstt.Laser] += 50
|
||||
|
||||
gstt.sizeY[gstt.Laser] -= 50
|
||||
|
||||
gstt.sizeY[gstt.Laser] += 50
|
||||
|
||||
gstt.finANGLE[gstt.Laser] -= 0.001
|
||||
|
||||
gstt.finANGLE[gstt.Laser] += 0.001
|
||||
|
||||
Code for bit analysis 2 bits / laser to encode order.
|
||||
|
||||
# Grid PL is Laser bit 0 = 1 and bit 1 = 1
|
||||
#order = r.get('/order')
|
||||
#neworder = order | (1<<laser*2)
|
||||
#neworder = neworder | (1<< 1+laser*2)
|
||||
#r.set('/order', str(neworder))
|
||||
|
||||
# Laser bit 0 = 0 and bit 1 = 0 : USER PL
|
||||
#order = r.get('/order')
|
||||
#neworder = order & ~(1<< laser*2)
|
||||
#neworder = neworder & ~(1<< 1+ laser*2)
|
||||
#r.set('/order', str(neworder))
|
||||
|
||||
# Laser bit 0 = 0 and bit 1 = 1 : New EDH
|
||||
#order = r.get('/order')
|
||||
#neworder = order & ~(1<< laser*2)
|
||||
#neworder = neworder | (1<< 1+laser*2)
|
||||
#r.set('/order', str(neworder))
|
||||
|
||||
# Black PL is Laser bit 0 = 1 and bit 1 = 0 :
|
||||
#order = r.get('/order')
|
||||
#neworder = order | (1<<laser*2)
|
||||
#neworder = neworder & ~(1<< 1+laser*2)
|
||||
|
||||
'''
|
||||
119
libs3/font1.py
Normal file
119
libs3/font1.py
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
# coding=UTF-8
|
||||
"""
|
||||
|
||||
LJ Font 1
|
||||
v0.7.0
|
||||
|
||||
|
||||
LICENCE : CC
|
||||
by Sam Neurohack
|
||||
from /team/laser
|
||||
|
||||
|
||||
"""
|
||||
from libs3 import gstt
|
||||
|
||||
def DigitsDots(number,color):
|
||||
dots =[]
|
||||
#print ASCII_GRAPHICS[ord(char) - 48]
|
||||
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
|
||||
|
||||
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 {
|
||||
]
|
||||
152
libs3/gstt.py
Normal file
152
libs3/gstt.py
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
# coding=UTF-8
|
||||
'''
|
||||
|
||||
LJ Global state
|
||||
v0.8.0
|
||||
|
||||
**
|
||||
Almost all values here Will be overriden by data in LJ.conf at startup
|
||||
**
|
||||
|
||||
LICENCE : CC BY
|
||||
by Sam Neurohack, Loloster, pclf
|
||||
from /team/laser
|
||||
|
||||
'''
|
||||
|
||||
#ConfigName = "setexample.conf"
|
||||
ConfigName = "LJ.conf"
|
||||
|
||||
debug = 0
|
||||
ljpath=''
|
||||
|
||||
anims= [[],[],[],[]]
|
||||
|
||||
# How many lasers are connected. Different that "currentlaser" and "dacnumber" (=autodetected)
|
||||
LaserNumber = -1
|
||||
|
||||
# What laser client to listen at launch
|
||||
SceneNumber = 0
|
||||
MaxScenes = 3
|
||||
|
||||
screen_size = [400,400]
|
||||
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
|
||||
Laser = 0
|
||||
|
||||
# gstt.simuPL select what point list number to display in webUI simulator
|
||||
# Can be changed with /noteon 24-31
|
||||
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]
|
||||
|
||||
# Transformation Matrix for each laser
|
||||
EDH = [[], [], [], []]
|
||||
|
||||
# Etherdreams reports
|
||||
# ipconn is initial newdac to its etherdream
|
||||
lstt_ipconn = [[-1], [-1], [-1], [-1]]
|
||||
# dacstt is dac light engine state
|
||||
lstt_dacstt = [[-1], [-1], [-1], [-1]]
|
||||
# store last dac answers : ACK, not ACK,...
|
||||
lstt_dacanswers = [[-1], [-1], [-1], [-1]]
|
||||
# store last number of points sent to etherdreams buffer
|
||||
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.
|
||||
stepshortline = [(1.0, 8)]
|
||||
stepslongline = [(0.25, 3), (0.75, 3), (1.0, 10)]
|
||||
|
||||
#stepslongline = [(0.25,1), (0.75, 1), (1.0, 1)]
|
||||
#stepshortline = [(1.0, 8)]
|
||||
#stepslongline = [(1.0, 1)]
|
||||
#stepshortline = [(1.0, 1)]
|
||||
|
||||
point = [0,0,0]
|
||||
|
||||
cc = [0] * 256
|
||||
lfo = [0] * 10
|
||||
osc = [0] * 255
|
||||
oscInUse = [0] * 255
|
||||
knob = [0] * 33
|
||||
# Viewer distance (cc 21)
|
||||
cc[21]=60
|
||||
viewer_distance = cc[21] * 8
|
||||
|
||||
# fov (cc 22)
|
||||
cc[22]= 60
|
||||
fov = 4 * cc[22]
|
||||
|
||||
|
||||
JumpFlag =0
|
||||
|
||||
# OSC ports
|
||||
#temporaray fix hack : iport=nozoport
|
||||
iport = 8002 # LJ input port
|
||||
oport = 8001 # LJ output port
|
||||
noziport=8003 #nozosc.py receiving commands port
|
||||
nozoport=8001 #nozosc.py sending port to LJay (main.py)
|
||||
nozuport=0 #linux serial usb port connecting nozoid devices ACM0 by default
|
||||
|
||||
|
||||
angleX = 0
|
||||
angleY = 0
|
||||
angleZ = 0
|
||||
|
||||
# multilasers arrays
|
||||
centerX = [0,0,0,0]
|
||||
centerY = [0,0,0,0]
|
||||
zoomX = [0,0,0,0]
|
||||
zoomY = [0,0,0,0]
|
||||
sizeX = [0,0,0,0]
|
||||
sizeY = [0,0,0,0]
|
||||
finANGLE = [0,0,0,0]
|
||||
|
||||
warpdest = [[[ 1. , 0. , 0.],[ 0. , 1. , 0.],[ 0. , 0. , 1.]],
|
||||
[[ 1. , 0. , 0.],[ 0. , 1. , 0.],[ 0. , 0. , 1.]],
|
||||
[[ 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
|
||||
252
libs3/homographyp.py
Normal file
252
libs3/homographyp.py
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: Python -*-
|
||||
|
||||
'''
|
||||
|
||||
LJay/LJ
|
||||
v0.7.0
|
||||
|
||||
LICENCE : CC
|
||||
Sam Neurohack
|
||||
|
||||
Homographies for align + swap corrections and warp corrections
|
||||
|
||||
Align + swap homography if found with 4 original points and corrected coordinates
|
||||
Warp correction is disabled for the moment. Should be computed at warp edition : set 1 curve 1
|
||||
|
||||
Use the :
|
||||
|
||||
########################################################################
|
||||
# Module to compute homographies #
|
||||
# #
|
||||
# Author : Alexis Mignon #
|
||||
# email : alexis.mignon@info.unicaen.fr #
|
||||
# date : 10/03/2010 #
|
||||
########################################################################
|
||||
|
||||
Module to compute homographies between two sets of 2D points
|
||||
|
||||
implemented functions :
|
||||
- find_homography(points1,points2) : finds the homography between
|
||||
two sets of 2D points
|
||||
- find_affine_homography(points1,points2) : finds the affine
|
||||
homography between two sets of 2D points
|
||||
- apply_homography(H,points) : applies homography H to the set of
|
||||
2D points 'points'
|
||||
|
||||
example :
|
||||
>>> from homography import *
|
||||
>>>
|
||||
>>> points1 = np.array([[ 0., 0. ],
|
||||
>>> [ 1., 0. ],
|
||||
>>> [ 0., 1. ],
|
||||
>>> [ 1., 1. ]])
|
||||
>>>
|
||||
>>> points2 = np.array([[ 0. , 0. ],
|
||||
>>> [ 1. , 0. ],
|
||||
>>> [ 0.25, 1. ],
|
||||
>>> [ 0.75, 1. ]])
|
||||
>>>
|
||||
>>> points3 = np.array([[-1., 0.],
|
||||
>>> [ 0.,-1.],
|
||||
>>> [ 0., 1.],
|
||||
>>> [ 1., 0.]])
|
||||
>>>
|
||||
>>> H1 = find_homography(points1,points2)
|
||||
>>> print H1
|
||||
>>> print apply_homography(H1,points1)
|
||||
>>> H2 = find_affine_homography(points1,points3)
|
||||
>>> print H2
|
||||
>>> print apply_homography(H2,points1)
|
||||
'''
|
||||
|
||||
|
||||
import numpy as np
|
||||
import math
|
||||
from scipy.linalg import svd,lstsq
|
||||
import ast
|
||||
from libs3 import gstt
|
||||
#from globalVars import xy_center
|
||||
import redis
|
||||
|
||||
|
||||
r = redis.StrictRedis(host=gstt.LjayServerIP, port=6379, db=0)
|
||||
|
||||
def find(points1,points2):
|
||||
if points1.shape[0] != points2.shape[0] : raise ValueError("The number of input and output points mismatches")
|
||||
if points1.shape[1] == 2 :
|
||||
p1 = np.ones((len(points1),3),'float64')
|
||||
p1[:,:2] = points1
|
||||
elif points1.shape[1] == 3 : p1 = points1
|
||||
else : raise ValueError("Bad shape for input points")
|
||||
|
||||
if points2.shape[1] == 2 :
|
||||
p2 = np.ones((len(points2),3),'float64')
|
||||
p2[:,:2] = points2
|
||||
elif points2.shape[1] == 3 : p2 = points2
|
||||
else : raise ValueError("Bad shape for output points")
|
||||
|
||||
npoints = len(points1)
|
||||
|
||||
A = np.zeros((3*npoints,9),'float64')
|
||||
|
||||
for i in range(npoints):
|
||||
p1i = p1[i]
|
||||
x2i,y2i,w2i = p2[i]
|
||||
xpi = x2i*p1i
|
||||
ypi = y2i*p1i
|
||||
wpi = w2i*p1i
|
||||
|
||||
A[i*3 ,3:6] = -wpi
|
||||
A[i*3 ,6:9] = ypi
|
||||
A[i*3+1,0:3] = wpi
|
||||
A[i*3+1,6:9] = -xpi
|
||||
A[i*3+2,0:3] = -ypi
|
||||
A[i*3+2,3:6] = xpi
|
||||
|
||||
U,s,Vt = svd(A,full_matrices = False, overwrite_a = True)
|
||||
del U,s
|
||||
h = Vt[-1]
|
||||
H = h.reshape(3,3)
|
||||
return H
|
||||
|
||||
def find_affine(points1,points2):
|
||||
if points1.shape[0] != points2.shape[0] : raise ValueError("The number of input and output points mismatches")
|
||||
if points1.shape[1] == 2 :
|
||||
p1 = np.ones((len(points1),3),'float64')
|
||||
p1[:,:2] = points1
|
||||
elif points1.shape[1] == 3 : p1 = points1
|
||||
else : raise ValueError("Bad shape for input points")
|
||||
|
||||
if points2.shape[1] == 2 :
|
||||
p2 = np.ones((len(points2),3),'float64')
|
||||
p2[:,:2] = points2
|
||||
elif points2.shape[1] == 3 : p2 = points2
|
||||
else : raise ValueError("Bad shape for output points")
|
||||
|
||||
npoints = len(points1)
|
||||
|
||||
A = np.zeros((3*npoints,6),'float64')
|
||||
b = np.zeros((3*npoints,1),'float64')
|
||||
for i in range(npoints):
|
||||
p1i = p1[i]
|
||||
x2i,y2i,w2i = p2[i]
|
||||
xpi = x2i*p1i
|
||||
ypi = y2i*p1i
|
||||
wpi = w2i*p1i
|
||||
|
||||
A[i*3 ,3:6] = -wpi
|
||||
A[i*3+1,0:3] = wpi
|
||||
A[i*3+2,0:3] = -ypi
|
||||
A[i*3+2,3:6] = xpi
|
||||
|
||||
b[i*3 ] = -y2i*p1i[2]
|
||||
b[i*3+1] = x2i*p1i[2]
|
||||
|
||||
h = lstsq(A,b,overwrite_a = True, overwrite_b = True)[0]
|
||||
H = np.zeros( (3,3) , 'float64' )
|
||||
H[:2,:] = h.reshape(2,3)
|
||||
H[2,2] = 1
|
||||
return H
|
||||
|
||||
def apply(H,points):
|
||||
|
||||
p = np.ones((len(points),3),'float64')
|
||||
p[:,:2] = points
|
||||
pp = np.dot(p,H.T)
|
||||
pp[:,:2]/=pp[:,2].reshape(len(p),1)
|
||||
return pp[:,:2]
|
||||
|
||||
# Align and axis swap corrections
|
||||
# Reference points
|
||||
pointsref = np.array([(300.0, 400.0), (500.0, 400.0), (500.0, 200.0), (300.0, 200.0)])
|
||||
|
||||
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])
|
||||
SinANGLE = math.sin(gstt.finANGLE[mylaser])
|
||||
|
||||
x = (gstt.xy_center[0] + ((XX * CosANGLE) - (YY * SinANGLE)) - gstt.xy_center[0]) * gstt.zoomX[mylaser] + gstt.centerX[mylaser]
|
||||
y = (gstt.xy_center[1] + ((XX * SinANGLE) + (YY * CosANGLE)) - gstt.xy_center[1]) * gstt.zoomY[mylaser] + gstt.centerY[mylaser]
|
||||
|
||||
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 "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])
|
||||
return [x * gstt.swapX[mylaser] , y * gstt.swapY[mylaser]]
|
||||
|
||||
'''
|
||||
def EDpoint((pygamex,pygamey)):
|
||||
|
||||
XX = pygamex - xy_center[0]
|
||||
YY = pygamey - xy_center[1]
|
||||
CosANGLE = math.cos(finangle)
|
||||
SinANGLE = math.sin(finangle)
|
||||
# Multilaser style
|
||||
x = (xy_center[0] + ((XX * CosANGLE) - (YY * SinANGLE)) - xy_center[0]) * zoomx + centerx
|
||||
y = (xy_center[1] + ((XX * SinANGLE) + (YY * CosANGLE)) - xy_center[1]) * zoomy + centery
|
||||
|
||||
return [x*1, y*1]
|
||||
'''
|
||||
|
||||
|
||||
# New total homography from always the same reference points : ED (= align + swap) transform + warp transform.
|
||||
# WARP IS DISABLED. Some bug tracking is needed !
|
||||
def newEDH(mylaser):
|
||||
|
||||
EDpoints = []
|
||||
for point in range(4):
|
||||
EDpoints.append(EDpoint(mylaser,pointsref[point]))
|
||||
|
||||
# H matrix tansform pygame points in Etherdream system with align and swap correction,
|
||||
H = find(pointsref, np.array(EDpoints))
|
||||
|
||||
# Computer Hwarp matrix with previously reference warped points in configuration file.
|
||||
Hwarp = find(pointsref, gstt.warpdest[mylaser])
|
||||
#Hwarp = np.identity(3, dtype = float)
|
||||
# EDH matrix
|
||||
gstt.EDH[mylaser] = H
|
||||
|
||||
# EDH matrix is H x Hwarp
|
||||
#gstt.EDH[mylaser] = np.dot(H,Hwarp)
|
||||
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.")
|
||||
else:
|
||||
print("New EDH not sent.")
|
||||
'''
|
||||
# Laser bit 0 = 0 and bit 1 = 1 : New EDH
|
||||
order = r.get('/order')
|
||||
print order
|
||||
neworder = order & ~(1<< mylaser*2)
|
||||
neworder = neworder | (1<< 1+mylaser*2)
|
||||
r.set('/order', str(neworder))
|
||||
'''
|
||||
|
||||
if gstt.debug >1:
|
||||
print("")
|
||||
print("laser ", mylaser)
|
||||
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])
|
||||
|
||||
72
libs3/kb.py
Normal file
72
libs3/kb.py
Normal 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
1417
libs3/launchpad.py
Normal file
File diff suppressed because it is too large
Load diff
BIN
libs3/link.cpython-35m-x86_64-linux-gnu.so
Normal file
BIN
libs3/link.cpython-35m-x86_64-linux-gnu.so
Normal file
Binary file not shown.
BIN
libs3/link.cpython-37m-darwin.so
Normal file
BIN
libs3/link.cpython-37m-darwin.so
Normal file
Binary file not shown.
BIN
libs3/link.cpython-38-darwin.so
Executable file
BIN
libs3/link.cpython-38-darwin.so
Executable file
Binary file not shown.
BIN
libs3/link.so
Executable file
BIN
libs3/link.so
Executable file
Binary file not shown.
1003
libs3/lj23layers.py
Normal file
1003
libs3/lj23layers.py
Normal file
File diff suppressed because it is too large
Load diff
986
libs3/lj23layers.sync-conflict-20200803-100618-TAXKCAL.py
Normal file
986
libs3/lj23layers.sync-conflict-20200803-100618-TAXKCAL.py
Normal file
|
|
@ -0,0 +1,986 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: Python -*-
|
||||
|
||||
'''
|
||||
|
||||
lj23layers v0.7.6 for LJ v0.8+
|
||||
|
||||
LJ functions (API) for python plugins/clients
|
||||
|
||||
"layers" version :
|
||||
- "PL" has been replaced by "layer"
|
||||
- "Client"
|
||||
|
||||
Each program using LJ should declare itself by call lj23layers Config :
|
||||
|
||||
Config(redisIP, client number, name)
|
||||
|
||||
|
||||
Basic Draw :
|
||||
|
||||
- PolyLineOneColor, rPolyLineOneColor, LineTo, Line
|
||||
- PolyLineRGB, rPolyLineRGB, LineRGBTo, LineRGB
|
||||
- rgb2int(r,g,b)
|
||||
- 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, layer , xpos, ypos, resize, rotx, roty, rotz) : Display a word
|
||||
- TextRGB(word, red, green, blue, ...)
|
||||
- Embeded font1
|
||||
|
||||
|
||||
Laser objects (name and convenient group of parameters for one or several point lists)
|
||||
|
||||
- RelativeObject
|
||||
- FixedObject
|
||||
|
||||
"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
|
||||
|
||||
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(): layer , scene, laser Add a destination
|
||||
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
|
||||
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
|
||||
Sam Neurohack
|
||||
|
||||
'''
|
||||
|
||||
import math
|
||||
import redis
|
||||
import sys
|
||||
import weakref
|
||||
import struct
|
||||
import numpy as np
|
||||
import gstt
|
||||
from multiprocessing import Process, Queue, TimeoutError
|
||||
|
||||
is_py2 = sys.version[0] == '2'
|
||||
if is_py2:
|
||||
from OSC import OSCServer, OSCClient, OSCMessage
|
||||
#print ("Importing lj23 and OSC from libs...")
|
||||
else:
|
||||
from OSC3 import OSCServer, OSCClient, OSCMessage
|
||||
#print ("Importing lj23 and OSC3 from libs...")
|
||||
|
||||
|
||||
#redisIP = '127.0.0.1'
|
||||
#r = redis.StrictRedis(host=redisIP, port=6379, db=0)
|
||||
|
||||
ClientNumber = 0
|
||||
name = "noname"
|
||||
oscrun = True
|
||||
point_list = []
|
||||
layers = [[],[],[],[],[],[],[],[],[],[]]
|
||||
|
||||
fft3Groups = [-1,-1,-1,-1]
|
||||
|
||||
Dests = dict()
|
||||
|
||||
oscIPresol = "127.0.0.1"
|
||||
oscPORTresol = 7000
|
||||
|
||||
# 3D to 2D projection parameters
|
||||
fov = 256
|
||||
viewer_distance = 2.2
|
||||
|
||||
|
||||
'''
|
||||
|
||||
Laser "objects"
|
||||
|
||||
|
||||
set a name and convenient group of parameters for one or several point lists
|
||||
|
||||
RelativeObject is for point lists around 0,0 with builtin move/rotation.
|
||||
|
||||
How to init with object color, xpos,... :
|
||||
osciObj = lj.RelativeObject('osciObj', True, 255, [], white, red, green,blue,0 , False, centerX , centerY , 1 , Xrot , Yrot , Zrot)
|
||||
How to use in drawing functions : you're free to use 0, some or all of any laserobject attributes
|
||||
- draw one or several pointlists with 'A' laserobject color and 'B' laserobject xpos ypos ?
|
||||
- Change color of 'main' object and all other objects using it will change also
|
||||
how to change attribute :
|
||||
osciObj.resize = 2 or /pluginame/change 'OsciObj' 'resize' 2
|
||||
|
||||
'''
|
||||
|
||||
class RelativeObject:
|
||||
|
||||
kind = 'relative'
|
||||
counter = 0
|
||||
|
||||
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
|
||||
self.xy = [] # Dots list
|
||||
self.color = color # RGB color in int
|
||||
self.red = red
|
||||
self.green = green
|
||||
self.blue = blue
|
||||
self.layer = layer
|
||||
self.closed = closed
|
||||
self.xpos = xpos
|
||||
self.ypos = ypos
|
||||
self.resize = resize
|
||||
self.rotx = rotx
|
||||
self.roty = roty
|
||||
self.rotz = rotz
|
||||
|
||||
RelativeObject.counter += 1
|
||||
#type(self).counter += 1
|
||||
|
||||
def __del__(self):
|
||||
RelativeObject.counter -= 1
|
||||
|
||||
|
||||
# Fixed Laser object : point list in 'pygame' space (top left = 0,0 / bottom right)
|
||||
class FixedObject:
|
||||
|
||||
kind = 'fixed'
|
||||
counter = 0
|
||||
|
||||
def __init__(self, name, intensity, active, xy, color, red, green, blue, layer , closed):
|
||||
self.name = name
|
||||
self.active = active # True/False
|
||||
self.intensity = intensity
|
||||
self.xy = []
|
||||
self.color = color
|
||||
self.red = red
|
||||
self.green = green
|
||||
self.blue = blue
|
||||
self.layer = layer
|
||||
self.closed = closed
|
||||
|
||||
FixedObject.counter += 1
|
||||
|
||||
def __del__(self):
|
||||
FixedObject.counter -= 1
|
||||
|
||||
'''
|
||||
|
||||
class IterDest(type):
|
||||
def __new__ (cls, name, bases, dct):
|
||||
dct['_instances'] = []
|
||||
return super().__new__(cls, name, bases, dct)
|
||||
|
||||
def __call__(cls, *args, **kwargs):
|
||||
instance = super().__call__(*args, **kwargs)
|
||||
cls._instances.append(instance)
|
||||
return instance
|
||||
|
||||
def __iter__(cls):
|
||||
return iter(cls._instances)
|
||||
|
||||
class DestObject():
|
||||
|
||||
# class Destinations(metaclass=IterDest):
|
||||
__metaclass__ = IterDest
|
||||
counter = 0
|
||||
def __init__(self, name, number, active, layer , scene, laser):
|
||||
self.name = name
|
||||
self.number = number
|
||||
self.active = active
|
||||
self.layer = layer
|
||||
self.scene = scene
|
||||
self.laser = laser
|
||||
|
||||
DestObject.counter += 1
|
||||
|
||||
def __del__(self):
|
||||
DestObject.counter -= 1
|
||||
'''
|
||||
class DestObject():
|
||||
|
||||
# class Destinations(metaclass=IterDest):
|
||||
_instances = set()
|
||||
counter = 0
|
||||
|
||||
def __init__(self, name, number, active, layer , scene, laser):
|
||||
self.name = name
|
||||
self.number = number
|
||||
self.active = active
|
||||
self.layer = layer
|
||||
self.scene = scene
|
||||
self.laser = laser
|
||||
self._instances.add(weakref.ref(self))
|
||||
DestObject.counter += 1
|
||||
|
||||
@classmethod
|
||||
def getinstances(cls):
|
||||
dead = set()
|
||||
for ref in cls._instances:
|
||||
obj = ref()
|
||||
if obj is not None:
|
||||
yield obj
|
||||
else:
|
||||
dead.add(ref)
|
||||
cls._instances -= dead
|
||||
|
||||
|
||||
def __del__(self):
|
||||
DestObject.counter -= 1
|
||||
|
||||
|
||||
|
||||
def Config(redIP,client,myname):
|
||||
global ClientNumber, name, redisIP, r
|
||||
|
||||
redisIP = redIP
|
||||
r = redis.StrictRedis(host=redisIP, port=6379, db=0)
|
||||
|
||||
# ClientNumber 255 are not drawing anything like artnet
|
||||
ClientNumber = client
|
||||
#print ("client configured",ClientNumber)
|
||||
name = myname
|
||||
print ("lj23layers : Plugin declare its name :",name)
|
||||
#print layer
|
||||
return r
|
||||
|
||||
|
||||
def LjClient(client):
|
||||
global ClientNumber
|
||||
|
||||
ClientNumber = client
|
||||
|
||||
|
||||
|
||||
def Ljlayer(somelayer):
|
||||
global layer
|
||||
|
||||
layer = somelayer
|
||||
|
||||
|
||||
def fromRedis(n):
|
||||
|
||||
encoded = r.get(n)
|
||||
#print("")
|
||||
#print('fromredis key',n,":",encoded)
|
||||
h, w = struct.unpack('>II',encoded[:8])
|
||||
#print("fromredis array size",n,":",h,w)
|
||||
a = np.frombuffer(encoded, dtype=np.int16, offset=8).reshape(h,w)
|
||||
#print("fromredis array",n,":",a)
|
||||
return a
|
||||
|
||||
# Store Numpy array 'a' in Redis key 'n'
|
||||
# Write also in redis key 'a' numpy array, its 2 dimensions size : h time w values
|
||||
def toRedis(n,a):
|
||||
|
||||
#print("array.shape", a.shape, len(a.shape) )
|
||||
if len(a.shape) == 1:
|
||||
h = a.shape[0]
|
||||
w = 1
|
||||
else:
|
||||
h,w = a.shape
|
||||
#print("toredis", n,"h",h,"w",w,"a",a)
|
||||
shape = struct.pack('>II',h,w)
|
||||
|
||||
#shape = struct.pack('>II',len(a),1)
|
||||
#print("toredis",n,a)
|
||||
encoded = shape + a.tobytes()
|
||||
|
||||
# Store encoded data in Redis
|
||||
return r.set(n,encoded)
|
||||
|
||||
|
||||
#
|
||||
# OSC functions
|
||||
#
|
||||
|
||||
# OSC clients
|
||||
|
||||
def SendLJ(oscaddress,oscargs=''):
|
||||
|
||||
oscmsg = OSCMessage()
|
||||
oscmsg.setAddress(oscaddress)
|
||||
oscmsg.append(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")
|
||||
try:
|
||||
osclientlj.sendto(oscmsg, (redisIP, 8002))
|
||||
oscmsg.clearData()
|
||||
except:
|
||||
print ('Connection to LJ refused : died ?')
|
||||
pass
|
||||
#time.sleep(0.001
|
||||
|
||||
|
||||
|
||||
# Resolume OSC Arena client.
|
||||
# sendresol(oscaddress, [arg1, arg2,...])
|
||||
# example : sendresol("/noteon",note)
|
||||
|
||||
def SendResol(oscaddress,oscargs):
|
||||
|
||||
oscmsg = OSCMessage()
|
||||
oscmsg.setAddress(oscaddress)
|
||||
oscmsg.append(oscargs)
|
||||
|
||||
osclientresol = OSCClient()
|
||||
osclientresol.connect((oscIPresol, oscPORTresol))
|
||||
|
||||
print("lj23layers sending OSC message : ", oscmsg, "to Resolume", oscIPresol, ":", oscPORTresol)
|
||||
try:
|
||||
osclientresol.sendto(oscmsg, (oscIPresol, oscPORTresol))
|
||||
oscmsg.clearData()
|
||||
except:
|
||||
print ('Connection to Resolume refused : died ?')
|
||||
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):
|
||||
SendLJ("/status", message)
|
||||
|
||||
|
||||
# Closing plugin messages to LJ
|
||||
def ClosePlugin():
|
||||
WebStatus(name+" Exiting")
|
||||
SendLJ("/"+name+"/start",0)
|
||||
|
||||
|
||||
|
||||
|
||||
# RAW OSC Frame available ?
|
||||
def OSCframe():
|
||||
# clear timed_out flag
|
||||
#print "oscframe"
|
||||
oscserver.timed_out = False
|
||||
# handle all pending requests then return
|
||||
while not oscserver.timed_out:
|
||||
oscserver.handle_request()
|
||||
|
||||
# Answer to LJ pings with /pong value
|
||||
def OSCping(path, tags, args, source):
|
||||
#def OSCping():
|
||||
if gstt.debug >0:
|
||||
print(name, "lj23layers got /ping from LJ -> reply /pong", name)
|
||||
SendLJ("/pong",name)
|
||||
|
||||
# Properly close the system. Todo
|
||||
def OSCstop():
|
||||
oscserver.close()
|
||||
|
||||
|
||||
# /quit
|
||||
def OSCquit(path, tags, args, source):
|
||||
global oscrun
|
||||
|
||||
oscrun = False
|
||||
print('lj23layers got /quit for',name)
|
||||
#WebStatus(name + " quit.")
|
||||
#SendLJ("/"+name+"/start",0)
|
||||
#print("Stopping OSC...")
|
||||
#OSCstop()
|
||||
#sys.exit()
|
||||
|
||||
|
||||
# default handler
|
||||
def OSChandler(path, tags, args, source):
|
||||
|
||||
oscaddress = ''.join(path.split("/"))
|
||||
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)
|
||||
|
||||
#oscIPout = str(source[0])
|
||||
#osclient.connect((oscIPout, oscPORTout))
|
||||
|
||||
|
||||
# for any laser object : /pluginame/obj objectname attribute value
|
||||
# like : /pluginname/obj 'fft' 'xpos' 100
|
||||
# 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):
|
||||
|
||||
obj = eval(args[0]+"."+ args[1])
|
||||
obj = args[2]
|
||||
|
||||
|
||||
def OSCvar(path, tags, args, source):
|
||||
|
||||
obj = eval(args[0])
|
||||
obj = args[1]
|
||||
|
||||
|
||||
def addOSCdefaults(server):
|
||||
global oscserver
|
||||
|
||||
oscserver = server
|
||||
oscserver.addMsgHandler( "default", OSChandler )
|
||||
oscserver.addMsgHandler( "/ping", OSCping)
|
||||
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
|
||||
#
|
||||
|
||||
# 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 )
|
||||
|
||||
|
||||
# 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
|
||||
#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, layer )
|
||||
LineTo(xy0,c, layer )
|
||||
else:
|
||||
#print "xy:",xy
|
||||
LineTo(xy,c, layer )
|
||||
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
|
||||
def Pointransf(xy, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0):
|
||||
|
||||
x = xy[0] * resize
|
||||
y = xy[1] * resize
|
||||
z = xy[2] * resize
|
||||
|
||||
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
|
||||
""" 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):
|
||||
print("Stupido !! your code is to old : use Drawlayer() instead of LinesPL()")
|
||||
Drawlayer(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])
|
||||
layers[layer] = []
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def Resetlayer(self, layer):
|
||||
layers[layer] = []
|
||||
|
||||
|
||||
#
|
||||
# "Destinations" management for layers
|
||||
#
|
||||
|
||||
|
||||
# Add a destination for a given layer
|
||||
def Addest(layer, scene, laser):
|
||||
|
||||
print (name,'adding',layer,scene,laser,'?')
|
||||
if Findest(layer, scene, laser) == -1:
|
||||
newdest = DestsObjects.counter + 1
|
||||
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 layer
|
||||
# /pluginame/dest layer, scene, laser
|
||||
def OSCadddest(path, tags, args, source):
|
||||
|
||||
Addests(int(args[0]),int(args[1]),int(args[2]))
|
||||
|
||||
|
||||
# Find layer destination with its parameters in destinations dictionnary
|
||||
def Findest(layer, scene, laser):
|
||||
|
||||
print(name, 'searching layer,scene,laser',layer,scene,laser)
|
||||
for item in DestObjects.getinstances():
|
||||
#print(item)
|
||||
if item.layer == layer and item.scene == scene and item.laser == laser:
|
||||
#Dests.append(item[0])
|
||||
print('found number',item.number)
|
||||
return item.number
|
||||
else:
|
||||
print('no destination found')
|
||||
return -1
|
||||
'''
|
||||
#Dests = list()
|
||||
allDests = Dests.items()
|
||||
for item in allDests:
|
||||
print(item)
|
||||
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 layer destination with its parameters in destinations dictionnary
|
||||
def Deldest(layer, scene, laser):
|
||||
|
||||
Destnumber = Findest(layer, scene, laser)
|
||||
print(name,'deleting Destination layer, scene, laser', layer,scene, laser)
|
||||
|
||||
if Destnumber != -1:
|
||||
print('found DestObject', Destnumber)
|
||||
delattr(DestObjects, str(Destnumber))
|
||||
print("Destination", Destnumber,"was removed")
|
||||
else:
|
||||
print("Destination was not found")
|
||||
|
||||
|
||||
# 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])
|
||||
|
||||
|
||||
# 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
|
||||
|
||||
#print("DrawDest")
|
||||
|
||||
for destination in DestObject.getinstances():
|
||||
|
||||
#print(Dests[str(destination)])
|
||||
#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(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 layer can be sent to multiple destination so they are all reset *after* all sending.
|
||||
for layerss in range(4):
|
||||
|
||||
layers[layerss] = []
|
||||
|
||||
'''
|
||||
# Dictionnary style
|
||||
|
||||
#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(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 layer can be sent to multiple destination so they are all reset *after* all sending.
|
||||
for destination in range(len(Dests)):
|
||||
|
||||
layers[Dests[str(destination)]["layer"]] = []
|
||||
'''
|
||||
'''
|
||||
scenes = 4
|
||||
|
||||
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(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
|
||||
|
||||
'''
|
||||
|
||||
#
|
||||
# High level drawing functions
|
||||
#
|
||||
|
||||
|
||||
# Font1
|
||||
|
||||
|
||||
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é 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
|
||||
[(-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é 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
|
||||
[(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
|
||||
|
||||
# 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
|
||||
|
||||
]
|
||||
|
||||
|
||||
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, layer, xpos, ypos, resize, rotx, roty, rotz):
|
||||
|
||||
dots =[]
|
||||
|
||||
l = len(message)
|
||||
i= 0
|
||||
#print()
|
||||
# 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_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_layer_list[0][0] + x_offset,char_layer_list[0][1],0))
|
||||
|
||||
for xy in char_layer_list:
|
||||
char_draw.append((xy[0] + x_offset,xy[1],c))
|
||||
i +=1
|
||||
#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, layer, xpos, ypos, resize, rotx, roty, rotz):
|
||||
|
||||
Text(message,int('0x%02x%02x%02x' % (red,green,blue),0), layer, xpos, ypos, resize, rotx, roty, rotz)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
659
libs3/lj3.py
Normal file
659
libs3/lj3.py
Normal file
|
|
@ -0,0 +1,659 @@
|
|||
|
||||
'''
|
||||
|
||||
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)
|
||||
PolyLineOneColor
|
||||
rPolyLineOneColor
|
||||
|
||||
Text(word, color, PL, xpos, ypos, resize, rotx, roty, rotz) : Display a word
|
||||
SendLJ(adress,message) : LJ remote control. See commands.py
|
||||
WebStatus(message) : display message on webui
|
||||
DrawPL(point list number) : once you stacked all wanted elements, like 2 polylines, send them to lasers.
|
||||
rgb2int(r,g,b)
|
||||
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
|
||||
|
||||
OSCstart(): Start the OSC system.
|
||||
OSCframe(): Handle incoming OSC message. Calling the right callback
|
||||
OSCstop(): Properly close the OSC system
|
||||
OSCping(): Answer to LJ pings by sending /pong name
|
||||
OSCquit(): Exit calling script using name in terminal
|
||||
|
||||
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
|
||||
|
||||
|
||||
LICENCE : CC
|
||||
Sam Neurohack
|
||||
|
||||
'''
|
||||
|
||||
import math
|
||||
import redis
|
||||
|
||||
# Import needed modules from osc4py3
|
||||
from osc4py3.as_eventloop import *
|
||||
from osc4py3 import oscbuildparse
|
||||
#from osc4py3 import oscmethod as osm
|
||||
from osc4py3.oscmethod import *
|
||||
|
||||
|
||||
#redisIP = '127.0.0.1'
|
||||
#r = redis.StrictRedis(host=redisIP, port=6379, db=0)
|
||||
|
||||
print('Importing lj3 from libs...')
|
||||
ClientNumber = 0
|
||||
name = "noname"
|
||||
point_list = []
|
||||
pl = [[],[],[],[]]
|
||||
|
||||
#
|
||||
# OSC interaction with LJ
|
||||
#
|
||||
|
||||
def OSCstart():
|
||||
# Start the system.
|
||||
osc_startup()
|
||||
#osc_udp_client(redisIP, 8002, "LJ 8002")
|
||||
|
||||
def OSCframe():
|
||||
#print("OSCprocess")
|
||||
osc_process()
|
||||
|
||||
# Properly close the system. Todo
|
||||
def OSCstop():
|
||||
osc_terminate()
|
||||
|
||||
|
||||
def SendLJ(oscaddress,oscargs=''):
|
||||
|
||||
try:
|
||||
msg = oscbuildparse.OSCMessage(oscaddress, None, [oscargs])
|
||||
# print(msg)
|
||||
print("lj3 sending OSC message to", redisIP, ":8002")
|
||||
osc_send(msg, "LJ 8002")
|
||||
OSCframe()
|
||||
|
||||
except:
|
||||
print (oscaddress,'Connection to LJ refused : died ?')
|
||||
pass
|
||||
|
||||
def WebStatus(message):
|
||||
SendLJ("/status", message)
|
||||
|
||||
|
||||
# Answer to LJ /ping 1 with /pong name
|
||||
def OSCping(value):
|
||||
print(name,"got /ping 1 from LJ -> reply /pong", name)
|
||||
SendLJ("/pong",name)
|
||||
|
||||
|
||||
# Closing plugin messages to LJ
|
||||
def ClosePlugin():
|
||||
WebStatus(name+" Exit")
|
||||
SendLJ("/"+name+"/start",0)
|
||||
print("Stopping OSC...")
|
||||
OSCstop()
|
||||
|
||||
'''
|
||||
# /quit
|
||||
def OSCquit():
|
||||
|
||||
WebStatus(name + " quit.")
|
||||
SendLJ("/"+name+"/start",0)
|
||||
print("Stopping OSC...")
|
||||
OSCstop()
|
||||
sys.exit()
|
||||
'''
|
||||
'''
|
||||
def handlerfunction(s, x, y):
|
||||
# Will receive message data unpacked in s, x, y
|
||||
pass
|
||||
|
||||
def handlerfunction2(address, s, x, y):
|
||||
# Will receive message address, and message data flattened in s, x, y
|
||||
pass
|
||||
|
||||
# Make server channels to receive packets.
|
||||
osc_udp_server("127.0.0.1", 3721, "localhost")
|
||||
osc_udp_server("0.0.0.0", 3724, "anotherserver")
|
||||
'''
|
||||
|
||||
|
||||
|
||||
ASCII_GRAPHICS = [
|
||||
|
||||
# caracteres corrects
|
||||
|
||||
[(-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
|
||||
|
||||
# caracteres 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)], #@
|
||||
|
||||
# Caracteres corrects
|
||||
|
||||
|
||||
[(-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 rgb2int(r,g,b):
|
||||
return int('0x%02x%02x%02x' % (r,g,b),0)
|
||||
|
||||
|
||||
def Config(redisIP,client,myname):
|
||||
global ClientNumber, r, name
|
||||
|
||||
name = myname
|
||||
print ("lj3 got a name to use :", name)
|
||||
r = redis.StrictRedis(host=redisIP, port=6379, db=0)
|
||||
ClientNumber = client
|
||||
osc_udp_client(redisIP, 8002, "LJ 8002")
|
||||
return r
|
||||
|
||||
|
||||
def LjClient(client):
|
||||
global ClientNumber
|
||||
|
||||
ClientNumber = client
|
||||
|
||||
def LjPl(pl):
|
||||
global PL
|
||||
|
||||
PL = pl
|
||||
|
||||
|
||||
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 = rotx * math.pi / 180
|
||||
cosaX = math.cos(rad)
|
||||
sinaX = math.sin(rad)
|
||||
|
||||
y2 = y
|
||||
y = y2 * cosaX - z * sinaX
|
||||
z = y2 * sinaX + z * cosaX
|
||||
|
||||
rad = roty * math.pi / 180
|
||||
cosaY = math.cos(rad)
|
||||
sinaY = math.sin(rad)
|
||||
|
||||
z2 = z
|
||||
z = z2 * cosaY - x * sinaY
|
||||
x = z2 * sinaY + x * cosaY
|
||||
|
||||
rad = rotz * math.pi / 180
|
||||
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:
|
||||
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)
|
||||
#print i,x_offset
|
||||
# if digit
|
||||
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)
|
||||
#print ("laser",PL,"message",message)
|
||||
#dots.append(char_draw)
|
||||
|
||||
|
||||
|
||||
import re
|
||||
|
||||
def setup_controls(joystick):
|
||||
"""
|
||||
Joystick wrapper.
|
||||
"""
|
||||
if re.search('playstation', joystick.get_name(), re.I):
|
||||
return Ps3Controller(joystick)
|
||||
|
||||
elif re.search('X-box', joystick.get_name(), re.I):
|
||||
return XboxController(joystick)
|
||||
|
||||
elif re.search('Saitek', joystick.get_name(), re.I):
|
||||
return MySaitekController(joystick)
|
||||
|
||||
elif re.search('Thrustmaster dual analog 3.2', joystick.get_name(), re.I):
|
||||
return MyThrustController(joystick)
|
||||
|
||||
elif re.search('2n1 USB', joystick.get_name(), re.I):
|
||||
return CSLController(joystick)
|
||||
|
||||
elif re.search('Joystick', joystick.get_name(), re.I):
|
||||
return USBController(joystick)
|
||||
|
||||
return Controller(joystick)
|
||||
|
||||
class Controller(object):
|
||||
|
||||
def __init__(self, joystick):
|
||||
"""Pass a PyGame joystick instance."""
|
||||
self.js = joystick
|
||||
|
||||
def getLeftHori(self):
|
||||
return self.js.get_axis(2)
|
||||
|
||||
def getLeftVert(self):
|
||||
return self.js.get_axis(3)
|
||||
|
||||
def getRightHori(self):
|
||||
return self.js.get_axis(0)
|
||||
|
||||
def getRightVert(self):
|
||||
return self.js.get_axis(1)
|
||||
|
||||
def getLeftTrigger(self):
|
||||
return self.js.get_button(9)
|
||||
|
||||
def getRightTrigger(self):
|
||||
return self.js.get_button(2)
|
||||
|
||||
class XboxController(Controller):
|
||||
|
||||
def __init__(self, joystick):
|
||||
super(XboxController, self).__init__(joystick)
|
||||
|
||||
def getLeftHori(self):
|
||||
return self.js.get_axis(0)
|
||||
|
||||
def getLeftVert(self):
|
||||
return self.js.get_axis(1)
|
||||
|
||||
def getRightHori(self):
|
||||
return self.js.get_axis(3)
|
||||
|
||||
def getRightVert(self):
|
||||
return self.js.get_axis(4)
|
||||
|
||||
def getLeftTrigger(self):
|
||||
return self.js.get_axis(2)
|
||||
|
||||
def getRightTrigger(self):
|
||||
return self.js.get_button(11)
|
||||
|
||||
class Ps3Controller(Controller):
|
||||
|
||||
#up 4 _DOWN 6 left 7 right 5 croix 14 rond 13 triangle 12
|
||||
|
||||
def __init__(self, joystick):
|
||||
super(Ps3Controller, self).__init__(joystick)
|
||||
|
||||
def getLeftHori(self):
|
||||
return self.js.get_axis(0)
|
||||
|
||||
def getLeftVert(self):
|
||||
return self.js.get_axis(1)
|
||||
|
||||
def getRightHori(self):
|
||||
return self.js.get_axis(2)
|
||||
|
||||
def getRightVert(self):
|
||||
return self.js.get_axis(3)
|
||||
|
||||
def getLeftTrigger(self):
|
||||
# TODO: Verify
|
||||
return self.js.get_button(8)
|
||||
|
||||
def getRightTrigger(self):
|
||||
# TODO: Verify
|
||||
return self.js.get_button(9)
|
||||
|
||||
def getUp(self):
|
||||
return self.js.get_button(4)
|
||||
|
||||
def getDown(self):
|
||||
return self.js.get_button(6)
|
||||
|
||||
def getLeft(self):
|
||||
return self.js.get_button(7)
|
||||
|
||||
def getRight(self):
|
||||
return self.js.get_button(5)
|
||||
|
||||
def getFire1(self):
|
||||
return self.js.get_button(14)
|
||||
|
||||
def getFire2(self):
|
||||
return self.js.get_button(13)
|
||||
|
||||
|
||||
class MySaitekController(Controller):
|
||||
|
||||
def __init__(self, joystick):
|
||||
super(MySaitekController, self).__init__(joystick)
|
||||
|
||||
def getLeftHori(self):
|
||||
return self.js.get_axis(0)
|
||||
|
||||
def getLeftVert(self):
|
||||
return self.js.get_axis(1)
|
||||
|
||||
def getRightHori(self):
|
||||
return self.js.get_axis(3)
|
||||
|
||||
def getRightVert(self):
|
||||
return self.js.get_axis(2)
|
||||
|
||||
def getLeftTrigger(self):
|
||||
return self.js.get_button(6)
|
||||
|
||||
def getRightTrigger(self):
|
||||
return self.js.get_button(7)
|
||||
|
||||
class MyThrustController(Controller):
|
||||
|
||||
def __init__(self, joystick):
|
||||
super(MyThrustController, self).__init__(joystick)
|
||||
|
||||
def getLeftHori(self):
|
||||
return self.js.get_axis(0)
|
||||
|
||||
def getLeftVert(self):
|
||||
return self.js.get_axis(1)
|
||||
|
||||
def getRightHori(self):
|
||||
return self.js.get_axis(2)
|
||||
|
||||
def getRightVert(self):
|
||||
return self.js.get_axis(3)
|
||||
|
||||
def getLeftTrigger(self):
|
||||
return self.js.get_button(5)
|
||||
|
||||
def getRightTrigger(self):
|
||||
return self.js.get_button(7)
|
||||
|
||||
|
||||
class CSLController(Controller):
|
||||
|
||||
def __init__(self, joystick):
|
||||
super(CSLController, self).__init__(joystick)
|
||||
|
||||
def getLeftHori(self):
|
||||
return self.js.get_axis(2)
|
||||
|
||||
def getLeftVert(self):
|
||||
return self.js.get_axis(3)
|
||||
|
||||
def getRightHori(self):
|
||||
return self.js.get_axis(0)
|
||||
|
||||
def getRightVert(self):
|
||||
return self.js.get_axis(1)
|
||||
|
||||
def getLeftTrigger(self):
|
||||
return self.js.get_button(6)
|
||||
|
||||
def getRightTrigger(self):
|
||||
return self.js.get_button(7)
|
||||
|
||||
def getFire1(self):
|
||||
return self.js.get_button(2)
|
||||
|
||||
def getFire2(self):
|
||||
return self.js.get_button(1)
|
||||
|
||||
class USBController(Controller):
|
||||
|
||||
|
||||
# my USB Joystick
|
||||
#up axis 0 -1 DOWN axis 0 1 left axis 1 1 right axis 1 -1 bouton gauche 10 bouton droite 9
|
||||
|
||||
def __init__(self, joystick):
|
||||
super(USBController, self).__init__(joystick)
|
||||
|
||||
|
||||
def getUp(self):
|
||||
if self.js.get_axis(0) == -1:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def getDown(self):
|
||||
if self.js.get_axis(0) > 0.9:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def getLeft(self):
|
||||
if self.js.get_axis(1) == 1:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def getRight(self):
|
||||
if self.js.get_axis(1) == -1:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def getLeftTrigger(self):
|
||||
return self.js.get_button(10)
|
||||
|
||||
def getRightTrigger(self):
|
||||
return self.js.get_button(9)
|
||||
|
||||
def getFire1(self):
|
||||
if self.js.get_button(10) == 1:
|
||||
print ("fire 1")
|
||||
return self.js.get_button(10)
|
||||
|
||||
def getFire2(self):
|
||||
if self.js.get_button(9) == 1:
|
||||
print ("fire 2")
|
||||
return self.js.get_button(9)
|
||||
|
||||
|
||||
|
||||
|
||||
43
libs3/log.py
Normal file
43
libs3/log.py
Normal 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
404
libs3/maxwellccs.py
Normal 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)
|
||||
|
||||
|
||||
|
||||
452
libs3/midi.py
Normal file
452
libs3/midi.py
Normal file
|
|
@ -0,0 +1,452 @@
|
|||
#!/usr/bin/python2.7
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
LJay/LJ
|
||||
v0.7.0
|
||||
|
||||
Midi Handler
|
||||
|
||||
Deprecated, see midi3
|
||||
|
||||
by Sam Neurohack
|
||||
from /team/laser
|
||||
|
||||
"""
|
||||
|
||||
print "importing midi 0"
|
||||
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)
|
||||
import mido
|
||||
from mido import MidiFile
|
||||
#import mido
|
||||
import sys
|
||||
from serial.tools import list_ports
|
||||
import serial
|
||||
|
||||
from sys import platform
|
||||
import gstt
|
||||
|
||||
# import bhoroscp
|
||||
|
||||
import bhoreal
|
||||
import launchpad
|
||||
from OSC import OSCServer, OSCClient, OSCMessage
|
||||
#import orbits
|
||||
|
||||
|
||||
midiname = ["Name"] * 16
|
||||
midiport = [rtmidi.MidiOut() for i in range(16) ]
|
||||
|
||||
|
||||
|
||||
is_py2 = sys.version[0] == '2'
|
||||
if is_py2:
|
||||
from Queue import Queue
|
||||
else:
|
||||
from queue import Queue
|
||||
|
||||
# max 16 midi port array
|
||||
|
||||
midinputsname = ["Name"] * 16
|
||||
midinputsqueue = [Queue() for i in range(16) ]
|
||||
midinputs = []
|
||||
|
||||
|
||||
BhorealMidiName = "Bhoreal"
|
||||
LaunchMidiName = "Launch"
|
||||
|
||||
BhorealPort, Midi1Port, Midi2Port, VirtualPort, MPort = -1,-1,-1, -1, -1
|
||||
VirtualName = "LaunchPad Mini"
|
||||
Mser = False
|
||||
|
||||
# Myxolidian 3 notes chords list
|
||||
Myxo = [(59,51,54),(49,52,56),(49,52,56),(51,54,57),(52,56,59),(52,56,59),(54,57,48),(57,49,52)]
|
||||
MidInsNumber = 0
|
||||
|
||||
try:
|
||||
input = raw_input
|
||||
except NameError:
|
||||
# Python 3
|
||||
StandardError = Exception
|
||||
|
||||
|
||||
STATUS_MAP = {
|
||||
'noteon': NOTE_ON,
|
||||
'noteoff': NOTE_OFF,
|
||||
'programchange': PROGRAM_CHANGE,
|
||||
'controllerchange': CONTROLLER_CHANGE,
|
||||
'pitchbend': PITCH_BEND,
|
||||
'polypressure': POLY_PRESSURE,
|
||||
'channelpressure': CHANNEL_PRESSURE
|
||||
}
|
||||
|
||||
# OSC destination list for incoming midi
|
||||
midi2OSC = {
|
||||
"lj": {"oscip": "127.0.0.1", "oscport": 8002, "notes": False, "msgs": False},
|
||||
"nozoid": {"oscip": "127.0.0.1", "oscport": 8003, "notes": False, "msgs": False},
|
||||
"dump": {"oscip": "127.0.0.1", "oscport": 8040, "notes": True, "msgs": True}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#mycontroller.midiport[LaunchHere].send_message([CONTROLLER_CHANGE, LaunchTop[number-1], color])
|
||||
|
||||
def send(device,msg):
|
||||
|
||||
'''
|
||||
# if device is the midi name
|
||||
if device in midiname:
|
||||
deviceport = midiname.index(device)
|
||||
midiport[deviceport].send_message(msg)
|
||||
'''
|
||||
if device == "Launchpad":
|
||||
#print LaunchHere
|
||||
midiport[gstt.LaunchHere].send_message(msg)
|
||||
|
||||
if device == "Bhoreal":
|
||||
midiport[gstt.BhorealHere].send_message(msg)
|
||||
|
||||
def NoteOn(note, color):
|
||||
global MidInsNumber
|
||||
|
||||
gstt.note = note
|
||||
gstt.velocity = color
|
||||
|
||||
for port in range(MidInsNumber):
|
||||
|
||||
if midiname[port].find(LaunchMidiName) == 0:
|
||||
launchpad.PadNoteOn(note%64,color)
|
||||
|
||||
if midiname[port].find(BhorealMidiName) == 0:
|
||||
gstt.BhorLeds[note%64]=color
|
||||
midiport[port].send_message([NOTE_ON, note%64, color])
|
||||
#bhorosc.sendosc("/bhoreal", [note%64 , color])
|
||||
|
||||
if midiname[port].find(BhorealMidiName) != 0 and midiname[port].find(LaunchMidiName) != 0:
|
||||
midiport[port].send_message([NOTE_ON, note, color])
|
||||
|
||||
#virtual.send_message([NOTE_ON, note, color])
|
||||
|
||||
for OSCtarget in midi2OSC:
|
||||
if midi2OSC[OSCtarget]['notes']:
|
||||
pass
|
||||
#OSCsend(OSCtarget, "/noteon", [note, color])
|
||||
|
||||
|
||||
def NoteOff(note):
|
||||
global MidInsNumber
|
||||
|
||||
gstt.note = note
|
||||
gstt.velocity = 0
|
||||
for port in range(MidInsNumber):
|
||||
|
||||
if midiname[port].find(LaunchMidiName) == 0:
|
||||
launchpad.PadNoteOff(note%64)
|
||||
|
||||
if midiname[port].find(BhorealMidiName) == 0:
|
||||
midiport[port].send_message([NOTE_OFF, note%64, 0])
|
||||
gstt.BhorLeds[note%64]=0
|
||||
#bhorosc.sendosc("/bhoreal", [note%64 , 0])
|
||||
|
||||
if midiname[port].find(BhorealMidiName) != 0 and midiname[port].find(LaunchMidiName) != 0:
|
||||
midiport[port].send_message([NOTE_OFF, note, 0])
|
||||
#virtual.send_message([NOTE_OFF, note, 0])
|
||||
|
||||
for OSCtarget in midi2OSC:
|
||||
if midi2OSC[OSCtarget]["notes"]:
|
||||
pass
|
||||
#OSCsend(OSCtarget, "/noteoff", note)
|
||||
|
||||
|
||||
|
||||
def MidiMsg(midimsg):
|
||||
|
||||
print ("MidiMsg", midimsg)
|
||||
for port in range(MidInsNumber):
|
||||
if midiname[port].find(BhorealMidiName) != 0:
|
||||
midiport[port].send_message(midimsg)
|
||||
|
||||
|
||||
def OSCsend(name, oscaddress, oscargs =''):
|
||||
|
||||
|
||||
ip = midi2OSC[name]["oscip"]
|
||||
port = midi2OSC[name]["oscport"]
|
||||
osclient = OSCClient()
|
||||
osclient.connect((ip, port))
|
||||
oscmsg = OSCMessage()
|
||||
oscmsg.setAddress(oscaddress)
|
||||
oscmsg.append(oscargs)
|
||||
|
||||
try:
|
||||
if gstt.debug > 0:
|
||||
print("Midi OSCSend : sending", oscmsg, "to", name, "at", gstt.LjayServerIP, ":", PluginPort)
|
||||
osclient.sendto(oscmsg, (ip, port))
|
||||
oscmsg.clearData()
|
||||
#if gstt.debug >0:
|
||||
# print oscaddress, oscargs, "was sent to",name
|
||||
return True
|
||||
|
||||
except:
|
||||
if gstt.debug > 0:
|
||||
print ('Midi OSCSend : Connection to IP', ip ,':', port,'refused : died ?')
|
||||
#sendWSall("/status No plugin.")
|
||||
#sendWSall("/status " + name + " is offline")
|
||||
#sendWSall("/" + name + "/start 0")
|
||||
#PluginStart(name)
|
||||
return False
|
||||
|
||||
def WebStatus(message):
|
||||
OSCsend("lj","/status", message)
|
||||
|
||||
#
|
||||
# MIDI Startup and handling
|
||||
#
|
||||
|
||||
mqueue = Queue()
|
||||
inqueue = Queue()
|
||||
|
||||
#
|
||||
# Events from Generic MIDI Handling
|
||||
#
|
||||
|
||||
def midinProcess(midiqueue):
|
||||
|
||||
midiqueue_get = midiqueue.get
|
||||
while True:
|
||||
msg = midiqueue_get()
|
||||
print ("midin ", msg)
|
||||
time.sleep(0.001)
|
||||
|
||||
# Event from Bhoreal or Launchpad
|
||||
def MidinProcess(inqueue):
|
||||
|
||||
inqueue_get = inqueue.get
|
||||
while True:
|
||||
time.sleep(0.001)
|
||||
msg = inqueue_get()
|
||||
print ("Midinproces", msg[0])
|
||||
|
||||
# Note On
|
||||
if msg[0]==NOTE_ON:
|
||||
NoteOn(msg[1],msg[2])
|
||||
#if bhorosc.oscdevice == 1:
|
||||
WebStatus(''.join(("note ",msg[1]," to ",msg[2])))
|
||||
|
||||
# Note Off
|
||||
if msg[0]==NOTE_OFF:
|
||||
print ("noteoff")
|
||||
NoteOff(msg[1],msg[2])
|
||||
#if bhorosc.oscdevice == 1:
|
||||
WebStatus(''.join(("note ",msg[1]," to ",msg[2])))
|
||||
|
||||
# Midi CC message
|
||||
if msg[0] == CONTROLLER_CHANGE:
|
||||
print ("CC :", msg[1], msg[2])
|
||||
WebStatus("CC :" + str(msg[1]) + " " + str(msg[2]))
|
||||
#orbits.RotX(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:
|
||||
|
||||
MidiMsg(msg[0],msg[1],msg[2])
|
||||
#if bhorosc.oscdevice == 1:
|
||||
WebStatus(''.join(("msg : ",msg[0]," ",msg[1]," ",msg[2])))
|
||||
|
||||
|
||||
# Generic call back : new msg forwarded to queue
|
||||
class AddQueue(object):
|
||||
def __init__(self, port):
|
||||
self.port = port
|
||||
print ("AddQueue", port)
|
||||
self._wallclock = time.time()
|
||||
|
||||
def __call__(self, event, data=None):
|
||||
message, deltatime = event
|
||||
self._wallclock += deltatime
|
||||
print("[%s] @%0.6f %r" % (self.port, self._wallclock, message))
|
||||
inqueue.put(message)
|
||||
|
||||
|
||||
#
|
||||
# MIDI OUT Handling
|
||||
#
|
||||
|
||||
def OutConfig():
|
||||
global midiout, MidInsNumber
|
||||
|
||||
print("")
|
||||
print("MIDIout...")
|
||||
print("List and attach to available devices on host with IN port :")
|
||||
|
||||
# Display list of available midi IN devices on the host, create and start an OUT instance to talk to each of these Midi IN devices
|
||||
midiout = rtmidi.MidiOut()
|
||||
available_ports = midiout.get_ports()
|
||||
|
||||
for port, name in enumerate(available_ports):
|
||||
|
||||
midiname[port]=name
|
||||
midiport[port].open_port(port)
|
||||
print("Will send to [%i] %s" % (port, name))
|
||||
#MidIns[port][1].open_port(port)
|
||||
|
||||
# Search for a Bhoreal
|
||||
if name.find(BhorealMidiName) == 0:
|
||||
print("Bhoreal start animation")
|
||||
gstt.BhorealHere = port
|
||||
bhoreal.StartBhoreal(port)
|
||||
bhoreal.UpdateCurve()
|
||||
bhoreal.UpdateSet()
|
||||
bhoreal.UpdateLaser()
|
||||
bhoreal.UpdateSimu()
|
||||
time.sleep(0.2)
|
||||
|
||||
# Search for a LaunchPad
|
||||
if name.find(LaunchMidiName) == 0:
|
||||
print("Launchpad mini start animation")
|
||||
gstt.LaunchHere = port
|
||||
print(gstt.LaunchHere)
|
||||
launchpad.StartLaunchPad(port)
|
||||
time.sleep(0.2)
|
||||
|
||||
# Search for a Guitar Wing
|
||||
if name.find("Livid") == 0:
|
||||
print("Livid Guitar Wing start animation")
|
||||
gstt.WingHere = port
|
||||
print(gstt.WingHere)
|
||||
#guitarwing.StartWing(port)
|
||||
time.sleep(0.2)
|
||||
|
||||
print ("")
|
||||
MidInsNumber = port+1
|
||||
|
||||
|
||||
#
|
||||
# MIDI IN Handling
|
||||
# Create processing thread and queue for each device
|
||||
#
|
||||
def InConfig():
|
||||
|
||||
print("")
|
||||
print("MIDIin...")
|
||||
print("List and attach to available devices on host with OUT port :")
|
||||
if platform == 'darwin':
|
||||
mido.set_backend('mido.backends.rtmidi/MACOSX_CORE')
|
||||
for port, name in enumerate(mido.get_input_names()):
|
||||
|
||||
#print (name)
|
||||
midinputsname[port]=name
|
||||
print(port,name)
|
||||
|
||||
# Bhoreal found ?
|
||||
if name.find(BhorealMidiName) == 0:
|
||||
|
||||
# thread launch to handle all queued MIDI messages from Bhoreal device
|
||||
thread = Thread(target=bhoreal.MidinProcess, args=(bhoreal.bhorqueue,))
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
try:
|
||||
bhorealin, port_name = open_midiinput(port+1) # weird rtmidi call port number is not the same in mido enumeration and here
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
sys.exit()
|
||||
|
||||
midinputs.append(bhorealin)
|
||||
print("Attaching MIDI in callback handler to Bhoreal : ", name)
|
||||
midinputs[port].set_callback(bhoreal.AddQueue(name))
|
||||
print("Bhor",port,port_name)
|
||||
|
||||
# LaunchPad Mini Found ?
|
||||
if name.find(LaunchMidiName) == 0:
|
||||
|
||||
# thread launch to handle all queued MIDI messages from LauchPad device
|
||||
thread = Thread(target=launchpad.LaunchMidinProcess, args=(launchpad.launchqueue,))
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
try:
|
||||
launchin, port_name = open_midiinput(port+1) # weird port number is not the same in mido enumeration and here
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
sys.exit()
|
||||
|
||||
midinputs.append(launchin)
|
||||
print ("Attaching MIDI in callback handler to Launchpad : ", name)
|
||||
launchin.set_callback(launchpad.LaunchAddQueue(name))
|
||||
#print "Launch",port,port_name
|
||||
|
||||
# all other devices
|
||||
|
||||
'''
|
||||
|
||||
|
||||
port = mido.open_ioport(name,callback=AddQueue(name))
|
||||
|
||||
This doesn't work on OS X on French system "Réseau Session" has a bug with accent.
|
||||
Todo : stop using different midi framework.
|
||||
|
||||
if name.find(BhorealMidiName) != 0 and name.find(LaunchMidiName) != 0:
|
||||
thread = Thread(target=midinProcess, args=(midinputsqueue[port],))
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
try:
|
||||
port = mido.open_ioport(name,callback=AddQueue(name))
|
||||
#port_port, port_name = open_midiinput(port)
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
sys.exit()
|
||||
|
||||
#midinputs.append(port_port)
|
||||
print "Attaching MIDI in callback handler to : ", name
|
||||
#midinputs[port].set_callback(AddQueue(name))
|
||||
#MIDInport = mido.open_ioport("Laser",virtual=True,callback=MIDIn)
|
||||
|
||||
'''
|
||||
|
||||
if name.find(BhorealMidiName) != 0 and name.find(LaunchMidiName) != 0:
|
||||
thread = Thread(target=midinProcess, args=(midinputsqueue[port],))
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
|
||||
|
||||
try:
|
||||
port_port, port_name = open_midiinput(port)
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
sys.exit()
|
||||
|
||||
midinputs.append(port_port)
|
||||
print("Attaching MIDI in callback handler to : ", name)
|
||||
midinputs[port].set_callback(AddQueue(name))
|
||||
#MIDInport = mido.open_ioport("Laser",virtual=True,callback=MIDIn)
|
||||
|
||||
|
||||
def End():
|
||||
global midiout
|
||||
|
||||
#midiin.close_port()
|
||||
midiout.close_port()
|
||||
|
||||
#del virtual
|
||||
if gstt.LaunchHere != -1:
|
||||
del gstt.LaunchHere
|
||||
if gstt.BhorealHere != -1:
|
||||
del gstt.BhorealHere
|
||||
|
||||
|
||||
def listdevice(number):
|
||||
|
||||
return midiname[number]
|
||||
|
||||
def check():
|
||||
|
||||
InConfig()
|
||||
OutConfig()
|
||||
#return listdevice(255)
|
||||
|
||||
|
||||
760
libs3/midi3.py
Normal file
760
libs3/midi3.py
Normal file
|
|
@ -0,0 +1,760 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Midi3
|
||||
v0.7.0
|
||||
|
||||
Midi Handler :
|
||||
|
||||
- Hook to the MIDI host
|
||||
- Enumerate connected midi devices and spawn a process/device to handle incoming events
|
||||
- Provide sending functions to
|
||||
- found midi devices with IN port
|
||||
- OSC targets /noteon /noteoff /cc (see midi2OSC).
|
||||
- Launchpad mini led matrix from/to, see launchpad.py
|
||||
- Bhoreal led matrix from/to, see bhoreal.py
|
||||
|
||||
|
||||
todo :
|
||||
|
||||
Midi macros : plusieurs parametres evoluant les uns apres les autres ou en meme temps.
|
||||
cadence
|
||||
|
||||
by Sam Neurohack
|
||||
from /team/laser
|
||||
|
||||
for python 2 & 3
|
||||
|
||||
Laser selection
|
||||
one universe / laser
|
||||
|
||||
Plugin selection
|
||||
bank change/scene/
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
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)
|
||||
import mido
|
||||
from mido import MidiFile
|
||||
import traceback
|
||||
import weakref
|
||||
import sys
|
||||
from sys import platform
|
||||
|
||||
print()
|
||||
print('Midi startup...')
|
||||
|
||||
import gstt, bhoreal, launchpad, LPD8
|
||||
from queue import Queue
|
||||
from OSC3 import OSCServer, OSCClient, OSCMessage
|
||||
|
||||
|
||||
midiname = ["Name"] * 16
|
||||
midiport = [rtmidi.MidiOut() for i in range(16) ]
|
||||
|
||||
OutDevice = []
|
||||
InDevice = []
|
||||
|
||||
# max 16 midi port array
|
||||
|
||||
midinputsname = ["Name"] * 16
|
||||
midinputsqueue = [Queue() for i in range(16) ]
|
||||
midinputs = []
|
||||
|
||||
|
||||
BhorealMidiName = "Bhoreal"
|
||||
LaunchMidiName = "Launch"
|
||||
|
||||
BhorealPort, Midi1Port, Midi2Port, VirtualPort, MPort = -1,-1,-1, -1, -1
|
||||
VirtualName = "LaunchPad Mini"
|
||||
Mser = False
|
||||
|
||||
# Myxolidian 3 notes chords list
|
||||
Myxo = [(59,51,54),(49,52,56),(49,52,56),(51,54,57),(52,56,59),(52,56,59),(54,57,48),(57,49,52)]
|
||||
MidInsNumber = 0
|
||||
|
||||
|
||||
clock = mido.Message(type="clock")
|
||||
|
||||
start = mido.Message(type ="start")
|
||||
stop = mido.Message(type ="stop")
|
||||
ccontinue = mido.Message(type ="continue")
|
||||
reset = mido.Message(type ="reset")
|
||||
songpos = mido.Message(type ="songpos")
|
||||
|
||||
mode = "maxwell"
|
||||
|
||||
'''
|
||||
print("clock",clock)
|
||||
print("start",start)
|
||||
print("continue", ccontinue)
|
||||
print("reset",reset)
|
||||
print("sonpos",songpos)
|
||||
'''
|
||||
|
||||
try:
|
||||
input = raw_input
|
||||
except NameError:
|
||||
# Python 3
|
||||
StandardError = Exception
|
||||
|
||||
|
||||
STATUS_MAP = {
|
||||
'noteon': NOTE_ON,
|
||||
'noteoff': NOTE_OFF,
|
||||
'programchange': PROGRAM_CHANGE,
|
||||
'controllerchange': CONTROLLER_CHANGE,
|
||||
'pitchbend': PITCH_BEND,
|
||||
'polypressure': POLY_PRESSURE,
|
||||
'channelpressure': CHANNEL_PRESSURE
|
||||
}
|
||||
|
||||
# OSC targets list
|
||||
midi2OSC = {
|
||||
"lj": {"oscip": "127.0.0.1", "oscport": 8002, "notes": False, "msgs": False},
|
||||
"nozoid": {"oscip": "127.0.0.1", "oscport": 8003, "notes": False, "msgs": False},
|
||||
"dump": {"oscip": "127.0.0.1", "oscport": 8040, "notes": True, "msgs": True},
|
||||
"maxwell": {"oscip": "127.0.0.1", "oscport": 8012, "notes": True, "msgs": True}
|
||||
}
|
||||
|
||||
notes = ["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"]
|
||||
def midi2note(midinote):
|
||||
|
||||
print("midinote",midinote, "note", notes[midinote%12]+str(round(midinote/12)))
|
||||
return notes[midinote%12]+str(round(midinote/12))
|
||||
|
||||
|
||||
#mycontroller.midiport[LaunchHere].send_message([CONTROLLER_CHANGE, LaunchTop[number-1], color])
|
||||
|
||||
def send(msg,device):
|
||||
|
||||
'''
|
||||
# if device is the midi name
|
||||
if device in midiname:
|
||||
deviceport = midiname.index(device)
|
||||
midiport[deviceport].send_message(msg)
|
||||
'''
|
||||
if device == "Launchpad":
|
||||
#print LaunchHere
|
||||
midiport[launchpad.Here].send_message(msg)
|
||||
|
||||
if device == "Bhoreal":
|
||||
midiport[bhoreal.Here].send_message(msg)
|
||||
|
||||
# mididest : all, launchpad, bhoreal, specificname
|
||||
def NoteOn(note,color, mididest):
|
||||
global MidInsNumber
|
||||
|
||||
gstt.note = note
|
||||
gstt.velocity = color
|
||||
|
||||
for port in range(MidInsNumber):
|
||||
|
||||
# To Launchpad, if present.
|
||||
if mididest == "launchpad" and midiname[port].find(LaunchMidiName) == 0:
|
||||
launchpad.PadNoteOn(note%64,color)
|
||||
|
||||
# To Bhoreal, if present.
|
||||
elif mididest == "bhoreal" and midiname[port].find(BhorealMidiName) == 0:
|
||||
gstt.BhorLeds[note%64]=color
|
||||
midiport[port].send_message([NOTE_ON, note%64, color])
|
||||
#bhorosc.sendosc("/bhoreal", [note%64 , 0])
|
||||
|
||||
# To mididest
|
||||
elif midiname[port].find(mididest) == 0:
|
||||
midiport[port].send_message([NOTE_ON, note, color])
|
||||
|
||||
# To All
|
||||
elif mididest == "all" and midiname[port].find(mididest) != 0 and midiname[port].find(BhorealMidiName) != 0 and midiname[port].find(LaunchMidiName) != 0:
|
||||
midiport[port].send_message([NOTE_ON, note, color])
|
||||
|
||||
#virtual.send_message([NOTE_ON, note, color])
|
||||
|
||||
for OSCtarget in midi2OSC:
|
||||
if (OSCtarget == mididest or mididest == 'all') and midi2OSC[OSCtarget]["notes"]:
|
||||
OSCsend(OSCtarget, "/noteon", [note, color])
|
||||
|
||||
# mididest : all, launchpad, bhoreal, specificname
|
||||
def NoteOff(note, mididest):
|
||||
global MidInsNumber
|
||||
|
||||
gstt.note = note
|
||||
gstt.velocity = 0
|
||||
|
||||
for port in range(MidInsNumber):
|
||||
|
||||
# To Launchpad, if present.
|
||||
if mididest == "launchpad" and midiname[port].find(LaunchMidiName) == 0:
|
||||
launchpad.PadNoteOff(note%64)
|
||||
|
||||
# To Bhoreal, if present.
|
||||
elif mididest == "bhoreal" and midiname[port].find(BhorealMidiName) == 0:
|
||||
midiport[port].send_message([NOTE_OFF, note%64, 0])
|
||||
gstt.BhorLeds[note%64] = 0
|
||||
#bhorosc.sendosc("/bhoreal", [note%64 , 0])
|
||||
|
||||
# To mididest
|
||||
elif midiname[port].find(mididest) != -1:
|
||||
midiport[port].send_message([NOTE_OFF, note, 0])
|
||||
|
||||
# To All
|
||||
elif mididest == "all" and midiname[port].find(mididest) == -1 and midiname[port].find(BhorealMidiName) == -1 and midiname[port].find(LaunchMidiName) == -1:
|
||||
midiport[port].send_message([NOTE_OFF, note, 0])
|
||||
|
||||
#virtual.send_message([NOTE_OFF, note, 0])
|
||||
|
||||
for OSCtarget in midi2OSC:
|
||||
if (OSCtarget == mididest or mididest == 'all') and midi2OSC[OSCtarget]["notes"]:
|
||||
OSCsend(OSCtarget, "/noteoff", note)
|
||||
|
||||
|
||||
# mididest : all or specifiname, won't be sent to launchpad or Bhoreal.
|
||||
def MidiMsg(midimsg, mididest):
|
||||
#print("midi3 got MidiMsg", midimsg, "Dest", mididest)
|
||||
|
||||
desterror = -1
|
||||
for port in range(MidInsNumber):
|
||||
#print("port",port,"midiname", midiname[port])
|
||||
|
||||
# To mididest
|
||||
if midiname[port].find(mididest) != -1:
|
||||
#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 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 =''):
|
||||
|
||||
|
||||
ip = midi2OSC[name]["oscip"]
|
||||
port = midi2OSC[name]["oscport"]
|
||||
osclient = OSCClient()
|
||||
osclient.connect((ip, port))
|
||||
oscmsg = OSCMessage()
|
||||
oscmsg.setAddress(oscaddress)
|
||||
oscmsg.append(oscargs)
|
||||
|
||||
try:
|
||||
if gstt.debug > 0:
|
||||
print("Midi OSCSend : sending", oscmsg,"to", name, "at", ip , ":", port)
|
||||
|
||||
osclient.sendto(oscmsg, (ip, port))
|
||||
oscmsg.clearData()
|
||||
return True
|
||||
|
||||
except:
|
||||
if gstt.debug > 0:
|
||||
print('Midi OSCSend : Connection to IP', ip ,':', port,'refused : died ?')
|
||||
#sendWSall("/status No plugin.")
|
||||
#sendWSall("/status " + name + " is offline")
|
||||
#sendWSall("/" + name + "/start 0")
|
||||
#PluginStart(name)
|
||||
return False
|
||||
|
||||
def Webstatus(message):
|
||||
OSCsend("lj","/status", message)
|
||||
|
||||
#
|
||||
# MIDI Startup and handling
|
||||
#
|
||||
|
||||
mqueue = Queue()
|
||||
inqueue = Queue()
|
||||
|
||||
#
|
||||
# Events from Generic MIDI Handling
|
||||
#
|
||||
'''
|
||||
def midinProcess(midiqueue):
|
||||
|
||||
midiqueue_get = midiqueue.get
|
||||
while True:
|
||||
msg = midiqueue_get()
|
||||
print("midin ", msg)
|
||||
time.sleep(0.001)
|
||||
'''
|
||||
# Event from Bhoreal or Launchpad
|
||||
# Or it could be the midinprocess in launchpad.py or bhoreal.py
|
||||
def MidinProcess(inqueue, portname):
|
||||
|
||||
inqueue_get = inqueue.get
|
||||
mididest = "to Maxwell 1"
|
||||
while True:
|
||||
time.sleep(0.001)
|
||||
msg = inqueue_get()
|
||||
#print("Midinprocess", msg[0])
|
||||
|
||||
# Note On
|
||||
if msg[0]==NOTE_ON:
|
||||
print ("from", portname, "noteon", msg[1])
|
||||
# NoteOn(msg[1],msg[2],mididest)
|
||||
|
||||
# Note Off
|
||||
if msg[0]==NOTE_OFF:
|
||||
print("from", portname,"noteoff")
|
||||
# NoteOff(msg[1],msg[2], mididest)
|
||||
|
||||
# Midi CC message
|
||||
if msg[0] == CONTROLLER_CHANGE:
|
||||
print("from", portname,"CC :", msg[1], msg[2])
|
||||
|
||||
|
||||
# other midi message
|
||||
if msg[0] != NOTE_OFF and msg[0] != NOTE_ON and msg[0] != CONTROLLER_CHANGE:
|
||||
print("from", portname,"other midi message")
|
||||
MidiMsg(msg[0],msg[1],msg[2],mididest)
|
||||
# Webstatus(''.join(("msg : ",msg[0]," ",msg[1]," ",msg[2])))
|
||||
|
||||
|
||||
# Generic call back : new msg forwarded to queue
|
||||
class AddQueue(object):
|
||||
def __init__(self, portname, port):
|
||||
self.portname = portname
|
||||
self.port = port
|
||||
#print("AddQueue", port)
|
||||
self._wallclock = time.time()
|
||||
|
||||
def __call__(self, event, data=None):
|
||||
message, deltatime = event
|
||||
self._wallclock += deltatime
|
||||
#print("inqueue : [%s] @%0.6f %r" % ( self.portname, self._wallclock, message))
|
||||
midinputsqueue[self.port].put(message)
|
||||
|
||||
|
||||
#
|
||||
# MIDI OUT Handling
|
||||
#
|
||||
|
||||
|
||||
class OutObject():
|
||||
|
||||
_instances = set()
|
||||
counter = 0
|
||||
|
||||
def __init__(self, name, kind, port):
|
||||
|
||||
self.name = name
|
||||
self.kind = kind
|
||||
self.port = port
|
||||
|
||||
self._instances.add(weakref.ref(self))
|
||||
OutObject.counter += 1
|
||||
|
||||
print(self.name, "kind", self.kind, "port", self.port)
|
||||
|
||||
@classmethod
|
||||
def getinstances(cls):
|
||||
dead = set()
|
||||
for ref in cls._instances:
|
||||
obj = ref()
|
||||
if obj is not None:
|
||||
yield obj
|
||||
else:
|
||||
dead.add(ref)
|
||||
cls._instances -= dead
|
||||
|
||||
def __del__(self):
|
||||
OutObject.counter -= 1
|
||||
|
||||
|
||||
|
||||
def OutConfig():
|
||||
global midiout, MidInsNumber
|
||||
|
||||
#
|
||||
if len(OutDevice) == 0:
|
||||
print("")
|
||||
print("MIDIout...")
|
||||
print("List and attach to available devices on host with IN port :")
|
||||
|
||||
# Display list of available midi IN devices on the host, create and start an OUT instance to talk to each of these Midi IN devices
|
||||
midiout = rtmidi.MidiOut()
|
||||
available_ports = midiout.get_ports()
|
||||
|
||||
for port, name in enumerate(available_ports):
|
||||
|
||||
midiname[port]=name
|
||||
midiport[port].open_port(port)
|
||||
#print("Will send to [%i] %s" % (port, name))
|
||||
#MidIns[port][1].open_port(port)
|
||||
|
||||
# Search for a Bhoreal
|
||||
if name.find(BhorealMidiName) == 0:
|
||||
|
||||
OutDevice.append(OutObject(name, "bhoreal", port))
|
||||
print("Bhoreal start animation")
|
||||
bhoreal.Here = port
|
||||
bhoreal.StartBhoreal(port)
|
||||
time.sleep(0.2)
|
||||
|
||||
# Search for a LaunchPad
|
||||
elif name.find(LaunchMidiName) == 0:
|
||||
|
||||
OutDevice.append(OutObject(name, "launchpad", port))
|
||||
print("Launchpad mini start animation")
|
||||
launchpad.Here = port
|
||||
launchpad.StartLaunchPad(port)
|
||||
time.sleep(0.2)
|
||||
|
||||
# Search for a LPD8
|
||||
elif name.find('LPD8') == 0:
|
||||
|
||||
OutDevice.append(OutObject(name, "LPD8", port))
|
||||
#print("LPD8 mini start animation")
|
||||
LPD8.Here = port
|
||||
#LPD8.StartLPD8(port)
|
||||
time.sleep(0.2)
|
||||
|
||||
# Search for a Guitar Wing
|
||||
elif name.find("Livid") == 0:
|
||||
OutDevice.append(OutObject(name, "livid", port))
|
||||
print("Livid Guitar Wing start animation")
|
||||
gstt.WingHere = port
|
||||
print(gstt.WingHere)
|
||||
|
||||
#guitarwing.StartWing(port)
|
||||
time.sleep(0.2)
|
||||
else:
|
||||
|
||||
OutDevice.append(OutObject(name, "generic", port))
|
||||
|
||||
#print("")
|
||||
print(len(OutDevice), "Out devices")
|
||||
#ListOutDevice()
|
||||
MidInsNumber = len(OutDevice)+1
|
||||
|
||||
def ListOutDevice():
|
||||
|
||||
for item in OutObject.getinstances():
|
||||
|
||||
print(item.name)
|
||||
|
||||
def FindOutDevice(name):
|
||||
|
||||
port = -1
|
||||
for item in OutObject.getinstances():
|
||||
#print("searching", name, "in", item.name)
|
||||
if name == item.name:
|
||||
#print('found port',item.port)
|
||||
port = item.port
|
||||
return port
|
||||
|
||||
|
||||
def DelOutDevice(name):
|
||||
|
||||
Outnumber = Findest(name)
|
||||
print('deleting OutDevice', name)
|
||||
|
||||
if Outnumber != -1:
|
||||
print('found OutDevice', Outnumber)
|
||||
delattr(OutObject, str(name))
|
||||
print("OutDevice", Outnumber,"was removed")
|
||||
else:
|
||||
print("OutDevice was not found")
|
||||
|
||||
|
||||
|
||||
#
|
||||
# MIDI IN Handling
|
||||
# Create processing thread and queue for each device
|
||||
#
|
||||
|
||||
class InObject():
|
||||
|
||||
_instances = set()
|
||||
counter = 0
|
||||
|
||||
def __init__(self, name, kind, port, rtmidi):
|
||||
|
||||
self.name = name
|
||||
self.kind = kind
|
||||
self.port = port
|
||||
self.rtmidi = rtmidi
|
||||
self.queue = Queue()
|
||||
|
||||
self._instances.add(weakref.ref(self))
|
||||
InObject.counter += 1
|
||||
|
||||
#print("Adding InDevice name", self.name, "kind", self.kind, "port", self.port,"rtmidi", self.rtmidi, "Queue", self.queue)
|
||||
|
||||
@classmethod
|
||||
def getinstances(cls):
|
||||
dead = set()
|
||||
for ref in cls._instances:
|
||||
obj = ref()
|
||||
if obj is not None:
|
||||
yield obj
|
||||
else:
|
||||
dead.add(ref)
|
||||
cls._instances -= dead
|
||||
|
||||
def __del__(self):
|
||||
InObject.counter -= 1
|
||||
|
||||
|
||||
def InConfig():
|
||||
|
||||
print("")
|
||||
print("MIDIin...")
|
||||
print("List and attach to available devices on host with OUT port :")
|
||||
|
||||
if platform == 'darwin':
|
||||
mido.set_backend('mido.backends.rtmidi/MACOSX_CORE')
|
||||
|
||||
genericnumber = 0
|
||||
|
||||
for port, name in enumerate(mido.get_input_names()):
|
||||
|
||||
#print()
|
||||
# Maxwell midi IN & OUT port names are different
|
||||
|
||||
if name.find("from ") == 0:
|
||||
#print ("name",name)
|
||||
name = "to "+name[5:]
|
||||
#print ("corrected to",name)
|
||||
|
||||
outport = FindOutDevice(name)
|
||||
midinputsname[port]=name
|
||||
|
||||
#print("name",name, "Port",port, "Outport", outport)
|
||||
|
||||
'''
|
||||
# New Bhoreal found ?
|
||||
if name.find(BhorealMidiName) == 0:
|
||||
|
||||
try:
|
||||
bhorealin, port_name = open_midiinput(outport) # weird rtmidi call port number is not the same in mido enumeration and here
|
||||
|
||||
BhoreralDevice = InObject(port_name, "bhoreal", outport, bhorealin)
|
||||
print("BhorealDevice.queue",BhoreralDevice.queue )
|
||||
# thread launch to handle all queued MIDI messages from Bhoreal device
|
||||
thread = Thread(target=bhoreal.MidinProcess, args=(bhoreal.bhorqueue,))
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
print("Attaching MIDI in callback handler to Bhoreal : ", name, "port", port, "portname", port_name)
|
||||
BhoreralDevice.rtmidi.set_callback(bhoreal.AddQueue(port_name))
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
|
||||
'''
|
||||
# Old Bhoreal found ?
|
||||
if name.find(BhorealMidiName) == 0:
|
||||
|
||||
try:
|
||||
bhorealin, port_name = open_midiinput(outport) # weird rtmidi call port number is not the same in mido enumeration and here
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
sys.exit
|
||||
|
||||
#midinputs.append(bhorealin)
|
||||
InDevice.append(InObject(name, "bhoreal", outport, bhorealin))
|
||||
# thread launch to handle all queued MIDI messages from Bhoreal device
|
||||
|
||||
thread = Thread(target=bhoreal.MidinProcess, args=(bhoreal.bhorqueue,))
|
||||
#thread = Thread(target=bhoreal.MidinProcess, args=(InDevice[port].queue,))
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
#print("midinputs[port]", midinputs[port])
|
||||
print(name)
|
||||
InDevice[port].rtmidi.set_callback(bhoreal.AddQueue(name))
|
||||
#midinputs[port].set_callback(bhoreal.AddQueue(name))
|
||||
|
||||
'''
|
||||
|
||||
# New LaunchPad Mini Found ?
|
||||
if name.find(LaunchMidiName) == 0:
|
||||
|
||||
|
||||
try:
|
||||
launchin, port_name = open_midiinput(outport)
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
sys.exit()
|
||||
|
||||
LaunchDevice = InObject(port_name, "launchpad", outport, launchin)
|
||||
thread = Thread(target=launchpad.MidinProcess, args=(launchpad.launchqueue,))
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
print("Attaching MIDI in callback handler to Launchpad : ", name, "port", port, "portname", port_name)
|
||||
LaunchDevice.rtmidi.set_callback(launchpad.LaunchAddQueue(name))
|
||||
|
||||
'''
|
||||
|
||||
# Old LaunchPad Mini Found ?
|
||||
if name.find(LaunchMidiName) == 0:
|
||||
|
||||
|
||||
try:
|
||||
launchin, port_name = open_midiinput(outport)
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
sys.exit()
|
||||
#midinputs.append(launchin)
|
||||
InDevice.append(InObject(name, "launchpad", outport, launchin))
|
||||
|
||||
thread = Thread(target=launchpad.MidinProcess, args=(launchpad.launchqueue,))
|
||||
#thread = Thread(target=launchpad.MidinProcess, args=(InDevice[port].queue,))
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
print(name, "port", port, "portname", port_name)
|
||||
InDevice[port].rtmidi.set_callback(launchpad.LaunchAddQueue(name))
|
||||
#launchin.set_callback(launchpad.LaunchAddQueue(name))
|
||||
|
||||
|
||||
# LPD8 Found ?
|
||||
if name.find('LPD8') == 0:
|
||||
|
||||
print()
|
||||
print('LPD8 Found..')
|
||||
|
||||
try:
|
||||
LPD8in, port_name = open_midiinput(outport)
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
sys.exit()
|
||||
#midinputs.append(LPD8in)
|
||||
InDevice.append(InObject(name, "LPD8", outport, LPD8in))
|
||||
print ("Launching LPD8 thread..")
|
||||
thread = Thread(target=LPD8.MidinProcess, args=(LPD8.LPD8queue,))
|
||||
#thread = Thread(target=LPD8.MidinProcess, args=(InDevice[port].queue,))
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
print(name, "port", port, "portname", port_name)
|
||||
InDevice[port].rtmidi.set_callback(LPD8.LPD8AddQueue(name))
|
||||
|
||||
|
||||
# Everything that is not Bhoreal or Launchpad
|
||||
if name.find(BhorealMidiName) != 0 and name.find(LaunchMidiName) != 0 and name.find('LPD8') != 0:
|
||||
|
||||
try:
|
||||
#print (name, name.find("RtMidi output"))
|
||||
if name.find("RtMidi output") > -1:
|
||||
print("No thread started for device", name)
|
||||
else:
|
||||
portin = object
|
||||
port_name = ""
|
||||
portin, port_name = open_midiinput(outport)
|
||||
#midinputs.append(portin)
|
||||
InDevice.append(InObject(name, "generic", outport, portin))
|
||||
|
||||
thread = Thread(target=MidinProcess, args=(midinputsqueue[port],port_name))
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
|
||||
print(name, "port", port, "portname", port_name)
|
||||
#midinputs[port].set_callback(AddQueue(name),midinputsqueue[port])
|
||||
#midinputs[port].set_callback(AddQueue(name))
|
||||
#genericnumber += 1
|
||||
InDevice[port].rtmidi.set_callback(AddQueue(name,port))
|
||||
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
|
||||
#print("")
|
||||
print(InObject.counter, "In devices")
|
||||
#ListInDevice()
|
||||
|
||||
|
||||
def ListInDevice():
|
||||
|
||||
for item in InObject.getinstances():
|
||||
|
||||
print(item.name)
|
||||
|
||||
def FindInDevice(name):
|
||||
|
||||
port = -1
|
||||
for item in InObject.getinstances():
|
||||
#print("searching", name, "in", item.name)
|
||||
if name in item.name:
|
||||
#print('found port',item.port)
|
||||
port = item.port
|
||||
return port
|
||||
|
||||
|
||||
def DelInDevice(name):
|
||||
|
||||
Innumber = Findest(name)
|
||||
print('deleting InDevice', name)
|
||||
|
||||
if Innumber != -1:
|
||||
print('found InDevice', Innumber)
|
||||
delattr(InObject, str(name))
|
||||
print("InDevice", Innumber,"was removed")
|
||||
else:
|
||||
print("InDevice was not found")
|
||||
|
||||
|
||||
# all other devices
|
||||
|
||||
'''
|
||||
|
||||
|
||||
port = mido.open_ioport(name,callback=AddQueue(name))
|
||||
|
||||
This doesn't work on OS X on French system "Réseau Session" has a bug with accent.
|
||||
Todo : stop using different midi framework.
|
||||
|
||||
if name.find(BhorealMidiName) != 0 and name.find(LaunchMidiName) != 0:
|
||||
thread = Thread(target=midinProcess, args=(midinputsqueue[port],))
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
try:
|
||||
port = mido.open_ioport(name,callback=AddQueue(name))
|
||||
#port_port, port_name = open_midiinput(port)
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
sys.exit()
|
||||
|
||||
#midinputs.append(port_port)
|
||||
print "Attaching MIDI in callback handler to : ", name
|
||||
#midinputs[port].set_callback(AddQueue(name))
|
||||
#MIDInport = mido.open_ioport("Laser",virtual=True,callback=MIDIn)
|
||||
|
||||
'''
|
||||
|
||||
def End():
|
||||
global midiout
|
||||
|
||||
#midiin.close_port()
|
||||
midiout.close_port()
|
||||
|
||||
#del virtual
|
||||
if launchpad.Here != -1:
|
||||
del launchpad.Here
|
||||
if bhoreal.Here != -1:
|
||||
del bhoreal.Here
|
||||
if LPD8.Here != -1:
|
||||
del LPD8.Here
|
||||
|
||||
|
||||
def listdevice(number):
|
||||
|
||||
return midiname[number]
|
||||
|
||||
def check():
|
||||
|
||||
OutConfig()
|
||||
InConfig()
|
||||
|
||||
#return listdevice(255)
|
||||
|
||||
|
||||
251
libs3/plugins.py
Normal file
251
libs3/plugins.py
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: Python -*-
|
||||
'''
|
||||
|
||||
LJ Laser Server v0.8.1
|
||||
|
||||
Plugins Handler.
|
||||
|
||||
'''
|
||||
|
||||
from OSC3 import OSCServer, OSCClient, OSCMessage
|
||||
from websocket_server import WebsocketServer
|
||||
from libs3 import gstt
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def Init(wserver):
|
||||
global WSserver
|
||||
|
||||
WSserver = wserver
|
||||
|
||||
|
||||
def sendWSall(message):
|
||||
#if gstt.debug >0:
|
||||
#print("WS sending %s" % (message))
|
||||
WSserver.send_message_to_all(message)
|
||||
|
||||
# What is plugin's OSC port ?
|
||||
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):
|
||||
|
||||
data = gstt.plugins.get(name)
|
||||
return data.get("command")
|
||||
|
||||
# Get all plugin current state
|
||||
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):
|
||||
|
||||
# get Plugin configuration.
|
||||
command = Command(name)
|
||||
|
||||
sendWSall("/status Starting "+name+"...")
|
||||
# Get LJ path
|
||||
#ljpath = r'%s' % os.getcwd().replace('\\','/')
|
||||
|
||||
|
||||
print("")
|
||||
print("LJ is starting plugin :", name)
|
||||
|
||||
|
||||
# Construct the command with absolute path.
|
||||
|
||||
PluginPath = command.split(" ")
|
||||
# Launch as a subprocess
|
||||
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)
|
||||
|
||||
'''
|
||||
# Maybe it's not fully started
|
||||
data = Data(name)
|
||||
|
||||
if command != "" and "pid" not in data :
|
||||
|
||||
sendWSall("/status Starting "+name+"...")
|
||||
# Get LJ path
|
||||
ljpath = r'%s' % os.getcwd().replace('\\','/')
|
||||
|
||||
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]])
|
||||
|
||||
if gstt.debug >0:
|
||||
print "LJ path :", ljpath
|
||||
print "New process pid for ", name, ":", PluginProcess.pid
|
||||
|
||||
data = Data(name)
|
||||
|
||||
data["pid"] = PluginProcess.pid
|
||||
data["process"] = PluginProcess
|
||||
|
||||
# Process can be terminated with :
|
||||
# PluginProcess.terminate()
|
||||
'''
|
||||
|
||||
def OSCsend(name, oscaddress, oscargs =''):
|
||||
|
||||
#print "OSCsend in plugins got for", name, ": oscaddress", oscaddress, "oscargs :", oscargs
|
||||
PluginPort = Port(name)
|
||||
#sendWSall("/status Checking "+ name + "...")
|
||||
|
||||
osclientplugin = OSCClient()
|
||||
osclientplugin.connect((gstt.LjayServerIP, PluginPort))
|
||||
oscmsg = OSCMessage()
|
||||
oscmsg.setAddress(oscaddress)
|
||||
oscmsg.append(oscargs)
|
||||
|
||||
try:
|
||||
if gstt.debug > 0:
|
||||
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)
|
||||
return True
|
||||
|
||||
except:
|
||||
if gstt.debug > 0:
|
||||
print('OSCSend : Connection to plugin IP', gstt.LjayServerIP ,':', PluginPort,'refused : died ?')
|
||||
#sendWSall("/status No plugin.")
|
||||
#sendWSall("/status " + name + " is offline")
|
||||
#sendWSall("/" + name + "/start 0")
|
||||
#PluginStart(name)
|
||||
return False
|
||||
|
||||
|
||||
|
||||
# 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)
|
||||
|
||||
for plugin in list(gstt.plugins.keys()):
|
||||
if gstt.debug > 0:
|
||||
print("sending ",oscpath,"to", plugin)
|
||||
#sendWSall("/"+ plugin + "/start 0")
|
||||
Send(plugin, "/"+plugin+oscpath)
|
||||
|
||||
|
||||
# Send a command to given plugin. Will also start it if command contain /start 1
|
||||
def Send(name, oscpath):
|
||||
|
||||
|
||||
if oscpath[0].find(name) != -1:
|
||||
|
||||
# Plugin is online ?
|
||||
if Ping(name):
|
||||
|
||||
# Light up the plugin button
|
||||
#sendWSall("/" + name + "/start 1")
|
||||
#sendWSall("/status " + name + " online")
|
||||
if gstt.debug > 0:
|
||||
print('')
|
||||
print("Plugins manager got", oscpath, "for plugin", name, "currently online.")
|
||||
|
||||
|
||||
# If start 0, try to kill plugin
|
||||
if oscpath[0].find("start") != -1 and oscpath[1] == "0":
|
||||
|
||||
if gstt.debug >0:
|
||||
print("start 0, so killing", name, "...")
|
||||
Kill(name)
|
||||
|
||||
# Send osc command
|
||||
elif len(oscpath) == 1:
|
||||
OSCsend(name, oscpath[0], oscargs='noargs')
|
||||
elif len(oscpath) == 2:
|
||||
OSCsend(name, oscpath[0], oscargs=oscpath[1])
|
||||
elif len(oscpath) == 3:
|
||||
OSCsend(name, oscpath[0], oscargs=(oscpath[1], oscpath[2]))
|
||||
|
||||
elif name == "trckr":
|
||||
#print("To trckr", name, oscpath, len(oscpath))
|
||||
OSCsend(name, oscpath[0], oscpath[1:])
|
||||
elif name == "aurora":
|
||||
#print("To Aurora", oscpath, len(oscpath))
|
||||
OSCsend(name, oscpath[0], oscpath[1:])
|
||||
return True
|
||||
|
||||
# Plugin not online..
|
||||
else:
|
||||
|
||||
if gstt.debug >0:
|
||||
print("Plugin manager send says plugin " + name + " is offline.")
|
||||
#print "Command", oscpath
|
||||
|
||||
sendWSall("/redstatus Plugin " + name + " offline")
|
||||
sendWSall("/"+ name + "/start 0")
|
||||
|
||||
# Try to Start it if /start 1
|
||||
if oscpath[0].find("start") != -1 and oscpath[1] == "1":
|
||||
if gstt.debug >0:
|
||||
print("Plugin Manager Trying to start", name, "...")
|
||||
Start(name)
|
||||
|
||||
return False
|
||||
82
libs3/pysimpledmx.py
Normal file
82
libs3/pysimpledmx.py
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import serial, sys
|
||||
|
||||
START_VAL = 0x7E
|
||||
END_VAL = 0xE7
|
||||
|
||||
COM_BAUD = 57600
|
||||
COM_TIMEOUT = 1
|
||||
COM_PORT = 7
|
||||
DMX_SIZE = 512
|
||||
|
||||
LABELS = {
|
||||
'GET_WIDGET_PARAMETERS' :3, #unused
|
||||
'SET_WIDGET_PARAMETERS' :4, #unused
|
||||
'RX_DMX_PACKET' :5, #unused
|
||||
'TX_DMX_PACKET' :6,
|
||||
'TX_RDM_PACKET_REQUEST' :7, #unused
|
||||
'RX_DMX_ON_CHANGE' :8, #unused
|
||||
}
|
||||
|
||||
|
||||
class DMXConnection(object):
|
||||
def __init__(self, comport = None):
|
||||
'''
|
||||
On Windows, the only argument is the port number. On *nix, it's the path to the serial device.
|
||||
For example:
|
||||
DMXConnection(4) # Windows
|
||||
DMXConnection('/dev/tty2') # Linux
|
||||
DMXConnection("/dev/ttyUSB0") # Linux
|
||||
'''
|
||||
self.dmx_frame = [0] * DMX_SIZE
|
||||
try:
|
||||
self.com = serial.Serial(comport, baudrate = COM_BAUD, timeout = COM_TIMEOUT)
|
||||
except:
|
||||
com_name = 'COM%s' % (comport + 1) if type(comport) == int else comport
|
||||
print("Could not open device %s. Quitting application." % com_name)
|
||||
sys.exit(0)
|
||||
|
||||
print("Opened %s." % (self.com.portstr))
|
||||
|
||||
|
||||
def setChannel(self, chan, val, autorender = False):
|
||||
'''
|
||||
Takes channel and value arguments to set a channel level in the local
|
||||
DMX frame, to be rendered the next time the render() method is called.
|
||||
'''
|
||||
if not 1 <= chan-1 <= DMX_SIZE:
|
||||
print('Invalid channel specified: %s' % chan-1)
|
||||
return
|
||||
# clamp value
|
||||
val = max(0, min(val, 255))
|
||||
self.dmx_frame[chan-1] = val
|
||||
if autorender: self.render()
|
||||
|
||||
def clear(self, chan = 0):
|
||||
'''
|
||||
Clears all channels to zero. blackout.
|
||||
With optional channel argument, clears only one channel.
|
||||
'''
|
||||
if chan == 0:
|
||||
self.dmx_frame = [0] * DMX_SIZE
|
||||
else:
|
||||
self.dmx_frame[chan-1] = 0
|
||||
|
||||
|
||||
def render(self):
|
||||
''''
|
||||
Updates the DMX output from the USB DMX Pro with the values from self.dmx_frame.
|
||||
'''
|
||||
packet = [
|
||||
START_VAL,
|
||||
LABELS['TX_DMX_PACKET'],
|
||||
len(self.dmx_frame) & 0xFF,
|
||||
(len(self.dmx_frame) >> 8) & 0xFF,
|
||||
]
|
||||
packet += self.dmx_frame
|
||||
packet.append(END_VAL)
|
||||
|
||||
packet = list(map(chr, packet))
|
||||
self.com.write(''.join(packet))
|
||||
|
||||
def close(self):
|
||||
self.com.close()
|
||||
803
libs3/scrolldisp.py
Normal file
803
libs3/scrolldisp.py
Normal file
|
|
@ -0,0 +1,803 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''
|
||||
ScrollDisp
|
||||
v0.7.0
|
||||
|
||||
An example of an unicornhat hack for Launchpad Mini or Bhoreal.
|
||||
|
||||
This is a custom version of scrolldisp.py that display text on unicornhat
|
||||
with use of bhorunicornhat to use with a Bhoreal or a Launchpad mini mk2
|
||||
|
||||
Default device is the launchpad.
|
||||
|
||||
|
||||
Command line to display 2 chars:
|
||||
|
||||
To display 'OK' :
|
||||
python3 scrolldisp.py OK
|
||||
|
||||
To display a rainbow :
|
||||
python3 scrolldisp.py ~R
|
||||
|
||||
See the end of this script for more option like scrolling or use a bhoreal in command line.
|
||||
|
||||
|
||||
As a Library :
|
||||
|
||||
Display(text, color=(255,255,255), delay=0.2, mididest ='launchpad')
|
||||
|
||||
DisplayScroll(text, color=(255,255,255), delay=0.2, mididest = 'launchpad')
|
||||
|
||||
Remember there is Cls functions
|
||||
launchpad.Cls()
|
||||
bhoreal.Cls()
|
||||
|
||||
'''
|
||||
|
||||
#from unicorn_hat_sim import unicornhat as u
|
||||
|
||||
import bhorunicornhat as u
|
||||
import time, math, sys
|
||||
|
||||
class ScrollDisp:
|
||||
columns = []
|
||||
mappings = {'!': [" ",
|
||||
"#",
|
||||
"#",
|
||||
"#",
|
||||
"#",
|
||||
" ",
|
||||
"#",
|
||||
" "],
|
||||
'\'': [" ",
|
||||
"#",
|
||||
"#",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" "],
|
||||
'(': [" ",
|
||||
" #",
|
||||
"# ",
|
||||
"# ",
|
||||
"# ",
|
||||
"# ",
|
||||
" #",
|
||||
" "],
|
||||
')': [" ",
|
||||
"# ",
|
||||
" #",
|
||||
" #",
|
||||
" #",
|
||||
" #",
|
||||
"# ",
|
||||
" "],
|
||||
',': [" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" #",
|
||||
"# "],
|
||||
'-': [" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
"###",
|
||||
" ",
|
||||
" ",
|
||||
" "],
|
||||
'.': [" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
"#",
|
||||
" "],
|
||||
'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': [" ",
|
||||
"####",
|
||||
" #",
|
||||
" # ",
|
||||
" # ",
|
||||
"# ",
|
||||
"####",
|
||||
" "],
|
||||
'[': [" ",
|
||||
"##",
|
||||
"# ",
|
||||
"# ",
|
||||
"# ",
|
||||
"# ",
|
||||
"##",
|
||||
" "],
|
||||
']': [" ",
|
||||
"##",
|
||||
" #",
|
||||
" #",
|
||||
" #",
|
||||
" #",
|
||||
"##",
|
||||
" "],
|
||||
'_': [" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
"####"],
|
||||
'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': [" ",
|
||||
" ",
|
||||
"####",
|
||||
" # ",
|
||||
" # ",
|
||||
"# ",
|
||||
"####",
|
||||
" "]
|
||||
}
|
||||
sharpnotes = {
|
||||
'A': [" #",
|
||||
" ## ",
|
||||
"# #",
|
||||
"# #",
|
||||
"####",
|
||||
"# #",
|
||||
"# #",
|
||||
" "],
|
||||
'C': [" #",
|
||||
" ## ",
|
||||
"# #",
|
||||
"# ",
|
||||
"# ",
|
||||
"# #",
|
||||
" ## ",
|
||||
" "],
|
||||
'D': [" #",
|
||||
"### ",
|
||||
"# #",
|
||||
"# #",
|
||||
"# #",
|
||||
"# #",
|
||||
"### ",
|
||||
" "],
|
||||
'F': [" #",
|
||||
"### ",
|
||||
"# ",
|
||||
"### ",
|
||||
"# ",
|
||||
"# ",
|
||||
"# ",
|
||||
" "],
|
||||
'G': [" #",
|
||||
" ## ",
|
||||
"# #",
|
||||
"# ",
|
||||
"# ##",
|
||||
"# #",
|
||||
" ## ",
|
||||
" "]
|
||||
}
|
||||
def append_mapping(self, char, color):
|
||||
#self.append_space()
|
||||
bitmap = self.mappings[char]
|
||||
n = len(bitmap[0])
|
||||
for x in range(n):
|
||||
self.columns.append([(color if bitmap[i][x] == '#' else (0,0,0)) for i in range(8)])
|
||||
|
||||
def append_rainbow(self):
|
||||
for x in range(8):
|
||||
r = int((math.cos(x * math.pi / 4) + 1) * 127)
|
||||
g = int((math.cos((x - 8.0 / 3.0) * math.pi / 4) + 1) * 127)
|
||||
b = int((math.cos((x + 8.0 / 3.0) * math.pi / 4) + 1) * 127)
|
||||
self.columns.append([(r,g,b) for i in range(8)])
|
||||
|
||||
def append_space(self, n=1):
|
||||
for x in range(n):
|
||||
self.columns.append([(0,0,0) for i in range(8)])
|
||||
|
||||
def append_buffer(self):
|
||||
self.append_space(9)
|
||||
|
||||
def append_letter(self, char, color=None):
|
||||
if char == ' ':
|
||||
self.append_space(2)
|
||||
elif char == 0:
|
||||
self.append_rainbow()
|
||||
elif char in self.mappings.keys():
|
||||
self.append_mapping(char, color)
|
||||
else:
|
||||
self.columns.append([(255,255,255),(255,255,255),(255,255,255),(255,255,255),(255,255,255),(255,255,255),(255,255,255),(255,255,255)])
|
||||
print("unknown char {0} ({1})".format(char, ord(char)))
|
||||
|
||||
|
||||
def append_sharpnote(self, text, color=(255,255,255)):
|
||||
|
||||
# Note
|
||||
# Should be a better test for A-G letter.
|
||||
if text[0] in self.mappings.keys():
|
||||
bitmap = self.sharpnotes[text[0]]
|
||||
|
||||
n = len(bitmap[0])
|
||||
for x in range(n):
|
||||
self.columns.append([(color if bitmap[i][x] == '#' else (0,0,0)) for i in range(8)])
|
||||
|
||||
|
||||
# Octave
|
||||
if text[2] in self.mappings.keys():
|
||||
self.append_letter(text[2], color)
|
||||
|
||||
|
||||
def append_string(self, text, color=(255,255,255)):
|
||||
i = 0
|
||||
while i < len(text):
|
||||
if text[i] == '~':
|
||||
i += 1
|
||||
if text[i] == 'R': #rainbow
|
||||
self.append_letter(0)
|
||||
else:
|
||||
self.append_letter(text[i], color)
|
||||
i += 1
|
||||
|
||||
def set_text(self, text, color=(255,255,255)):
|
||||
self.columns = []
|
||||
#self.append_buffer()
|
||||
|
||||
if len(text) == 3 and text[1] == "#":
|
||||
self.append_sharpnote(text)
|
||||
else:
|
||||
self.append_string(text)
|
||||
|
||||
self.append_buffer()
|
||||
|
||||
def __init__(self, text=""):
|
||||
self.set_text(text)
|
||||
|
||||
def start(self, delay=0.1):
|
||||
|
||||
u.set_pixels(self.columns[0:8])
|
||||
u.show()
|
||||
time.sleep(delay)
|
||||
|
||||
def startScroll(self, delay=0.1):
|
||||
|
||||
for x in range(len(self.columns) - 8):
|
||||
u.set_pixels(self.columns[x:x+8])
|
||||
u.show()
|
||||
time.sleep(delay)
|
||||
|
||||
|
||||
def Display(text, color=(255,255,255), delay=0.2, mididest ='launchpad'):
|
||||
disp = ScrollDisp()
|
||||
#print(text)
|
||||
|
||||
if mididest == 'bhoreal':
|
||||
u.dest(mididest,180)
|
||||
else:
|
||||
u.dest(mididest,270)
|
||||
|
||||
disp.set_text(text, color)
|
||||
disp.start(delay)
|
||||
|
||||
def DisplayScroll(text, color=(255,255,255), delay=0.2, mididest = 'launchpad'):
|
||||
disp = ScrollDisp()
|
||||
if mididest == 'bhoreal':
|
||||
u.dest(mididest,180)
|
||||
else:
|
||||
u.dest(mididest,270)
|
||||
disp.set_text(text, color)
|
||||
disp.startScroll(delay)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
from libs import midi3
|
||||
|
||||
# Implemented for script compatibility but actually do nothing on supported devices
|
||||
u.brightness(0.5)
|
||||
|
||||
# 2 chars with no scrolling
|
||||
Display(' '.join(sys.argv[1:]))
|
||||
|
||||
|
||||
# text with scrolling
|
||||
# DisplayScroll(' '.join(sys.argv[1:]))
|
||||
|
||||
|
||||
|
||||
# To use with a Bhoreal just add mididest = 'bhoreal' in Display()
|
||||
# or DisplayScroll()
|
||||
|
||||
# Display(' '.join(sys.argv[1:]), mididest = 'bhoreal')
|
||||
82
libs3/settings.py
Normal file
82
libs3/settings.py
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: Python -*-
|
||||
'''
|
||||
LJay/LJ
|
||||
v0.7.0
|
||||
|
||||
Settings Handler
|
||||
|
||||
LICENCE : CC
|
||||
'''
|
||||
|
||||
import configparser
|
||||
from libs3 import gstt
|
||||
import ast
|
||||
import numpy as np
|
||||
|
||||
|
||||
def Write():
|
||||
|
||||
config.set('General', 'lasernumber', str(gstt.LaserNumber))
|
||||
config.set('General', 'ljayserverip', str(gstt.LjayServerIP))
|
||||
config.set('General', 'wwwip', str(gstt.wwwIP))
|
||||
config.set('General', 'bhoroscip', str(gstt.oscIPin))
|
||||
config.set('General', 'nozoscip', str(gstt.nozoscIP))
|
||||
config.set('General', 'debug', str(gstt.debug))
|
||||
config.set('General', 'autostart', gstt.autostart)
|
||||
|
||||
for i in range(gstt.LaserNumber):
|
||||
laser = 'laser' + str(i)
|
||||
config.set(laser, 'ip', str(gstt.lasersIPS[i]))
|
||||
config.set(laser, 'type', str(gstt.lasertype[i]))
|
||||
config.set(laser, 'kpps', str(gstt.kpps[i]))
|
||||
config.set(laser, 'centerx', str(gstt.centerX[i]))
|
||||
config.set(laser, 'centery', str(gstt.centerY[i]))
|
||||
config.set(laser, 'zoomx', str(gstt.zoomX[i]))
|
||||
config.set(laser, 'zoomy', str(gstt.zoomY[i]))
|
||||
config.set(laser, 'sizex', str(gstt.sizeX[i]))
|
||||
config.set(laser, 'sizey', str(gstt.sizeY[i]))
|
||||
config.set(laser, 'finangle', str(gstt.finANGLE[i]))
|
||||
config.set(laser, 'swapx', str(gstt.swapX[i]))
|
||||
config.set(laser, 'swapy', str(gstt.swapY[i]))
|
||||
config.set(laser, 'warpdest', np.array2string(gstt.warpdest[i], precision=2, separator=',',suppress_small=True))
|
||||
config.write(open(gstt.ConfigName,'w'))
|
||||
|
||||
|
||||
|
||||
def Read():
|
||||
|
||||
gstt.LaserNumber = config.getint('General', 'lasernumber')
|
||||
gstt.LjayServerIP= config.get('General', 'ljayserverip')
|
||||
gstt.wwwIP= config.get('General', 'wwwip')
|
||||
gstt.oscIPin = config.get('General', 'bhoroscip')
|
||||
gstt.nozoscip = config.get('General', 'nozoscip')
|
||||
gstt.debug = config.get('General', 'debug')
|
||||
gstt.plugins = ast.literal_eval(config.get('plugins', 'plugins'))
|
||||
gstt.autostart = config.get('General', 'autostart')
|
||||
|
||||
|
||||
for i in range(4):
|
||||
laser = 'laser' + str(i)
|
||||
gstt.lasersIPS[i]= config.get(laser, 'ip')
|
||||
gstt.lasertype[i]= config.get(laser, 'type')
|
||||
gstt.kpps[i] = config.getint(laser, 'kpps')
|
||||
#gstt.lasersPLcolor[i] = config.getint(laser, 'color')
|
||||
gstt.centerX[i]= config.getint(laser, 'centerx')
|
||||
gstt.centerY[i] = config.getint(laser, 'centery')
|
||||
gstt.zoomX[i] = config.getfloat(laser, 'zoomx')
|
||||
gstt.zoomY[i] = config.getfloat(laser, 'zoomy')
|
||||
gstt.sizeX[i] = config.getint(laser, 'sizex')
|
||||
gstt.sizeY[i] = config.getint(laser, 'sizey')
|
||||
gstt.finANGLE[i] = config.getfloat(laser, 'finangle')
|
||||
gstt.swapX[i] = config.getint(laser, 'swapx')
|
||||
gstt.swapY[i] = config.getint(laser, 'swapy')
|
||||
gstt.lsteps[i] = ast.literal_eval(config.get(laser, 'lsteps'))
|
||||
gstt.warpdest[i]= np.array(ast.literal_eval(config.get(laser, 'warpdest')))
|
||||
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read(gstt.ConfigName)
|
||||
|
||||
|
||||
583
libs3/tracer3.py
Normal file
583
libs3/tracer3.py
Normal file
|
|
@ -0,0 +1,583 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: Python -*-
|
||||
|
||||
'''
|
||||
|
||||
Tracer v0.8.2
|
||||
|
||||
Etherdream DACs handler on network via Redis
|
||||
|
||||
LICENCE : CC
|
||||
Sam Neurohack, pclf
|
||||
|
||||
Includes live conversion in etherdream coordinates, geometric corrections, color balance change, intensity limitation, grid display,...
|
||||
|
||||
One tracer process is launched per requested laser by LJ. Lasers parameters in LJ.conf.
|
||||
Live I/O based on redis keys : inputs (Pointlists to draw,...) and outputs (DAC state, errors,..).
|
||||
Keys are mostly read and set at each main loop.
|
||||
This tracer include an enhanced version (support for several lasers) of the etherdream python library from j4cDAC.
|
||||
|
||||
|
||||
* Redis keys reference *
|
||||
|
||||
- Drawing things :
|
||||
|
||||
/pl/Scene/lasernumber [(x,y,color),(x1,y1,color),...] The live list of drawn pygame points. Tracer continously ask redis for key /clientkey+lasernumber
|
||||
/resampler/lasernumber [(1.0,8), (0.25,3),(0.75,3),(1.0,10)] : a string for resampling rules.
|
||||
the first tuple (1.0,8) is for short line < 4000 in etherdream space
|
||||
(0.25,3),(0.75,3),(1.0,10) for long line > 4000
|
||||
i.e (0.25,3) means go at 25% position on the line, send 3 times this position to etherdream
|
||||
/clientkey "/pl/SceneNumber/" What Scene to retrieve from redis
|
||||
/EDH/lasernumber
|
||||
|
||||
- Tracer control :
|
||||
|
||||
/order 0-8 Set redis key with new value then issue the order number
|
||||
|
||||
0 : Draw Normal point list
|
||||
1 : Get the new EDH = reread redis key /EDH/lasernumber
|
||||
2 : Draw BLACK point list
|
||||
3 : Draw GRID point list
|
||||
4 : Resampler Change (longs and shorts lsteps)
|
||||
5 : Client Key Change = reread redis key /clientkey
|
||||
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
|
||||
|
||||
|
||||
- Managing Etherdream DACs :
|
||||
|
||||
Discrete drawing values
|
||||
|
||||
/kpps 0- DAC output speed to laser, then order 7. Depends of actual angle
|
||||
/intensity 0-255 Laser output power, then order 6 (for alignement,...)
|
||||
/red 0-100 % of full red, then order 8
|
||||
/green 0-100 % of full green, then order 8
|
||||
/blue 0-100 % of full blue, then order 8
|
||||
|
||||
DAC status report
|
||||
|
||||
/lstt/lasernumber etherdream last_status.playback_state (0: idle 1: prepare 2: playing)
|
||||
/cap/lasernumber number of empty points sent to fill etherdream buffer (up to 1799)
|
||||
/lack/lasernumber "a": ACK "F": Full "I": invalid. 64 or 35 for no connection.
|
||||
|
||||
|
||||
Geometric corrections
|
||||
|
||||
Doctodo
|
||||
|
||||
|
||||
'''
|
||||
import socket
|
||||
import time
|
||||
import struct
|
||||
#from gstt import debug
|
||||
from libs3 import gstt,log
|
||||
import math
|
||||
from itertools import cycle
|
||||
#from globalVars import *
|
||||
import pdb
|
||||
import ast
|
||||
import redis
|
||||
|
||||
from libs3 import homographyp
|
||||
import numpy as np
|
||||
import binascii
|
||||
|
||||
black_points = [(278.0,225.0,0),(562.0,279.0,0),(401.0,375.0,0),(296.0,454.0,0),(298.0,165.0,0)]
|
||||
grid_points = [(300.0,200.0,0),(500.0,200.0,65280),(500.0,400.0,65280),(300.0,400.0,65280),(300.0,200.0,65280),(300.0,200.0,0),(200.0,100.0,0),(600.0,100.0,65280),(600.0,500.0,65280),(200.0,500.0,65280),(200.0,100.0,65280)]
|
||||
|
||||
r = redis.StrictRedis(host=gstt.LjayServerIP, port=6379, db=0)
|
||||
# r = redis.StrictRedis(host=gstt.LjayServerIP , port=6379, db=0, password='-+F816Y+-')
|
||||
ackstate = {'61': 'ACK', '46': 'FULL', '49': "INVALID", '21': 'STOP', '64': "NO CONNECTION ?", '35': "NO CONNECTION ?" , '97': 'ACK', '70': 'FULL', '73': "INVALID", '33': 'STOP', '100': "NOCONNECTION", '48': "NOCONNECTION", 'a': 'ACK', 'F': 'FULL', 'I': "INVALID", '!': 'STOP', 'd': "NO CONNECTION ?", '0': "NO CONNECTION ?"}
|
||||
lstate = {'0': 'IDLE', '1': 'PREPARE', '2': "PLAYING", '64': "NOCONNECTION ?" }
|
||||
|
||||
def pack_point(laser, intensity, x, y, r, g, b, i = -1, u1 = 0, u2 = 0, flags = 0):
|
||||
"""Pack some color values into a struct dac_point."""
|
||||
|
||||
#print("Tracer", laser,":", r,g,b,"intensity", intensity, "i", i)
|
||||
|
||||
if r > intensity:
|
||||
r = intensity
|
||||
if g > intensity:
|
||||
g = intensity
|
||||
if b > intensity:
|
||||
b = intensity
|
||||
|
||||
|
||||
if max(r, g, b) == 0:
|
||||
i = 0
|
||||
else:
|
||||
i = intensity
|
||||
|
||||
x = int(x)
|
||||
y = int(y)
|
||||
#print("Tracer ", laser, ": packing", x, y, r, g, b, "intensity", intensity, "i", i)
|
||||
|
||||
|
||||
if x < -32767:
|
||||
x = -32767
|
||||
if gstt.debug >1:
|
||||
log.err("Tracer "+ str(laser) +" : x coordinates was below -32767")
|
||||
|
||||
if x > 32767:
|
||||
x = 32767
|
||||
if gstt.debug >1:
|
||||
log.err("Tracer "+ str(laser) +" : x coordinates was bigger than 32767")
|
||||
|
||||
|
||||
if y < -32767:
|
||||
y = -32767
|
||||
if gstt.debug >1:
|
||||
log.err("Tracer "+ str(laser) +" : y coordinates was below -32767")
|
||||
|
||||
if y > 32767:
|
||||
y = 32767
|
||||
if gstt.debug >1:
|
||||
log.err("Tracer "+ str(laser) +" : y coordinates was bigger than 32767")
|
||||
|
||||
return struct.pack("<HhhHHHHHH", flags, x, y, r, g, b, i, u1, u2)
|
||||
#return struct.pack("<HhhHHHHHH", flags, round(x), round(y), r, g, b, i, u1, u2)
|
||||
|
||||
|
||||
class ProtocolError(Exception):
|
||||
"""Exception used when a protocol error is detected."""
|
||||
pass
|
||||
|
||||
|
||||
class Status(object):
|
||||
"""Represents a status response from the DAC."""
|
||||
|
||||
def __init__(self, data):
|
||||
"""Initialize from a chunk of data."""
|
||||
self.protocol_version, self.le_state, self.playback_state, \
|
||||
self.source, self.le_flags, self.playback_flags, \
|
||||
self.source_flags, self.fullness, self.point_rate, \
|
||||
self.point_count = \
|
||||
struct.unpack("<BBBBHHHHII", data)
|
||||
|
||||
def dump(self, prefix = " - "):
|
||||
"""Dump to a string."""
|
||||
lines = [
|
||||
""
|
||||
"Host ",
|
||||
"Light engine: state %d, flags 0x%x" %
|
||||
(self.le_state, self.le_flags),
|
||||
"Playback: state %d, flags 0x%x" %
|
||||
(self.playback_state, self.playback_flags),
|
||||
"Buffer: %d points" %
|
||||
(self.fullness, ),
|
||||
"Playback: %d kpps, %d points played" %
|
||||
(self.point_rate, self.point_count),
|
||||
"Source: %d, flags 0x%x" %
|
||||
(self.source, self.source_flags)
|
||||
]
|
||||
|
||||
if gstt.debug == 2:
|
||||
print()
|
||||
for l in lines:
|
||||
print(prefix + l)
|
||||
|
||||
|
||||
class BroadcastPacket(object):
|
||||
"""Represents a broadcast packet from the DAC."""
|
||||
|
||||
def __init__(self, st):
|
||||
"""Initialize from a chunk of data."""
|
||||
self.mac = st[:6]
|
||||
self.hw_rev, self.sw_rev, self.buffer_capacity, \
|
||||
self.max_point_rate = struct.unpack("<HHHI", st[6:16])
|
||||
self.status = Status(st[16:36])
|
||||
|
||||
def dump(self, prefix = " - "):
|
||||
"""Dump to a string."""
|
||||
lines = [
|
||||
"MAC: " + ":".join(
|
||||
"%02x" % (ord(o), ) for o in self.mac),
|
||||
"HW %d, SW %d" %
|
||||
(self.hw_rev, self.sw_rev),
|
||||
"Capabilities: max %d points, %d kpps" %
|
||||
(self.buffer_capacity, self.max_point_rate)
|
||||
]
|
||||
print()
|
||||
for l in lines:
|
||||
print(prefix + l)
|
||||
if gstt.debug > 1:
|
||||
self.status.dump(prefix)
|
||||
|
||||
|
||||
class DAC(object):
|
||||
"""A connection to a DAC."""
|
||||
|
||||
|
||||
# "Laser point List" Point generator
|
||||
# each points is yielded : Getpoints() call n times OnePoint()
|
||||
|
||||
def OnePoint(self):
|
||||
|
||||
while True:
|
||||
|
||||
#pdb.set_trace()
|
||||
for indexpoint,currentpoint in enumerate(self.pl):
|
||||
#print indexpoint, currentpoint
|
||||
xyc = [currentpoint[0],currentpoint[1],currentpoint[2]]
|
||||
self.xyrgb = self.EtherPoint(xyc)
|
||||
#print(self.xyrgb[2:])
|
||||
rgb = (round(self.xyrgb[2:][0] *self.intred/100), round(self.xyrgb[2:][1] *self.intgreen/100), round(self.xyrgb[2:][2] *self.intblue/100))
|
||||
#print("rgb :", rgb)
|
||||
|
||||
#round(*self.intred/100)
|
||||
#round(*self.intgreen/100)
|
||||
#round(*self.intblue/100)
|
||||
|
||||
delta_x, delta_y = self.xyrgb[0] - self.xyrgb_prev[0], self.xyrgb[1] - self.xyrgb_prev[1]
|
||||
|
||||
#test adaptation selon longueur ligne
|
||||
if math.hypot(delta_x, delta_y) < 4000:
|
||||
|
||||
# For glitch art : decrease lsteps
|
||||
#l_steps = [ (1.0, 8)]
|
||||
l_steps = gstt.stepshortline
|
||||
|
||||
else:
|
||||
# For glitch art : decrease lsteps
|
||||
#l_steps = [ (0.25, 3), (0.75, 3), (1.0, 10)]
|
||||
l_steps = gstt.stepslongline
|
||||
|
||||
for e in l_steps:
|
||||
step = e[0]
|
||||
|
||||
for i in range(0,e[1]):
|
||||
|
||||
self.xyrgb_step = (self.xyrgb_prev[0] + step*delta_x, self.xyrgb_prev[1] + step*delta_y) + rgb # + self.xyrgb_prev[2:]# + rgb
|
||||
#print(self.xyrgb_step)
|
||||
yield self.xyrgb_step
|
||||
|
||||
self.xyrgb_prev = self.xyrgb
|
||||
|
||||
|
||||
def GetPoints(self, n):
|
||||
|
||||
d = [next(self.newstream) for i in range(n)]
|
||||
#print d
|
||||
return d
|
||||
|
||||
|
||||
# Etherpoint all transform in one matrix, with warp !!
|
||||
# xyc : x y color
|
||||
def EtherPoint(self,xyc):
|
||||
|
||||
c = xyc[2]
|
||||
|
||||
#print("")
|
||||
#print("pygame point",[(xyc[0],xyc[1],xyc[2])])
|
||||
#gstt.EDH[self.mylaser]= np.array(ast.literal_eval(r.get('/EDH/'+str(self.mylaser))))
|
||||
position = homographyp.apply(gstt.EDH[self.mylaser],np.array([(xyc[0],xyc[1])]))
|
||||
|
||||
#print("etherdream point",position[0][0], position[0][1], ((c >> 16) & 0xFF) << 8, ((c >> 8) & 0xFF) << 8, (c & 0xFF) << 8)
|
||||
|
||||
return (position[0][0], position[0][1], ((c >> 16) & 0xFF) << 8, ((c >> 8) & 0xFF) << 8, (c & 0xFF) << 8)
|
||||
|
||||
|
||||
def read(self, l):
|
||||
"""Read exactly length bytes from the connection."""
|
||||
while l > len(self.buf):
|
||||
self.buf += self.conn.recv(4096)
|
||||
|
||||
obuf = self.buf
|
||||
self.buf = obuf[l:]
|
||||
return obuf[:l]
|
||||
|
||||
def readresp(self, cmd):
|
||||
"""Read a response from the DAC."""
|
||||
|
||||
|
||||
data = self.read(22)
|
||||
response = data[0]
|
||||
gstt.lstt_dacanswers[self.mylaser] = response
|
||||
cmdR = chr(data[1])
|
||||
status = Status(data[2:])
|
||||
|
||||
r.set('/lack/'+str(self.mylaser), response)
|
||||
|
||||
if cmdR != cmd:
|
||||
raise ProtocolError("expected resp for %r, got %r"
|
||||
% (cmd, cmdR))
|
||||
|
||||
if response != ord('a'):
|
||||
raise ProtocolError("expected ACK, got %r"
|
||||
% (response, ))
|
||||
|
||||
self.last_status = status
|
||||
return status
|
||||
|
||||
def __init__(self, mylaser, PL, port = 7765):
|
||||
"""Connect to the DAC over TCP."""
|
||||
socket.setdefaulttimeout(2)
|
||||
|
||||
self.mylaser = mylaser
|
||||
self.clientkey = r.get("/clientkey").decode('ascii')
|
||||
|
||||
#log.info("Tracer "+str(self.mylaser)+" connecting to "+ gstt.lasersIPS[mylaser])
|
||||
#print("DAC", self.mylaser, "Handler process, connecting to", gstt.lasersIPS[mylaser] )
|
||||
self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.connstatus = self.conn.connect_ex((gstt.lasersIPS[mylaser], port))
|
||||
if self.connstatus == 35 or self.connstatus == 64:
|
||||
log.err("Tracer "+ str(self.mylaser)+" ("+ gstt.lasersIPS[mylaser]+"): "+ackstate[str(self.connstatus)])
|
||||
else:
|
||||
print("Tracer "+ str(self.mylaser)+" ("+ gstt.lasersIPS[mylaser]+"): "+ackstate[str(self.connstatus)])
|
||||
|
||||
# ipconn state is -1 at startup (see gstt) and modified here
|
||||
r.set('/lack/'+str(self.mylaser), self.connstatus)
|
||||
gstt.lstt_ipconn[self.mylaser] = self.connstatus
|
||||
|
||||
self.buf = b''
|
||||
# Upper case PL is the Point List number
|
||||
self.PL = PL
|
||||
|
||||
# Lower case pl is the actual point list coordinates
|
||||
|
||||
|
||||
#pdb.set_trace()
|
||||
self.pl = ast.literal_eval(r.get(self.clientkey + str(self.mylaser)).decode('ascii'))
|
||||
if r.get('/EDH/'+str(self.mylaser)) == None:
|
||||
#print("Laser",self.mylaser,"NO EDH !! Computing one...")
|
||||
homographyp.newEDH(self.mylaser)
|
||||
else:
|
||||
|
||||
gstt.EDH[self.mylaser] = np.array(ast.literal_eval(r.get('/EDH/'+str(self.mylaser)).decode('ascii')))
|
||||
#print("Laser",self.mylaser,"found its EDH in redis")
|
||||
#print gstt.EDH[self.mylaser]
|
||||
|
||||
self.xyrgb = self.xyrgb_prev = (0,0,0,0,0)
|
||||
self.intensity = 65280
|
||||
self.intred = 100
|
||||
self.intgreen = 100
|
||||
self.intblue = 100
|
||||
self.newstream = self.OnePoint()
|
||||
|
||||
if gstt.debug >0:
|
||||
print("Tracer",self.mylaser,"init asked for ckey", self.clientkey+str(self.mylaser))
|
||||
if self.connstatus != 0:
|
||||
#print(""
|
||||
log.err("Connection ERROR " +str(self.connstatus)+" with laser "+str(mylaser)+" : "+str(gstt.lasersIPS[mylaser]))
|
||||
#print("first 10 points in PL",self.PL, self.GetPoints(10)
|
||||
else:
|
||||
print("Connection status for DAC "+str(self.mylaser)+" : "+ str(self.connstatus))
|
||||
|
||||
|
||||
# Reference points
|
||||
# Read the "hello" message
|
||||
first_status = self.readresp("?")
|
||||
first_status.dump()
|
||||
position = []
|
||||
|
||||
|
||||
def begin(self, lwm, rate):
|
||||
cmd = struct.pack("<cHI", b'b', lwm, rate)
|
||||
print("Tracer", str(self.mylaser), "begin with PL : ", str(self.PL))
|
||||
self.conn.sendall(cmd)
|
||||
return self.readresp("b")
|
||||
|
||||
def update(self, lwm, rate):
|
||||
print(("update", lwm, rate))
|
||||
cmd = struct.pack("<cHI", b'u', lwm, rate)
|
||||
self.conn.sendall(cmd)
|
||||
return self.readresp("u")
|
||||
|
||||
def encode_point(self, point):
|
||||
return pack_point(self.mylaser, self.intensity, *point)
|
||||
|
||||
def write(self, points):
|
||||
epoints = list(map(self.encode_point, points))
|
||||
cmd = struct.pack("<cH", b'd', len(epoints))
|
||||
self.conn.sendall(cmd + b''.join(epoints))
|
||||
return self.readresp('d')
|
||||
|
||||
def prepare(self):
|
||||
self.conn.sendall(b'p')
|
||||
return self.readresp('p')
|
||||
|
||||
|
||||
def stop(self):
|
||||
self.conn.sendall('s')
|
||||
return self.readresp('s')
|
||||
|
||||
def estop(self):
|
||||
self.conn.sendall("\xFF")
|
||||
return self.readresp("\xFF")
|
||||
|
||||
def clear_estop(self):
|
||||
self.conn.sendall("c")
|
||||
return self.readresp("c")
|
||||
|
||||
def ping(self):
|
||||
self.conn.sendall('?')
|
||||
return self.readresp('?')
|
||||
|
||||
|
||||
|
||||
def play_stream(self):
|
||||
|
||||
#print("laser", self.mylaser, "Pb : ",self.last_status.playback_state)
|
||||
|
||||
# error if etherdream is already playing state (from other source)
|
||||
if self.last_status.playback_state == 2:
|
||||
raise Exception("already playing?!")
|
||||
|
||||
# if idle go to prepare state
|
||||
elif self.last_status.playback_state == 0:
|
||||
self.prepare()
|
||||
|
||||
started = 0
|
||||
|
||||
while True:
|
||||
|
||||
#print("laser", self.mylaser, "Pb : ",self.last_status.playback_state)
|
||||
|
||||
order = int(r.get('/order/'+str(self.mylaser)).decode('ascii'))
|
||||
#print("tracer", str(self.mylaser),"order", order, type(order)
|
||||
|
||||
if order == 0:
|
||||
|
||||
# USER point list
|
||||
self.pl = ast.literal_eval(r.get(self.clientkey+str(self.mylaser)).decode('ascii'))
|
||||
#print("Tracer : laser", self.mylaser, " order 0 : pl : ",len(self.pl))
|
||||
|
||||
else:
|
||||
|
||||
# Get the new EDH
|
||||
if order == 1:
|
||||
print("Tracer",self.mylaser,"new EDH ORDER in redis")
|
||||
gstt.EDH[self.mylaser]= np.array(ast.literal_eval(r.get('/EDH/'+str(self.mylaser)).decode('ascii')))
|
||||
# Back to user point list
|
||||
r.set('/order/'+str(self.mylaser), 0)
|
||||
|
||||
# BLACK point list
|
||||
if order == 2:
|
||||
print("Tracer",self.mylaser,"BLACK ORDER in redis")
|
||||
self.pl = black_points
|
||||
|
||||
# GRID point list
|
||||
if order == 3:
|
||||
print("Tracer",self.mylaser,"GRID ORDER in redis")
|
||||
self.pl = grid_points
|
||||
|
||||
|
||||
# Resampler Change
|
||||
if order == 4:
|
||||
self.resampler = ast.literal_eval(r.get('/resampler/'+str(self.mylaser)).decode('ascii'))
|
||||
print("Tracer", self.mylaser," : resetting lsteps for",self.resampler)
|
||||
gstt.stepshortline = self.resampler[0]
|
||||
gstt.stepslongline[0] = self.resampler[1]
|
||||
gstt.stepslongline[1] = self.resampler[2]
|
||||
gstt.stepslongline[2] = self.resampler[3]
|
||||
# Back to user point list order
|
||||
r.set('/order/'+str(self.mylaser), 0)
|
||||
|
||||
# Client Key change
|
||||
if order == 5:
|
||||
print("Tracer", self.mylaser, "new clientkey")
|
||||
self.clientkey = r.get('/clientkey')
|
||||
# Back to user point list order
|
||||
r.set('/order/'+str(self.mylaser), 0)
|
||||
|
||||
# Intensity change
|
||||
if order == 6:
|
||||
self.intensity = int(r.get('/intensity/' + str(self.mylaser)).decode('ascii')) << 8
|
||||
print("Tracer" , self.mylaser, "new Intensity", self.intensity)
|
||||
gstt.intensity[self.mylaser] = self.intensity
|
||||
r.set('/order/'+str(self.mylaser), "0")
|
||||
|
||||
# kpps change
|
||||
if order == 7:
|
||||
gstt.kpps[self.mylaser] = int(r.get('/kpps/' + str(self.mylaser)).decode('ascii'))
|
||||
print("Tracer",self.mylaser,"new kpps", gstt.kpps[self.mylaser])
|
||||
self.update(0, gstt.kpps[self.mylaser])
|
||||
r.set('/order/'+str(self.mylaser), "0")
|
||||
|
||||
# color balance change
|
||||
if order == 8:
|
||||
self.intred = int(r.get('/red/' + str(self.mylaser)).decode('ascii'))
|
||||
self.intgreen = int(r.get('/green/' + str(self.mylaser)).decode('ascii'))
|
||||
self.intblue = int(r.get('/blue/' + str(self.mylaser)).decode('ascii'))
|
||||
print("Tracer", self.mylaser, "new color balance", self.intred,"% ", self.intgreen, "% ",self.intblue,"% ")
|
||||
r.set('/order/'+str(self.mylaser), "0")
|
||||
|
||||
|
||||
r.set('/lstt/'+str(self.mylaser), self.last_status.playback_state)
|
||||
# pdb.set_trace()
|
||||
# How much room?
|
||||
|
||||
cap = 1799 - self.last_status.fullness
|
||||
points = self.GetPoints(cap)
|
||||
|
||||
r.set('/cap/'+str(self.mylaser), cap)
|
||||
|
||||
if cap < 100:
|
||||
time.sleep(0.001)
|
||||
cap += 150
|
||||
|
||||
# print("Writing %d points" % (cap, ))
|
||||
#t0 = time.time()
|
||||
#print points
|
||||
self.write(points)
|
||||
#t1 = time.time()
|
||||
# print("Took %f" % (t1 - t0, )
|
||||
|
||||
if not started:
|
||||
print("Tracer", self.mylaser, "starting with", gstt.kpps[self.mylaser],"kpps")
|
||||
self.begin(0, gstt.kpps[self.mylaser])
|
||||
started = 1
|
||||
|
||||
# not used in LJ.
|
||||
def find_dac():
|
||||
"""Listen for broadcast packets."""
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.bind(("0.0.0.0", 7654))
|
||||
|
||||
while True:
|
||||
data, addr = s.recvfrom(1024)
|
||||
bp = BroadcastPacket(data)
|
||||
|
||||
print(("Packet from %s: " % (addr, )))
|
||||
bp.dump()
|
||||
|
||||
|
||||
'''
|
||||
#Laser order bit 0 = 0
|
||||
if not order & (1 << (self.mylaser*2)):
|
||||
#print("laser",mylaser,"bit 0 : 0")
|
||||
|
||||
# Laser bit 0 = 0 and bit 1 = 0 : USER PL
|
||||
if not order & (1 << (1+self.mylaser*2)):
|
||||
#print("laser",mylaser,"bit 1 : 0")
|
||||
self.pl = ast.literal_eval(r.get('/pl/'+str(self.mylaser)))
|
||||
|
||||
else:
|
||||
# Laser bit 0 = 0 and bit 1 = 1 : New EDH
|
||||
#print("laser",mylaser,"bit 1 : 1" )
|
||||
print("Laser",self.mylaser,"new EDH ORDER in redis"
|
||||
gstt.EDH[self.mylaser]= np.array(ast.literal_eval(r.get('/EDH/'+str(self.mylaser))))
|
||||
# Back to USER PL
|
||||
order = r.get('/order')
|
||||
neworder = order & ~(1<< self.mylaser*2)
|
||||
neworder = neworder & ~(1<< 1+ self.mylaser*2)
|
||||
r.set('/order', str(neworder))
|
||||
else:
|
||||
|
||||
# Laser bit 0 = 1
|
||||
print("laser",mylaser,"bit 0 : 1")
|
||||
|
||||
# Laser bit 0 = 1 and bit 1 = 0 : Black PL
|
||||
if not order & (1 << (1+self.mylaser*2)):
|
||||
#print("laser",mylaser,"bit 1 : 0")
|
||||
self.pl = black_points
|
||||
|
||||
else:
|
||||
# Laser bit 0 = 1 and bit 1 = 1 : GRID PL
|
||||
#print("laser",mylaser,"bit 1 : 1" )
|
||||
self.pl = grid_points
|
||||
'''
|
||||
542
libs3/tracer3.sync-conflict-20200728-024608-NJKFP4Q.py
Normal file
542
libs3/tracer3.sync-conflict-20200728-024608-NJKFP4Q.py
Normal file
|
|
@ -0,0 +1,542 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: Python -*-
|
||||
|
||||
'''
|
||||
|
||||
Tracer
|
||||
for LJ v0.8.2
|
||||
|
||||
Enhanced version (support for several lasers) of the etherdream python library from j4cDAC.
|
||||
One tracer process is launched per requested laser. I/O based on redis keys.
|
||||
|
||||
LICENCE : CC
|
||||
Sam Neurohack, pclf
|
||||
|
||||
Uses redis keys value for live inputs (Pointlists to draw,...) and outputs (DAC state, errors,..).
|
||||
Most of redis keys are read and set at each main loop.
|
||||
Includes live conversion in etherdream coordinates, geometric corrections,...
|
||||
Etherdream IP is found in conf file for given laser number. (LJ.conf)
|
||||
|
||||
Redis keys to draw things :
|
||||
/order select some change to adjust. See below
|
||||
/pl/lasernumber [(x,y,color),(x1,y1,color),...] A string of list of points list.
|
||||
/resampler/lasernumber [(1.0,8), (0.25,3),(0.75,3),(1.0,10)] : a string for resampling rules.
|
||||
the first tuple (1.0,8) is for short line < 4000 in etherdream space
|
||||
(0.25,3),(0.75,3),(1.0,10) for long line > 4000
|
||||
i.e (0.25,3) means go at 25% position on the line, send 3 times this position to etherdream
|
||||
/clientkey
|
||||
|
||||
|
||||
Redis keys for Etherdream DAC
|
||||
|
||||
- Control
|
||||
/kpps see order 7
|
||||
/intensity see order 6
|
||||
/red see order 8
|
||||
/green see order 8
|
||||
/blue see order 8
|
||||
|
||||
- DAC status report
|
||||
/lstt/lasernumber value etherdream last_status.playback_state (0: idle 1: prepare 2: playing)
|
||||
/cap/lasernumber value number of empty points sent to fill etherdream buffer (up to 1799)
|
||||
/lack/lasernumber value "a": ACK "F": Full "I": invalid. 64 or 35 for no connection.
|
||||
|
||||
|
||||
|
||||
Order
|
||||
|
||||
0 : Draw Normal point list
|
||||
1 : Get the new EDH
|
||||
2 : Draw BLACK point list
|
||||
3 : Draw GRID point list
|
||||
4 : Resampler Change (longs and shorts lsteps)
|
||||
5 : Client Key change
|
||||
6 : Intensity change
|
||||
7 : kpps change
|
||||
8 : color balance change
|
||||
|
||||
Geometric corrections :
|
||||
|
||||
Doctodo
|
||||
|
||||
|
||||
'''
|
||||
import socket
|
||||
import time
|
||||
import struct
|
||||
#from gstt import debug
|
||||
from libs3 import gstt,log
|
||||
import math
|
||||
from itertools import cycle
|
||||
#from globalVars import *
|
||||
import pdb
|
||||
import ast
|
||||
import redis
|
||||
|
||||
from libs3 import homographyp
|
||||
import numpy as np
|
||||
import binascii
|
||||
|
||||
black_points = [(278.0,225.0,0),(562.0,279.0,0),(401.0,375.0,0),(296.0,454.0,0),(298.0,165.0,0)]
|
||||
grid_points = [(300.0,200.0,0),(500.0,200.0,65280),(500.0,400.0,65280),(300.0,400.0,65280),(300.0,200.0,65280),(300.0,200.0,0),(200.0,100.0,0),(600.0,100.0,65280),(600.0,500.0,65280),(200.0,500.0,65280),(200.0,100.0,65280)]
|
||||
|
||||
r = redis.StrictRedis(host=gstt.LjayServerIP, port=6379, db=0)
|
||||
# r = redis.StrictRedis(host=gstt.LjayServerIP , port=6379, db=0, password='-+F816Y+-')
|
||||
ackstate = {'61': 'ACK', '46': 'FULL', '49': "INVALID", '21': 'STOP', '64': "NO CONNECTION ?", '35': "NO CONNECTION ?" , '97': 'ACK', '70': 'FULL', '73': "INVALID", '33': 'STOP', '100': "NOCONNECTION", '48': "NOCONNECTION", 'a': 'ACK', 'F': 'FULL', 'I': "INVALID", '!': 'STOP', 'd': "NO CONNECTION ?", '0': "NO CONNECTION ?"}
|
||||
lstate = {'0': 'IDLE', '1': 'PREPARE', '2': "PLAYING", '64': "NOCONNECTION ?" }
|
||||
|
||||
def pack_point(laser,intensity, x, y, r, g, b, i = -1, u1 = 0, u2 = 0, flags = 0):
|
||||
"""Pack some color values into a struct dac_point."""
|
||||
|
||||
#print("Tracer", laser,":", r,g,b,"intensity", intensity, "i", i)
|
||||
|
||||
if r > intensity:
|
||||
r = intensity
|
||||
if g > intensity:
|
||||
g = intensity
|
||||
if b > intensity:
|
||||
b = intensity
|
||||
|
||||
|
||||
if max(r, g, b) == 0:
|
||||
i = 0
|
||||
else:
|
||||
i = intensity
|
||||
|
||||
|
||||
#print("Tracer", laser,":", r,g,b,"intensity", intensity, "i", i)
|
||||
#print(x, type(x), int(x))
|
||||
return struct.pack("<HhhHHHHHH", flags, int(x), int(y), r, g, b, i, u1, u2)
|
||||
|
||||
|
||||
class ProtocolError(Exception):
|
||||
"""Exception used when a protocol error is detected."""
|
||||
pass
|
||||
|
||||
|
||||
class Status(object):
|
||||
"""Represents a status response from the DAC."""
|
||||
|
||||
def __init__(self, data):
|
||||
"""Initialize from a chunk of data."""
|
||||
self.protocol_version, self.le_state, self.playback_state, \
|
||||
self.source, self.le_flags, self.playback_flags, \
|
||||
self.source_flags, self.fullness, self.point_rate, \
|
||||
self.point_count = \
|
||||
struct.unpack("<BBBBHHHHII", data)
|
||||
|
||||
def dump(self, prefix = " - "):
|
||||
"""Dump to a string."""
|
||||
lines = [
|
||||
""
|
||||
"Host ",
|
||||
"Light engine: state %d, flags 0x%x" %
|
||||
(self.le_state, self.le_flags),
|
||||
"Playback: state %d, flags 0x%x" %
|
||||
(self.playback_state, self.playback_flags),
|
||||
"Buffer: %d points" %
|
||||
(self.fullness, ),
|
||||
"Playback: %d kpps, %d points played" %
|
||||
(self.point_rate, self.point_count),
|
||||
"Source: %d, flags 0x%x" %
|
||||
(self.source, self.source_flags)
|
||||
]
|
||||
|
||||
if gstt.debug == 2:
|
||||
print()
|
||||
for l in lines:
|
||||
print(prefix + l)
|
||||
|
||||
|
||||
class BroadcastPacket(object):
|
||||
"""Represents a broadcast packet from the DAC."""
|
||||
|
||||
def __init__(self, st):
|
||||
"""Initialize from a chunk of data."""
|
||||
self.mac = st[:6]
|
||||
self.hw_rev, self.sw_rev, self.buffer_capacity, \
|
||||
self.max_point_rate = struct.unpack("<HHHI", st[6:16])
|
||||
self.status = Status(st[16:36])
|
||||
|
||||
def dump(self, prefix = " - "):
|
||||
"""Dump to a string."""
|
||||
lines = [
|
||||
"MAC: " + ":".join(
|
||||
"%02x" % (ord(o), ) for o in self.mac),
|
||||
"HW %d, SW %d" %
|
||||
(self.hw_rev, self.sw_rev),
|
||||
"Capabilities: max %d points, %d kpps" %
|
||||
(self.buffer_capacity, self.max_point_rate)
|
||||
]
|
||||
print()
|
||||
for l in lines:
|
||||
print(prefix + l)
|
||||
if gstt.debug > 1:
|
||||
self.status.dump(prefix)
|
||||
|
||||
|
||||
class DAC(object):
|
||||
"""A connection to a DAC."""
|
||||
|
||||
|
||||
# "Laser point List" Point generator
|
||||
# each points is yielded : Getpoints() call n times OnePoint()
|
||||
|
||||
def OnePoint(self):
|
||||
|
||||
while True:
|
||||
|
||||
#pdb.set_trace()
|
||||
for indexpoint,currentpoint in enumerate(self.pl):
|
||||
#print indexpoint, currentpoint
|
||||
xyc = [currentpoint[0],currentpoint[1],currentpoint[2]]
|
||||
self.xyrgb = self.EtherPoint(xyc)
|
||||
|
||||
delta_x, delta_y = self.xyrgb[0] - self.xyrgb_prev[0], self.xyrgb[1] - self.xyrgb_prev[1]
|
||||
|
||||
#test adaptation selon longueur ligne
|
||||
if math.hypot(delta_x, delta_y) < 4000:
|
||||
|
||||
# For glitch art : decrease lsteps
|
||||
#l_steps = [ (1.0, 8)]
|
||||
l_steps = gstt.stepshortline
|
||||
|
||||
else:
|
||||
# For glitch art : decrease lsteps
|
||||
#l_steps = [ (0.25, 3), (0.75, 3), (1.0, 10)]
|
||||
l_steps = gstt.stepslongline
|
||||
|
||||
for e in l_steps:
|
||||
step = e[0]
|
||||
|
||||
for i in range(0,e[1]):
|
||||
|
||||
self.xyrgb_step = (self.xyrgb_prev[0] + step*delta_x, self.xyrgb_prev[1] + step*delta_y) + self.xyrgb[2:]
|
||||
yield self.xyrgb_step
|
||||
|
||||
self.xyrgb_prev = self.xyrgb
|
||||
|
||||
|
||||
def GetPoints(self, n):
|
||||
|
||||
d = [next(self.newstream) for i in range(n)]
|
||||
#print d
|
||||
return d
|
||||
|
||||
|
||||
# Etherpoint all transform in one matrix, with warp !!
|
||||
# xyc : x y color
|
||||
def EtherPoint(self,xyc):
|
||||
|
||||
c = xyc[2]
|
||||
|
||||
#print("")
|
||||
#print("pygame point",[(xyc[0],xyc[1],xyc[2])])
|
||||
#gstt.EDH[self.mylaser]= np.array(ast.literal_eval(r.get('/EDH/'+str(self.mylaser))))
|
||||
position = homographyp.apply(gstt.EDH[self.mylaser],np.array([(xyc[0],xyc[1])]))
|
||||
|
||||
#print("etherdream point",position[0][0], position[0][1], ((c >> 16) & 0xFF) << 8, ((c >> 8) & 0xFF) << 8, (c & 0xFF) << 8)
|
||||
|
||||
return (position[0][0], position[0][1], ((c >> 16) & 0xFF) << 8, ((c >> 8) & 0xFF) << 8, (c & 0xFF) << 8)
|
||||
|
||||
|
||||
def read(self, l):
|
||||
"""Read exactly length bytes from the connection."""
|
||||
while l > len(self.buf):
|
||||
self.buf += self.conn.recv(4096)
|
||||
|
||||
obuf = self.buf
|
||||
self.buf = obuf[l:]
|
||||
return obuf[:l]
|
||||
|
||||
def readresp(self, cmd):
|
||||
"""Read a response from the DAC."""
|
||||
|
||||
|
||||
data = self.read(22)
|
||||
response = data[0]
|
||||
gstt.lstt_dacanswers[self.mylaser] = response
|
||||
cmdR = chr(data[1])
|
||||
status = Status(data[2:])
|
||||
|
||||
r.set('/lack/'+str(self.mylaser), response)
|
||||
|
||||
if cmdR != cmd:
|
||||
raise ProtocolError("expected resp for %r, got %r"
|
||||
% (cmd, cmdR))
|
||||
|
||||
if response != ord('a'):
|
||||
raise ProtocolError("expected ACK, got %r"
|
||||
% (response, ))
|
||||
|
||||
self.last_status = status
|
||||
return status
|
||||
|
||||
def __init__(self, mylaser, PL, port = 7765):
|
||||
"""Connect to the DAC over TCP."""
|
||||
socket.setdefaulttimeout(2)
|
||||
|
||||
self.mylaser = mylaser
|
||||
self.clientkey = r.get("/clientkey").decode('ascii')
|
||||
|
||||
#log.info("Tracer "+str(self.mylaser)+" connecting to "+ gstt.lasersIPS[mylaser])
|
||||
#print("DAC", self.mylaser, "Handler process, connecting to", gstt.lasersIPS[mylaser] )
|
||||
self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.connstatus = self.conn.connect_ex((gstt.lasersIPS[mylaser], port))
|
||||
if self.connstatus == 35 or self.connstatus == 64:
|
||||
log.err("Tracer "+ str(self.mylaser)+" ("+ gstt.lasersIPS[mylaser]+"): "+ackstate[str(self.connstatus)])
|
||||
else:
|
||||
print("Tracer "+ str(self.mylaser)+" ("+ gstt.lasersIPS[mylaser]+"): "+ackstate[str(self.connstatus)])
|
||||
|
||||
# ipconn state is -1 at startup (see gstt) and modified here
|
||||
r.set('/lack/'+str(self.mylaser), self.connstatus)
|
||||
gstt.lstt_ipconn[self.mylaser] = self.connstatus
|
||||
|
||||
self.buf = b''
|
||||
# Upper case PL is the Point List number
|
||||
self.PL = PL
|
||||
|
||||
# Lower case pl is the actual point list coordinates
|
||||
|
||||
|
||||
#pdb.set_trace()
|
||||
self.pl = ast.literal_eval(r.get(self.clientkey + str(self.mylaser)).decode('ascii'))
|
||||
if r.get('/EDH/'+str(self.mylaser)) == None:
|
||||
#print("Laser",self.mylaser,"NO EDH !! Computing one...")
|
||||
homographyp.newEDH(self.mylaser)
|
||||
else:
|
||||
|
||||
gstt.EDH[self.mylaser] = np.array(ast.literal_eval(r.get('/EDH/'+str(self.mylaser)).decode('ascii')))
|
||||
#print("Laser",self.mylaser,"found its EDH in redis")
|
||||
#print gstt.EDH[self.mylaser]
|
||||
|
||||
self.xyrgb = self.xyrgb_prev = (0,0,0,0,0)
|
||||
self.intensity = 65280
|
||||
self.newstream = self.OnePoint()
|
||||
|
||||
if gstt.debug >0:
|
||||
print("Tracer",self.mylaser,"init asked for ckey", self.clientkey+str(self.mylaser))
|
||||
if self.connstatus != 0:
|
||||
#print(""
|
||||
log.err("Connection ERROR " +str(self.connstatus)+" with laser "+str(mylaser)+" : "+str(gstt.lasersIPS[mylaser]))
|
||||
#print("first 10 points in PL",self.PL, self.GetPoints(10)
|
||||
else:
|
||||
print("Connection status for DAC "+str(self.mylaser)+" : "+ str(self.connstatus))
|
||||
|
||||
|
||||
# Reference points
|
||||
# Read the "hello" message
|
||||
first_status = self.readresp("?")
|
||||
first_status.dump()
|
||||
position = []
|
||||
|
||||
|
||||
def begin(self, lwm, rate):
|
||||
cmd = struct.pack("<cHI", b'b', lwm, rate)
|
||||
print("Tracer", str(self.mylaser), "begin with PL : ", str(self.PL))
|
||||
self.conn.sendall(cmd)
|
||||
return self.readresp("b")
|
||||
|
||||
def update(self, lwm, rate):
|
||||
print(("update", lwm, rate))
|
||||
cmd = struct.pack("<cHI", b'u', lwm, rate)
|
||||
self.conn.sendall(cmd)
|
||||
return self.readresp("u")
|
||||
|
||||
def encode_point(self, point):
|
||||
return pack_point(self.mylaser, self.intensity, *point)
|
||||
|
||||
def write(self, points):
|
||||
epoints = list(map(self.encode_point, points))
|
||||
cmd = struct.pack("<cH", b'd', len(epoints))
|
||||
self.conn.sendall(cmd + b''.join(epoints))
|
||||
return self.readresp("d")
|
||||
|
||||
def prepare(self):
|
||||
self.conn.sendall("p")
|
||||
return self.readresp("p")
|
||||
|
||||
|
||||
def stop(self):
|
||||
self.conn.sendall("s")
|
||||
return self.readresp("s")
|
||||
|
||||
def estop(self):
|
||||
self.conn.sendall("\xFF")
|
||||
return self.readresp("\xFF")
|
||||
|
||||
def clear_estop(self):
|
||||
self.conn.sendall("c")
|
||||
return self.readresp("c")
|
||||
|
||||
def ping(self):
|
||||
self.conn.sendall("?")
|
||||
return self.readresp("?")
|
||||
|
||||
|
||||
|
||||
def play_stream(self):
|
||||
|
||||
#print("laser", self.mylaser, "Pb : ",self.last_status.playback_state)
|
||||
|
||||
# error if etherdream is already playing state (from other source)
|
||||
if self.last_status.playback_state == 2:
|
||||
raise Exception("already playing?!")
|
||||
|
||||
# if idle go to prepare state
|
||||
elif self.last_status.playback_state == 0:
|
||||
self.prepare()
|
||||
|
||||
started = 0
|
||||
|
||||
while True:
|
||||
|
||||
#print("laser", self.mylaser, "Pb : ",self.last_status.playback_state)
|
||||
|
||||
order = int(r.get('/order/'+str(self.mylaser)).decode('ascii'))
|
||||
#print("tracer", str(self.mylaser),"order", order, type(order)
|
||||
|
||||
if order == 0:
|
||||
|
||||
# USER point list
|
||||
self.pl = ast.literal_eval(r.get(self.clientkey+str(self.mylaser)).decode('ascii'))
|
||||
#print("Tracer : laser", self.mylaser, " order 0 : pl : ",len(self.pl))
|
||||
|
||||
else:
|
||||
|
||||
# Get the new EDH
|
||||
if order == 1:
|
||||
print("Tracer",self.mylaser,"new EDH ORDER in redis")
|
||||
gstt.EDH[self.mylaser]= np.array(ast.literal_eval(r.get('/EDH/'+str(self.mylaser)).decode('ascii')))
|
||||
# Back to user point list
|
||||
r.set('/order/'+str(self.mylaser), 0)
|
||||
|
||||
# BLACK point list
|
||||
if order == 2:
|
||||
print("Tracer",self.mylaser,"BLACK ORDER in redis")
|
||||
self.pl = black_points
|
||||
|
||||
# GRID point list
|
||||
if order == 3:
|
||||
print("Tracer",self.mylaser,"GRID ORDER in redis")
|
||||
self.pl = grid_points
|
||||
|
||||
|
||||
# Resampler Change
|
||||
if order == 4:
|
||||
self.resampler = ast.literal_eval(r.get('/resampler/'+str(self.mylaser)).decode('ascii'))
|
||||
print("Tracer", self.mylaser," : resetting lsteps for",self.resampler)
|
||||
gstt.stepshortline = self.resampler[0]
|
||||
gstt.stepslongline[0] = self.resampler[1]
|
||||
gstt.stepslongline[1] = self.resampler[2]
|
||||
gstt.stepslongline[2] = self.resampler[3]
|
||||
# Back to user point list order
|
||||
r.set('/order/'+str(self.mylaser), 0)
|
||||
|
||||
# Client Key change
|
||||
if order == 5:
|
||||
print("Tracer", self.mylaser, "new clientkey")
|
||||
self.clientkey = r.get('/clientkey')
|
||||
# Back to user point list order
|
||||
r.set('/order/'+str(self.mylaser), 0)
|
||||
|
||||
# Intensity change
|
||||
if order == 6:
|
||||
self.intensity = int(r.get('/intensity/' + str(self.mylaser)).decode('ascii')) << 8
|
||||
print("Tracer" , self.mylaser, "new Intensity", self.intensity)
|
||||
gstt.intensity[self.mylaser] = self.intensity
|
||||
r.set('/order/'+str(self.mylaser), "0")
|
||||
|
||||
# kpps change
|
||||
if order == 7:
|
||||
gstt.kpps[self.mylaser] = int(r.get('/kpps/' + str(self.mylaser)).decode('ascii'))
|
||||
print("Tracer",self.mylaser,"new kpps", gstt.kpps[self.mylaser])
|
||||
self.update(0, gstt.kpps[self.mylaser])
|
||||
r.set('/order/'+str(self.mylaser), "0")
|
||||
|
||||
# color balance change
|
||||
if order == 8:
|
||||
gstt.red[self.mylaser] = int(r.get('/red/' + str(self.mylaser)).decode('ascii'))
|
||||
gstt.green[self.mylaser] = int(r.get('/green/' + str(self.mylaser)).decode('ascii'))
|
||||
gstt.blue[self.mylaser] = int(r.get('/blue/' + str(self.mylaser)).decode('ascii'))
|
||||
print("Tracer",self.mylaser,"new color balance", gstt.red[self.mylaser], gstt.green[self.mylaser], gstt.blue[self.mylaser])
|
||||
r.set('/order/'+str(self.mylaser), "0")
|
||||
|
||||
|
||||
|
||||
r.set('/lstt/'+str(self.mylaser), self.last_status.playback_state)
|
||||
# pdb.set_trace()
|
||||
# How much room?
|
||||
|
||||
cap = 1799 - self.last_status.fullness
|
||||
points = self.GetPoints(cap)
|
||||
|
||||
r.set('/cap/'+str(self.mylaser), cap)
|
||||
|
||||
if cap < 100:
|
||||
time.sleep(0.001)
|
||||
cap += 150
|
||||
|
||||
# print("Writing %d points" % (cap, ))
|
||||
#t0 = time.time()
|
||||
#print points
|
||||
self.write(points)
|
||||
#t1 = time.time()
|
||||
# print("Took %f" % (t1 - t0, )
|
||||
|
||||
if not started:
|
||||
print("Tracer", self.mylaser, "starting with", gstt.kpps[self.mylaser],"kpps")
|
||||
self.begin(0, gstt.kpps[self.mylaser])
|
||||
started = 1
|
||||
|
||||
# not used in LJay.
|
||||
def find_dac():
|
||||
"""Listen for broadcast packets."""
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.bind(("0.0.0.0", 7654))
|
||||
|
||||
while True:
|
||||
data, addr = s.recvfrom(1024)
|
||||
bp = BroadcastPacket(data)
|
||||
|
||||
print(("Packet from %s: " % (addr, )))
|
||||
bp.dump()
|
||||
|
||||
|
||||
'''
|
||||
#Laser order bit 0 = 0
|
||||
if not order & (1 << (self.mylaser*2)):
|
||||
#print("laser",mylaser,"bit 0 : 0")
|
||||
|
||||
# Laser bit 0 = 0 and bit 1 = 0 : USER PL
|
||||
if not order & (1 << (1+self.mylaser*2)):
|
||||
#print("laser",mylaser,"bit 1 : 0")
|
||||
self.pl = ast.literal_eval(r.get('/pl/'+str(self.mylaser)))
|
||||
|
||||
else:
|
||||
# Laser bit 0 = 0 and bit 1 = 1 : New EDH
|
||||
#print("laser",mylaser,"bit 1 : 1" )
|
||||
print("Laser",self.mylaser,"new EDH ORDER in redis"
|
||||
gstt.EDH[self.mylaser]= np.array(ast.literal_eval(r.get('/EDH/'+str(self.mylaser))))
|
||||
# Back to USER PL
|
||||
order = r.get('/order')
|
||||
neworder = order & ~(1<< self.mylaser*2)
|
||||
neworder = neworder & ~(1<< 1+ self.mylaser*2)
|
||||
r.set('/order', str(neworder))
|
||||
else:
|
||||
|
||||
# Laser bit 0 = 1
|
||||
print("laser",mylaser,"bit 0 : 1")
|
||||
|
||||
# Laser bit 0 = 1 and bit 1 = 0 : Black PL
|
||||
if not order & (1 << (1+self.mylaser*2)):
|
||||
#print("laser",mylaser,"bit 1 : 0")
|
||||
self.pl = black_points
|
||||
|
||||
else:
|
||||
# Laser bit 0 = 1 and bit 1 = 1 : GRID PL
|
||||
#print("laser",mylaser,"bit 1 : 1" )
|
||||
self.pl = grid_points
|
||||
'''
|
||||
Loading…
Add table
Add a link
Reference in a new issue