mirror of
https://github.com/cyberboy666/r_e_c_u_r.git
synced 2025-12-12 03:10:17 +01:00
tidy up + change way plugins are found+listed, solves some problems, plugins use the active status to indicate disabled and now have start/stop methods (seems to work to stop+restart Sound+WJ ok, needs restart to get MidiFeedback working if its disabled? needs more tidying up and testing and fixing
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,6 +5,8 @@
|
||||
json_objects/display_data.json
|
||||
json_objects/shader_bank_data.json
|
||||
json_objects/settings.json
|
||||
json_objects/plugins/*/*.json
|
||||
json_objects/active_plugins.json
|
||||
*.patch
|
||||
*.orig
|
||||
*.rej
|
||||
|
||||
@@ -119,8 +119,11 @@ class Data(object):
|
||||
self.plugins = plugin_collection.PluginCollection("plugins", self.message_handler, self)
|
||||
self.compare_plugins_list()
|
||||
|
||||
def get_active_plugin_class_names(self):
|
||||
return [k for k,v in self.active_plugins.items() if v is True]
|
||||
|
||||
def compare_plugins_list(self):
|
||||
current_plugins = [type(plugin).__name__ for plugin in self.plugins.get_plugins(plugin_collection.Plugin)]
|
||||
current_plugins = [type(plugin).__name__ for plugin in self.plugins.get_plugins(include_disabled=True)]
|
||||
plugins_to_add = set(current_plugins) - set(self.active_plugins.keys())
|
||||
plugins_to_remove = set(self.active_plugins) - set(current_plugins)
|
||||
for k in plugins_to_remove:
|
||||
@@ -466,14 +469,12 @@ class Data(object):
|
||||
display_modes.append(["SHDR_BNK",'PLAY_SHADER'])
|
||||
if self.settings['detour']['TRY_DEMO']['value'] == 'enabled':
|
||||
display_modes.append(["FRAMES",'NAV_DETOUR'])
|
||||
if self.settings['system']['USE_PLUGINS']['value'] == 'enabled':
|
||||
if self.settings['system'].setdefault('USE_PLUGINS',self.default_settings.setdefault('USE_PLUGINS',{'value': 'enabled'})).get('value') == 'enabled':
|
||||
display_modes.append(["PLUGINS",'NAV_PLUGINS'])
|
||||
|
||||
if hasattr(self, 'plugins') and self.plugins is not None:
|
||||
from data_centre.plugin_collection import DisplayPlugin
|
||||
for plugin in self.plugins.get_plugins(DisplayPlugin):
|
||||
is_active = self.active_plugins[type(plugin).__name__]
|
||||
if is_active:
|
||||
display_modes.append(plugin.get_display_modes())
|
||||
|
||||
if not with_nav_mode:
|
||||
|
||||
@@ -9,14 +9,20 @@ 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
|
||||
#disabled = False
|
||||
@property
|
||||
def disabled(self):
|
||||
return type(self).__name__ not in self.pc.data.get_active_plugin_class_names()
|
||||
|
||||
def __init__(self, plugin_collection):
|
||||
self.description = 'UNKNOWN'
|
||||
self.pc = plugin_collection
|
||||
|
||||
def quit_plugin(self):
|
||||
print("quitting " + type(self).__name__)
|
||||
def stop_plugin(self):
|
||||
print(">>Stopping plugin " + type(self).__name__)
|
||||
|
||||
def start_plugin(self):
|
||||
print(">>Starting plugin " + type(self).__name__)
|
||||
|
||||
class MidiFeedbackPlugin(Plugin):
|
||||
"""Base class for MIDI feedback plugins
|
||||
@@ -100,16 +106,18 @@ class SequencePlugin(Plugin):
|
||||
speed = 0.25 #1.0
|
||||
def move_delta(self, delta, speed):
|
||||
self.position += delta * speed
|
||||
if self.looping and self.position>1.0:
|
||||
self.position = 0.0
|
||||
elif self.looping and self.position<0:
|
||||
self.position = 1.0
|
||||
if self.position>1.0:
|
||||
self.position = self.position-1.0
|
||||
self.iterations_count += 1
|
||||
elif self.position<0.0:
|
||||
self.position = self.position+1.0
|
||||
self.iterations_count += 1
|
||||
|
||||
store_passed = None
|
||||
pause_flag = True
|
||||
stop_flag = False
|
||||
looping = True
|
||||
automation_start = None
|
||||
#automation_start = None
|
||||
iterations_count = 0
|
||||
duration = 2000
|
||||
frequency = 100
|
||||
@@ -146,12 +154,12 @@ class SequencePlugin(Plugin):
|
||||
#print ("%s: reset automation_start to %s" % (time.time()-self.automation_start,self.automation_start))
|
||||
#return"""
|
||||
|
||||
if not self.stop_flag: # and (now - self.automation_start < self.duration/1000):
|
||||
if not self.stop_flag and not self.disabled: # and (now - self.automation_start < self.duration/1000):
|
||||
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) )
|
||||
#print("%s: stopping ! (stop_flag %s)" % ((now - self.automation_start),self.stop_flag) )
|
||||
self.stop_flag = False
|
||||
self.automation_start = None
|
||||
#self.automation_start = None
|
||||
self.iterations_count = 0
|
||||
|
||||
def is_paused(self):
|
||||
@@ -482,13 +490,29 @@ class PluginCollection(object):
|
||||
def quit_plugins(self):
|
||||
# tell each plugin to quit
|
||||
for plugin in self.get_plugins():
|
||||
plugin.quit_plugin()
|
||||
if not plugin.disabled: plugin.stop_plugin()
|
||||
|
||||
def get_plugins(self, clazz = None):
|
||||
def stop_plugin_name(self, name):
|
||||
for plugin in self.get_plugins(include_disabled=True):
|
||||
if type(plugin).__name__ == name:
|
||||
plugin.stop_plugin()
|
||||
|
||||
def start_plugin_name(self, name):
|
||||
#print("start_plugin_name got %s"%name)
|
||||
for plugin in self.get_plugins(include_disabled=True):
|
||||
#print("looking for %s vs %s" % (type(plugin).__name__, name))
|
||||
if type(plugin).__name__ == name:
|
||||
#print("starting %s" %name)
|
||||
plugin.start_plugin()
|
||||
|
||||
|
||||
def get_plugins(self, clazz = None, include_disabled = False):
|
||||
# is_active = self.active_plugins[type(plugin).__name__]
|
||||
if clazz:
|
||||
return [c for c in self.plugins if (isinstance(c, clazz) and not c.disabled)]
|
||||
return [c for c in self.plugins if isinstance(c, clazz) and (include_disabled or not c.disabled)]
|
||||
#and type(c).__name__ in self.data.get_active_plugin_class_names())
|
||||
else:
|
||||
return [c for c in self.plugins if not c.disabled]
|
||||
return [c for c in self.plugins if include_disabled or not c.disabled]
|
||||
|
||||
def walk_package(self, package):
|
||||
"""Recursively walk the supplied package to retrieve all plugins
|
||||
@@ -510,7 +534,7 @@ class PluginCollection(object):
|
||||
|
||||
# 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 = []
|
||||
"""all_current_paths = []
|
||||
if isinstance(imported_package.__path__, str):
|
||||
all_current_paths.append(imported_package.__path__)
|
||||
else:
|
||||
@@ -525,4 +549,4 @@ class PluginCollection(object):
|
||||
|
||||
# For each sub directory, apply the walk_package method recursively
|
||||
for child_pkg in child_pkgs:
|
||||
self.walk_package(package + '.' + child_pkg)
|
||||
self.walk_package(package + '.' + child_pkg)"""
|
||||
|
||||
@@ -180,7 +180,10 @@ class Display(object):
|
||||
self.display_text.insert(END, '{} \n'.format(self.body_title))
|
||||
self.display_text.insert(END, '{:<40} {:<5} \n'.format('plugin', 'is_active'))
|
||||
## showing list of plugins:
|
||||
plugins_list = sorted(self.data.active_plugins.items())
|
||||
plugins_list = sorted([
|
||||
(type(plugin).__name__, type(plugin).__name__ in self.data.get_active_plugin_class_names())\
|
||||
for plugin in self.data.plugins.get_plugins(include_disabled=True)
|
||||
])
|
||||
self.plugins_menu.menu_list = plugins_list
|
||||
|
||||
number_of_plugins = len(plugins_list)
|
||||
|
||||
@@ -209,6 +209,10 @@ class PluginsMenu(Menu):
|
||||
selected_item = sorted(self.data.active_plugins)[self.selected_list_index]
|
||||
state = self.data.active_plugins[selected_item]
|
||||
self.data.update_active_plugins(selected_item, not state)
|
||||
if state:
|
||||
self.data.plugins.stop_plugin_name(selected_item)
|
||||
else:
|
||||
self.data.plugins.start_plugin_name(selected_item)
|
||||
|
||||
|
||||
class ShadersMenu(Menu):
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"LFOModulationPlugin": false,
|
||||
"ManipulatePlugin": true,
|
||||
"MidiFeedbackAPCKey25Plugin": true,
|
||||
"MidiFeedbackLaunchpadPlugin": false,
|
||||
"ShaderLoopRecordPlugin": false,
|
||||
"ShaderQuickPresetPlugin": true,
|
||||
"WJSendPlugin": false
|
||||
}
|
||||
@@ -3,7 +3,6 @@ import data_centre.plugin_collection
|
||||
from data_centre.plugin_collection import ActionsPlugin, SequencePlugin, DisplayPlugin
|
||||
|
||||
class LFOModulationPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
|
||||
disabled = False
|
||||
|
||||
MAX_LFOS = 4
|
||||
|
||||
@@ -20,8 +19,10 @@ class LFOModulationPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
|
||||
|
||||
#self.PRESET_FILE_NAME = "ShaderLoopRecordPlugin/frames.json"
|
||||
|
||||
self.pc.shaders.root.after(1000, self.run_automation)
|
||||
self.pc.shaders.root.after(1000, self.start_plugin)
|
||||
|
||||
def start_plugin(self):
|
||||
self.pc.shaders.root.after(0, self.run_automation)
|
||||
|
||||
# DisplayPlugin methods
|
||||
def get_display_modes(self):
|
||||
@@ -100,10 +101,10 @@ class LFOModulationPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
|
||||
import time
|
||||
now = time.time()
|
||||
|
||||
if self.pc.data.plugins is None:
|
||||
if self.pc.data.plugins is None: # not initialised yet
|
||||
return
|
||||
|
||||
if not self.active:
|
||||
if not self.active: # output is disabled
|
||||
return
|
||||
|
||||
for lfo in range(0,self.MAX_LFOS):
|
||||
|
||||
@@ -42,7 +42,6 @@ TODO: >> ?? invert|set_the_shader_param_0_layer_>>print_arguments>>set_variab
|
||||
"""
|
||||
|
||||
class ManipulatePlugin(ActionsPlugin,DisplayPlugin,ModulationReceiverPlugin):
|
||||
disabled = False
|
||||
|
||||
DEBUG = False
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ from data_centre.plugin_collection import MidiFeedbackPlugin
|
||||
import mido
|
||||
|
||||
class MidiFeedbackAPCKey25Plugin(MidiFeedbackPlugin):
|
||||
disabled = False
|
||||
#disabled = False
|
||||
|
||||
status = {}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from data_centre import plugin_collection
|
||||
from data_centre.plugin_collection import MidiFeedbackPlugin
|
||||
import mido
|
||||
from plugins.MidiFeedbackAPCKey25Plugin import MidiFeedbackAPCKey25Plugin
|
||||
import plugins
|
||||
#from plugins.MidiFeedbackAPCKey25Plugin import MidiFeedbackAPCKey25Plugin
|
||||
|
||||
class MidiFeedbackLaunchpadPlugin(MidiFeedbackAPCKey25Plugin):
|
||||
disabled = False
|
||||
class MidiFeedbackLaunchpadPlugin(plugins.MidiFeedbackAPCKey25Plugin.MidiFeedbackAPCKey25Plugin):
|
||||
|
||||
status = {}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ from data_centre.plugin_collection import ActionsPlugin, SequencePlugin, Display
|
||||
from plugins.frame_manager import Frame
|
||||
|
||||
class ShaderLoopRecordPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
|
||||
disabled = False
|
||||
|
||||
MAX_CLIPS = 8
|
||||
frames = []
|
||||
|
||||
@@ -45,8 +45,8 @@ class ShaderLoopRecordPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
|
||||
def save_presets(self):
|
||||
self.pc.update_json(self.PRESET_FILE_NAME, self.frames)
|
||||
|
||||
def quit_plugin(self):
|
||||
super().quit_plugin()
|
||||
def stop_plugin(self):
|
||||
super().stop_plugin()
|
||||
self.save_presets()
|
||||
|
||||
# DisplayPlugin methods
|
||||
|
||||
@@ -4,7 +4,6 @@ import copy
|
||||
from plugins.frame_manager import Frame
|
||||
|
||||
class ShaderQuickPresetPlugin(ActionsPlugin): #,SequencePlugin):
|
||||
disabled = False
|
||||
|
||||
MAX_PRESETS = 8
|
||||
|
||||
@@ -25,8 +24,8 @@ class ShaderQuickPresetPlugin(ActionsPlugin): #,SequencePlugin):
|
||||
def save_presets(self):
|
||||
self.pc.update_json(self.PRESET_FILE_NAME, self.presets)
|
||||
|
||||
def quit_plugin(self):
|
||||
super().quit_plugin()
|
||||
def stop_plugin(self):
|
||||
super().stop_plugin()
|
||||
self.save_presets()
|
||||
|
||||
@property
|
||||
|
||||
@@ -12,7 +12,6 @@ from statistics import mean
|
||||
np.set_printoptions(suppress=True) # don't use scientific notationn
|
||||
|
||||
class SoundReactPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
|
||||
disabled = False
|
||||
|
||||
DEBUG = False
|
||||
|
||||
@@ -20,6 +19,8 @@ class SoundReactPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
|
||||
stop_flag = False
|
||||
pause_flag = False
|
||||
|
||||
stream = None
|
||||
|
||||
CHUNK = 4096 # number of data points to read at a time
|
||||
RATE = 48000 #44100 # time resolution of the recording device (Hz)
|
||||
|
||||
@@ -30,7 +31,7 @@ class SoundReactPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
|
||||
def __init__(self, plugin_collection):
|
||||
super().__init__(plugin_collection)
|
||||
|
||||
#self.PRESET_FILE_NAME = "ShaderLoopRecordPlugin/frames.json"
|
||||
"""#self.PRESET_FILE_NAME = "ShaderLoopRecordPlugin/frames.json"
|
||||
if self.active and not self.disabled:
|
||||
try:
|
||||
p=pyaudio.PyAudio()
|
||||
@@ -43,7 +44,37 @@ class SoundReactPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
|
||||
|
||||
print ("now setting to run automation..")
|
||||
|
||||
self.pc.shaders.root.after(500, self.run_automation)
|
||||
self.pc.shaders.root.after(500, self.run_automation)"""
|
||||
if not self.disabled:
|
||||
self.start_plugin()
|
||||
|
||||
def stop_plugin(self):
|
||||
self.close_sound_device()
|
||||
super().stop_plugin()
|
||||
|
||||
def start_plugin(self):
|
||||
super().start_plugin()
|
||||
self.open_sound_device()
|
||||
|
||||
def open_sound_device(self):
|
||||
try:
|
||||
self.p=pyaudio.PyAudio()
|
||||
self.stream=self.p.open(format=pyaudio.paInt16,channels=1,rate=self.RATE,input=True,
|
||||
frames_per_buffer=self.CHUNK)
|
||||
except:
|
||||
print("Failed to open sound device - disabling SoundReactPlugin!")
|
||||
self.active = False
|
||||
return
|
||||
|
||||
self.pc.shaders.root.after(250, self.run_automation)
|
||||
|
||||
def close_sound_device(self):
|
||||
if self.stream:
|
||||
self.stream.stop_stream()
|
||||
self.stream.close()
|
||||
self.stream = None
|
||||
if self.p:
|
||||
self.p.terminate()
|
||||
|
||||
@property
|
||||
def sources(self):
|
||||
@@ -97,7 +128,7 @@ class SoundReactPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
|
||||
energy_history = []
|
||||
def run_sequence(self, position):
|
||||
# position is irrelvant for this plugin, we just want to run continuously
|
||||
if not self.active:
|
||||
if not self.active or self.stream is None:
|
||||
return
|
||||
|
||||
data = np.fromstring(self.stream.read(self.CHUNK, exception_on_overflow = False),dtype=np.int16)
|
||||
|
||||
@@ -5,7 +5,6 @@ from data_centre.plugin_collection import ActionsPlugin, SequencePlugin, Display
|
||||
import threading
|
||||
|
||||
class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationReceiverPlugin, AutomationSourcePlugin):
|
||||
disabled = False#True
|
||||
DEBUG = False #True
|
||||
ser = None
|
||||
|
||||
@@ -28,24 +27,23 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
|
||||
def __init__(self, plugin_collection):
|
||||
super().__init__(plugin_collection)
|
||||
|
||||
if self.disabled:
|
||||
"""if self.disabled:
|
||||
print ("WJSendPlugin is disabled, not opening serial")
|
||||
return
|
||||
return"""
|
||||
|
||||
self.presets = self.load_presets()
|
||||
print("read presets:\n%s\n" % self.presets)
|
||||
# load the stored modulation levels into the current config
|
||||
for cmd,levels in self.presets['modulation_levels'].items(): #.setdefault(cmd,[{},{},{},{}]):
|
||||
print("setting commands[%s]['modulation'] to %s" % (cmd, levels))
|
||||
for cmd,levels in self.presets['modulation_levels'].items():
|
||||
self.commands[cmd]['modulation'] = levels
|
||||
|
||||
# build a reverse map for later use
|
||||
# build a reverse map of friendly name -> command struct for later use
|
||||
for cmd,struct in self.commands.items():
|
||||
self.command_by_queue[struct['queue']] = struct
|
||||
|
||||
self.pc.actions.tk.after(500, self.refresh)
|
||||
self.pc.actions.tk.after(500, self.start_plugin)
|
||||
|
||||
self.selected_command_name = list(sorted(self.commands.keys()))[0]
|
||||
self.selected_command_name = list(sorted(self.commands.keys()))[0] # select first command
|
||||
|
||||
def load_presets(self):
|
||||
print("trying load presets? %s " % self.PRESET_FILE_NAME)
|
||||
@@ -56,8 +54,11 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
|
||||
self.presets.setdefault('modulation_levels',{})[cmd] = struct.get('modulation',[{},{},{},{}])
|
||||
self.pc.update_json(self.PRESET_FILE_NAME, self.presets)
|
||||
|
||||
def quit_plugin(self):
|
||||
super().quit_plugin()
|
||||
def start_plugin(self):
|
||||
self.pc.actions.tk.after(0, self.refresh)
|
||||
|
||||
def stop_plugin(self):
|
||||
super().stop_plugin()
|
||||
self.save_presets()
|
||||
|
||||
|
||||
@@ -70,9 +71,6 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
|
||||
#print(">>> reporting frame data for rec\n\t%s" % diff)
|
||||
return diff
|
||||
|
||||
"""def clear_recorded_frame(self):
|
||||
self.last_record = {}"""
|
||||
|
||||
def recall_frame_data(self, data):
|
||||
if data is None:
|
||||
return
|
||||
@@ -219,7 +217,7 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
|
||||
with self.queue_lock:
|
||||
self.queue.clear()
|
||||
|
||||
if self.ser is not None:
|
||||
if self.ser is not None and not self.disabled:
|
||||
self.pc.shaders.root.after(self.THROTTLE, self.refresh)
|
||||
|
||||
def send(self, queue, form, args):
|
||||
|
||||
Reference in New Issue
Block a user