Merge pull request #122 from doctea/feature_plugins

feature_plugins updated with latest dev branch+fixes merged in
This commit is contained in:
langolierz
2020-02-29 17:02:25 +01:00
committed by GitHub
19 changed files with 293 additions and 50 deletions

View File

@@ -1,8 +1,8 @@
# Auto-generated Actions list # Auto-generated Actions list
Fri 21 Feb 00:56:39 UTC 2020 Sat 29 Feb 16:00:23 UTC 2020
for branch=feature_plugins_shader_gadgets for branch=feature_plugins
# Methods # Methods
* change_composite_setting(setting_value) * change_composite_setting(setting_value)
@@ -30,6 +30,7 @@ for branch=feature_plugins_shader_gadgets
* decrease_speed * decrease_speed
* decrease_this_param * decrease_this_param
* disable_feedback * disable_feedback
* eject_all_usb_drives
* enable_feedback * enable_feedback
* enter_on_browser_selection * enter_on_browser_selection
* enter_on_settings_selection * enter_on_settings_selection
@@ -58,12 +59,17 @@ for branch=feature_plugins_shader_gadgets
* 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_page_down
* move_browser_selection_page_up
* move_browser_selection_up * move_browser_selection_up
* move_settings_selection_down * move_settings_selection_down
* move_settings_selection_page_down
* move_settings_selection_page_up
* move_settings_selection_up * move_settings_selection_up
* move_shaders_selection_down * move_shaders_selection_down
* move_shaders_selection_page_down
* move_shaders_selection_page_up
* move_shaders_selection_up * move_shaders_selection_up
* next_bank * next_bank
* next_shader_layer * next_shader_layer
@@ -125,6 +131,7 @@ for branch=feature_plugins_shader_gadgets
* set_the_shader_param_3_layer_offset_2_continuous(amount) * set_the_shader_param_3_layer_offset_2_continuous(amount)
* set_the_shader_param_3_layer_offset_3_continuous(amount) * set_the_shader_param_3_layer_offset_3_continuous(amount)
* shutdown_pi * shutdown_pi
* stop_remote_process
* switch_conjur_player_type(value) * switch_conjur_player_type(value)
* switch_dev_mode(state) * switch_dev_mode(state)
* switch_display_to_hdmi * switch_display_to_hdmi
@@ -136,6 +143,8 @@ for branch=feature_plugins_shader_gadgets
* switch_to_next_player * switch_to_next_player
* switch_to_this_detour(number) * switch_to_this_detour(number)
* switch_video_backend(state) * switch_video_backend(state)
* toggle_access_point_delay(setting_value, osc_setting_state )
* toggle_access_point(setting_value)
* toggle_action_on_player * toggle_action_on_player
* toggle_capture_preview * toggle_capture_preview
* toggle_capture_recording * toggle_capture_recording
@@ -175,6 +184,7 @@ for branch=feature_plugins_shader_gadgets
### Plugin routes ### Plugin routes
* set_lfo_modulation_([0-3])_level (from LFOModulation) * set_lfo_modulation_([0-3])_level (from LFOModulation)
* toggle_lfo_active (from LFOModulation) * toggle_lfo_active (from LFOModulation)
* set_lfo_speed (from LFOModulation)
* (.*)&&(.*) (from ManipulatePlugin) * (.*)&&(.*) (from ManipulatePlugin)
* invert|(.*) (from ManipulatePlugin) * invert|(.*) (from ManipulatePlugin)
* f:(.*):|(.*) (from ManipulatePlugin) * f:(.*):|(.*) (from ManipulatePlugin)
@@ -202,6 +212,9 @@ for branch=feature_plugins_shader_gadgets
* switch_to_preset_([0-%i]) (from ShaderQuickPresetPlugin) * switch_to_preset_([0-%i]) (from ShaderQuickPresetPlugin)
* select_preset_([0-%i]) (from ShaderQuickPresetPlugin) * select_preset_([0-%i]) (from ShaderQuickPresetPlugin)
* clear_current_preset (from ShaderQuickPresetPlugin) * clear_current_preset (from ShaderQuickPresetPlugin)
* toggle_sound_react_active (from SoundReactPlugin)
* sound_set_config_([a-z]*)_([a-z]*) (from SoundReactPlugin)
* sound_set_modulation_([a-z]*)_slot_([0-3])_level (from SoundReactPlugin)
* test_plugin (from TestPlugin) * test_plugin (from TestPlugin)
* cycle_shaders (from TestPlugin) * cycle_shaders (from TestPlugin)
* run_automation (from TestPlugin) * run_automation (from TestPlugin)
@@ -211,14 +224,20 @@ for branch=feature_plugins_shader_gadgets
* toggle_loop_automation (from TestPlugin) * toggle_loop_automation (from TestPlugin)
* print_arguments (from TestPlugin) * print_arguments (from TestPlugin)
* set_the_shader_param_([0-3])_layer_offset_([0-2])_continuous_inverted_example (from TestPlugin) * set_the_shader_param_([0-3])_layer_offset_([0-2])_continuous_inverted_example (from TestPlugin)
* wj_send_serial_([0-9a-zA-Z:]*) (from WJSendPlugin) * wj_send_serial:([0-9a-zA-Z:]*) (from WJSendPlugin)
* wj_set_colour_([A|B|T])_([x|y]) (from WJSendPlugin) * wj_set_colour:([A|B|T])_([x|y]) (from WJSendPlugin)
* wj_set_back_colour_([x|y|z]) (from WJSendPlugin) * wj_set_back_colour:([x|y|z]) (from WJSendPlugin)
* wj_set_back_wash_colour_([x|y|z]) (from WJSendPlugin) * wj_set_position:([N|L])_([x|y]) (from WJSendPlugin)
* wj_set_position_([N|L])_([x|y]) (from WJSendPlugin)
* wj_set_mix (from WJSendPlugin) * wj_set_mix (from WJSendPlugin)
* wj_send_append_pad_([0-9]*)_([[:0-9a-zA-Z]*) (from WJSendPlugin) * wj_set_modulation_([a-zA-Z_]*)[:]?([a-zA-Z_]*)_slot_([0-3])_level (from WJSendPlugin)
* wj_send_append_([:0-9a-zA-Z]*) (from WJSendPlugin) * wj_set_current_modulation_slot_([0-3])_level (from WJSendPlugin)
* wj_send_append_pad:([0-9]*)_([[:0-9a-zA-Z]*) (from WJSendPlugin)
* wj_send_append:([:0-9a-zA-Z]*) (from WJSendPlugin)
* wj_set_([a-zA-Z_]*)[:]?([a-zA-Z_]*) (from WJSendPlugin)
* wj_select_next_command (from WJSendPlugin)
* wj_select_previous_command (from WJSendPlugin)
* wj_select_next_argument (from WJSendPlugin)
* wj_select_previous_argument (from WJSendPlugin)
---- ----

View File

@@ -728,6 +728,8 @@ class Actions(object):
def quit_the_program(self): def quit_the_program(self):
self.data._update_json(self.data.SETTINGS_JSON, self.data.settings)
self.data.plugins.quit_plugins()
self.video_driver.exit_all_players() self.video_driver.exit_all_players()
self.exit_openframeworks() self.exit_openframeworks()
self.exit_osc_server('','') self.exit_osc_server('','')
@@ -971,8 +973,8 @@ 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): #"""def modulate_param_layer_offset_to_amount(self, param, layer, amount):
self.shaders.modulate_param_layer_offset_to_amount(param, amount, layer_offset=layer) # 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):

View File

@@ -88,17 +88,20 @@ class Data(object):
self.shader_bank_data = [self.create_empty_shader_bank() for i in range(3)] self.shader_bank_data = [self.create_empty_shader_bank() for i in range(3)]
if os.path.isfile(self.PATH_TO_DATA_OBJECTS + self.SHADER_BANK_DATA_JSON): if os.path.isfile(self.PATH_TO_DATA_OBJECTS + self.SHADER_BANK_DATA_JSON):
self.shader_bank_data = self._read_json(self.SHADER_BANK_DATA_JSON) self.shader_bank_data = self._read_json(self.SHADER_BANK_DATA_JSON)
self.settings = self._read_json(self.DEFAULT_SETTINGS_JSON) self.settings = self.default_settings = self._read_json(self.DEFAULT_SETTINGS_JSON)
if os.path.isfile(self.PATH_TO_DATA_OBJECTS + self.SETTINGS_JSON): if os.path.isfile(self.PATH_TO_DATA_OBJECTS + self.SETTINGS_JSON):
self.settings = self._read_json(self.SETTINGS_JSON) self.settings = self._read_json(self.SETTINGS_JSON)
self.settings['user_input']['REMOTE_SERVER']['value'] = 'disabled' # remote server off at boot self.settings['user_input'].setdefault('REMOTE_SERVER',
self.default_settings['user_input']['REMOTE_SERVER'])['value'] = 'disabled' # remote server off at boot
self.key_mappings = self._read_json(self.KEYPAD_MAPPING_JSON) self.key_mappings = self._read_json(self.KEYPAD_MAPPING_JSON)
self.osc_mappings = self._read_json(self.OSC_MAPPING_JSON) self.osc_mappings = self._read_json(self.OSC_MAPPING_JSON)
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)
# TODO: move this to a triggerable command/menu item that will spit out files in a place viewable in browser by the 'remote' system
# TODO eventually: have config configurable via remote browser
from utils import docs from utils import docs
docs.generate_mappings_doc("MIDI mappings", self.midi_mappings) docs.generate_mappings_doc("MIDI mappings", self.midi_mappings)
docs.generate_mappings_doc("OSC mappings", self.osc_mappings, column_one_header="OSC address") docs.generate_mappings_doc("OSC mappings", self.osc_mappings, column_one_header="OSC address")
@@ -108,7 +111,6 @@ class Data(object):
def initialise_plugins(self): def initialise_plugins(self):
#initialise plugin manager #initialise plugin manager
self.plugins = plugin_collection.PluginCollection("plugins", self.message_handler, self) self.plugins = plugin_collection.PluginCollection("plugins", self.message_handler, self)
self.plugins.apply_all_plugins_on_value(5)
def load_midi_mapping_for_device(self, device_name): def load_midi_mapping_for_device(self, device_name):
# check if custom config file exists on disk for this device name # check if custom config file exists on disk for this device name

