mirror of
https://github.com/cyberboy666/r_e_c_u_r.git
synced 2025-12-11 19:00:04 +01:00
Backported basic code for MIDI controller autodetection (custom config file per controller), plugins with example plugin, and Akai APC Key 25 feedback plugin
This commit is contained in:
16
ACTIONS.md
16
ACTIONS.md
@@ -1,8 +1,8 @@
|
|||||||
# Auto-generated Actions list
|
# Auto-generated Actions list
|
||||||
|
|
||||||
Fri 3 Jan 22:08:36 UTC 2020
|
Fri 10 Jan 17:25:14 UTC 2020
|
||||||
|
|
||||||
for branch=feature_shader_midi
|
for branch=feature_plugins
|
||||||
|
|
||||||
# Methods
|
# Methods
|
||||||
* change_composite_setting(setting_value)
|
* change_composite_setting(setting_value)
|
||||||
@@ -58,6 +58,7 @@ for branch=feature_shader_midi
|
|||||||
* load_this_detour_shader
|
* load_this_detour_shader
|
||||||
* _load_this_slot_into_next_player(slot)
|
* _load_this_slot_into_next_player(slot)
|
||||||
* map_on_shaders_selection
|
* map_on_shaders_selection
|
||||||
|
* modulate_param_layer_offset_to_amount(param, layer, amount)
|
||||||
* move_browser_selection_down
|
* move_browser_selection_down
|
||||||
* move_browser_selection_up
|
* move_browser_selection_up
|
||||||
* move_settings_selection_down
|
* move_settings_selection_down
|
||||||
@@ -156,7 +157,7 @@ for branch=feature_shader_midi
|
|||||||
* toggle_x_autorepeat
|
* toggle_x_autorepeat
|
||||||
* try_pull_code_and_reset
|
* try_pull_code_and_reset
|
||||||
|
|
||||||
# Dynamic routes
|
## Dynamic routes
|
||||||
* play_shader_([0-9])_([0-9])
|
* play_shader_([0-9])_([0-9])
|
||||||
* toggle_shader_layer_([0-2])
|
* toggle_shader_layer_([0-2])
|
||||||
* start_shader_layer_([0-2])
|
* start_shader_layer_([0-2])
|
||||||
@@ -171,6 +172,15 @@ for branch=feature_shader_midi
|
|||||||
* set_shader_speed_layer_offset_([0-2])_amount
|
* set_shader_speed_layer_offset_([0-2])_amount
|
||||||
* set_shader_speed_layer_([0-2])_amount
|
* set_shader_speed_layer_([0-2])_amount
|
||||||
|
|
||||||
|
### Plugin routes
|
||||||
|
* test_plugin (from MidiActionsTestPlugin)
|
||||||
|
* cycle_shaders (from MidiActionsTestPlugin)
|
||||||
|
* run_automation (from MidiActionsTestPlugin)
|
||||||
|
* stop_automation (from MidiActionsTestPlugin)
|
||||||
|
* toggle_pause_automation (from MidiActionsTestPlugin)
|
||||||
|
* pause_automation (from MidiActionsTestPlugin)
|
||||||
|
* toggle_loop_automation (from MidiActionsTestPlugin)
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
Autogenerated by dotfiles/generate-list-actions.sh
|
Autogenerated by dotfiles/generate-list-actions.sh
|
||||||
|
|||||||
28
actions.py
28
actions.py
@@ -530,7 +530,7 @@ class Actions(object):
|
|||||||
self.data.settings['shader']['STROBE_AMOUNT']['value'] = scaled_amount
|
self.data.settings['shader']['STROBE_AMOUNT']['value'] = scaled_amount
|
||||||
|
|
||||||
def get_midi_status(self):
|
def get_midi_status(self):
|
||||||
self.message_handler.set_message('INFO', 'midi status is {}'.format(self.data.midi_status))
|
self.message_handler.set_message('INFO', ("midi status is {} to %s"%(self.data.midi_device_name)).format(self.data.midi_status))
|
||||||
|
|
||||||
def cycle_midi_port_index(self):
|
def cycle_midi_port_index(self):
|
||||||
self.data.midi_port_index = self.data.midi_port_index + 1
|
self.data.midi_port_index = self.data.midi_port_index + 1
|
||||||
@@ -591,8 +591,9 @@ class Actions(object):
|
|||||||
|
|
||||||
def check_if_should_start_openframeworks(self):
|
def check_if_should_start_openframeworks(self):
|
||||||
if self.data.settings['video']['VIDEOPLAYER_BACKEND']['value'] != 'omxplayer':
|
if self.data.settings['video']['VIDEOPLAYER_BACKEND']['value'] != 'omxplayer':
|
||||||
self.openframeworks_process = subprocess.Popen([self.data.PATH_TO_OPENFRAMEWORKS +'apps/myApps/c_o_n_j_u_r/bin/c_o_n_j_u_r'])
|
with open("conjur.log","w+") as out:
|
||||||
print('conjur pid is {}'.format(self.openframeworks_process.pid))
|
self.openframeworks_process = subprocess.Popen([self.data.PATH_TO_OPENFRAMEWORKS +'apps/myApps/c_o_n_j_u_r/bin/c_o_n_j_u_r'], stdout=out)
|
||||||
|
print('conjur pid is {}'.format(self.openframeworks_process.pid))
|
||||||
|
|
||||||
def exit_openframeworks(self):
|
def exit_openframeworks(self):
|
||||||
self.video_driver.osc_client.send_message("/exit", True)
|
self.video_driver.osc_client.send_message("/exit", True)
|
||||||
@@ -736,13 +737,13 @@ class Actions(object):
|
|||||||
options = self.data.settings['shader']['SHADER_PARAM']['options']
|
options = self.data.settings['shader']['SHADER_PARAM']['options']
|
||||||
current_index = [index for index, item in enumerate(options) if item == self.data.settings['shader']['SHADER_PARAM']['value'] ][0]
|
current_index = [index for index, item in enumerate(options) if item == self.data.settings['shader']['SHADER_PARAM']['value'] ][0]
|
||||||
self.data.settings['shader']['SHADER_PARAM']['value'] = options[(current_index + 1) % len(options) ]
|
self.data.settings['shader']['SHADER_PARAM']['value'] = options[(current_index + 1) % len(options) ]
|
||||||
self.message_handler.set_message('INFO', 'The Param amountis now ' + str(self.data.settings['shader']['SHADER_PARAM']['value']))
|
self.message_handler.set_message('INFO', 'The Param amount is now ' + str(self.data.settings['shader']['SHADER_PARAM']['value']))
|
||||||
|
|
||||||
def decrease_shader_param(self):
|
def decrease_shader_param(self):
|
||||||
options = self.data.settings['shader']['SHADER_PARAM']['options']
|
options = self.data.settings['shader']['SHADER_PARAM']['options']
|
||||||
current_index = [index for index, item in enumerate(options) if item == self.data.settings['shader']['SHADER_PARAM']['value'] ][0]
|
current_index = [index for index, item in enumerate(options) if item == self.data.settings['shader']['SHADER_PARAM']['value'] ][0]
|
||||||
self.data.settings['shader']['SHADER_PARAM']['value'] = options[(current_index - 1) % len(options) ]
|
self.data.settings['shader']['SHADER_PARAM']['value'] = options[(current_index - 1) % len(options) ]
|
||||||
self.message_handler.set_message('INFO', 'The Param amountis now ' + str(self.data.settings['shader']['SHADER_PARAM']['value']))
|
self.message_handler.set_message('INFO', 'The Param amount is now ' + str(self.data.settings['shader']['SHADER_PARAM']['value']))
|
||||||
|
|
||||||
|
|
||||||
def set_fixed_length(self, value):
|
def set_fixed_length(self, value):
|
||||||
@@ -893,6 +894,9 @@ class Actions(object):
|
|||||||
def clear_message(self):
|
def clear_message(self):
|
||||||
self.message_handler.clear_all_messages()
|
self.message_handler.clear_all_messages()
|
||||||
|
|
||||||
|
def modulate_param_layer_offset_to_amount(self, param, layer, amount):
|
||||||
|
self.shaders.modulate_param_layer_offset_to_amount(param, amount, layer_offset=layer)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def try_remove_file(path):
|
def try_remove_file(path):
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
@@ -907,7 +911,7 @@ class Actions(object):
|
|||||||
( r"toggle_shader_layer_([0-2])", self.toggle_shader_layer ),
|
( r"toggle_shader_layer_([0-2])", self.toggle_shader_layer ),
|
||||||
( r"start_shader_layer_([0-2])", self.shaders.start_shader ),
|
( r"start_shader_layer_([0-2])", self.shaders.start_shader ),
|
||||||
( r"stop_shader_layer_([0-2])", self.shaders.stop_shader ),
|
( r"stop_shader_layer_([0-2])", self.shaders.stop_shader ),
|
||||||
( r"set_the_shader_param_([0-3])_layer_([0-2])_continuous", self.shaders.set_param_layer_to_amount ),
|
( r"set_the_shader_param_([0-3])_layer_([0-2])_continuous", self.shaders.set_param_layer_to_amount ),
|
||||||
( r"modulate_param_([0-3])_to_amount_continuous", self.shaders.modulate_param_to_amount ),
|
( r"modulate_param_([0-3])_to_amount_continuous", self.shaders.modulate_param_to_amount ),
|
||||||
( r"set_param_([0-3])_layer_([0-2])_modulation_level_continuous", self.shaders.set_param_layer_offset_modulation_level ),
|
( r"set_param_([0-3])_layer_([0-2])_modulation_level_continuous", self.shaders.set_param_layer_offset_modulation_level ),
|
||||||
( r"set_param_([0-3])_layer_offset_([0-2])_modulation_level_continuous", self.shaders.set_param_layer_offset_modulation_level ),
|
( r"set_param_([0-3])_layer_offset_([0-2])_modulation_level_continuous", self.shaders.set_param_layer_offset_modulation_level ),
|
||||||
@@ -915,7 +919,7 @@ class Actions(object):
|
|||||||
( r"reset_modulation_([0-3])", self.shaders.reset_modulation ),
|
( r"reset_modulation_([0-3])", self.shaders.reset_modulation ),
|
||||||
( r"select_shader_modulation_slot_([0-3])", self.shaders.select_shader_modulation_slot ),
|
( r"select_shader_modulation_slot_([0-3])", self.shaders.select_shader_modulation_slot ),
|
||||||
( r"set_shader_speed_layer_offset_([0-2])_amount", self.shaders.set_speed_offset_to_amount ),
|
( r"set_shader_speed_layer_offset_([0-2])_amount", self.shaders.set_speed_offset_to_amount ),
|
||||||
( r"set_shader_speed_layer_([0-2])_amount", self.shaders.set_speed_layer_to_amount ),
|
( r"set_shader_speed_layer_([0-2])_amount", self.shaders.set_speed_layer_to_amount ),
|
||||||
}
|
}
|
||||||
|
|
||||||
def detect_types(self, args):
|
def detect_types(self, args):
|
||||||
@@ -951,6 +955,16 @@ class Actions(object):
|
|||||||
|
|
||||||
|
|
||||||
def call_parse_method_name(self, method_name, argument):
|
def call_parse_method_name(self, method_name, argument):
|
||||||
|
# first test if a registered plugin handles this for us
|
||||||
|
from data_centre.plugin_collection import ActionsPlugin
|
||||||
|
for plugin in self.data.plugins.get_plugins(ActionsPlugin):
|
||||||
|
if plugin.is_handled(method_name):
|
||||||
|
print ("Plugin %s is handling %s" % (plugin, method_name))
|
||||||
|
method, arguments = plugin.get_callback_for_method(method_name, argument)
|
||||||
|
method(*arguments)
|
||||||
|
return
|
||||||
|
|
||||||
|
# if not then fall back to using internal method
|
||||||
try:
|
try:
|
||||||
method, arguments = self.get_callback_for_method(method_name, argument)
|
method, arguments = self.get_callback_for_method(method_name, argument)
|
||||||
method(*arguments)
|
method(*arguments)
|
||||||
|
|||||||
@@ -7,6 +7,24 @@ import inspect
|
|||||||
from itertools import cycle
|
from itertools import cycle
|
||||||
from omxplayer.player import OMXPlayer
|
from omxplayer.player import OMXPlayer
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
|
import threading
|
||||||
|
|
||||||
|
from data_centre import plugin_collection
|
||||||
|
|
||||||
|
class AsyncWrite(threading.Thread):
|
||||||
|
def __init__(self, filename, data, mode='json'):
|
||||||
|
threading.Thread.__init__(self)
|
||||||
|
self.filename = filename
|
||||||
|
self.data = data
|
||||||
|
self.mode = mode
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
with open(self.filename, "w+") as data_file:
|
||||||
|
if self.mode=='json':
|
||||||
|
json.dump(self.data, data_file, indent=4, sort_keys=True)
|
||||||
|
else:
|
||||||
|
data_file.write(self.data)
|
||||||
|
data_file.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -33,6 +51,11 @@ class Data(object):
|
|||||||
#self.EMPTY_BANK = [self.EMPTY_SLOT for i in range(10)]
|
#self.EMPTY_BANK = [self.EMPTY_SLOT for i in range(10)]
|
||||||
self.PATHS_TO_BROWSER = [self.PATH_TO_EXTERNAL_DEVICES, '/home/pi/Videos' ]
|
self.PATHS_TO_BROWSER = [self.PATH_TO_EXTERNAL_DEVICES, '/home/pi/Videos' ]
|
||||||
self.PATHS_TO_SHADERS = [self.PATH_TO_EXTERNAL_DEVICES, '/home/pi/r_e_c_u_r/Shaders', '/home/pi/Shaders' ]
|
self.PATHS_TO_SHADERS = [self.PATH_TO_EXTERNAL_DEVICES, '/home/pi/r_e_c_u_r/Shaders', '/home/pi/Shaders' ]
|
||||||
|
self.PATHS_TO_PLUGIN_DATA = [ '/home/pi/r_e_c_u_r/json_objects/plugins', self.PATH_TO_EXTERNAL_DEVICES ]
|
||||||
|
|
||||||
|
#initialise plugin manager
|
||||||
|
self.plugins = plugin_collection.PluginCollection("plugins", message_handler, self)
|
||||||
|
self.plugins.apply_all_plugins_on_value(5)
|
||||||
|
|
||||||
### state data
|
### state data
|
||||||
self.auto_repeat_on = True
|
self.auto_repeat_on = True
|
||||||
@@ -78,7 +101,17 @@ class Data(object):
|
|||||||
self.midi_mappings = self._read_json(self.MIDI_MAPPING_JSON)
|
self.midi_mappings = self._read_json(self.MIDI_MAPPING_JSON)
|
||||||
self.analog_mappings = self._read_json(self.ANALOG_MAPPING_JSON)
|
self.analog_mappings = self._read_json(self.ANALOG_MAPPING_JSON)
|
||||||
|
|
||||||
|
def load_midi_mapping_for_device(self, device_name):
|
||||||
|
# check if custom config file exists on disk for this device name
|
||||||
|
custom_file = self.MIDI_MAPPING_JSON.replace(".json","_%s.json"%device_name)
|
||||||
|
if os.path.isfile(self.PATH_TO_DATA_OBJECTS + custom_file):
|
||||||
|
self.midi_mappings = self._read_json(custom_file)
|
||||||
|
self.message_handler.set_message('INFO', "Loaded %s for %s" % (custom_file, device_name)) #the slot you pressed is empty')
|
||||||
|
print ("loaded custom midi mapping for %s" % custom_file)
|
||||||
|
else:
|
||||||
|
print ("loading default midi mapping for %s" % (device_name))
|
||||||
|
self.midi_mappings = self._read_json(self.MIDI_MAPPINGS_JSON)
|
||||||
|
return self.midi_mappings
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -100,6 +133,23 @@ class Data(object):
|
|||||||
with open('{}{}'.format(self.PATH_TO_DATA_OBJECTS, file_name), 'w') as data_file:
|
with open('{}{}'.format(self.PATH_TO_DATA_OBJECTS, file_name), 'w') as data_file:
|
||||||
json.dump(data, data_file, indent=4, sort_keys=True)
|
json.dump(data, data_file, indent=4, sort_keys=True)
|
||||||
|
|
||||||
|
def _read_plugin_json(self, file_name):
|
||||||
|
for path in self.PATHS_TO_PLUGIN_DATA:
|
||||||
|
print("trying path %s"%path)
|
||||||
|
try:
|
||||||
|
with open("%s/%s" % (path,file_name)) as data_file:
|
||||||
|
data = json.load(data_file)
|
||||||
|
return data
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
print ("no plugin data loaded for %s" % file_name)
|
||||||
|
|
||||||
|
def _update_plugin_json(self, file_name, data):
|
||||||
|
#with open("%s/%s" % (self.PATHS_TO_PLUGIN_DATA[0], file_name), "w+") as data_file:
|
||||||
|
# json.dump(data, data_file, indent=4, sort_keys=True)
|
||||||
|
writer = AsyncWrite("%s/%s" % (self.PATHS_TO_PLUGIN_DATA[0], file_name), data, mode='json')
|
||||||
|
writer.start()
|
||||||
|
|
||||||
def update_conjur_dev_mode(self, value):
|
def update_conjur_dev_mode(self, value):
|
||||||
print(value)
|
print(value)
|
||||||
tree = ET.parse(self.PATH_TO_CONJUR_DATA)
|
tree = ET.parse(self.PATH_TO_CONJUR_DATA)
|
||||||
|
|||||||
270
data_centre/plugin_collection.py
Normal file
270
data_centre/plugin_collection.py
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
import inspect
|
||||||
|
import os
|
||||||
|
import pkgutil
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin(object):
|
||||||
|
"""Base class that each plugin must inherit from. within this class
|
||||||
|
you must define the methods that all of your plugins must implement
|
||||||
|
"""
|
||||||
|
disabled = False
|
||||||
|
|
||||||
|
def __init__(self, plugin_collection):
|
||||||
|
self.description = 'UNKNOWN'
|
||||||
|
self.pc = plugin_collection
|
||||||
|
|
||||||
|
class MidiFeedbackPlugin(Plugin):
|
||||||
|
"""Base class for MIDI feedback plugins
|
||||||
|
"""
|
||||||
|
def __init__(self, plugin_collection):
|
||||||
|
super().__init__(plugin_collection)
|
||||||
|
self.description = 'Outputs feedback about status to device eg MIDI pads'
|
||||||
|
|
||||||
|
def supports_midi_feedback(self, device_name):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def set_midi_device(self, midi_device):
|
||||||
|
self.midi_feedback_device = midi_device
|
||||||
|
|
||||||
|
def refresh_midi_feedback(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class SequencePlugin(Plugin):
|
||||||
|
def __init__(self, plugin_collection):
|
||||||
|
super().__init__(plugin_collection)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parserlist(self):
|
||||||
|
return [
|
||||||
|
( r"run_automation", self.run_automation ),
|
||||||
|
( r"stop_automation", self.stop_automation ),
|
||||||
|
( r"toggle_pause_automation", self.toggle_pause_automation ),
|
||||||
|
( r"pause_automation", self.pause_automation ),
|
||||||
|
( r"toggle_loop_automation", self.toggle_loop_automation ),
|
||||||
|
]
|
||||||
|
|
||||||
|
def position(self, now):
|
||||||
|
import time
|
||||||
|
passed = now - self.automation_start
|
||||||
|
if self.duration>0:
|
||||||
|
position = passed / self.duration*1000
|
||||||
|
return position
|
||||||
|
|
||||||
|
def toggle_automation(self):
|
||||||
|
if not self.is_playing():
|
||||||
|
self.run_automation()
|
||||||
|
else:
|
||||||
|
self.stop_automation()
|
||||||
|
|
||||||
|
def toggle_loop_automation(self):
|
||||||
|
self.looping = not self.looping
|
||||||
|
|
||||||
|
def pause_automation(self):
|
||||||
|
self.pause_flag = not self.is_paused() and self.is_playing()
|
||||||
|
|
||||||
|
def stop_automation(self):
|
||||||
|
self.stop_flag = True
|
||||||
|
|
||||||
|
def toggle_pause_automation(self):
|
||||||
|
self.pause_flag = not self.is_paused()
|
||||||
|
self.pause_flag = self.is_paused() and self.is_playing()
|
||||||
|
if not self.is_paused() and not self.is_playing():
|
||||||
|
self.run_automation()
|
||||||
|
|
||||||
|
store_passed = None
|
||||||
|
pause_flag = True
|
||||||
|
stop_flag = False
|
||||||
|
looping = True
|
||||||
|
automation_start = None
|
||||||
|
iterations_count = 0
|
||||||
|
duration = 2000
|
||||||
|
frequency = 100
|
||||||
|
def run_automation(self):
|
||||||
|
import time
|
||||||
|
|
||||||
|
now = time.time()
|
||||||
|
|
||||||
|
if self.looping and self.automation_start is not None and (now - self.automation_start >= self.duration/1000):
|
||||||
|
print("restarting as start reached %s" % self.automation_start)
|
||||||
|
self.iterations_count += 1
|
||||||
|
self.automation_start = None
|
||||||
|
|
||||||
|
if not self.automation_start:
|
||||||
|
self.automation_start = now
|
||||||
|
print ("%s: starting automation" % self.automation_start)
|
||||||
|
self.pause_flag = False
|
||||||
|
|
||||||
|
#print("running automation at %s!" % self.position)
|
||||||
|
if not self.is_paused():
|
||||||
|
self.store_passed = None
|
||||||
|
self.run_sequence(self.position(now))
|
||||||
|
#print ("%s: automation_start is %s" % (time.time()-self.automation_start,self.automation_start))
|
||||||
|
else:
|
||||||
|
#print ("%s: about to reset automation_start" % self.automation_start)
|
||||||
|
#print (" got passed %s" % (time.time() - self.automation_start))
|
||||||
|
if not self.store_passed:
|
||||||
|
self.store_passed = (now - self.automation_start)
|
||||||
|
self.automation_start = now - self.store_passed
|
||||||
|
#print ("%s: reset automation_start to %s" % (time.time()-self.automation_start,self.automation_start))
|
||||||
|
#return
|
||||||
|
|
||||||
|
if (now - self.automation_start < self.duration/1000) and not self.stop_flag:
|
||||||
|
self.pc.midi_input.root.after(self.frequency, self.run_automation)
|
||||||
|
else:
|
||||||
|
print("%s: stopping ! (stop_flag %s)" % ((now - self.automation_start),self.stop_flag) )
|
||||||
|
self.stop_flag = False
|
||||||
|
self.automation_start = None
|
||||||
|
self.iterations_count = 0
|
||||||
|
|
||||||
|
def is_paused(self):
|
||||||
|
return self.pause_flag
|
||||||
|
|
||||||
|
def is_playing(self):
|
||||||
|
return self.automation_start is not None
|
||||||
|
|
||||||
|
def run_sequence(self, position):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
class ActionsPlugin(Plugin):
|
||||||
|
def __init__(self, plugin_collection):
|
||||||
|
super().__init__(plugin_collection)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parserlist(self):
|
||||||
|
return [
|
||||||
|
#( r"test_plugin", self.test_plugin )
|
||||||
|
]
|
||||||
|
|
||||||
|
def is_handled(self, method_name):
|
||||||
|
for a in self.parserlist:
|
||||||
|
if (a[0]==method_name):
|
||||||
|
return True
|
||||||
|
regex = a[0]
|
||||||
|
me = a[1]
|
||||||
|
matches = re.match(regex, method_name)
|
||||||
|
if matches:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_callback_for_method(self, method_name, argument):
|
||||||
|
for a in self.parserlist:
|
||||||
|
regex = a[0]
|
||||||
|
me = a[1]
|
||||||
|
matches = re.search(regex, method_name)
|
||||||
|
|
||||||
|
if matches:
|
||||||
|
found_method = me
|
||||||
|
parsed_args = self.pc.actions.detect_types(matches.groups())
|
||||||
|
if argument is not None:
|
||||||
|
args = parsed_args + [argument]
|
||||||
|
else:
|
||||||
|
args = parsed_args
|
||||||
|
|
||||||
|
return (found_method, args)
|
||||||
|
|
||||||
|
#def call_parse_method_name(self, method_name, argument):
|
||||||
|
# method, arguments = self.actions.get_callback_for_method(method_name, argument)
|
||||||
|
# method(*arguments)
|
||||||
|
|
||||||
|
|
||||||
|
# adapted from https://github.com/gdiepen/python_plugin_example
|
||||||
|
class PluginCollection(object):
|
||||||
|
"""Upon creation, this class will read the plugins package for modules
|
||||||
|
that contain a class definition that is inheriting from the Plugin class
|
||||||
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def shaders(self):
|
||||||
|
return self.message_handler.shaders
|
||||||
|
|
||||||
|
@property
|
||||||
|
def actions(self):
|
||||||
|
return self.message_handler.actions
|
||||||
|
|
||||||
|
"""@property
|
||||||
|
def midi_input(self):
|
||||||
|
return self.data.midi_input"""
|
||||||
|
|
||||||
|
def __init__(self, plugin_package, message_handler, data):
|
||||||
|
"""Constructor that initiates the reading of all available plugins
|
||||||
|
when an instance of the PluginCollection object is created
|
||||||
|
"""
|
||||||
|
self.plugin_package = plugin_package
|
||||||
|
self.message_handler = message_handler
|
||||||
|
#self.shaders = lambda: data.shaders
|
||||||
|
self.data = data
|
||||||
|
#self.actions = message_handler.actions
|
||||||
|
self.reload_plugins()
|
||||||
|
|
||||||
|
def read_json(self, file_name):
|
||||||
|
return self.data._read_plugin_json(file_name)
|
||||||
|
def update_json(self, file_name, data):
|
||||||
|
return self.data._update_plugin_json(file_name, data)
|
||||||
|
|
||||||
|
def reload_plugins(self):
|
||||||
|
"""Reset the list of all plugins and initiate the walk over the main
|
||||||
|
provided plugin package to load all available plugins
|
||||||
|
"""
|
||||||
|
self.plugins = []
|
||||||
|
self.seen_paths = []
|
||||||
|
print()
|
||||||
|
print("Looking for plugins under package %s" % self.plugin_package)
|
||||||
|
self.walk_package(self.plugin_package)
|
||||||
|
|
||||||
|
|
||||||
|
def get_plugins(self, clazz = None):
|
||||||
|
if clazz:
|
||||||
|
return [c for c in self.plugins if (isinstance(c, clazz) and not c.disabled)]
|
||||||
|
else:
|
||||||
|
return [c for c in self.plugins if not c.disabled]
|
||||||
|
|
||||||
|
def apply_all_plugins_on_value(self, argument):
|
||||||
|
"""Apply all of the plugins on the argument supplied to this function
|
||||||
|
"""
|
||||||
|
print()
|
||||||
|
print('Applying all plugins on value %s:' %argument)
|
||||||
|
for plugin in self.plugins:
|
||||||
|
#print(" Applying %s on value %s yields value %s" % (plugin.description, argument, plugin.perform_operation(argument)))
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def walk_package(self, package):
|
||||||
|
"""Recursively walk the supplied package to retrieve all plugins
|
||||||
|
"""
|
||||||
|
imported_package = __import__(package, fromlist=['blah'])
|
||||||
|
|
||||||
|
for _, pluginname, ispkg in pkgutil.iter_modules(imported_package.__path__, imported_package.__name__ + '.'):
|
||||||
|
if not ispkg:
|
||||||
|
plugin_module = __import__(pluginname, fromlist=['blah'])
|
||||||
|
clsmembers = inspect.getmembers(plugin_module, inspect.isclass)
|
||||||
|
for (_, c) in clsmembers:
|
||||||
|
# Only add classes that are a sub class of Plugin, but NOT Plugin itself
|
||||||
|
# or one of the base classes
|
||||||
|
ignore_list = [ Plugin, ActionsPlugin, SequencePlugin, MidiFeedbackPlugin ]
|
||||||
|
if issubclass(c, Plugin) & (c not in ignore_list):
|
||||||
|
print(' Found plugin class: %s.%s' % (c.__module__,c.__name__))
|
||||||
|
self.plugins.append(c(self))
|
||||||
|
|
||||||
|
|
||||||
|
# Now that we have looked at all the modules in the current package, start looking
|
||||||
|
# recursively for additional modules in sub packages
|
||||||
|
all_current_paths = []
|
||||||
|
if isinstance(imported_package.__path__, str):
|
||||||
|
all_current_paths.append(imported_package.__path__)
|
||||||
|
else:
|
||||||
|
all_current_paths.extend([x for x in imported_package.__path__])
|
||||||
|
|
||||||
|
for pkg_path in all_current_paths:
|
||||||
|
if pkg_path not in self.seen_paths:
|
||||||
|
self.seen_paths.append(pkg_path)
|
||||||
|
|
||||||
|
# Get all sub directory of the current package path directory
|
||||||
|
child_pkgs = [p for p in os.listdir(pkg_path) if os.path.isdir(os.path.join(pkg_path, p))]
|
||||||
|
|
||||||
|
# For each sub directory, apply the walk_package method recursively
|
||||||
|
for child_pkg in child_pkgs:
|
||||||
|
self.walk_package(package + '.' + child_pkg)
|
||||||
@@ -11,10 +11,14 @@ grep " def " actions.py | grep -v "^#" | sed -e 's/ def //' | sed -e 's/self//'
|
|||||||
| grep -v "parserlist\|check_if_should_start_openframeworks\|create_serial_port_process\|__init__\|persist_composite_setting\|receive_detour_info\|_refresh_frame_buffer\|refresh_frame_buffer_and_restart_openframeworks\|run_script\|setup_osc_server\|start_confirm_action\|stop_serial_port_process\|stop_openframeworks_process\|update_capture_settings\|update_config_settings\|update_video_settings\|try_remove_file\|get_callback\|call_method_name\|call_parse_method\|detect_types"
|
| grep -v "parserlist\|check_if_should_start_openframeworks\|create_serial_port_process\|__init__\|persist_composite_setting\|receive_detour_info\|_refresh_frame_buffer\|refresh_frame_buffer_and_restart_openframeworks\|run_script\|setup_osc_server\|start_confirm_action\|stop_serial_port_process\|stop_openframeworks_process\|update_capture_settings\|update_config_settings\|update_video_settings\|try_remove_file\|get_callback\|call_method_name\|call_parse_method\|detect_types"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
echo "# Dynamic routes"
|
echo "## Dynamic routes"
|
||||||
grep '( r"' actions.py | sed -e 's/\(.*\)"\(.*\)"\(.*\)/ * \2/'
|
grep '( r"' actions.py | sed -e 's/\(.*\)"\(.*\)"\(.*\)/ * \2/'
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
echo "### Plugin routes"
|
||||||
|
grep "( r\"" plugins/*.py | sed -e 's/plugins\/\(.*\)\.py:\(.*\)\( r\"\)\(.*\)\"\(.*\)/ * \4\t(from \1)/' | grep -v "open_serial"
|
||||||
|
echo
|
||||||
|
|
||||||
echo "----"
|
echo "----"
|
||||||
echo
|
echo
|
||||||
echo "Autogenerated by dotfiles/generate-list-actions.sh"
|
echo "Autogenerated by dotfiles/generate-list-actions.sh"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"control_change 0": {
|
"control_change 0": {
|
||||||
"DEFAULT": ["set_the_shader_param_0_layer_offset_0_continuous"],
|
"DEFAULT": ["set_the_shader_param_0_layer_offset_0_continuous","set_strobe_amount_continuous"],
|
||||||
"NAV_DETOUR": ["set_detour_mix_continuous"]
|
"NAV_DETOUR": ["set_detour_mix_continuous"]
|
||||||
},
|
},
|
||||||
"control_change 1": {
|
"control_change 1": {
|
||||||
|
|||||||
266
json_objects/midi_action_mapping_APC Key 25.json
Normal file
266
json_objects/midi_action_mapping_APC Key 25.json
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
{
|
||||||
|
"control_change 0": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_0_layer_offset_0_continuous"],
|
||||||
|
"NAV_DETOUR": ["set_detour_mix_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 1": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_1_layer_offset_0_continuous"],
|
||||||
|
"NAV_DETOUR": ["set_detour_speed_position_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 2": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_2_layer_offset_0_continuous"],
|
||||||
|
"NAV_DETOUR": ["set_detour_start_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 3": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_3_layer_offset_0_continuous"],
|
||||||
|
"NAV_DETOUR": ["set_detour_end_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 4": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_0_layer_offset_1_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 5": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_1_layer_offset_1_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 6": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_2_layer_offset_1_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 7": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_3_layer_offset_1_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 8": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_0_layer_offset_2_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 9": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_1_layer_offset_2_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 10": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_2_layer_offset_2_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 11": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_3_layer_offset_2_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 48": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_0_layer_offset_0_continuous","set_strobe_amount_continuous"],
|
||||||
|
"NAV_DETOUR": ["set_detour_speed_position_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 49": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_1_layer_offset_0_continuous","set_shader_speed_layer_0_amount"],
|
||||||
|
"NAV_DETOUR": ["set_detour_start_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 50": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_2_layer_offset_0_continuous","set_shader_speed_layer_1_amount"],
|
||||||
|
"NAV_DETOUR": ["set_detour_end_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 51": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_3_layer_offset_0_continuous","set_shader_speed_layer_2_amount"],
|
||||||
|
"NAV_DETOUR": ["set_detour_end_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 52": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_0_layer_offset_1_continuous","set_param_0_layer_offset_0_modulation_level_continuous"],
|
||||||
|
"NAV_DETOUR": ["set_detour_speed_position_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 53": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_1_layer_offset_1_continuous","set_param_1_layer_offset_0_modulation_level_continuous"],
|
||||||
|
"NAV_DETOUR": ["set_detour_start_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 54": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_2_layer_offset_1_continuous","set_param_2_layer_offset_0_modulation_level_continuous"],
|
||||||
|
"NAV_DETOUR": ["set_detour_end_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 55": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_3_layer_offset_1_continuous","set_param_3_layer_offset_0_modulation_level_continuous"],
|
||||||
|
"NAV_DETOUR": ["set_detour_end_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 56": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_0_layer_offset_2_continuous"],
|
||||||
|
"NAV_DETOUR": ["set_detour_speed_position_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 57": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_1_layer_offset_2_continuous"],
|
||||||
|
"NAV_DETOUR": ["set_detour_start_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 58": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_2_layer_offset_2_continuous"],
|
||||||
|
"NAV_DETOUR": ["set_detour_end_continuous"]
|
||||||
|
},
|
||||||
|
"control_change 59": {
|
||||||
|
"DEFAULT": ["set_the_shader_param_3_layer_offset_2_continuous"],
|
||||||
|
"NAV_DETOUR": ["set_detour_end_continuous"]
|
||||||
|
},
|
||||||
|
"note_on 64": {
|
||||||
|
"DEFAULT": ["clear_automation"]
|
||||||
|
},
|
||||||
|
"note_on 65": {
|
||||||
|
"DEFAULT": ["toggle_pause_automation"]
|
||||||
|
},
|
||||||
|
"note_on 66": {
|
||||||
|
"DEFAULT": ["toggle_record_automation"]
|
||||||
|
},
|
||||||
|
"note_on 67": {
|
||||||
|
"DEFAULT": ["toggle_overdub_automation"]
|
||||||
|
},
|
||||||
|
"note_on 68": {
|
||||||
|
"DEFAULT": ["store_next_preset"]
|
||||||
|
},
|
||||||
|
"note_on 69": {
|
||||||
|
"DEFAULT": ["store_current_preset","clear_current_preset"]
|
||||||
|
},
|
||||||
|
"note_on 0": {
|
||||||
|
"DEFAULT": ["switch_to_preset_0","select_preset_0"]
|
||||||
|
},
|
||||||
|
"note_on 1": {
|
||||||
|
"DEFAULT": ["switch_to_preset_1","select_preset_1"]
|
||||||
|
},
|
||||||
|
"note_on 2": {
|
||||||
|
"DEFAULT": ["switch_to_preset_2","select_preset_2"]
|
||||||
|
},
|
||||||
|
"note_on 3": {
|
||||||
|
"DEFAULT": ["switch_to_preset_3","select_preset_3"]
|
||||||
|
},
|
||||||
|
"note_on 4": {
|
||||||
|
"DEFAULT": ["switch_to_preset_4","select_preset_4"]
|
||||||
|
},
|
||||||
|
"note_on 5": {
|
||||||
|
"DEFAULT": ["switch_to_preset_5","select_preset_5"]
|
||||||
|
},
|
||||||
|
"note_on 6": {
|
||||||
|
"DEFAULT": ["switch_to_preset_6","select_preset_6"]
|
||||||
|
},
|
||||||
|
"note_on 7": {
|
||||||
|
"DEFAULT": ["switch_to_preset_7","select_preset_7"]
|
||||||
|
},
|
||||||
|
"note_on 81": {
|
||||||
|
"DEFAULT": ["","reset_selected_modulation"]
|
||||||
|
},
|
||||||
|
"note_on 82": {
|
||||||
|
"DEFAULT": ["toggle_shader_layer_0","select_shader_modulation_slot_0"]
|
||||||
|
},
|
||||||
|
"note_on 83": {
|
||||||
|
"DEFAULT": ["toggle_shader_layer_1","select_shader_modulation_slot_1"]
|
||||||
|
},
|
||||||
|
"note_on 84": {
|
||||||
|
"DEFAULT": ["toggle_shader_layer_2","select_shader_modulation_slot_2"]
|
||||||
|
},
|
||||||
|
"note_on 85": {
|
||||||
|
"DEFAULT": ["toggle_feedback","select_shader_modulation_slot_3"]
|
||||||
|
},
|
||||||
|
"note_on 86": {
|
||||||
|
"DEFAULT": ["toggle_capture_preview"]
|
||||||
|
},
|
||||||
|
"note_on 70": {
|
||||||
|
"DEFAULT": ["previous_shader_layer"]
|
||||||
|
},
|
||||||
|
"note_on 71": {
|
||||||
|
"DEFAULT": ["next_shader_layer"]
|
||||||
|
},
|
||||||
|
"note_on 8": {
|
||||||
|
"DEFAULT": ["toggle_automation_clip_0","select_automation_clip_0"]
|
||||||
|
},
|
||||||
|
"note_on 9": {
|
||||||
|
"DEFAULT": ["toggle_automation_clip_1","select_automation_clip_1"]
|
||||||
|
},
|
||||||
|
"note_on 10": {
|
||||||
|
"DEFAULT": ["toggle_automation_clip_2","select_automation_clip_2"]
|
||||||
|
},
|
||||||
|
"note_on 11": {
|
||||||
|
"DEFAULT": ["toggle_automation_clip_3","select_automation_clip_3"]
|
||||||
|
},
|
||||||
|
"note_on 12": {
|
||||||
|
"DEFAULT": ["toggle_automation_clip_4","select_automation_clip_4"]
|
||||||
|
},
|
||||||
|
"note_on 13": {
|
||||||
|
"DEFAULT": ["toggle_automation_clip_5","select_automation_clip_5"]
|
||||||
|
},
|
||||||
|
"note_on 14": {
|
||||||
|
"DEFAULT": ["toggle_automation_clip_6","select_automation_clip_6"]
|
||||||
|
},
|
||||||
|
"note_on 15": {
|
||||||
|
"DEFAULT": ["toggle_automation_clip_7","select_automation_clip_7"]
|
||||||
|
},
|
||||||
|
|
||||||
|
"note_on 32": {
|
||||||
|
"DEFAULT": ["play_shader_0_0"]
|
||||||
|
},
|
||||||
|
"note_on 33": {
|
||||||
|
"DEFAULT": ["play_shader_0_1"]
|
||||||
|
},
|
||||||
|
"note_on 34": {
|
||||||
|
"DEFAULT": ["play_shader_0_2"]
|
||||||
|
},
|
||||||
|
"note_on 35": {
|
||||||
|
"DEFAULT": ["play_shader_0_3"]
|
||||||
|
},
|
||||||
|
"note_on 36": {
|
||||||
|
"DEFAULT": ["play_shader_0_4"]
|
||||||
|
},
|
||||||
|
"note_on 37": {
|
||||||
|
"DEFAULT": ["play_shader_0_5"]
|
||||||
|
},
|
||||||
|
"note_on 38": {
|
||||||
|
"DEFAULT": ["play_shader_0_6"]
|
||||||
|
},
|
||||||
|
"note_on 39": {
|
||||||
|
"DEFAULT": ["play_shader_0_7"]
|
||||||
|
},
|
||||||
|
"note_on 24": {
|
||||||
|
"DEFAULT": ["play_shader_1_0"]
|
||||||
|
},
|
||||||
|
"note_on 25": {
|
||||||
|
"DEFAULT": ["play_shader_1_1"]
|
||||||
|
},
|
||||||
|
"note_on 26": {
|
||||||
|
"DEFAULT": ["play_shader_1_2"]
|
||||||
|
},
|
||||||
|
"note_on 27": {
|
||||||
|
"DEFAULT": ["play_shader_1_3"]
|
||||||
|
},
|
||||||
|
"note_on 28": {
|
||||||
|
"DEFAULT": ["play_shader_1_4"]
|
||||||
|
},
|
||||||
|
"note_on 29": {
|
||||||
|
"DEFAULT": ["play_shader_1_5"]
|
||||||
|
},
|
||||||
|
"note_on 30": {
|
||||||
|
"DEFAULT": ["play_shader_1_6"]
|
||||||
|
},
|
||||||
|
"note_on 31": {
|
||||||
|
"DEFAULT": ["play_shader_1_7"]
|
||||||
|
},
|
||||||
|
"note_on 16": {
|
||||||
|
"DEFAULT": ["play_shader_2_0"]
|
||||||
|
},
|
||||||
|
"note_on 17": {
|
||||||
|
"DEFAULT": ["play_shader_2_1"]
|
||||||
|
},
|
||||||
|
"note_on 18": {
|
||||||
|
"DEFAULT": ["play_shader_2_2"]
|
||||||
|
},
|
||||||
|
"note_on 19": {
|
||||||
|
"DEFAULT": ["play_shader_2_3"]
|
||||||
|
},
|
||||||
|
"note_on 20": {
|
||||||
|
"DEFAULT": ["play_shader_2_4"]
|
||||||
|
},
|
||||||
|
"note_on 21": {
|
||||||
|
"DEFAULT": ["play_shader_2_5"]
|
||||||
|
},
|
||||||
|
"note_on 22": {
|
||||||
|
"DEFAULT": ["play_shader_2_6"]
|
||||||
|
},
|
||||||
|
"note_on 23": {
|
||||||
|
"DEFAULT": ["play_shader_2_7"]
|
||||||
|
},
|
||||||
|
"note_on 98": {
|
||||||
|
"DEFAULT": ["function_on"]
|
||||||
|
},
|
||||||
|
"note_off 98": {
|
||||||
|
"DEFAULT": ["function_off"]
|
||||||
|
},
|
||||||
|
"note_on 91": {
|
||||||
|
"DEFAULT": ["send_serial_macro_0","send_serial_macro_1"]
|
||||||
|
},
|
||||||
|
"note_on 93": {
|
||||||
|
"DEFAULT": ["send_serial_string_hellO","send_random_settings"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
51
plugins/MidiActionsTestPlugin.py
Normal file
51
plugins/MidiActionsTestPlugin.py
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import data_centre.plugin_collection
|
||||||
|
from data_centre.plugin_collection import ActionsPlugin, SequencePlugin
|
||||||
|
|
||||||
|
class MidiActionsTestPlugin(ActionsPlugin,SequencePlugin):
|
||||||
|
disabled = True
|
||||||
|
|
||||||
|
def __init__(self, plugin_collection):
|
||||||
|
super().__init__(plugin_collection)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parserlist(self):
|
||||||
|
return [
|
||||||
|
( r"test_plugin", self.test_plugin ),
|
||||||
|
( r"cycle_shaders", self.cycle_shaders ),
|
||||||
|
( r"run_automation", self.run_automation ),
|
||||||
|
( r"stop_automation", self.stop_automation ),
|
||||||
|
( r"toggle_pause_automation", self.toggle_pause_automation ),
|
||||||
|
( r"pause_automation", self.pause_automation ),
|
||||||
|
( r"toggle_loop_automation", self.toggle_loop_automation ),
|
||||||
|
]
|
||||||
|
|
||||||
|
def test_plugin(self):
|
||||||
|
print ("TEST PLUGIN test_plugin CALLED!!")
|
||||||
|
# can now access various parts of recur via self.pc
|
||||||
|
|
||||||
|
cycle_count = 0
|
||||||
|
def cycle_shaders(self):
|
||||||
|
print ("Cycle shaders!!!")
|
||||||
|
if self.cycle_count>9:
|
||||||
|
self.cycle_count = 0
|
||||||
|
|
||||||
|
for i,shader in enumerate(self.pc.message_handler.shaders.selected_shader_list):
|
||||||
|
self.pc.midi_input.call_method_name(
|
||||||
|
"play_shader_%s_%s" % (i, self.cycle_count), None
|
||||||
|
)
|
||||||
|
self.pc.midi_input.call_method_name(
|
||||||
|
"start_shader_layer_%s" % i, None
|
||||||
|
)
|
||||||
|
self.cycle_count += 1
|
||||||
|
|
||||||
|
duration = 5000
|
||||||
|
frequency = 50
|
||||||
|
def run_sequence(self, position):
|
||||||
|
self.pc.midi_input.call_method_name(
|
||||||
|
"set_the_shader_param_0_layer_0_continuous", position
|
||||||
|
)
|
||||||
|
|
||||||
|
self.pc.midi_input.call_method_name(
|
||||||
|
"set_the_shader_param_1_layer_0_continuous", position
|
||||||
|
)
|
||||||
|
|
||||||
202
plugins/MidiFeedbackAPCKey25Plugin.py
Normal file
202
plugins/MidiFeedbackAPCKey25Plugin.py
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
from data_centre import plugin_collection
|
||||||
|
from data_centre.plugin_collection import MidiFeedbackPlugin
|
||||||
|
import mido
|
||||||
|
|
||||||
|
class MidiFeedbackAPCKey25Plugin(MidiFeedbackPlugin):
|
||||||
|
disabled = False
|
||||||
|
|
||||||
|
status = {}
|
||||||
|
|
||||||
|
def __init__(self, plugin_collection):
|
||||||
|
super().__init__(plugin_collection)
|
||||||
|
self.description = 'Outputs feedback to APC Key 25'
|
||||||
|
|
||||||
|
def set_midi_device(self, device):
|
||||||
|
super().set_midi_device(device)
|
||||||
|
self.last_state = None
|
||||||
|
|
||||||
|
def supports_midi_feedback(self, device_name):
|
||||||
|
supported_devices = ['APC Key 25']
|
||||||
|
for supported_device in supported_devices:
|
||||||
|
if device_name.startswith(supported_device):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def set_status(self, command='note_on', note=None, velocity=None):
|
||||||
|
self.status[note] = {
|
||||||
|
'command': command,
|
||||||
|
'note': note,
|
||||||
|
'velocity': velocity
|
||||||
|
}
|
||||||
|
#print("set status to %s: %s" % (note, self.status[note]))
|
||||||
|
|
||||||
|
def send_command(self, command='note_on', note=None, velocity=None):
|
||||||
|
#print("send_command(%s, %s)" % (note, velocity))
|
||||||
|
self.midi_feedback_device.send(
|
||||||
|
mido.Message(command, note=note, velocity=velocity)
|
||||||
|
)
|
||||||
|
|
||||||
|
def feedback_shader_feedback(self, on):
|
||||||
|
self.set_status(note=85, velocity=int(on))
|
||||||
|
|
||||||
|
def feedback_capture_preview(self, on):
|
||||||
|
self.set_status(note=86, velocity=int(on))
|
||||||
|
|
||||||
|
def feedback_shader_on(self, layer, slot, colour=None):
|
||||||
|
if colour is None: colour = self.COLOUR_GREEN
|
||||||
|
self.set_status(note=(32-(layer)*8)+slot, velocity=int(colour))
|
||||||
|
|
||||||
|
def feedback_shader_off(self, layer, slot):
|
||||||
|
self.set_status(note=(32-(layer)*8)+slot, velocity=self.COLOUR_OFF)
|
||||||
|
|
||||||
|
NOTE_SCENE_LAUNCH_COLUMN = 82
|
||||||
|
def feedback_shader_layer_on(self, layer):
|
||||||
|
self.set_status(note=self.NOTE_SCENE_LAUNCH_COLUMN+layer, velocity=self.COLOUR_GREEN)
|
||||||
|
|
||||||
|
def feedback_shader_layer_off(self, layer):
|
||||||
|
self.set_status(note=self.NOTE_SCENE_LAUNCH_COLUMN+layer, velocity=self.COLOUR_OFF)
|
||||||
|
|
||||||
|
def feedback_show_layer(self, layer):
|
||||||
|
self.set_status(note=70, velocity=layer)
|
||||||
|
|
||||||
|
def feedback_show_modulation(self, slot):
|
||||||
|
for i in range(self.NOTE_SCENE_LAUNCH_COLUMN,self.NOTE_SCENE_LAUNCH_COLUMN+4):
|
||||||
|
if slot==i-self.NOTE_SCENE_LAUNCH_COLUMN:
|
||||||
|
self.set_status(note=i, velocity=self.COLOUR_GREEN)
|
||||||
|
else:
|
||||||
|
self.set_status(note=i, velocity=self.COLOUR_OFF)
|
||||||
|
|
||||||
|
def feedback_plugin_status(self):
|
||||||
|
from data_centre.plugin_collection import SequencePlugin
|
||||||
|
|
||||||
|
from plugins.MidiActionsTestPlugin import MidiActionsTestPlugin
|
||||||
|
from plugins.ShaderLoopRecordPlugin import ShaderLoopRecordPlugin
|
||||||
|
for plugin in self.pc.get_plugins(SequencePlugin):
|
||||||
|
if isinstance(plugin, ShaderLoopRecordPlugin): #MidiActionsTestPlugin):
|
||||||
|
|
||||||
|
NOTE_PLAY_STATUS = 65
|
||||||
|
NOTE_RECORD_STATUS = 66
|
||||||
|
NOTE_OVERDUB_STATUS = 67
|
||||||
|
NOTE_CLIP_STATUS_ROW = 8
|
||||||
|
|
||||||
|
colour = self.COLOUR_OFF
|
||||||
|
if plugin.is_playing():
|
||||||
|
colour = self.COLOUR_GREEN
|
||||||
|
if plugin.is_paused():
|
||||||
|
colour += self.BLINK
|
||||||
|
self.set_status(command='note_on', note=NOTE_PLAY_STATUS, velocity=colour)
|
||||||
|
|
||||||
|
colour = self.COLOUR_OFF
|
||||||
|
if plugin.recording:
|
||||||
|
colour = self.COLOUR_GREEN
|
||||||
|
if plugin.is_ignoring():
|
||||||
|
colour += self.BLINK
|
||||||
|
self.set_status(command='note_on', note=NOTE_RECORD_STATUS, velocity=colour)
|
||||||
|
|
||||||
|
colour = self.COLOUR_OFF
|
||||||
|
if plugin.overdub:
|
||||||
|
colour = self.COLOUR_RED
|
||||||
|
if plugin.is_paused() or plugin.is_ignoring():
|
||||||
|
colour += self.BLINK
|
||||||
|
self.set_status(command='note_on', note=NOTE_OVERDUB_STATUS, velocity=colour)
|
||||||
|
|
||||||
|
for i in range(plugin.MAX_CLIPS):
|
||||||
|
if i in plugin.running_clips:
|
||||||
|
if plugin.is_playing() and not plugin.is_paused():
|
||||||
|
colour = self.COLOUR_GREEN
|
||||||
|
else:
|
||||||
|
colour = self.COLOUR_AMBER
|
||||||
|
if plugin.selected_clip==i: #blink if selected
|
||||||
|
colour += self.BLINK
|
||||||
|
elif plugin.selected_clip==i:
|
||||||
|
colour = self.COLOUR_RED_BLINK
|
||||||
|
else:
|
||||||
|
colour = self.COLOUR_OFF
|
||||||
|
self.set_status(command='note_on', note=NOTE_CLIP_STATUS_ROW+i, velocity=colour)
|
||||||
|
|
||||||
|
|
||||||
|
from plugins.ShaderQuickPresetPlugin import ShaderQuickPresetPlugin
|
||||||
|
#print ("feedback_plugin_status")
|
||||||
|
for plugin in self.pc.get_plugins(ShaderQuickPresetPlugin):
|
||||||
|
#print ("for plugin %s" % plugin)
|
||||||
|
for pad in range(0,8):
|
||||||
|
#print ("checking selected_preset %s vs pad %s" % (plugin.selected_preset, pad))
|
||||||
|
colour = self.COLOUR_OFF
|
||||||
|
if plugin.presets[pad] is not None:
|
||||||
|
colour = self.COLOUR_AMBER
|
||||||
|
if plugin.last_recalled==pad:
|
||||||
|
colour = self.COLOUR_GREEN
|
||||||
|
if plugin.selected_preset==pad:
|
||||||
|
if plugin.presets[pad] is None:
|
||||||
|
colour = self.COLOUR_RED
|
||||||
|
colour += self.BLINK
|
||||||
|
self.set_status(command='note_on', note=pad, velocity=colour)
|
||||||
|
|
||||||
|
BLINK = 1
|
||||||
|
COLOUR_OFF = 0
|
||||||
|
COLOUR_GREEN = 1
|
||||||
|
COLOUR_GREEN_BLINK = 2
|
||||||
|
COLOUR_RED = 3
|
||||||
|
COLOUR_RED_BLINK = 4
|
||||||
|
COLOUR_AMBER = 5
|
||||||
|
COLOUR_AMBER_BLINK = 6
|
||||||
|
|
||||||
|
def refresh_midi_feedback(self):
|
||||||
|
|
||||||
|
# show which layer is selected (where parameter offset goes to)
|
||||||
|
self.feedback_show_layer(self.pc.data.shader_layer)
|
||||||
|
|
||||||
|
# show if internal feedback (the shader layer kind) is enabled
|
||||||
|
if self.pc.data.feedback_active and not self.pc.data.function_on:
|
||||||
|
self.feedback_shader_feedback(self.COLOUR_GREEN)
|
||||||
|
#elif self.pc.data.settings['shader']['X3_AS_SPEED']['value'] == 'enabled' and self.pc.data.function_on:
|
||||||
|
# self.feedback_shader_feedback(self.COLOUR_GREEN_BLINK)
|
||||||
|
else:
|
||||||
|
self.feedback_shader_feedback(self.COLOUR_OFF)
|
||||||
|
|
||||||
|
if self.pc.message_handler.actions.display.capture.is_previewing and not self.pc.data.function_on:
|
||||||
|
self.feedback_capture_preview(self.COLOUR_GREEN)
|
||||||
|
else:
|
||||||
|
self.feedback_capture_preview(self.COLOUR_OFF)
|
||||||
|
|
||||||
|
if self.pc.data.function_on:
|
||||||
|
self.feedback_show_modulation(self.pc.shaders.selected_modulation_slot)
|
||||||
|
|
||||||
|
self.feedback_plugin_status()
|
||||||
|
|
||||||
|
for n,shader in enumerate(self.pc.message_handler.shaders.selected_shader_list):
|
||||||
|
#print ("%s: in refresh_midi_feedback, got shader: %s" % (n,shader))
|
||||||
|
# show if layer is running or not
|
||||||
|
if not self.pc.data.function_on:
|
||||||
|
if self.pc.message_handler.shaders.selected_status_list[n] == '▶':
|
||||||
|
self.feedback_shader_layer_on(n)
|
||||||
|
else:
|
||||||
|
self.feedback_shader_layer_off(n)
|
||||||
|
for x in range(0,8):
|
||||||
|
if 'slot' in shader and shader.get('slot',None)==x:
|
||||||
|
if self.pc.message_handler.shaders.selected_status_list[n] == '▶':
|
||||||
|
# show that slot is selected and running
|
||||||
|
self.feedback_shader_on(n, x, self.COLOUR_GREEN)
|
||||||
|
else:
|
||||||
|
# show that slot is selected but not running
|
||||||
|
self.feedback_shader_on(n, x, self.COLOUR_AMBER_BLINK)
|
||||||
|
elif self.pc.data.shader_bank_data[n][x]['path']:
|
||||||
|
# show that slot is full but not selected
|
||||||
|
self.feedback_shader_on(n, x, self.COLOUR_AMBER)
|
||||||
|
else:
|
||||||
|
# hos that nothing in slot
|
||||||
|
self.feedback_shader_off(n, x)
|
||||||
|
|
||||||
|
self.update_device()
|
||||||
|
|
||||||
|
#print("refresh_midi_feedback")
|
||||||
|
|
||||||
|
last_state = None
|
||||||
|
def update_device(self):
|
||||||
|
from copy import deepcopy
|
||||||
|
#print("in update device status is %s" % self.status)
|
||||||
|
for i,c in self.status.items():
|
||||||
|
#'print("comparing\n%s to\n%s" % (c, self.last_state[i]))
|
||||||
|
if self.last_state is None or self.last_state[i]!=c:
|
||||||
|
#print("got command: %s: %s" % (i,c))
|
||||||
|
self.send_command(**c)
|
||||||
|
self.last_state = deepcopy(self.status)
|
||||||
@@ -52,10 +52,13 @@ display = Display(tk, video_driver, shaders, message_handler, data)
|
|||||||
|
|
||||||
# setup the actions
|
# setup the actions
|
||||||
actions = Actions(tk, message_handler, data, video_driver, shaders, display, osc_client)
|
actions = Actions(tk, message_handler, data, video_driver, shaders, display, osc_client)
|
||||||
|
message_handler.actions = actions
|
||||||
|
|
||||||
numpad_input = NumpadInput(tk, message_handler, display, actions, data)
|
numpad_input = NumpadInput(tk, message_handler, display, actions, data)
|
||||||
osc_input = OscInput(tk, message_handler, display, actions, data)
|
osc_input = OscInput(tk, message_handler, display, actions, data)
|
||||||
midi_input = MidiInput(tk, message_handler, display, actions, data)
|
midi_input = MidiInput(tk, message_handler, display, actions, data)
|
||||||
|
data.plugins.midi_input = midi_input
|
||||||
|
|
||||||
analog_input = AnalogInput(tk, message_handler, display, actions, data)
|
analog_input = AnalogInput(tk, message_handler, display, actions, data)
|
||||||
|
|
||||||
actions.check_and_set_output_mode_on_boot()
|
actions.check_and_set_output_mode_on_boot()
|
||||||
|
|||||||
@@ -9,13 +9,18 @@ class Shaders(object):
|
|||||||
self.root = root
|
self.root = root
|
||||||
self.osc_client = osc_client
|
self.osc_client = osc_client
|
||||||
self.message_handler = message_handler
|
self.message_handler = message_handler
|
||||||
|
self.message_handler.shaders = self
|
||||||
self.data = data
|
self.data = data
|
||||||
self.shaders_menu = menu.ShadersMenu(self.data, self.message_handler, self.MENU_HEIGHT )
|
self.shaders_menu = menu.ShadersMenu(self.data, self.message_handler, self.MENU_HEIGHT )
|
||||||
self.selected_shader_list = [self.EMPTY_SHADER for i in range(3)]
|
self.selected_shader_list = [self.EMPTY_SHADER for i in range(3)]
|
||||||
self.focused_param = 0
|
self.focused_param = 0
|
||||||
self.shaders_menu_list = self.generate_shaders_list()
|
self.shaders_menu_list = self.generate_shaders_list()
|
||||||
|
|
||||||
|
self.selected_modulation_slot = 0
|
||||||
|
|
||||||
self.selected_status_list = ['-','-','-'] ## going to try using symbols for this : '-' means empty, '▶' means running, '■' means not running, '!' means error
|
self.selected_status_list = ['-','-','-'] ## going to try using symbols for this : '-' means empty, '▶' means running, '■' means not running, '!' means error
|
||||||
|
self.selected_modulation_level = [[[0.0,0.0,0.0,0.0] for i in range(4)] for i in range(3)]
|
||||||
|
self.modulation_value = [0.0,0.0,0.0,0.0]
|
||||||
self.selected_param_list = [[0.0,0.0,0.0,0.0] for i in range(3)]
|
self.selected_param_list = [[0.0,0.0,0.0,0.0] for i in range(3)]
|
||||||
self.selected_speed_list = [1.0, 1.0, 1.0]
|
self.selected_speed_list = [1.0, 1.0, 1.0]
|
||||||
|
|
||||||
@@ -87,11 +92,13 @@ class Shaders(object):
|
|||||||
|
|
||||||
def start_shader(self, layer):
|
def start_shader(self, layer):
|
||||||
self.osc_client.send_message("/shader/{}/is_active".format(str(layer)), True)
|
self.osc_client.send_message("/shader/{}/is_active".format(str(layer)), True)
|
||||||
self.selected_status_list[layer] = '▶'
|
if self.selected_status_list[layer] != '-':
|
||||||
|
self.selected_status_list[layer] = '▶'
|
||||||
|
|
||||||
def stop_shader(self, layer):
|
def stop_shader(self, layer):
|
||||||
self.osc_client.send_message("/shader/{}/is_active".format(str(layer)), False)
|
self.osc_client.send_message("/shader/{}/is_active".format(str(layer)), False)
|
||||||
self.selected_status_list[layer] = '■'
|
if self.selected_status_list[layer] != '-':
|
||||||
|
self.selected_status_list[layer] = '■'
|
||||||
|
|
||||||
def start_selected_shader(self):
|
def start_selected_shader(self):
|
||||||
self.start_shader(self.data.shader_layer)
|
self.start_shader(self.data.shader_layer)
|
||||||
@@ -128,9 +135,10 @@ class Shaders(object):
|
|||||||
|
|
||||||
def play_that_shader(self, layer, slot):
|
def play_that_shader(self, layer, slot):
|
||||||
if self.data.shader_bank_data[layer][slot]['path']:
|
if self.data.shader_bank_data[layer][slot]['path']:
|
||||||
self.selected_shader_list[layer] = self.data.shader_bank_data[layer][slot]
|
if self.selected_shader_list[layer].get('slot') is None or self.selected_shader_list[layer]['slot'] != slot:
|
||||||
self.selected_shader_list[layer]['slot'] = slot
|
self.selected_shader_list[layer] = self.data.shader_bank_data[layer][slot]
|
||||||
self.load_shader_layer(layer)
|
self.selected_shader_list[layer]['slot'] = slot
|
||||||
|
self.load_shader_layer(layer)
|
||||||
else:
|
else:
|
||||||
self.message_handler.set_message('INFO', "shader slot %s:%s is empty"%(layer,slot))
|
self.message_handler.set_message('INFO', "shader slot %s:%s is empty"%(layer,slot))
|
||||||
|
|
||||||
@@ -259,4 +267,203 @@ class Shaders(object):
|
|||||||
self.osc_client.send_message("/shader/{}/speed".format(str(layer)), amount )
|
self.osc_client.send_message("/shader/{}/speed".format(str(layer)), amount )
|
||||||
self.selected_speed_list[layer] = amount
|
self.selected_speed_list[layer] = amount
|
||||||
|
|
||||||
|
# methods for helping dealing with storing and recalling shader parameter frame states
|
||||||
|
def get_live_frame(self):
|
||||||
|
#print("get_live_frame: %s" % self.pc.message_handler.shaders.selected_param_list)
|
||||||
|
import copy #from copy import deepcopy
|
||||||
|
frame = {
|
||||||
|
'selected_shader_slots': [ shader.get('slot',None) for shader in self.selected_shader_list ],
|
||||||
|
'shader_params': copy.deepcopy(self.selected_param_list),
|
||||||
|
'layer_active_status': copy.deepcopy(self.selected_status_list),
|
||||||
|
'feedback_active': self.data.feedback_active,
|
||||||
|
'x3_as_speed': self.data.settings['shader']['X3_AS_SPEED']['value'],
|
||||||
|
'shader_speeds': copy.deepcopy(self.selected_speed_list),
|
||||||
|
'strobe_amount': self.data.settings['shader']['STROBE_AMOUNT']['value'] / 10.0
|
||||||
|
}
|
||||||
|
#print("built frame: %s" % frame['shader_params'])
|
||||||
|
return frame
|
||||||
|
|
||||||
|
def recall_frame_params(self, preset):
|
||||||
|
if preset is None:
|
||||||
|
return
|
||||||
|
#print("recall_frame_params got: %s" % preset.get('shader_params'))
|
||||||
|
for (layer, param_list) in enumerate(preset.get('shader_params',[])):
|
||||||
|
if param_list:
|
||||||
|
for param,value in enumerate(param_list):
|
||||||
|
#if (ignored is not None and ignored['shader_params'][layer][param] is not None):
|
||||||
|
# print ("ignoring %s,%s because value is %s" % (layer,param,ignored['shader_params'][layer][param]))
|
||||||
|
# continue
|
||||||
|
if (value is not None):
|
||||||
|
#print("recalling layer %s param %s: value %s" % (layer,param,value))
|
||||||
|
self.data.plugins.actions.call_method_name('set_the_shader_param_%s_layer_%s_continuous' % (param,layer), value)
|
||||||
|
|
||||||
|
if preset.get('feedback_active') is not None:
|
||||||
|
self.data.feedback_active = preset.get('feedback_active',self.data.feedback_active)
|
||||||
|
if self.data.feedback_active:
|
||||||
|
self.data.plugins.actions.call_method_name('enable_feedback')
|
||||||
|
else:
|
||||||
|
self.data.plugins.actions.call_method_name('disable_feedback')
|
||||||
|
|
||||||
|
if preset.get('x3_as_speed') is not None:
|
||||||
|
self.data.settings['shader']['X3_AS_SPEED']['value'] = preset.get('x3_as_speed',self.data.settings['shader']['X3_AS_SPEED']['value'])
|
||||||
|
"""if self.data.settings['shader']['X3_AS_SPEED']['value']:
|
||||||
|
self.data.plugins.actions.call_method_name('enable_x3_as_speed')
|
||||||
|
else:
|
||||||
|
self.data.plugins.actions.call_method_name('disable_x3_as_speed')"""
|
||||||
|
|
||||||
|
for (layer, speed) in enumerate(preset.get('shader_speeds',[])):
|
||||||
|
if speed is not None:
|
||||||
|
self.data.plugins.actions.call_method_name('set_shader_speed_layer_%s_amount' % layer, speed)
|
||||||
|
|
||||||
|
if preset.get('strobe_amount') is not None:
|
||||||
|
self.data.plugins.actions.set_strobe_amount_continuous(preset.get('strobe_amount'))
|
||||||
|
|
||||||
|
def recall_frame(self, preset):
|
||||||
|
|
||||||
|
self.data.settings['shader']['X3_AS_SPEED']['value'] = preset.get('x3_as_speed')
|
||||||
|
|
||||||
|
# x3_as_speed affects preset recall, so do that first
|
||||||
|
self.recall_frame_params(preset)
|
||||||
|
|
||||||
|
for (layer, slot) in enumerate(preset.get('selected_shader_slots',[])):
|
||||||
|
if slot is not None:
|
||||||
|
#print("setting layer %s to slot %s" % (layer, slot))
|
||||||
|
self.data.plugins.actions.call_method_name('play_shader_%s_%s' % (layer, slot))
|
||||||
|
|
||||||
|
for (layer, active) in enumerate(preset.get('layer_active_status',[])):
|
||||||
|
# print ("got %s layer with status %s " % (layer,active))
|
||||||
|
if active=='▶':
|
||||||
|
self.data.plugins.actions.call_method_name('start_shader_layer_%s' % layer)
|
||||||
|
else:
|
||||||
|
self.data.plugins.actions.call_method_name('stop_shader_layer_%s' % layer)
|
||||||
|
|
||||||
|
DEBUG_FRAMES = False
|
||||||
|
|
||||||
|
# overlay frame2 on frame1
|
||||||
|
def merge_frames(self, frame1, frame2):
|
||||||
|
from copy import deepcopy
|
||||||
|
f = deepcopy(frame1) #frame1.copy()
|
||||||
|
if self.DEBUG_FRAMES: print("merge_frames: got frame1\t%s" % frame1)
|
||||||
|
if self.DEBUG_FRAMES: print("merge_frames: got frame2\t%s" % frame2)
|
||||||
|
for i,f2 in enumerate(frame2['shader_params']):
|
||||||
|
for i2,p in enumerate(f2):
|
||||||
|
if p is not None:
|
||||||
|
f['shader_params'][i][i2] = p
|
||||||
|
|
||||||
|
if frame2['feedback_active'] is not None:
|
||||||
|
f['feedback_active'] = frame2['feedback_active']
|
||||||
|
|
||||||
|
if frame2['x3_as_speed'] is not None:
|
||||||
|
f['x3_as_speed'] = frame2['x3_as_speed']
|
||||||
|
|
||||||
|
if f.get('shader_speeds') is None:
|
||||||
|
f['shader_speeds'] = frame2.get('shader_speeds')
|
||||||
|
else:
|
||||||
|
for i,s in enumerate(frame2['shader_speeds']):
|
||||||
|
if s is not None:
|
||||||
|
f['shader_speeds'][i] = s
|
||||||
|
|
||||||
|
if frame2.get('strobe_amount'):
|
||||||
|
f['strobe_amount'] = frame2.get('strobe_amount')
|
||||||
|
|
||||||
|
if self.DEBUG_FRAMES: print("merge_frames: got return\t%s" % f)
|
||||||
|
return f
|
||||||
|
|
||||||
|
def get_frame_ignored(self, frame, ignored):
|
||||||
|
from copy import deepcopy
|
||||||
|
f = deepcopy(frame) #frame1.copy()
|
||||||
|
if self.DEBUG_FRAMES: print("get_frame_ignored: got frame\t%s" % frame)
|
||||||
|
for i,f2 in enumerate(frame['shader_params']):
|
||||||
|
for i2,p in enumerate(f2):
|
||||||
|
if ignored['shader_params'][i][i2] is not None:
|
||||||
|
f['shader_params'][i][i2] = None
|
||||||
|
if ignored.get('feedback_active') is not None:
|
||||||
|
f['feedback_active'] = None
|
||||||
|
if ignored.get('x3_as_speed') is not None:
|
||||||
|
f['x3_as_speed'] = None
|
||||||
|
if ignored.get('shader_speeds') is not None and frame.get('shader_speeds'):
|
||||||
|
for i,s in enumerate(frame.get('shader_speeds')):
|
||||||
|
if ignored['shader_speeds'][i] is not None:
|
||||||
|
f['shader_speeds'][i] = None
|
||||||
|
if ignored.get('strobe_amount') is not None:
|
||||||
|
f['strobe_amount'] = None
|
||||||
|
if self.DEBUG_FRAMES: print("get_frame_ignored: got return\t%s" % f)
|
||||||
|
return f
|
||||||
|
|
||||||
|
def is_frame_empty(self, frame):
|
||||||
|
#from copy import deepcopy
|
||||||
|
#f = deepcopy(frame) #frame1.copy()
|
||||||
|
if self.DEBUG_FRAMES: print("is_frame_empty: got frame\t%s" % frame)
|
||||||
|
|
||||||
|
if frame.get('feedback_active') is not None:
|
||||||
|
return False
|
||||||
|
if frame.get('x3_as_speed') is not None:
|
||||||
|
return False
|
||||||
|
if frame.get('strobe_amount') is not None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
for i,f in enumerate(frame['shader_params']):
|
||||||
|
for i2,p in enumerate(f):
|
||||||
|
if p is not None: #ignored['shader_params'][i][i2] is not None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if frame.get('shader_speeds') is not None:
|
||||||
|
for i,f in enumerate(frame['shader_speeds']):
|
||||||
|
if f is not None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self.DEBUG_FRAMES: print("is_frame_empty: got return true")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_frame_diff(self, last_frame, current_frame):
|
||||||
|
if not last_frame: return current_frame
|
||||||
|
|
||||||
|
if self.DEBUG_FRAMES:
|
||||||
|
print(">>>>get_frame_diff>>>>")
|
||||||
|
print("last_frame: \t%s" % last_frame['shader_params'])
|
||||||
|
print("current_frame: \t%s" % current_frame['shader_params'])
|
||||||
|
|
||||||
|
param_values = [[None]*4,[None]*4,[None]*4]
|
||||||
|
for layer,params in enumerate(current_frame.get('shader_params',[[None]*4]*3)):
|
||||||
|
#if self.DEBUG_FRAMES: print("got layer %s params: %s" % (layer, params))
|
||||||
|
for param,p in enumerate(params):
|
||||||
|
if p is not None and p != last_frame.get('shader_params')[layer][param]:
|
||||||
|
if self.DEBUG_FRAMES: print("setting layer %s param %s to %s" % (layer,param,p))
|
||||||
|
param_values[layer][param] = p
|
||||||
|
|
||||||
|
if current_frame['feedback_active'] is not None and last_frame['feedback_active'] != current_frame['feedback_active']:
|
||||||
|
feedback_active = current_frame['feedback_active']
|
||||||
|
else:
|
||||||
|
feedback_active = None
|
||||||
|
|
||||||
|
if current_frame['x3_as_speed'] is not None and last_frame['x3_as_speed'] != current_frame['x3_as_speed']:
|
||||||
|
x3_as_speed = current_frame['x3_as_speed']
|
||||||
|
else:
|
||||||
|
x3_as_speed = None
|
||||||
|
|
||||||
|
speed_values = [None]*3
|
||||||
|
for layer,param in enumerate(current_frame.get('shader_speeds',[None]*3)):
|
||||||
|
if param is not None and param != last_frame['shader_speeds'][layer]:
|
||||||
|
speed_values[layer] = param
|
||||||
|
|
||||||
|
if current_frame['strobe_amount'] is not None and last_frame['strobe_amount'] != current_frame['strobe_amount']:
|
||||||
|
strobe_amount = current_frame['strobe_amount']
|
||||||
|
else:
|
||||||
|
strobe_amount = None
|
||||||
|
|
||||||
|
if self.DEBUG_FRAMES:
|
||||||
|
print("param_values is\t%s" % param_values)
|
||||||
|
print("speed_values is\t%s" % speed_values)
|
||||||
|
|
||||||
|
diff = {
|
||||||
|
'shader_params': param_values,
|
||||||
|
'feedback_active': feedback_active,
|
||||||
|
'x3_as_speed': x3_as_speed,
|
||||||
|
'shader_speeds': speed_values,
|
||||||
|
'strobe_amount': strobe_amount,
|
||||||
|
}
|
||||||
|
if self.DEBUG_FRAMES: print("returning\t%s\n^^^^" % diff['shader_params'])
|
||||||
|
|
||||||
|
return diff
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user