Merge branch 'feature_plugins' into feature_plugins_shader_gadgets

This commit is contained in:
Tristan Rowley
2020-02-16 17:13:37 +00:00
6 changed files with 163 additions and 73 deletions

View File

@@ -1,6 +1,6 @@
# Auto-generated Actions list # Auto-generated Actions list
Wed 12 Feb 00:09:50 UTC 2020 Sun 16 Feb 17:13:17 UTC 2020
for branch=feature_plugins_shader_gadgets for branch=feature_plugins_shader_gadgets
@@ -173,6 +173,8 @@ for branch=feature_plugins_shader_gadgets
* set_shader_speed_layer_([0-2])_amount * set_shader_speed_layer_([0-2])_amount
### Plugin routes ### Plugin routes
* set_lfo_modulation_([0-3])_level (from LFOModulation)
* toggle_lfo_active (from LFOModulation)
* (.*)&&(.*) (from ManipulatePlugin) * (.*)&&(.*) (from ManipulatePlugin)
* invert|(.*) (from ManipulatePlugin) * invert|(.*) (from ManipulatePlugin)
* f:(.*):|(.*) (from ManipulatePlugin) * f:(.*):|(.*) (from ManipulatePlugin)

View File

@@ -977,7 +977,7 @@ class Actions(object):
return return
try: try:
#print ("for method_name %s, arguments is %s and len is %s" % (method_name, arguments, len(signature(method).parameters))) #print ("for method_name %s, arguments is %s and len is %s, got method %s" % (method_name, arguments, len(signature(method).parameters), method))
if arguments is not None and len(signature(method).parameters)==len(arguments): # only pass arguments if count matches method sig if arguments is not None and len(signature(method).parameters)==len(arguments): # only pass arguments if count matches method sig
method(*arguments) method(*arguments)
else: else:

View File

@@ -222,6 +222,7 @@ class DisplayPlugin(Plugin):
#display_text.insert(END, 'test from DisplayPlugin') #display_text.insert(END, 'test from DisplayPlugin')
display.display_text.insert(END, '{} \n'.format(display.body_title)) display.display_text.insert(END, '{} \n'.format(display.body_title))
class ModulationReceiverPlugin(Plugin): class ModulationReceiverPlugin(Plugin):
def __init__(self, plugin_collection): def __init__(self, plugin_collection):
super().__init__(plugin_collection) super().__init__(plugin_collection)
@@ -231,6 +232,24 @@ class ModulationReceiverPlugin(Plugin):
raise NotImplementedError raise NotImplementedError
class AutomationSourcePlugin(Plugin):
@property
def frame_key(self):
return self.__class__.__name__
def __init__(self, plugin_collection):
super().__init__(plugin_collection)
def get_frame_data(self):
raise NotImplementedError
def recall_frame_data(self, data):
raise NotImplementedError
def get_frame_diff(self, last_frame, current_frame):
raise NotImplementedError
# adapted from https://github.com/gdiepen/python_plugin_example # adapted from https://github.com/gdiepen/python_plugin_example
class PluginCollection(object): class PluginCollection(object):
"""Upon creation, this class will read the plugins package for modules """Upon creation, this class will read the plugins package for modules
@@ -306,7 +325,7 @@ class PluginCollection(object):
for (_, c) in clsmembers: for (_, c) in clsmembers:
# Only add classes that are a sub class of Plugin, but NOT Plugin itself # Only add classes that are a sub class of Plugin, but NOT Plugin itself
# or one of the base classes # or one of the base classes
ignore_list = [ Plugin, ActionsPlugin, SequencePlugin, MidiFeedbackPlugin, DisplayPlugin, ModulationReceiverPlugin ] ignore_list = [ Plugin, ActionsPlugin, SequencePlugin, MidiFeedbackPlugin, DisplayPlugin, ModulationReceiverPlugin, AutomationSourcePlugin ]
if issubclass(c, Plugin) & (c not in ignore_list): if issubclass(c, Plugin) & (c not in ignore_list):
print(' Found plugin class: %s.%s' % (c.__module__,c.__name__)) print(' Found plugin class: %s.%s' % (c.__module__,c.__name__))
self.plugins.append(c(self)) self.plugins.append(c(self))

View File