View File

@@ -15,6 +15,9 @@ class Plugin(object):
self.description = 'UNKNOWN' self.description = 'UNKNOWN'
self.pc = plugin_collection self.pc = plugin_collection
def quit_plugin(self):
print("quitting " + type(self).__name__)
class MidiFeedbackPlugin(Plugin): class MidiFeedbackPlugin(Plugin):
"""Base class for MIDI feedback plugins """Base class for MIDI feedback plugins
""" """
@@ -476,6 +479,10 @@ class PluginCollection(object):
print("Looking for plugins under package %s" % self.plugin_package) print("Looking for plugins under package %s" % self.plugin_package)
self.walk_package(self.plugin_package) self.walk_package(self.plugin_package)
def quit_plugins(self):
# tell each plugin to quit
for plugin in self.get_plugins():
plugin.quit_plugin()
def get_plugins(self, clazz = None): def get_plugins(self, clazz = None):
if clazz: if clazz:
@@ -483,16 +490,6 @@ class PluginCollection(object):
else: else:
return [c for c in self.plugins if not c.disabled] 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): def walk_package(self, package):
"""Recursively walk the supplied package to retrieve all plugins """Recursively walk the supplied package to retrieve all plugins
""" """

View File

@@ -256,7 +256,7 @@ class Display(object):
self.display_text.insert(END, "%s "%a) self.display_text.insert(END, "%s "%a)
self.display_text.insert(END, "\n") self.display_text.insert(END, "\n")
bar = u"_\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588" bar = u"_\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588"
for layer, modulations in enumerate(self.shaders.selected_modulation_level): for layer, modulations in enumerate(self.shaders.modulation_level):
if (layer==self.data.shader_layer): if (layer==self.data.shader_layer):
self.display_text.insert(END, '*') self.display_text.insert(END, '*')
else: else:

