LJ/plugins/maxwell.py

1036 lines
28 KiB
Python

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
Maxwell
v0.1.0
This client uses the relative drawing functions (rpolyline) -> your coordinates must be centered around 0,0.
- Mixer :
LRmixer : right curve percent
LRtype : "add", "minus", "multiply"
- points numbers
- Curve objects : required parameters :
name, curvetype, freqlimit, freq, inversion
- Scaler :
Everything is resize by a constant
- Translator :
translations X Y Z by a constant
- Rotator :
rotations X Y Z by a constant
- Duplicator : duplicators, duplicatorsAngle
Duplicators are extra rpolyline with Angle added as global rotation parameter along *all* axis, this need to be checked conceptually
TODO :
- in Curve Objects :
amptype, amp, phasemodtype, phasemodspeed, phasemodspeed, phaseoffsettype, phaseoffset
- Other functions for lfos, translator, rotator, scaler, duplicator,...
- CC inputs for all parameters
LICENCE : CC
by Sam Neurohack
'''
import sys
import os
print()
ljpath = r'%s' % os.getcwd().replace('\\','/')
# import from shell
sys.path.append(ljpath +'/../libs/')
#import from LJ
sys.path.append(ljpath +'/libs/')
print ('Maxwell plugin startup')
import lj23 as lj
sys.path.append('../libs')
from OSC3 import OSCServer, OSCClient, OSCMessage
import redis
import socketserver
import math
import time
import argparse
import numpy as np
import weakref
from math import pi as PI
import scipy.signal as signal
import midi3
OSCinPort = 8012
#oscrun = True
# myIP = "127.0.0.1"
PL = 0
print ("")
print ("Arguments parsing if needed...")
argsparser = argparse.ArgumentParser(description="Text Cycling for LJ")
argsparser.add_argument("-r","--redisIP",help="IP of the Redis server used by LJ (127.0.0.1 by default) ",type=str)
argsparser.add_argument("-c","--client",help="LJ client number (0 by default)",type=int)
argsparser.add_argument("-l","--laser",help="Laser number to be displayed (0 by default)",type=int)
argsparser.add_argument("-v","--verbose",help="Verbosity level (0 by default)",type=int)
argsparser.add_argument("-m","--myIP",help="Local IP (127.0.0.1 by default) ",type=str)
args = argsparser.parse_args()
if args.client:
ljclient = args.client
else:
ljclient = 0
if args.laser:
plnumber = args.laser
else:
plnumber = 0
# Redis Computer IP
if args.redisIP != None:
redisIP = args.redisIP
else:
redisIP = '127.0.0.1'
print("redisIP",redisIP)
# myIP
if args.myIP != None:
myIP = args.myIP
else:
myIP = '127.0.0.1'
print("myIP",myIP)
if args.verbose:
debug = args.verbose
else:
debug = 0
lj.Config(redisIP,ljclient,"maxw")
white = lj.rgb2int(255,255,255)
red = lj.rgb2int(255,0,0)
blue = lj.rgb2int(0,0,255)
green = lj.rgb2int(0,255,0)
points = 512
# maxpoints = 500
samples = points
samparray = [0] * samples
# Channel 1 midi CC
cc1 = [0]*127
# Channel 2 midi CC
cc2 = [0]*127
# Mixer
LRmixer = 0
LRtype = 'minus' # "minus", 'multiply'
# Duplicators
duplicators = 1
duplicatorsAngle = 30
Oscillators = []
LFOs = []
Rotators = []
Translators = []
width = 800
height = 600
centerX = width / 2
centerY = height / 2
# 3D to 2D projection parameters
fov = 256
viewer_distance = 2.2
# Anaglyph computation parameters for right and left eyes.
eye_spacing = 100
nadir = 0.5
observer_altitude = 30000
#observer_altitude = 10000
# elevation = z coordinate
# 0.0, -2000 pop out
map_plane_altitude = 0.0
# Relative Object (name, active, intensity, xy, color, red, green, blue, PL , closed, xpos , ypos , resize , rotx , roty , rotz)
#Leftshape = lj.RelativeObject('Leftshape', True, 255, [], red, 255, 0, 0, PL , True, 100 , 100 , 1 , 0 , 0 , 0)
# name, intensity, active, xy, color, red, green, blue, PL , closed):
Leftshape = lj.FixedObject('Leftshape', True, 255, [], red, 255, 0, 0, PL , False)
#Rightshape = lj.FixedObject('Rightshape', True, 255, [], green, 0, 255, 0, PL , False)
# 'Destination' for each PL
# name, number, active, PL , scene, laser
# PL 0
Dest0 = lj.DestObject('0', 0, True, 0 , 0, 0)
#Dest1 = lj.DestObject('1', 1, True, 0 , 1, 1)
'''
viewgen3Lasers = [True,False,False,False]
# Add here, one by one, as much destination as you want for each PL.
# LJ and OSC can remotely add/delete destinations here.
lj.Dests = {
"0": {"PL": 0, "scene": 0, "laser": 0},
"1": {"PL": 0, "scene": 1, "laser": 1}
}
'''
#
# OSC
#
oscserver = OSCServer( (myIP, OSCinPort) )
oscserver.timeout = 0
# this method of reporting timeouts only works by convention
# that before calling handle_request() field .timed_out is
# set to False
def handle_timeout(self):
self.timed_out = True
# funny python's way to add a method to an instance of a class
import types
oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver)
# OSC callbacks
# /viewgen/ljclient
def OSCljclient(path, tags, args, source):
print("Got /viewgen/ljclient with values", args[0])
lj.WebStatus("viewgen to virtual "+ str(args[0]))
ljclient = args[0]
lj.LjClient(ljclient)
# /noteon note velocity
def OSCnoteon(path, tags, args, source):
note = args[0]
velocity = args[1]
# Do something with it
# /noteoff note
def OSCnoteoff(path, tags, args, source):
note = args[0]
# Do something with it
# /cc number value
def OSCcc(path, tags, args, source):
cc1[args[0]]= args[1]
#cc = args[0]
#value = args[1]
#
# CC functions
#
# /cc cc number value
def cc(ccnumber, value):
if ccnumber > 127:
cc2[ccnumber - 127]= value
else:
midichannel = basemidichannel
cc1[ccnumber]= value
#print("Sending Midi channel", midichannel, "cc", ccnumber, "value", value)
#midi3.MidiMsg([CONTROLLER_CHANGE+midichannel-1,ccnumber,value], learner)
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...")
f=open("maxwell.json","r")
s = f.read()
maxwell = json.loads(s)
print(len(maxwell['ccs']),"Functions")
print("Loaded.")
def SendCC(path,init):
funcpath = path.split("/")
func = funcpath[len(funcpath)-1]
if func in specificvalues:
value = specificvalues[func][init]
else:
value = int(init)
#print("sending CC", FindCC(path), "with value", value)
cc(FindCC(path),value)
time.sleep(0.005)
#
# computing functions
#
def ssawtooth(samples, freq, phase):
samparray = [0] * samples
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):
samparray = [0] * samples
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):
samparray = [0] * samples
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 sline(samples, 1):
samparray = [0] * samples
for ww in range(samples):
samparray[ww] = ww
return samparray
'''
def slinear(samples, min, max):
samparray = [0] * samples
linearinc = (max-min)/samples
for ww in range(samples):
if ww == 0:
samparray[ww] = min
else:
samparray[ww] = samparray[ww-1] + linearinc
#print('linear min max', min, max)
#print ('linear',samparray)
return samparray
def sconstant(samples, values):
samparray = [0] * samples
for ww in range(samples):
samparray[ww] = values
return samparray
def remap(s,min1,max1, min2, max2):
a1, a2 = min1, max1
b1, b2 = min2, max2
return b1 + ((s - a1) * (b2 - b1) / (a2 - a1))
def cc2range(s,min,max):
a1, a2 = 0,127
b1, b2 = min, max
return b1 + ((s - a1) * (b2 - b1) / (a2 - a1))
def range2cc(s,min,max):
a1, a2 = min, max
b1, b2 = 0,127
return b1 + ((s - a1) * (b2 - b1) / (a2 - a1))
def LeftShift(elevation):
diff = elevation - map_plane_altitude
return nadir * eye_spacing * diff / (observer_altitude - elevation)
def RightShift(elevation):
diff = map_plane_altitude - elevation
return (1 - nadir) * eye_spacing * diff / (observer_altitude - elevation)
def Proj(x,y,z,angleX,angleY,angleZ):
rad = angleX * math.pi / 180
cosa = math.cos(rad)
sina = math.sin(rad)
y2 = y
y = y2 * cosa - z * sina
z = y2 * sina + z * cosa
rad = angleY * math.pi / 180
cosa = math.cos(rad)
sina = math.sin(rad)
z2 = z
z = z2 * cosa - x * sina
x = z2 * sina + x * cosa
rad = angleZ * math.pi / 180
cosa = math.cos(rad)
sina = math.sin(rad)
x2 = x
x = x2 * cosa - y * sina
y = x2 * sina + y * cosa
""" Transforms this 3D point to 2D using a perspective projection. """
factor = fov / (viewer_distance + z)
x = x * factor + centerX
y = - y * factor + centerY
return (x,y)
#
# Main Oscillators
#
specificvalues = {
"sine": 0,
"saw": 33,
"square": 95,
"linear": 127,
"constant" : 128,
"1": 0,
"4": 26,
"16": 52,
"32": 80,
"127": 127,
"solid": 0,
"lfo": 127,
"off": 0,
"on": 127,
"add": 0,
"minus": 50,
"multiply": 127,
"lfo1": 33,
"lfo2": 95,
"lfo3": 127,
"manual": 0,
}
'''
"colormodtype": {
"sin": 0,
"linear": 127
}
'''
# return v1,v2,v3 or v4 according to "value" 0-127
def vals4(value,v1,v2,v3,v4):
if value < 32:
return v1
if value > 31 and value < 64:
return v2
if value > 61 and value < 96:
return v3
if value > 95:
return v4
# return v1,v2,v3,v4 or v5 according to "value" 0-127
def vals5(value,v1,v2,v3,v4,v5):
if value < 26:
return v1
if value > 25 and value < 52:
return v2
if value > 51 and value < 80:
return v3
if value > 79 and value < 104:
return v4
if value > 104:
return v5
class OsciObject:
_instances = set()
counter = 0
kind = 'fixed'
def __init__(self, name, curvetype, amp, inversion, baseCC):
self.name = name
self.baseCC = baseCC
# Amplitude 64 values positive and 64 values negative -256 to +256
self.amp = amp
# curvetypes : sine, saw, square, linear, constant ?
self.curvetype = curvetype
self.freqlimit = 4
# Curvetype frequency : 128 possible values between 1 - freqlimit
self.freq = 2
# Amplitude Curvetype : constant, lfo1, lfo2, lfo3
self.amptype = 'constant'
# Phase modification type : linear or sine.
self.phasemodtype = 'linear'
# Phase modification 64 speed forward and 64 speed backward.
# Speed is increment browsing
self.phasemodspeed = 1
#self.phasemodspeed = 0
self.phaseoffsettype = 'manual'
self.phaseoffset = 200
self.ampoffset = cc2range(cc1[self.baseCC + 9],0,32)
self.ampoffsettype = cc1[self.baseCC + 10]
self.inversion = inversion
self.phasemodcurve = [0]*points # ssine(points, self.freq, self.phasemodspeed)
self.phaseoffsetcurve = ssine(points, self.freq, self.phasemodspeed)
self.values = ssine(points, self.freq, self.phasemodspeed)
self.counter = 0
self.samples = samples
self._instances.add(weakref.ref(self))
OsciObject.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):
OsciObject.counter -= 1
def CC2VAR(self):
if cc1[self.baseCC] == 128:
self.curvetype = "constant"
else:
self.curvetype = vals4(cc1[self.baseCC], "sine", "saw","square","linear")
self.freqlimit = vals5(cc1[self.baseCC + 2],"1","4","16","32","127")
self.freq = cc2range(cc1[self.baseCC + 1], 0, self.freqlimit)
self.amptype = vals4(cc1[self.baseCC + 4], "constant", "lfo1","lfo2","lfo3")
self.amp = cc2range(cc1[self.baseCC + 3] , -256, 256)
if cc1[self.baseCC]+ 6 < 64:
self.phasemodtype = "linear"
else:
self.phasemodtype ="sine"
# phasemodspeed : 0 to 32 ?, because why not 32 ? to test.
self.phasemodspeed = cc2range(cc1[self.baseCC + 5], 0, 32)
self.phaseoffsettype = vals4(cc1[self.baseCC + 8], "manual", "lfo1","lfo2","lfo3")
# phaseoffset : between 0 to 10 ?
self.phaseoffset = cc2range(cc1[self.baseCC + 7], 0, 10)
self.ampoffsettype = vals4(cc1[self.baseCC + 10], "manual", "lfo1","lfo2","lfo3")
# ampoffset : between 0 to 10 ?
self.ampoffset = cc2range(cc1[self.baseCC + 9], 0, 10)
self.inversion = cc1[self.baseCC + 11]
def VAR2CC(self):
'''
/osc/left/X/curvetype is Artnet 0 MIDI Channel 1 CC 0 "sine"/0 - "saw"/33 - "square"/95 - "linear"/127 - "constant"/128
/osc/left/X/freq is Artnet 1 MIDI Channel 1 CC 1 0 - freqlimit
/osc/left/X/freqlimit is Artnet 2 MIDI Channel 1 CC 2 "1"/0 - "4"/26 - "16"/52 - "32"/80 - "127"/127
/osc/left/X/amp is Artnet 3 MIDI Channel 1 CC 3 0/-256 - 127/256
/osc/left/X/amptype is Artnet 4 MIDI Channel 1 CC 4 "constant"/0 - "lfo1"/33 - "lfo2"/95 - "lfo3"/127
/osc/left/X/phasemodspeed is Artnet 5 MIDI Channel 1 CC 5 0 - 32 ?
/osc/left/X/phasemodtype is Artnet 6 MIDI Channel 1 CC 6 : "linear"/ - "sin"/
/osc/left/X/phaseoffset is Artnet 7 MIDI Channel 1 CC 7 0 - 10 ?
/osc/left/X/phaseoffsettype is Artnet 8 MIDI Channel 1 CC 8 "manual"/0 - "lfo1"/33 - "lfo2"/95 - "lfo3"/127
/osc/left/X/ampoffset is Artnet 9 MIDI Channel 1 CC 9 0 - 10 ?
/osc/left/X/ampoffsettype is Artnet 10 MIDI Channel 1 CC 10 "manual"/0 - "lfo1"/33 - "lfo2"/95 - "lfo3"/127
/osc/left/X/inversion is Artnet 11 MIDI Channel 1 CC 11 : "off"/0 - "on"/127
'''
cc1[self.baseCC + 3] = range2cc(self.amp, -256, 256)
cc1[self.baseCC] = specificvalues[self.curvetype]
cc1[self.baseCC + 2] = specificvalues[str(self.freqlimit)]
cc1[self.baseCC + 1] = range2cc(self.freq, 0, self.freqlimit)
if self.amptype == 'constant':
cc1[self.baseCC + 4] = 0
else:
cc1[self.baseCC + 4] = specificvalues[self.amptype]
# Phase modification type : linear or sine.
if self.phasemodtype == 'linear':
cc1[self.baseCC + 6] = 0
else:
cc1[self.baseCC + 6] = 90
cc1[self.baseCC + 5] = range2cc(self.phasemodspeed, 0, 32)
# Phase offset
cc1[self.baseCC + 8] = specificvalues[self.phaseoffsettype]
cc1[self.baseCC + 7] = range2cc(self.phaseoffset, 0, 10)
# Amp offset
cc1[self.baseCC + 9] = range2cc(self.ampoffset, 0, 10)
cc1[self.baseCC + 10] = specificvalues[self.ampoffsettype]
if self.inversion == True:
cc1[self.baseCC + 11] = 127
else:
cc1[self.baseCC + 11] = 0
def Curve(self):
self.values = [0] * points
self.ampcurve = [0] * points
self.phasemodcurve = [0] * points
self.phaseoffsetcurve = [0] * points
self.counter += 1
#print ('counter', self.counter)
if self.counter == points:
self.counter = 0
# Phase offset curve
#self.phasemodcurve = slinear(points, -PI, PI) # ssine(points, self.freq, self.phasemodspeed)
if self.phaseoffsettype == 'manual':
self.phaseoffsetcurve = sconstant(points, self.phaseoffset)
if self.phaseoffsettype == 'lfo1':
self.phaseoffsetcurve = lfo1.Curve()
if self.phaseoffsettype == 'lfo2':
self.phaseoffsetcurve = lfo2.Curve()
if self.phaseoffsettype == 'lfo3':
self.phaseoffsetcurve = lfo3.Curve()
# Phase mod curve : phasemodspeed is 'speed' of change
if self.phasemodtype == 'linear':
self.phasemodcurve = slinear(points, -PI*self.phasemodspeed, PI*self.phasemodspeed)
if self.phasemodtype == 'lfo1':
self.phasemodcurve = lfo1.Curve()
if self.phasemodtype == 'lfo2':
self.phasemodcurve = lfo2.Curve()
if self.phasemodtype == 'lfo3':
self.phasemodcurve = lfo3.Curve()
self.phasemodspeed = self.phasemodcurve[self.counter]
#print('counter', self.counter, 'phasemod',self.phasemodspeed)
# Base values curve, trigo functions between -1 and + 1
if self.curvetype == 'sine':
self.ampcurve = ssine(points, self.freq, self.phasemodspeed)
if self.curvetype == 'saw':
self.ampcurve = ssawtooth(points, self.freq, self.phasemodspeed)
if self.curvetype == 'square':
self.ampcurve = ssquare(points, self.freq, self.phasemodspeed)
if self.curvetype == 'linear':
self.ampcurve = slinear(points, -1, 1)
if self.curvetype == 'constant':
self.ampcurve = sconstant(points, self.freq)
for point in range(points):
# curve points = base curve * amp + curve modifier
if self.amptype == 'constant':
self.values[point] = self.ampcurve[point] * self.amp
if self.amptype == 'lfo1':
self.values[point] = (self.ampcurve[point] * self.amp) + (lfo1.values[point] * self.amp)
if self.amptype == 'lfo2':
self.values[point] = (self.ampcurve[point] * self.amp) + (lfo2.values[point] * self.amp)
if self.amptype == 'lfo3':
self.values[point] = (self.ampcurve[point] * self.amp) + (lfo3.values[point] * self.amp)
if self.inversion == True:
self.values = self.values[::-1]
#
# LFOs
#
class LFObject:
_instances = set()
counter = 0
kind = 'fixed'
def __init__(self, name):
self.name = name
self.freqlimit = 4
self.freq = 1
self.curvetype = 'sine'
# -1 1
self.phasemodspeed = 0
self.inversion = False
self.values = ssine(points, self.freq, self.phasemodspeed)
self._instances.add(weakref.ref(self))
LFObject.counter += 1
#print(self.name, "type", self.curvetype, "freq", self.freq)
@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 Curve(self):
#print(self.name, "type", self.curvetype, "freq", self.freq)
self.values = [0]*points
if self.curvetype == 'sine':
self.values = ssine(points, self.freq, self.phasemodspeed)
if self.curvetype == 'saw':
self.values = ssawtooth(points, self.freq, self.phasemodspeed)
if self.curvetype == 'square':
self.values = ssquare(points, self.freq, self.phasemodspeed)
if self.curvetype == 'linear':
self.values = slinear(points, self.freq)
if self.curvetype == 'constant':
self.values = sconstant(points, self.freq)
if self.inversion == True:
self.values = self.values[::-1]
def __del__(self):
LFObject.counter -= 1
#
# Rotators
#
class RotatorObject:
'''
# anim format (name, xpos, ypos, resize, currentframe, totalframe, count, speed)
# 0 1 2 3 4 5 6 7
# total frames is fetched from directory by lengthPOSE()
#anims[0] = ['boredhh' , xy_center[0] - 100, xy_center[1] + 30, 550, 0, 0, 0, animspeed]
anim[4] = anim[4]+anim[7]
if anim[4] >= anim[5]:
anim[4] = 0
'''
_instances = set()
counter = 0
kind = 'fixed'
def __init__(self, name):
self.name = name
self.curvetype = 'constant'
self.speed = 0
self.lfo = False
self.direction = 0
self._instances.add(weakref.ref(self))
RotatorObject.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):
RotatorObject.counter -= 1
def Curve(self):
self.values = [0]*points
if self.curvetype == 'sine':
self.values = ssine(points, self.direction, self.phasemodspeed)
if self.curvetype == 'saw':
self.values = ssawtooth(points, self.direction, self.phasemodspeed)
if self.curvetype == 'square':
self.values = ssquare(points, self.direction, self.phasemodspeed)
if self.curvetype == 'linear':
self.values = slinear(points, self.direction)
if self.curvetype == 'constant':
self.values = sconstant(points, 0)
#
# Translators
#
class TranslatorObject:
_instances = set()
counter = 0
kind = 'fixed'
def __init__(self, name, amt, speed):
self.name = name
self.curvetype = 'constant'
self.speed = speed
self.lfo = False
self.amt = amt
#self.values = ssine(points, self.amt, self.speed)
self.values = sconstant(points, self.amt)
self._instances.add(weakref.ref(self))
TranslatorObject.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):
TranslatorObject.counter -= 1
def Curve(self):
self.values = [0]*points
if self.curvetype == 'sine':
self.values = ssine(points, self.amt, self.speed)
if self.curvetype == 'saw':
self.values = ssawtooth(points, self.amt, self.speed)
if self.curvetype == 'square':
self.values = ssquare(points, self.amt, self.speed)
if self.curvetype == 'linear':
self.values = slinear(points, self.amt)
if self.curvetype == 'constant':
self.values = sconstant(points, self.amt)
#
# Scaler
#
Scalercurvetype = 'constant'
Scalercurve = [0.05] * points
Scalerspeed = 0
Scalerbutton = False
Scalerwidth = 0
Scaleramt = 0
def ScalerCurve():
Scalercurve = [0]*points
if Scalercurvetype == 'sine':
Scalercurve = ssine(points, Scaleramt, Scalerspeed)
if Scalercurvetype == 'saw':
Scalercurve = ssawtooth(points, Scaleramt, Scalerspeed)
if Scalercurvetype == 'square':
Scalercurve = ssquare(points, Scaleramt, Scalerspeed)
if Scalercurvetype == 'linear':
Scalercurve = slinear(points, Scaleramt)
if Scalercurvetype == 'constant':
Scalercurve = sconstant(points, 0.05)
#
# Main
#
def Run():
Left = []
Right = []
counter =0
lj.WebStatus("Maxwellator")
lj.SendLJ("/maxw/start 1")
# OSC
# OSC Server callbacks
print("Starting OSC server at",myIP," port",OSCinPort,"...")
oscserver.addMsgHandler( "/maxw/ljclient", OSCljclient )
# You will receive midi callbacks in OSC messages form if this plugin is in midi2OSC list in midi3.py and midi3.py is imported somewhere
oscserver.addMsgHandler( "/noteon", OSCnoteon)
oscserver.addMsgHandler( "/noteoff", OSCnoteoff)
oscserver.addMsgHandler( "/cc", OSCnoteon)
# Add OSC generic plugins commands : 'default", /ping, /quit, /pluginame/obj, /pluginame/var, /pluginame/adddest, /pluginame/deldest
lj.addOSCdefaults(oscserver)
# Drawing parameters
# LFOs
lfo1 = LFObject("lfo1")
lfo2 = LFObject("lfo2")
lfo3 = LFObject("lfo3")
# Rotators
rotX = RotatorObject("rotX")
rotY = RotatorObject("rotY")
rotZ = RotatorObject("rotZ")
# Translators : name amount speed
transX = TranslatorObject("transX",0,0)
transY = TranslatorObject("transY",0,0)
transZ = TranslatorObject("transZ",0,0)
Scaler = ScalerCurve()
# Left parameters : name, type, amp, inversion, base midi CC
leftX = OsciObject("leftX", "sine", 30, False, 0)
leftY = OsciObject("leftY", "sine", 30, True, 12)
leftZ = OsciObject("leftZ", "constant", 0, False, 24)
# Right parameters : name, type, amp, inversion, base midi CC
rightX = OsciObject("rightX", "saw", 30, False, 36)
rightY = OsciObject("rightY", 'saw', 30, True, 48)
rightZ = OsciObject("rightZ", 'constant', 0, False, 60)
try:
while lj.oscrun:
lj.OSCframe()
Left = []
Right = []
lfo1.Curve()
lfo2.Curve()
lfo3.Curve()
transX.Curve()
transY.Curve()
transZ.Curve()
rotX.Curve()
rotY.Curve()
rotZ.Curve()
leftX.Curve()
leftY.Curve()
leftZ.Curve()
rightX.Curve()
rightY.Curve()
rightZ.Curve()
for point in range(points):
if LRtype == 'add':
CurveX = (leftX.values[point]*(100-LRmixer)/100) + (rightX.values[point]*LRmixer/100) + transX.values[point]
CurveY = (leftY.values[point]*(100-LRmixer)/100) + (rightY.values[point]*LRmixer/100) + transY.values[point]
CurveZ = (leftZ.values[point]*(100-LRmixer)/100) + (rightZ.values[point]*LRmixer/100) + transZ.values[point]
if LRtype == 'minus':
CurveX = (leftX.values[point]*(100-LRmixer)/100) - (rightX.values[point]*LRmixer/100) + transX.values[point]
CurveY = (leftY.values[point]*(100-LRmixer)/100) - (rightY.values[point]*LRmixer/100) + transY.values[point]
CurveZ = (leftZ.values[point]*(100-LRmixer)/100) - (rightZ.values[point]*LRmixer/100) + transZ.values[point]
if LRtype == 'multiply':
CurveX = (leftX.values[point]*(100-LRmixer)/100) * (rightX.values[point]*LRmixer/100) + transX.values[point]
CurveY = (leftY.values[point]*(100-LRmixer)/100) * (rightY.values[point]*LRmixer/100) + transY.values[point]
CurveZ = (leftZ.values[point]*(100-LRmixer)/100) * (rightZ.values[point]*LRmixer/100) + transZ.values[point]
Left.append(Proj(CurveX+LeftShift(CurveZ*25), CurveY, CurveZ, 0, 0, 0))
#Right.append(Proj(CurveX+RightShift(CurveZ*25), CurveY, CurveZ, 0, 0, 0))
for clone in range(duplicators):
# Drawing step, 2 possibilities
# Red and Green drawn by laser 0
lj.rPolyLineOneColor(Left, c = Leftshape.color , PL = Leftshape.PL, closed = Leftshape.closed, xpos = 350, ypos = 350, resize = Scalercurve[0], rotx = rotX.values[0] + (clone * duplicatorsAngle), roty = rotY.values[0] + (clone * duplicatorsAngle), rotz = rotZ.values[0] + (clone * duplicatorsAngle))
#lj.PolyLineOneColor(Right, c = Rightshape.color , PL = Rightshape.PL, closed = Rightshape.closed)
#lj.DrawPL(PL)
lj.DrawDests()
time.sleep(0.01)
counter += 1
if counter > 360:
counter = 0
except KeyboardInterrupt:
pass
# Gently stop on CTRL C
finally:
lj.ClosePlugin()
Run()