@@ -29,7 +29,8 @@
"SHADER_PARAM": ["return_to_default_control_mode"], "SHADER_PARAM": ["return_to_default_control_mode"],
"CONFIRM": ["perform_confirm_action"], "CONFIRM": ["perform_confirm_action"],
"NAV_DETOUR": ["toggle_detour_play"], "NAV_DETOUR": ["toggle_detour_play"],
"PLAY_SHADER": ["toggle_shaders", "toggle_shader_speed"] "PLAY_SHADER": ["toggle_shaders", "toggle_shader_speed"],
"LFOMODU": ["toggle_lfo_active"]
}, },
"d": { "d": {
"DEFAULT": ["switch_to_next_player", "toggle_player_mode"], "DEFAULT": ["switch_to_next_player", "toggle_player_mode"],

View File

@@ -5,7 +5,11 @@ from plugins.frame_manager import Frame
class LFOModulationPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin): class LFOModulationPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
disabled = False disabled = False
stop_flat = True active = False
level = [0.0, 0.0, 0.0, 0.0]
stop_flag = False
pause_flag = False pause_flag = False
def __init__(self, plugin_collection): def __init__(self, plugin_collection):
super().__init__(plugin_collection) super().__init__(plugin_collection)
@@ -23,13 +27,23 @@ class LFOModulationPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
display.display_text.insert(END, '{} \n'.format(display.body_title)) display.display_text.insert(END, '{} \n'.format(display.body_title))
display.display_text.insert(END, "test from LFOModulationPlugin!\n") display.display_text.insert(END, "test from LFOModulationPlugin!\n")
display.display_text.insert(END, "\tACTIVE\n" if self.active else "not active\n")
for i,value in enumerate(self.level):
display.display_text.insert(END, "{} level: {:03.2f}%\n".format(i,value))
@property @property
def parserlist(self): def parserlist(self):
return [ ] return [
"""( r"run_automation", self.run_automation ), ( r"^set_lfo_modulation_([0-3])_level$", self.set_lfo_modulation_level ),
( r"stop_automation", self.stop_automation ), ( r"^toggle_lfo_active$", self.toggle_lfo_active )
( r"toggle_pause_automation", self.toggle_pause_automation ), ]
( r"pause_automation", self.pause_automation ),"""
def set_lfo_modulation_level(self, slot, value):
self.level[slot] = value
def toggle_lfo_active(self):
self.active = not self.active
def run_sequence(self, position): def run_sequence(self, position):
import time import time
@@ -38,10 +52,12 @@ class LFOModulationPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
if self.pc.data.plugins is None: if self.pc.data.plugins is None:
return return
print("run_automation position %s!"%position) if not self.active:
return
#print("run_automation position %s!"%position)
import math import math
self.pc.actions.call_method_name("modulate_param_0_to_amount_continuous", math.sin(position*math.pi)) #(now*100)%300) self.pc.actions.call_method_name("modulate_param_0_to_amount_continuous", 0.5+(0.5*self.level[0] * math.sin(position*math.pi))) #(now*100)%300)
self.pc.actions.call_method_name("modulate_param_1_to_amount_continuous", math.cos(position*math.pi)/math.pi) self.pc.actions.call_method_name("modulate_param_1_to_amount_continuous", 0.5+(0.5*self.level[1] * math.cos(position*math.pi)/math.pi))
self.pc.actions.call_method_name("modulate_param_2_to_amount_continuous", math.atan(position*math.pi)/math.pi) self.pc.actions.call_method_name("modulate_param_2_to_amount_continuous", 0.5+(0.5*self.level[2] * math.atan(position*math.pi)/math.pi))
self.pc.actions.call_method_name("modulate_param_3_to_amount_continuous", math.sin(math.sin(position*math.pi)*math.pi)) self.pc.actions.call_method_name("modulate_param_3_to_amount_continuous", 0.5+(0.5*self.level[3] * math.sin(math.sin(position*math.pi)*math.pi)))

View File

@@ -1,10 +1,10 @@
import serial import serial
from serial import Serial from serial import Serial
import data_centre.plugin_collection import data_centre.plugin_collection
from data_centre.plugin_collection import ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationReceiverPlugin from data_centre.plugin_collection import ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationReceiverPlugin, AutomationSourcePlugin
import threading import threading
class WJSendPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin,ModulationReceiverPlugin): class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationReceiverPlugin, AutomationSourcePlugin):
disabled = False#True disabled = False#True
ser = None ser = None
# from http://depot.univ-nc.nc/sources/boxtream-0.9999/boxtream/switchers/panasonic.py # from http://depot.univ-nc.nc/sources/boxtream-0.9999/boxtream/switchers/panasonic.py
@@ -42,9 +42,44 @@ class WJSendPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin,ModulationReceiver
self.pc.actions.tk.after(500, self.refresh) self.pc.actions.tk.after(500, self.refresh)
#tk.after(500, self.refresh) #tk.after(500, self.refresh)
# methods/vars for AutomationSourcePlugin
last_record = {}
def get_frame_data(self):
diff = self.last_record.copy()
#self.last_record = {}
return diff
def get_frame_diff(self, last_frame, current_frame):
lf = last_frame.get(self.frame_key)
cf = current_frame.get(self.frame_key)
if cf is None or not cf:
return {}
if lf is None or not lf:
return { self.frame_key: cf.copy() }
diff = {}
for queue,message in cf.items():
if lf.get(queue) is None or lf.get(queue)!=message:
diff[queue] = message
#print (">>>>>> returning diff\n%s\n<<<<<" % diff)
return diff
def recall_frame_data(self, data):
if data is None:
return
# print(">>>>recall from data:\n\t%s\n" %data)
for queue, item in data.items():
self.send_buffered(queue, item, record = False)
# methods for ModulationReceiverPlugin - receives changes to the in-built modulation levels (-1 to +1)
# experimental & hardcoded !
def set_modulation_value(self, param, value): def set_modulation_value(self, param, value):
# take modulation value and throw it to local parameter # take modulation value and throw it to local parameter
print("||||| wjsend set_modulation_value for param %s with value %s!" % (param, value)) print("||||| wjsend received set_modulation_value for param %s with value %s!" % (param, value))
if param==0: if param==0:
self.set_mix((0.5+value)/2) self.set_mix((0.5+value)/2)
elif param==1: elif param==1:
@@ -56,6 +91,21 @@ class WJSendPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin,ModulationReceiver
else: else:
print("unknown param %s!" % param) print("unknown param %s!" % param)
#methods for DisplayPlugin
def show_plugin(self, display, display_mode):
from tkinter import Text, END
#super(DisplayPlugin).show_plugin(display, display_mode)
#print("show plugin?")
display.display_text.insert(END, '{} \n'.format(display.body_title))
display.display_text.insert(END, "test from WJSendPlugin!\n\n")
for queue, last in self.last.items():
display.display_text.insert(END, "last %s:\t%s\n" % (queue,self.last.get(queue)))
def get_display_modes(self):
return ["WJMXSEND","NAV_WJMX"]
# methods for SerialPlugin (todo!)
def open_serial(self, port='/dev/ttyUSB0', baudrate=9600): def open_serial(self, port='/dev/ttyUSB0', baudrate=9600):
if self.ser is not None: if self.ser is not None:
self.ser.close() self.ser.close()
@@ -79,19 +129,60 @@ class WJSendPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin,ModulationReceiver
import traceback import traceback
traceback.print_exc() traceback.print_exc()
def show_plugin(self, display, display_mode): def send_serial_string(self, string):
from tkinter import Text, END try:
#super(DisplayPlugin).show_plugin(display, display_mode) print("sending string %s " % string)
#print("show plugin?") output = b'\2' + string.encode('ascii') + b'\3'
display.display_text.insert(END, '{} \n'.format(display.body_title)) self.ser.write(output) #.encode())
display.display_text.insert(END, "test from WJSendPlugin!\n\n") print("sent string '%s'" % output) #.encode('ascii'))
#if 'S' in string:
# self.get_device_status()
except Exception as e:
print("%s: send_serial_string failed for '%s'" % (e,string)) #.encode()
for queue, last in self.last.items(): queue = {}
display.display_text.insert(END, "last %s:\t%s\n" % (queue,self.last.get(queue))) def refresh(self):
#print("refresh called!")
if not self.ser or self.ser is None:
self.open_serial()
def get_display_modes(self): try:
return ["WJMXSEND","NAV_WJMX"] for queue, command in self.queue.items():
self.send_buffered(queue, command)
#self.queue.clear()
except Exception:
print ("!!! CAUGHT EXCEPTION running queue !!!")
import traceback
print(traceback.format_exc())
finally:
self.queue.clear()
if self.ser is not None:
self.pc.shaders.root.after(self.THROTTLE, self.refresh)
def send(self, queue, output):
#self.send_buffered(queue,output)
self.queue[queue] = output
last = {}
def send_buffered(self, queue, output, record = True):
if self.last.get(queue)!=output:
self.send_serial_string(output)
self.last[queue] = output
if record:
print("### send_buffered is setting last_record[%s] to %s" % (queue,output))
self.last_record[queue] = output
def send_append(self, command, value):
# append value to the command as a hex value
self.send(command.split(':')[0], "{}{:02X}".format(command,int(255*value)))
def send_append_pad(self, pad, command, value):
# append value, padded to length
self.send(command.split(':')[0], ("{}{:0%iX}"%pad).format(command,int(255*value)))
# methods for ActionPlugin
@property @property
def parserlist(self): def parserlist(self):
return [ return [
@@ -106,42 +197,9 @@ class WJSendPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin,ModulationReceiver
( r"^wj_send_append_([:0-9a-zA-Z]*)$", self.send_append ), ( r"^wj_send_append_([:0-9a-zA-Z]*)$", self.send_append ),
] ]
def send_serial_string(self, string): # methods for handling some Panasonic control settings
try: # todo: come up with a way to represent this programmatically
print("sending string %s " % string) # todo: add more!
output = b'\2' + string.encode('ascii') + b'\3'
self.ser.write(output) #.encode())
print("sent string '%s'" % output) #.encode('ascii'))
#if 'S' in string:
# self.get_device_status()
except Exception as e:
print("%s: send_serial_string failed for '%s'" % (e,string.encode()))
queue = {}
def refresh(self):
#print("refresh called!")
if not self.ser or self.ser is None:
self.open_serial()
try:
for queue, command in self.queue.items():
self.send_buffered(queue, command)
self.queue.clear()
except:
print ("!!! CAUGHT EXCEPTION running queue !!!")
if self.ser is not None:
self.pc.shaders.root.after(self.THROTTLE, self.refresh)
def send(self, queue, output):
#self.send_buffered(queue,output)
self.queue[queue] = output
last = {}
def send_buffered(self, queue, output):
if self.last.get(queue)!=output:
self.send_serial_string(output)
self.last[queue] = output
colour_x = 127 colour_x = 127
colour_y = 127 colour_y = 127
@@ -155,6 +213,7 @@ class WJSendPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin,ModulationReceiver
output = "VCC:{}{:02X}{:02X}".format(chan, self.colour_x,self.colour_y) output = "VCC:{}{:02X}{:02X}".format(chan, self.colour_x,self.colour_y)
self.send('VCC', output) self.send('VCC', output)
# RGB control of matte colour!
back_colour_x = 127 back_colour_x = 127
back_colour_y = 127 back_colour_y = 127
back_colour_z = 127 back_colour_z = 127
@@ -186,7 +245,7 @@ class WJSendPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin,ModulationReceiver
output = "VBW:{:02X}{:02X}{:02X}".format(self.back_wash_colour_x,self.back_wash_colour_y,self.back_wash_colour_z) output = "VBW:{:02X}{:02X}{:02X}".format(self.back_wash_colour_x,self.back_wash_colour_y,self.back_wash_colour_z)
self.send('VBW', output) self.send('VBW', output)
# positioner joystick
position_x = 127 position_x = 127
position_y = 127 position_y = 127
def set_position(self, mode, dim, value): def set_position(self, mode, dim, value):
@@ -198,15 +257,8 @@ class WJSendPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin,ModulationReceiver
output = "VPS:{}{:02X}{:02X}".format(mode,self.position_x,self.position_y) output = "VPS:{}{:02X}{:02X}".format(mode,self.position_x,self.position_y)
self.send('VPS:{}'.format(mode), output) self.send('VPS:{}'.format(mode), output)
# wipe / mix level
def set_mix(self, value): def set_mix(self, value):
output = "VMM:{:04X}".format(int(255*255*value)) output = "VMM:{:04X}".format(int(255*255*value))
self.send('VMM', output) self.send('VMM', output)
def send_append(self, command, value):
# append value to the command as a hex value
self.send(command.split(':')[0], "{}{:02X}".format(command,int(255*value)))
def send_append_pad(self, pad, command, value):
# append value, padded to length
self.send(command.split(':')[0], ("{}{:0%iX}"%pad).format(command,int(255*value)))