View File

@@ -8,7 +8,7 @@ echo
echo "# Methods" echo "# Methods"
grep " def " actions.py | grep -v "^#" | sed -e 's/ def //' | sed -e 's/self//' | sed -e 's/(, /(/' | sed -e 's/()//' | sed -e 's/\(.*\)/ *\1/' | sed -e 's/://' | sort -n \ grep " def " actions.py | grep -v "^#" | sed -e 's/ def //' | sed -e 's/self//' | sed -e 's/(, /(/' | sed -e 's/()//' | sed -e 's/\(.*\)/ *\1/' | sed -e 's/://' | sort -n \
| 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\|show_ip\|toggle_remote_server\|enable_osc\|shutdown_osc_server"
echo echo
echo "## Dynamic routes" echo "## Dynamic routes"

View File

@@ -31,7 +31,8 @@
"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"],
"NAV_LFO": ["toggle_lfo_active"] "NAV_LFO": ["toggle_lfo_active"],
"NAV_SND": ["toggle_sound_react_active"]
}, },
"d": { "d": {
"DEFAULT": ["switch_to_next_player", "toggle_player_mode"], "DEFAULT": ["switch_to_next_player", "toggle_player_mode"],

View File

@@ -45,14 +45,16 @@
"NAV_WJMX": ["wj_set_position_N:x"], "NAV_WJMX": ["wj_set_position_N:x"],
"NAV_MANI": ["set_variable_A"], "NAV_MANI": ["set_variable_A"],
"NAV_LPRC": ["set_automation_speed"], "NAV_LPRC": ["set_automation_speed"],
"NAV_LFO": ["set_lfo_modulation_0_level"] "NAV_LFO": ["set_lfo_modulation_0_level"],
"NAV_SND": ["sound_set_config_energy_gain"]
}, },
"control_change 49": { "control_change 49": {
"DEFAULT": ["set_the_shader_param_1_layer_offset_0_continuous","set_shader_speed_layer_0_amount"], "DEFAULT": ["set_the_shader_param_1_layer_offset_0_continuous","set_shader_speed_layer_0_amount"],
"NAV_DETOUR": ["set_detour_start_continuous"], "NAV_DETOUR": ["set_detour_start_continuous"],
"NAV_WJMX": ["wj_set_position_N:y"], "NAV_WJMX": ["wj_set_position_N:y"],
"NAV_MANI": ["f:sin(x*pi):|set_variable_SIN"], "NAV_MANI": ["f:sin(x*pi):|set_variable_SIN"],
"NAV_LFO": ["set_lfo_modulation_1_level"] "NAV_LFO": ["set_lfo_modulation_1_level"],
"NAV_SND": ["sound_set_config_energy_threshold"]
}, },
"control_change 50": { "control_change 50": {
"DEFAULT": ["set_the_shader_param_2_layer_offset_0_continuous","set_shader_speed_layer_1_amount"], "DEFAULT": ["set_the_shader_param_2_layer_offset_0_continuous","set_shader_speed_layer_1_amount"],
@@ -70,22 +72,26 @@
"DEFAULT": ["set_the_shader_param_0_layer_offset_1_continuous","set_param_0_layer_offset_0_modulation_level_continuous"], "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"], "NAV_DETOUR": ["set_detour_speed_position_continuous"],
"NAV_WJMX": ["wj_set_mix","wj_set_current_modulation_slot_0_level"], "NAV_WJMX": ["wj_set_mix","wj_set_current_modulation_slot_0_level"],
"NAV_LFO": ["set_lfo_speed"] "NAV_LFO": ["set_lfo_speed"],
"NAV_SND": ["sound_set_modulation_energy_slot_0_level"]
}, },
"control_change 53": { "control_change 53": {
"DEFAULT": ["set_the_shader_param_1_layer_offset_1_continuous","set_param_1_layer_offset_0_modulation_level_continuous"], "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"], "NAV_DETOUR": ["set_detour_start_continuous"],
"NAV_WJMX": ["wj_set_back_colour:h","wj_set_current_modulation_slot_1_level"] "NAV_WJMX": ["wj_set_back_colour:h","wj_set_current_modulation_slot_1_level"],
"NAV_SND": ["sound_set_modulation_energy_slot_1_level"]
}, },
"control_change 54": { "control_change 54": {
"DEFAULT": ["set_the_shader_param_2_layer_offset_1_continuous","set_param_2_layer_offset_0_modulation_level_continuous"], "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"], "NAV_DETOUR": ["set_detour_end_continuous"],
"NAV_WJMX": ["wj_set_back_colour:s","wj_set_current_modulation_slot_2_level"] "NAV_WJMX": ["wj_set_back_colour:s","wj_set_current_modulation_slot_2_level"],
"NAV_SND": ["sound_set_modulation_energy_slot_2_level"]
}, },
"control_change 55": { "control_change 55": {
"DEFAULT": ["set_the_shader_param_3_layer_offset_1_continuous","set_param_3_layer_offset_0_modulation_level_continuous"], "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"], "NAV_DETOUR": ["set_detour_end_continuous"],
"NAV_WJMX": ["wj_set_back_colour:v","wj_set_current_modulation_slot_3_level"] "NAV_WJMX": ["wj_set_back_colour:v","wj_set_current_modulation_slot_3_level"],
"NAV_SND": ["sound_set_modulation_energy_slot_3_level"]
}, },
"control_change 56": { "control_change 56": {
"DEFAULT": ["set_the_shader_param_0_layer_offset_2_continuous"], "DEFAULT": ["set_the_shader_param_0_layer_offset_2_continuous"],

View File

@@ -45,6 +45,11 @@ class ShaderLoopRecordPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
def save_presets(self): def save_presets(self):
self.pc.update_json(self.PRESET_FILE_NAME, self.frames) self.pc.update_json(self.PRESET_FILE_NAME, self.frames)
def quit_plugin(self):
super().quit_plugin()
self.save_presets()
# DisplayPlugin methods
def get_display_modes(self): def get_display_modes(self):
return ['LOOPREC','NAV_LPRC'] return ['LOOPREC','NAV_LPRC']

View File

@@ -25,6 +25,10 @@ class ShaderQuickPresetPlugin(ActionsPlugin): #,SequencePlugin):
def save_presets(self): def save_presets(self):
self.pc.update_json(self.PRESET_FILE_NAME, self.presets) self.pc.update_json(self.PRESET_FILE_NAME, self.presets)
def quit_plugin(self):
super().quit_plugin()
self.save_presets()
@property @property
def parserlist(self): def parserlist(self):
return [ return [

171
plugins/SoundReactPlugin.py Normal file
View File

@@ -0,0 +1,171 @@
import math
import data_centre.plugin_collection
from data_centre.plugin_collection import ActionsPlugin, SequencePlugin, DisplayPlugin, AutomationSourcePlugin
import pyaudio
import numpy as np
#import matplotlib.pyplot as plt
np.set_printoptions(suppress=True) # don't use scientific notationn
class SoundReactPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
disabled = False
DEBUG = False
active = True
stop_flag = False
pause_flag = False
CHUNK = 4096 # number of data points to read at a time
RATE = 48000 #44100 # time resolution of the recording device (Hz)
frequency = 10 # how often messages are sampled+calculated+sent, not anything to do with audio frequency
config = {}
def __init__(self, plugin_collection):
super().__init__(plugin_collection)
#self.PRESET_FILE_NAME = "ShaderLoopRecordPlugin/frames.json"
if self.active and not self.disabled:
try:
p=pyaudio.PyAudio()
self.stream=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.disabled = True
return
print ("now setting to run automation..")
self.pc.shaders.root.after(500, self.run_automation)
@property
def sources(self):
# TODO: write more interpreters
return {
"energy": self.energy,
#"low": self.low,
#"mid": self.mid,
#"high": self.high,
"peakfreq": self.peakfreq
}
values = {}
levels = {
"energy": [ 0.0, 0.0, 1.0, 0.0 ],
"peakfreq": [ 0.0, 0.0, 0.0, 1.0 ]
}
last_values = {}
display_values = {}
# triggers?
# sudden drop - sudden leap?
# DisplayPlugin methods
def get_display_modes(self):
return ['SOUNDMOD','NAV_SND']
def show_plugin(self, display, display_mode):
from tkinter import Text, END
#super(DisplayPlugin).show_plugin(display, display_mode)
display.display_text.insert(END, '{} \n'.format(display.body_title))
display.display_text.insert(END, "SoundReactPlugin - ")
display.display_text.insert(END, "ACTIVE\n" if self.active else "not active\n")
#display.display_text.insert(END, "\tSpeed: {:03.2f}\n\n".format(self.speed))
for sourcename in sorted(self.sources):
value = self.display_values.get(sourcename) or "{:03.2f}%".format(self.values.get(sourcename,0)*100) or "None"
value += "\t"
for i,l in enumerate(self.levels[sourcename]):
bar = u"_\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588"
g = "ABCD"[i]+'%s '%bar[int(l*(len(bar)-1))]
value += g
display.display_text.insert(END, "{}:\t{}\n".format(sourcename,value))
"""display.display_text.insert(END, "%s\n" %self.last_lfo_status[lfo])
display.display_text.insert(END, "\t%s\n" % self.formula[lfo])"""
#display.display_text.insert(END, "\nLevels:%s\n\n" % self.levels)
display.display_text.insert(END, "\n\n\n")
def run_sequence(self, position):
# position is irrelvant for this plugin, we just want to run continuously
if not self.active:
return
data = np.fromstring(self.stream.read(self.CHUNK, exception_on_overflow = False),dtype=np.int16)
for sourcename in self.sources:
value = self.sources[sourcename](data)
self.values[sourcename] = value
if value is None:
continue
for slot,level in enumerate(self.levels.get(sourcename,[])):
if level>0.0 and self.values.get(sourcename)!=self.last_values.get(sourcename):
self.pc.actions.call_method_name("modulate_param_%s_to_amount_continuous"%slot, self.values[sourcename])
self.last_values[sourcename] = self.values[sourcename]
config.setdefault('energy',{})['gain'] = 0.5 # how much to multiply signal by
config.setdefault('energy',{})['threshold'] = 0.5 # subtract from post-gain signal (hence ignore all values below)
GAIN_MULT = 1.0
def energy(self,data):
peak=np.average(np.abs(data))*2
value = (peak/2**16)/16 * 100
value *= (self.GAIN_MULT * self.config['energy']['gain'])
value = value - self.config['energy']['threshold']
if value<0.0:
value = 0.0
if value>1.0:
value = 1.0
bars="#"*int(50*value)
if self.DEBUG: print("energy:\t\t%05d %s\t(converted to %s)"%(peak,bars,value))
bar = u"_\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588"
g = '%s'%bar[int(value*(len(bar)-1))]
self.display_values['energy'] = "{} g{:03.2f} t{:03.2f}".format(g, self.config['energy']['gain'], self.config['energy']['threshold'])
return value
# dont think this works properly, or maybe it do just be like that
def peakfreq(self,data):
data = data.copy() * np.hanning(len(data)) # smooth the FFT by windowing data
fft = abs(np.fft.fft(data).real)
fft = fft[:int(len(fft)/2)] # keep only first half
freq = np.fft.fftfreq(self.CHUNK,1.0/self.RATE)
freq = freq[:int(len(freq)/2)] # keep only first half
freqPeak = freq[np.where(fft==np.max(fft))[0][0]]+1
if freqPeak<400:
return False
value = freqPeak/16000
value = value**16/16
if self.DEBUG: print("peak frequency:\t%d\tHz\t(converted to %s)"%(freqPeak,value))
self.display_values['peakfreq'] = ("%d Hz\t"%freqPeak) + "{:03.2f}".format(value)
return value
# ActionsPlugin methods
@property
def parserlist(self):
return [
( r"^toggle_sound_react_active$", self.toggle_active ),
( r"^sound_set_config_([a-z]*)_([a-z]*)$", self.set_config ),
( r"^sound_set_modulation_([a-z]*)_slot_([0-3])_level$", self.set_modulation_source_slot_level ),
]
def set_modulation_source_slot_level(self, sourcename, slot, level):
self.levels.setdefault(sourcename,[0.0,0.0,0.0,0.0])[slot] = level
def set_config(self, sourcename, setting, value):
if type(self.config.get(sourcename,{}).get(setting)) is str:
print ("SoundReactPlugin: type of existing setting is string, probably doesnt make sense to set this to a value of this type!")
self.config[sourcename][setting] = value
def toggle_active(self):
self.active = not self.active

View File

@@ -8,6 +8,9 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
disabled = False#True disabled = False#True
DEBUG = False #True DEBUG = False #True
ser = None ser = None
PRESET_FILE_NAME = "WJSendPlugin/presets.json"
presets = {}
# 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
"""serial.Serial(device, baudrate=9600, """serial.Serial(device, baudrate=9600,
bytesize=serial.SEVENBITS, bytesize=serial.SEVENBITS,
@@ -29,12 +32,34 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
print ("WJSendPlugin is disabled, not opening serial") 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))
self.commands[cmd]['modulation'] = levels
# build a reverse map for later use
for cmd,struct in self.commands.items(): for cmd,struct in self.commands.items():
self.command_by_queue[struct['queue']] = struct self.command_by_queue[struct['queue']] = struct
self.pc.actions.tk.after(500, self.refresh) self.pc.actions.tk.after(500, self.refresh)
self.selected_command_name = list(self.commands.keys())[0] self.selected_command_name = list(sorted(self.commands.keys()))[0]
def load_presets(self):
print("trying load presets? %s " % self.PRESET_FILE_NAME)
return self.pc.read_json(self.PRESET_FILE_NAME) or { 'modulation_levels': {} }
def save_presets(self):
for cmd,struct in self.commands.items():
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()
self.save_presets()
# methods/vars for AutomationSourcePlugin # methods/vars for AutomationSourcePlugin
# a lot of the nitty-gritty handled in parent class, these are for interfacing to the plugin # a lot of the nitty-gritty handled in parent class, these are for interfacing to the plugin
@@ -159,6 +184,9 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
output = b'\2' + string.encode('ascii') + b'\3' output = b'\2' + string.encode('ascii') + b'\3'
#with self.serial_lock: #with self.serial_lock:
self.ser.write(output) #.encode()) self.ser.write(output) #.encode())
# TODO: sleeping here seems to help serial response lag problem?
#import time
#time.sleep(0.02)
#yield from self.ser.drain() #yield from self.ser.drain()
if self.DEBUG: if self.DEBUG:
print("send_serial_string: sent string '%s'" % output) #.encode('ascii')) print("send_serial_string: sent string '%s'" % output) #.encode('ascii'))
@@ -251,11 +279,9 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
def set_modulation_command_argument_level(self, command_name, argument_name, slot, level): def set_modulation_command_argument_level(self, command_name, argument_name, slot, level):
if self.DEBUG: print("set_modulation_command_argument_level(%s, %s, %s, %s)" % (command_name, argument_name, slot, level)) if self.DEBUG: print("set_modulation_command_argument_level(%s, %s, %s, %s)" % (command_name, argument_name, slot, level))
if not argument_name: argument_name = 'v' if not argument_name: self.commands[command_name]['arg_names'][0] #argument_name = 'v'
if self.commands[command_name].get('modulation') is None: self.commands[command_name].setdefault('modulation',[{},{},{},{}])[slot][argument_name] = level
self.commands[command_name]['modulation'] = [{},{},{},{}]
self.commands[command_name]['modulation'][slot][argument_name] = level
def set_current_modulation_level(self, slot, level): def set_current_modulation_level(self, slot, level):
self.set_modulation_command_argument_level(self.selected_command_name, self.commands[self.selected_command_name]['arg_names'][self.selected_argument_index], slot, level) self.set_modulation_command_argument_level(self.selected_command_name, self.commands[self.selected_command_name]['arg_names'][self.selected_argument_index], slot, level)
@@ -331,7 +357,7 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
'form': 'VCC:T{:02X}{:02X}', 'form': 'VCC:T{:02X}{:02X}',
'arg_names': [ 'x', 'y' ], 'arg_names': [ 'x', 'y' ],
'arguments': { 'x': 127, 'y': 127 }, 'arguments': { 'x': 127, 'y': 127 },
'modulation': [ {}, {}, { 'x': 1.0 }, { 'y': 1.0 } ] #'modulation': [ {}, {}, { 'x': 1.0 }, { 'y': 1.0 } ]
#'callback': self.set_colour #'callback': self.set_colour
}, },
'mix': { 'mix': {

View File

@@ -48,7 +48,7 @@ class MidiInput(object):
self.data.midi_device_name = self.midi_device.name self.data.midi_device_name = self.midi_device.name
self.message_handler.set_message('INFO', 'connected to midi device {}'.format(self.midi_device.name)) self.message_handler.set_message('INFO', 'connected to midi device {}'.format(self.midi_device.name))
self.midi_mappings = self.data.load_midi_mapping_for_device(self.midi_device.name.split(":")[0]) self.midi_mappings = self.data.load_midi_mapping_for_device(self.midi_device.name.split(":")[0])
self.midi_output = self.find_output_plugin(midi_device_on_port[subport_index]) self.midi_output = self.find_output_plugin(midi_devices[subport_index])
if self.midi_output: if self.midi_output:
#self.midi_feedback_device = mido.open_output(midi_device_on_port[subport_index]) #self.midi_feedback_device = mido.open_output(midi_device_on_port[subport_index])
self.root.after(self.midi_delay, self.refresh_midi_feedback) self.root.after(self.midi_delay, self.refresh_midi_feedback)

View File

@@ -59,11 +59,11 @@ class NumpadInput(object):
else: else:
is_function = 0 is_function = 0
print('the action being called is {}'.format(this_mapping[mode][is_function])) print('the numpad action being called is {} (mode is {})'.format(this_mapping[mode][is_function], mode))
if value != -1: if value != -1:
getattr(self.actions, this_mapping[mode][is_function])(value) self.actions.call_method_name(this_mapping[mode][is_function],value)
else: else:
getattr(self.actions, this_mapping[mode][is_function])() self.actions.call_method_name(this_mapping[mode][is_function])
if is_function and self.data.settings['sampler']['FUNC_GATED']['value'] == 'off': if is_function and self.data.settings['sampler']['FUNC_GATED']['value'] == 'off':
self.data.function_on = False self.data.function_on = False

View File

@@ -23,6 +23,8 @@ class OscInput(object):
self.poll_settings_for_osc_info() self.poll_settings_for_osc_info()
def poll_settings_for_osc_info(self): def poll_settings_for_osc_info(self):
self.data.settings['user_input'].setdefault('OSC_INPUT',
self.data.default_settings['user_input'].get('OSC_INPUT'))
osc_setting_enabled = self.data.settings['user_input']['OSC_INPUT']['value'] == 'enabled' osc_setting_enabled = self.data.settings['user_input']['OSC_INPUT']['value'] == 'enabled'
if osc_setting_enabled and not self.osc_enabled: if osc_setting_enabled and not self.osc_enabled:
self.setup_osc_server() self.setup_osc_server()
@@ -50,8 +52,11 @@ class OscInput(object):
this_dispatcher.map("/shaderparam2", self.on_param_osc_input) this_dispatcher.map("/shaderparam2", self.on_param_osc_input)
this_dispatcher.map("/shaderparam3", self.on_param_osc_input) this_dispatcher.map("/shaderparam3", self.on_param_osc_input)
this_dispatcher.map("/shutdown", self.exit_osc_server) this_dispatcher.map("/shutdown", self.exit_osc_server)
#this_dispatcher.map("/*", print)
# this is for accepting any old osc message to allow binding of modulation to osc messages
# TODO: make configurable?
this_dispatcher.map("/*", self.on_param_osc_input)
osc_server.ThreadingOSCUDPServer.allow_reuse_address = True osc_server.ThreadingOSCUDPServer.allow_reuse_address = True
server = osc_server.ThreadingOSCUDPServer((server_args.ip, server_args.port), this_dispatcher) server = osc_server.ThreadingOSCUDPServer((server_args.ip, server_args.port), this_dispatcher)
server_thread = threading.Thread(target=server.serve_forever) server_thread = threading.Thread(target=server.serve_forever)

View File

@@ -24,11 +24,16 @@ class Shaders(object):
self.selected_speed_list = [1.0, 1.0, 1.0] self.selected_speed_list = [1.0, 1.0, 1.0]
self.selected_modulation_slot = 0 self.selected_modulation_slot = 0
self.selected_modulation_level = [[[0.0,0.0,0.0,0.0] for i in range(4)] for i in range(3)] #self.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.modulation_value = [0.0,0.0,0.0,0.0]
#self.load_selected_shader() #self.load_selected_shader()
@property
def modulation_level(self):
return self.data.settings['shader'].setdefault('modulation_level',
[[[0.0,0.0,0.0,0.0] for i in range(4)] for i in range(3)])
def generate_shaders_list(self): def generate_shaders_list(self):
shaders_menu_list = [] shaders_menu_list = []
raw_list = self.shaders_menu.generate_raw_shaders_list() raw_list = self.shaders_menu.generate_raw_shaders_list()
@@ -170,7 +175,7 @@ class Shaders(object):
self.selected_modulation_slot = slot self.selected_modulation_slot = slot
def reset_modulation(self, slot): def reset_modulation(self, slot):
for layer in self.selected_modulation_level: for layer in self.modulation_level:
for layer,levels in enumerate(layer): for layer,levels in enumerate(layer):
levels[slot] = 0.0 levels[slot] = 0.0
@@ -234,7 +239,7 @@ class Shaders(object):
plugin.set_modulation_value(param, self.modulation_value[param]) plugin.set_modulation_value(param, self.modulation_value[param])
for layer,params in enumerate(self.selected_param_list): for layer,params in enumerate(self.selected_param_list):
for ip,p in enumerate(params): for ip,p in enumerate(params):
for p2,v in enumerate(self.selected_modulation_level[layer][ip]): for p2,v in enumerate(self.modulation_level[layer][ip]):
if v!=0: if v!=0:
self.update_param_layer(ip,layer) self.update_param_layer(ip,layer)
break break
@@ -244,7 +249,7 @@ class Shaders(object):
self.set_param_layer_modulation_level(param, layer, level) self.set_param_layer_modulation_level(param, layer, level)
def set_param_layer_modulation_level(self, param, layer, level): def set_param_layer_modulation_level(self, param, layer, level):
self.selected_modulation_level[layer][param][self.selected_modulation_slot] = level self.modulation_level[layer][param][self.selected_modulation_slot] = level
self.update_param_layer(param, layer) self.update_param_layer(param, layer)
def update_param_layer(self, param, layer): def update_param_layer(self, param, layer):
@@ -254,7 +259,7 @@ class Shaders(object):
self.get_modulation_value_list( self.get_modulation_value_list(
self.selected_param_list[layer][param], self.selected_param_list[layer][param],
self.modulation_value,#[0], #param], self.modulation_value,#[0], #param],
self.selected_modulation_level[layer][param] self.modulation_level[layer][param]
) )
) )