Whitespace

This commit is contained in:
Ryan Jarvis
2020-05-01 11:28:50 -07:00
parent 9ebbb439cb
commit 81a37df50e
31 changed files with 1575 additions and 1600 deletions

View File

@@ -32,7 +32,7 @@ class Actions(object):
self.remote_process = None
self.set_capture_object('value')
self.server = self.setup_osc_server()
def set_capture_object(self, value):
if self.data.settings['video']['VIDEOPLAYER_BACKEND']['value'] != 'omxplayer':
self.python_capture.close_capture()
@@ -54,7 +54,6 @@ class Actions(object):
def move_browser_selection_page_up(self):
self.display.browser_menu.navigate_menu_page_up()
def enter_on_browser_selection(self):
self.display.browser_menu.enter_on_browser_selection()
@@ -70,7 +69,6 @@ class Actions(object):
def move_settings_selection_page_up(self):
self.display.settings_menu.navigate_menu_page_up()
def enter_on_settings_selection(self):
is_setting, setting = self.display.settings_menu.enter_on_setting_selection()
if is_setting:
@@ -92,7 +90,6 @@ class Actions(object):
def move_shaders_selection_page_up(self):
self.shaders.shaders_menu.navigate_menu_page_up()
def enter_on_shaders_selection(self):
##want to select shader if its not selected, and want to enter 'param' mode if it already is
is_shader, is_selected_shader, selected_shader = self.shaders.enter_on_shaders_selection()
@@ -122,7 +119,7 @@ class Actions(object):
self.display.browser_menu.generate_browser_list()
def _load_this_slot_into_next_player(self, slot):
### load next player for seamless type otherwise respect player mode
### load next player for seamless type otherwise respect player mode
if self.data.settings['sampler']['LOOP_TYPE']['value'] == 'seamless':
if self.data.update_next_slot_number(slot):
print('should reload next player !! ')
@@ -134,8 +131,6 @@ class Actions(object):
else:
if self.data.update_next_slot_number(slot, is_current=True):
self.video_driver.reload_current_player()
def load_slot_0_into_next_player(self):
self._load_this_slot_into_next_player(0)
@@ -177,8 +172,8 @@ class Actions(object):
def set_display_mode(self, display_mode):
mapmodes = {
'shader': 'SHADERS',
'shader_bank': 'SHDR_BNK'
'shader': 'SHADERS',
'shader_bank': 'SHDR_BNK'
}
if display_mode in mapmodes:
display_mode = mapmodes[display_mode]
@@ -186,7 +181,7 @@ class Actions(object):
display_mode = display_mode.upper()
display_modes = self.data.get_display_modes_list(with_nav_mode=True)
for i,dm in enumerate(display_modes):
for i, dm in enumerate(display_modes):
if display_mode in dm:
self.data.display_mode = display_modes[i][0]
self.data.control_mode = display_modes[i][1]
@@ -195,7 +190,7 @@ class Actions(object):
display_modes = self.data.get_display_modes_list(with_nav_mode=True)
current_mode_index = [index for index, i in enumerate(display_modes) if self.data.display_mode in i][0]
next_mode_index = (current_mode_index + 1) % len(display_modes)
next_mode_index = (current_mode_index + 1) % len(display_modes)
self.data.display_mode = display_modes[next_mode_index][0]
self.data.control_mode = display_modes[next_mode_index][1]
@@ -203,11 +198,10 @@ class Actions(object):
display_modes = self.data.get_display_modes_list(with_nav_mode=True)
current_mode_index = [index for index, i in enumerate(display_modes) if self.data.display_mode in i][0]
next_mode_index = (current_mode_index - 1) % len(display_modes)
next_mode_index = (current_mode_index - 1) % len(display_modes)
self.data.display_mode = display_modes[next_mode_index][0]
self.data.control_mode = display_modes[next_mode_index][1]
def toggle_action_on_player(self):
play = 'play' in self.data.settings['sampler']['ON_ACTION']['value']
show = 'show' in self.data.settings['sampler']['ON_ACTION']['value']
@@ -230,19 +224,17 @@ class Actions(object):
def increase_seek_time(self):
options = self.data.settings['sampler']['SEEK_TIME']['options']
current_index = [index for index, item in enumerate(options) if item == self.data.settings['sampler']['SEEK_TIME']['value'] ][0]
self.data.update_setting_value('sampler', 'SEEK_TIME', options[(current_index + 1) % len(options) ])
current_index = [index for index, item in enumerate(options) if item == self.data.settings['sampler']['SEEK_TIME']['value']][0]
self.data.update_setting_value('sampler', 'SEEK_TIME', options[(current_index + 1) % len(options)])
self.message_handler.set_message('INFO', 'The Seek Time is now ' + str(self.data.settings['sampler']['SEEK_TIME']['value']) + 's')
def decrease_seek_time(self):
options = self.data.settings['sampler']['SEEK_TIME']['options']
current_index = [index for index, item in enumerate(options) if item == self.data.settings['sampler']['SEEK_TIME']['value'] ][0]
self.data.update_setting_value('sampler', 'SEEK_TIME', options[(current_index - 1) % len(options) ])
current_index = [index for index, item in enumerate(options) if item == self.data.settings['sampler']['SEEK_TIME']['value']][0]
self.data.update_setting_value('sampler', 'SEEK_TIME', options[(current_index - 1) % len(options)])
self.message_handler.set_message('INFO', 'The Seek Time is now ' + str(self.data.settings['sampler']['SEEK_TIME']['value']) + 's')
def seek_forward_on_player(self):
def seek_forward_on_player(self):
self.video_driver.current_player.seek(self.data.settings['sampler']['SEEK_TIME']['value'])
def seek_back_on_player(self):
@@ -264,24 +256,24 @@ class Actions(object):
def previous_bank(self):
self.data.update_bank_number_by_amount(-1)
print('current bank is {} , the number of banks is {} '.format(self.data.bank_number, len(self.data.bank_data)))
def increase_speed(self):
print("increasing speed !")
new_rate = self.video_driver.current_player.change_rate(1)
current_bank, current_slot = self.data.split_bankslot_number(self.video_driver.current_player.bankslot_number)
self.data.update_slot_rate_to_this(current_slot, new_rate)
#self._load_this_slot_into_next_player(current_slot)
# self._load_this_slot_into_next_player(current_slot)
def decrease_speed(self):
print("increasing speed !")
new_rate = self.video_driver.current_player.change_rate(-1)
current_bank, current_slot = self.data.split_bankslot_number(self.video_driver.current_player.bankslot_number)
self.data.update_slot_rate_to_this(current_slot, new_rate)
#self._load_this_slot_into_next_player(current_slot)
# self._load_this_slot_into_next_player(current_slot)
def set_playing_sample_start_to_current_duration(self):
current_bank, current_slot = self.data.split_bankslot_number(self.video_driver.current_player.bankslot_number)
current_position = round(self.video_driver.current_player.get_position(),3)
current_position = round(self.video_driver.current_player.get_position(), 3)
self.data.update_slot_start_to_this_time(current_slot, current_position)
self._load_this_slot_into_next_player(current_slot)
@@ -292,7 +284,7 @@ class Actions(object):
def set_playing_sample_end_to_current_duration(self):
current_bank, current_slot = self.data.split_bankslot_number(self.video_driver.current_player.bankslot_number)
current_position = round(self.video_driver.current_player.get_position(),0)
current_position = round(self.video_driver.current_player.get_position(), 0)
self.data.update_slot_end_to_this_time(current_slot, current_position)
self._load_this_slot_into_next_player(current_slot)
@@ -305,19 +297,18 @@ class Actions(object):
is_previewing = self.capture.is_previewing
if is_previewing:
self.capture.stop_preview()
#if self.video_driver.current_player.status == 'PAUSED':
#self.video_driver.current_player.toggle_pause()
# if self.video_driver.current_player.status == 'PAUSED':
# self.video_driver.current_player.toggle_pause()
else:
is_successful = self.capture.start_preview()
#if is_successful and self.video_driver.current_player.status != 'PAUSED':
#self.video_driver.current_player.toggle_pause()
# if is_successful and self.video_driver.current_player.status != 'PAUSED':
# self.video_driver.current_player.toggle_pause()
def toggle_capture_recording(self):
is_recording = self.capture.is_recording
if is_recording:
self.capture.stop_recording()
else:
else:
self.capture.start_recording()
def toggle_screen_mirror(self):
@@ -360,12 +351,12 @@ class Actions(object):
self.data.detour_active = True
shader_input = self.data.settings['detour']['SHADER_POSITION']['value'] == 'input'
self.video_driver.osc_client.send_message("/detour/start", shader_input)
self.load_this_detour_shader()
self.load_this_detour_shader()
def toggle_detour_play(self):
if self.data.settings['detour']['TRY_DEMO']['value'] == 'enabled':
is_playing = not self.data.detour_settings['is_playing']
self.data.detour_settings['is_playing'] = is_playing
is_playing = not self.data.detour_settings['is_playing']
self.data.detour_settings['is_playing'] = is_playing
self.video_driver.osc_client.send_message("/detour/is_playing", is_playing)
def toggle_feedback(self):
@@ -432,14 +423,14 @@ class Actions(object):
def toggle_detour_record(self):
if self.data.settings['detour']['TRY_DEMO']['value'] == 'enabled':
is_recording = not self.data.detour_settings['is_recording']
self.data.detour_settings['is_recording'] = is_recording
is_recording = not self.data.detour_settings['is_recording']
self.data.detour_settings['is_recording'] = is_recording
self.video_driver.osc_client.send_message("/detour/is_recording", is_recording)
def toggle_detour_record_loop(self):
if self.data.settings['detour']['TRY_DEMO']['value'] == 'enabled':
record_loop = not self.data.detour_settings['record_loop']
self.data.detour_settings['record_loop'] = record_loop
self.data.detour_settings['record_loop'] = record_loop
self.video_driver.osc_client.send_message("/detour/record_loop", record_loop)
def clear_this_detour(self):
@@ -477,10 +468,9 @@ class Actions(object):
def switch_to_this_detour(self, number):
if self.data.settings['detour']['TRY_DEMO']['value'] == 'enabled':
self.data.detour_settings['current_detour'] = number
self.data.detour_settings['current_detour'] = number
self.video_driver.osc_client.send_message("/detour/switch_to_detour_number", number)
def set_detour_delay_mode(self, state):
self.video_driver.osc_client.send_message("/detour/set_delay_mode", state == 'enabled')
self.data.update_conjur_delay_mode(state == 'enabled')
@@ -513,19 +503,19 @@ class Actions(object):
self.set_detour_mix_continuous(1)
def set_the_camera_colour_u_continuous(self, amount):
self.capture.set_colour(amount*255, None)
self.capture.set_colour(amount * 255, None)
def set_the_camera_colour_v_continuous(self, amount):
self.capture.set_colour(None, amount*255)
self.capture.set_colour(None, amount * 255)
def set_the_camera_alpha_continuous(self, amount):
self.capture.set_alpha(amount*255)
self.capture.set_alpha(amount * 255)
def set_the_current_video_alpha_continuous(self, amount):
self.video_driver.current_player.set_alpha_value(amount*255)
self.video_driver.current_player.set_alpha_value(amount * 255)
def set_the_next_video_alpha_continuous(self, amount):
self.video_driver.next_player.set_alpha_value(amount*255)
self.video_driver.next_player.set_alpha_value(amount * 255)
def set_the_shader_param_0_layer_offset_0_continuous(self, amount):
self.shaders.set_param_to_amount(0, amount, layer_offset=0)
@@ -583,8 +573,8 @@ class Actions(object):
self.data.update_setting_value('shader', 'STROBE_AMOUNT', scaled_amount)
def get_midi_status(self):
device_name = 'none' if not hasattr(self.data,'midi_device_name') else self.data.midi_device_name
self.message_handler.set_message('INFO', ("midi status is {} to %s"%(device_name)).format(self.data.midi_status))
device_name = 'none' if not hasattr(self.data, 'midi_device_name') else self.data.midi_device_name
self.message_handler.set_message('INFO', ("midi status is {} to %s" % (device_name)).format(self.data.midi_status))
def cycle_midi_port_index(self):
self.data.midi_port_index = self.data.midi_port_index + 1
@@ -629,24 +619,23 @@ class Actions(object):
self.data.update_setting_value('video', 'OUTPUT', 'hdmi')
if self.data.settings['video']['HDMI_MODE']['value'] == "CEA 4 HDMI":
self.data.update_setting_value('video', 'HDMI_MODE', 'CEA 4 HDMI')
self.change_hdmi_settings('CEA 4 HDMI')
def check_dev_mode(self):
#### check if in dev mode:(ie not using the lcd screen)
with open('/boot/config.txt', 'r') as config:
if '##no_waveshare_overlay' in config.read():
self.data.update_setting_value('system','DEV_MODE_RESET', 'on')
else:
self.data.update_setting_value('system','DEV_MODE_RESET', 'off')
if '##no_waveshare_overlay' in config.read():
self.data.update_setting_value('system', 'DEV_MODE_RESET', 'on')
else:
self.data.update_setting_value('system', 'DEV_MODE_RESET', 'off')
def check_if_should_start_openframeworks(self):
if self.data.settings['video']['VIDEOPLAYER_BACKEND']['value'] != 'omxplayer':
with open("conjur.log","w+") as out:
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)
with open("conjur.log", "w+") as out:
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):
@@ -669,7 +658,7 @@ class Actions(object):
self.set_capture_object('nothing')
self.display.settings_menu.generate_settings_list()
self.reset_players()
def reset_players(self):
self.video_driver.reset_all_players()
@@ -680,16 +669,15 @@ class Actions(object):
progressive = ''
if self.data.settings['video']['COMPOSITE_PROGRESSIVE']['value'] == 'on':
progressive = 'p'
if output == 'composite':
subprocess.call(['tvservice --sdtvon="{} {} {}"'.format(mode, aspect, progressive)],shell=True)
subprocess.call(['tvservice --sdtvon="{} {} {}"'.format(mode, aspect, progressive)], shell=True)
self.refresh_frame_buffer_and_restart_openframeworks()
self.persist_composite_setting(mode, progressive, aspect)
def _refresh_frame_buffer(self):
self.data.open_omxplayer_for_reset()
subprocess.run(["fbset -depth 16; fbset -depth 32; xrefresh -display :0" ], shell=True)
subprocess.run(["fbset -depth 16; fbset -depth 32; xrefresh -display :0"], shell=True)
def persist_composite_setting(self, mode, progressive, aspect):
sdtv_mode = ''
@@ -714,7 +702,7 @@ class Actions(object):
self.update_config_settings(sdtv_mode, sdtv_aspect)
def update_config_settings(self, sdtv_mode, sdtv_aspect):
self.run_script('set_composite_mode',sdtv_mode, sdtv_aspect)
self.run_script('set_composite_mode', sdtv_mode, sdtv_aspect)
def switch_dev_mode(self, state):
if state == 'on':
@@ -727,13 +715,12 @@ class Actions(object):
self.switch_display_to_lcd()
def switch_display_to_hdmi(self):
with open('/boot/config.txt', 'r') as config:
with open('/boot/config.txt', 'r') as config:
with open('/usr/share/X11/xorg.conf.d/99-fbturbo.conf') as framebuffer_conf:
if 'dtoverlay=waveshare35a:rotate=270' in config.read() and 'dev/fb1' in framebuffer_conf.read():
self.run_script('switch_display_to_hdmi')
else:
self.message_handler.set_message('INFO', 'failed to switch display')
def switch_display_to_lcd(self):
with open('/boot/config.txt', 'r') as config:
@@ -745,9 +732,9 @@ class Actions(object):
self.message_handler.set_message('INFO', 'failed to switch display')
def run_script(self, script_name, first_argument='', second_argument=''):
print('first arg is {} , second is {}'.format(first_argument,second_argument))
subprocess.call(['/home/pi/r_e_c_u_r/dotfiles/{}.sh'.format(script_name),first_argument, second_argument ])
print('first arg is {} , second is {}'.format(first_argument, second_argument))
subprocess.call(['/home/pi/r_e_c_u_r/dotfiles/{}.sh'.format(script_name), first_argument, second_argument])
def toggle_x_autorepeat(self):
if self.data.auto_repeat_on:
subprocess.call(['xset', 'r', 'off'])
@@ -756,13 +743,12 @@ class Actions(object):
subprocess.call(['xset', 'r', 'on'])
self.data.auto_repeat_on = True
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.exit_openframeworks()
self.exit_osc_server('','')
self.exit_osc_server('', '')
self.create_client_and_shutdown_osc_server()
self.stop_serial_port_process()
self.stop_openframeworks_process()
@@ -772,8 +758,8 @@ class Actions(object):
def restart_the_program(self):
self.quit_the_program()
os.execv('/usr/bin/python3', [sys.argv[0],'/home/pi/r_e_c_u_r/r_e_c_u_r.py'])
os.execv('/usr/bin/python3', [sys.argv[0], '/home/pi/r_e_c_u_r/r_e_c_u_r.py'])
def set_shader_param_mode(self):
self.data.control_mode = 'SHADER_PARAM'
self.message_handler.set_message('INFO', '[ ]: focus < >: level ■: back')
@@ -786,21 +772,21 @@ class Actions(object):
self.shaders.decrease_this_param(self.data.settings['shader']['SHADER_PARAM']['value'])
def increase_param_focus(self):
self.shaders.focused_param = (self.shaders.focused_param + 1)%self.shaders.selected_shader_list[self.data.shader_layer]['param_number']
self.shaders.focused_param = (self.shaders.focused_param + 1) % self.shaders.selected_shader_list[self.data.shader_layer]['param_number']
def decrease_param_focus(self):
self.shaders.focused_param = (self.shaders.focused_param - 1)%self.shaders.selected_shader_list[self.data.shader_layer]['param_number']
self.shaders.focused_param = (self.shaders.focused_param - 1) % self.shaders.selected_shader_list[self.data.shader_layer]['param_number']
def increase_shader_param(self):
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]
self.data.update_setting_value('shader', 'SHADER_PARAM', options[(current_index + 1) % len(options) ])
current_index = [index for index, item in enumerate(options) if item == self.data.settings['shader']['SHADER_PARAM']['value']][0]
self.data.update_setting_value('shader', 'SHADER_PARAM', options[(current_index + 1) % len(options)])
self.message_handler.set_message('INFO', 'The Param amount is now ' + str(self.data.settings['shader']['SHADER_PARAM']['value']))
def decrease_shader_param(self):
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]
self.data.update_setting_value('shader', 'SHADER_PARAM', options[(current_index - 1) % len(options) ])
current_index = [index for index, item in enumerate(options) if item == self.data.settings['shader']['SHADER_PARAM']['value']][0]
self.data.update_setting_value('shader', 'SHADER_PARAM', options[(current_index - 1) % len(options)])
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):
@@ -808,12 +794,11 @@ class Actions(object):
self.message_handler.set_message('INFO', 'tap: ■ ; < > : back')
self.fixed_length_setter = length_setter.FixedLengthSetter(self.data)
def return_to_default_control_mode(self):
display_list = self.data.get_display_modes_list(with_nav_mode=True)
for display, control in display_list:
if display == self.data.display_mode:
self.data.control_mode = control
self.data.control_mode = control
def perform_confirm_action(self):
action = self.data.confirm_action
@@ -829,10 +814,10 @@ class Actions(object):
self.message_handler.set_message('INFO', 'confirm: {} ■:y < >:no'.format(action_title[:22]))
def confirm_shutdown(self):
self.start_confirm_action('shutdown_pi' )
self.start_confirm_action('shutdown_pi')
def confirm_quit(self):
self.start_confirm_action('quit_the_program', message='quit' )
self.start_confirm_action('quit_the_program', message='quit')
def confirm_switch_dev_mode(self, state):
# i startd writing a confirm dev mod but it messed with the state if you say no ...
@@ -843,7 +828,6 @@ class Actions(object):
self.fixed_length_setter.record_input()
self.display.settings_menu.generate_settings_list()
def setup_osc_server(self):
server_parser = argparse.ArgumentParser()
server_parser.add_argument("--ip", default="127.0.0.1", help="the ip")
@@ -861,7 +845,7 @@ class Actions(object):
this_dispatcher.map("/detour/detour_info", self.receive_detour_info)
this_dispatcher.map("/capture/recording_finished", self.capture.receive_recording_finished)
this_dispatcher.map("/shutdown", self.exit_osc_server)
#this_dispatcher.map("/player/a/status", self.set_status)
# this_dispatcher.map("/player/a/status", self.set_status)
osc_server.ThreadingOSCUDPServer.allow_reuse_address = True
server = osc_server.ThreadingOSCUDPServer((server_args.ip, server_args.port), this_dispatcher)
@@ -889,10 +873,10 @@ class Actions(object):
def toggle_access_point(self, setting_value):
osc_setting_state = self.data.settings['user_input']['OSC_INPUT']['value']
self.data.update_setting_value('user_input', 'OSC_INPUT', 'disabled')
self.data.update_setting_value('user_input', 'OSC_INPUT', 'disabled')
self.tk.after(2000, self.toggle_access_point_delay, setting_value, osc_setting_state)
def toggle_access_point_delay(self, setting_value, osc_setting_state ):
def toggle_access_point_delay(self, setting_value, osc_setting_state):
if setting_value == 'enabled':
subprocess.call(['sudo', 'bash', '/home/pi/raspiApWlanScripts/switchToAP.sh'])
else:
@@ -914,7 +898,6 @@ class Actions(object):
def enable_osc(self, osc_setting_state):
self.data.update_setting_value('user_input', 'OSC_INPUT', osc_setting_state)
def show_ip(self, *args):
address = self.data.get_ip_address()
self.message_handler.set_message('INFO', 'ip is {}:8080'.format(address))
@@ -922,14 +905,13 @@ class Actions(object):
def create_serial_port_process(self):
if self.serial_port_process == None:
self.serial_port_process = subprocess.Popen("exec " + "ttymidi -s /dev/serial0 -b 38400 -n serial", shell=True)
print('created the serial port process ? {}'.format(self.serial_port_process))
print('created the serial port process ? {}'.format(self.serial_port_process))
def stop_serial_port_process(self):
if self.serial_port_process is not None:
self.serial_port_process.kill()
self.serial_port_process = None
def stop_remote_process(self):
if self.remote_process is not None:
self.remote_process.kill()
@@ -939,7 +921,7 @@ class Actions(object):
self.reset_players()
self.exit_openframeworks()
self.stop_openframeworks_process()
self.check_if_should_start_openframeworks()
self.check_if_should_start_openframeworks()
def refresh_frame_buffer_and_restart_openframeworks(self):
if self.data.settings['video']['VIDEOPLAYER_BACKEND']['value'] != 'omxplayer':
@@ -948,7 +930,7 @@ class Actions(object):
self.stop_openframeworks_process()
self._refresh_frame_buffer()
self.check_if_should_start_openframeworks()
#self.tk.after(1000, self.check_if_should_start_openframeworks)
# self.tk.after(1000, self.check_if_should_start_openframeworks)
else:
self._refresh_frame_buffer()
@@ -960,21 +942,21 @@ class Actions(object):
subprocess.call(['killall', 'c_o_n_j_u_r'])
def try_pull_code_and_reset(self):
#self.message_handler.set_message('INFO', 'checkin fo updates pls wait')
# self.message_handler.set_message('INFO', 'checkin fo updates pls wait')
recur_repo = git.Repo("~/r_e_c_u_r")
conjur_repo = git.Repo(self.data.PATH_TO_OPENFRAMEWORKS + "apps/myApps/c_o_n_j_u_r")
ofxVideoArtTools_repo = git.Repo(self.data.PATH_TO_OPENFRAMEWORKS + "/addons/ofxVideoArtTools")
ofxVideoArtTools_repo = git.Repo(self.data.PATH_TO_OPENFRAMEWORKS + "/addons/ofxVideoArtTools")
current_recur_hash = recur_repo.head.object.hexsha
current_conjur_hash = conjur_repo.head.object.hexsha
current_ofxVideoArtTools_hash = ofxVideoArtTools_repo.head.object.hexsha
self.data.try_remove_file(self.data.PATH_TO_DATA_OBJECTS + self.data.SETTINGS_JSON )
self.data.try_remove_file(self.data.PATH_TO_DEFAULT_CONJUR_DATA)
self.data.try_remove_file(self.data.PATH_TO_DATA_OBJECTS + self.data.SETTINGS_JSON)
self.data.try_remove_file(self.data.PATH_TO_DEFAULT_CONJUR_DATA)
try:
recur_repo.remotes.origin.pull()
conjur_repo.remotes.origin.pull()
ofxVideoArtTools_repo.remotes.origin.pull()
except git.exc.GitCommandError as e:
except git.exc.GitCommandError as e:
if 'unable to access' in str(e):
self.message_handler.set_message('INFO', 'not connected to network')
else:
@@ -982,22 +964,22 @@ class Actions(object):
error_info = e.message
else:
error_info = e
self.message_handler.set_message('ERROR',error_info)
self.message_handler.set_message('ERROR', error_info)
return
new_recur_hash = recur_repo.head.object.hexsha
new_conjur_hash = conjur_repo.head.object.hexsha
new_ofxVideoArtTools_hash = ofxVideoArtTools_repo.head.object.hexsha
if current_recur_hash != new_recur_hash or current_conjur_hash != new_conjur_hash or current_ofxVideoArtTools_hash != new_ofxVideoArtTools_hash :
#something has changed!
if current_recur_hash != new_recur_hash or current_conjur_hash != new_conjur_hash or current_ofxVideoArtTools_hash != new_ofxVideoArtTools_hash:
# something has changed!
self.restart_the_program()
else:
self.message_handler.set_message('INFO', 'up to date !')
# def complie_openframeworks(self):
# subprocess.call(['make', '--directory=' + self.data.PATH_TO_OPENFRAMEWORKS + 'apps/myApps/c_o_n_j_u_r' ])
# self.message_handler.set_message('INFO', 'finished compiling!')
# self.restart_the_program()
# def complie_openframeworks(self):
# subprocess.call(['make', '--directory=' + self.data.PATH_TO_OPENFRAMEWORKS + 'apps/myApps/c_o_n_j_u_r' ])
# self.message_handler.set_message('INFO', 'finished compiling!')
# self.restart_the_program()
def shutdown_pi(self):
subprocess.call(['sudo', 'shutdown', '-h', 'now'])
@@ -1005,7 +987,7 @@ class Actions(object):
def clear_message(self):
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)"""
@staticmethod
@@ -1016,35 +998,34 @@ class Actions(object):
def eject_all_usb_drives(self):
for i in range(1, 4):
if os.path.exists('/dev/sda{}'.format(i)):
subprocess.call(['sudo', 'eject', '/dev/sda{}'.format(i)])
subprocess.call(['sudo', 'eject', '/dev/sda{}'.format(i)])
self.message_handler.set_message('INFO', 'usb ejected')
# TODO: make this interrogate the various components for available routes to parse
# this would include eg a custom script module..
@property
def parserlist(self):
return {
( r"^play_shader_([0-9])_([0-9])$", self.shaders.play_that_shader ),
( r"^toggle_shader_layer_([0-2])$", self.toggle_shader_layer ),
( r"^start_shader_layer_([0-2])$", self.shaders.start_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"^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_modulation_level ),
( r"^set_param_([0-3])_layer_offset_([0-2])_modulation_level_continuous$", self.shaders.set_param_layer_offset_modulation_level ),
( r"^reset_selected_modulation$", self.shaders.reset_selected_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_next_shader_modulation_slot$", self.shaders.select_next_shader_modulation_slot ),
( r"^select_previous_shader_modulation_slot$", self.shaders.select_previous_shader_modulation_slot ),
( 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_display_mode_([a-zA-Z_]*)$", self.set_display_mode )
(r"^play_shader_([0-9])_([0-9])$", self.shaders.play_that_shader),
(r"^toggle_shader_layer_([0-2])$", self.toggle_shader_layer),
(r"^start_shader_layer_([0-2])$", self.shaders.start_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"^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_modulation_level),
(r"^set_param_([0-3])_layer_offset_([0-2])_modulation_level_continuous$", self.shaders.set_param_layer_offset_modulation_level),
(r"^reset_selected_modulation$", self.shaders.reset_selected_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_next_shader_modulation_slot$", self.shaders.select_next_shader_modulation_slot),
(r"^select_previous_shader_modulation_slot$", self.shaders.select_previous_shader_modulation_slot),
(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_display_mode_([a-zA-Z_]*)$", self.set_display_mode)
}
def detect_types(self, args):
a = [ int(arg) if str(arg).isnumeric() else str(arg) for arg in list(args) ]
a = [int(arg) if str(arg).isnumeric() else str(arg) for arg in list(args)]
return a
def get_callback_for_method(self, method_name, argument):
@@ -1054,13 +1035,13 @@ class Actions(object):
matches = re.search(regex, method_name)
if matches:
found_method = me
parsed_args = self.detect_types(matches.groups()) #list(map(int,matches.groups()))
found_method = me
parsed_args = self.detect_types(matches.groups()) # list(map(int,matches.groups()))
if argument is not None:
args = parsed_args + [argument]
else:
args = parsed_args
args = parsed_args
return (found_method, args)
return None, None
@@ -1072,7 +1053,7 @@ class Actions(object):
# first check if we have a native method to handle this for us
# todo: assess whether it would still be performant/desirable to be able to override core actions with plugins?
if hasattr(self, method_name):
method = getattr(self, method_name)
if argument is not None:
arguments = [argument]
@@ -1089,29 +1070,28 @@ class Actions(object):
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))
print("Plugin %s is handling %s" % (plugin, method_name))
method, arguments = plugin.get_callback_for_method(method_name, argument)
break # only deal with the first plugin
break # only deal with the first plugin
if method is None:
print ("Failed to find a method for '%s'" % method_name)
print("Failed to find a method for '%s'" % method_name)
import traceback
traceback.print_exc()
return
try:
#print ("for method_name %s, arguments is %s and len is %s, got method %s" % (method_name, arguments, len(signature(method).parameters), method))
# for the case where cc is being used as switch, we ignore note_off
#print(type(argument))
# print ("for method_name %s, arguments is %s and len is %s, got method %s" % (method_name, arguments, len(signature(method).parameters), method))
# for the case where cc is being used as switch, we ignore note_off
# print(type(argument))
if len(signature(method).parameters) == 0 and isinstance(argument, float) and argument == 0:
print('cc off ?')
return
if arguments is not None and len(signature(method).parameters)==len(arguments): # only pass arguments if count matches method sig
if arguments is not None and len(signature(method).parameters) == len(arguments): # only pass arguments if count matches method sig
method(*arguments)
else:
method()
except:
print ("Exception calling action for '%s' with arguments ( %s ) " % ( method_name, arguments))
print("Exception calling action for '%s' with arguments ( %s ) " % (method_name, arguments))
import traceback
traceback.print_exc()

View File

@@ -21,7 +21,7 @@ class AsyncWrite(threading.Thread):
def run(self):
with open(self.filename, "w+") as data_file:
if self.mode=='json':
if self.mode == 'json':
json.dump(self.data, data_file, indent=4, sort_keys=True)
else:
data_file.write(self.data)
@@ -29,7 +29,6 @@ class AsyncWrite(threading.Thread):
class Data(object):
BANK_DATA_JSON = 'display_data.json'
SHADER_BANK_DATA_JSON = 'shader_bank_data.json'
SETTINGS_JSON = 'settings.json'
@@ -48,11 +47,11 @@ class Data(object):
def __init__(self, message_handler):
self.message_handler = message_handler
#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_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 ]
# 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_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]
### state data
self.auto_repeat_on = True
@@ -66,20 +65,20 @@ class Data(object):
self.update_screen = True
self.confirm_action = None
self.player_mode = 'now'
self.feedback_active = False
self.detour_active = False
self.detour_mix_shaders = self.get_list_of_two_input_shaders()
self.detour_settings = collections.OrderedDict([('current_detour',0), ('is_playing', False), ('is_recording', False), ('record_loop', False), ('detour_size', False), ('detour_speed', 0), ('memory_full', False), ('mix_shader', self.detour_mix_shaders[0]), ('detour_position', 5), ('detour_start', 0), ('detour_end', 0), ('detour_mix', 0), ('is_delay', False)])
self.detour_settings = collections.OrderedDict([('current_detour', 0), ('is_playing', False), ('is_recording', False), ('record_loop', False), ('detour_size', False), ('detour_speed', 0), ('memory_full', False), ('mix_shader', self.detour_mix_shaders[0]), ('detour_position', 5), ('detour_start', 0), ('detour_end', 0), ('detour_mix', 0), ('is_delay', False)])
self.next_bankslot = '0-0'
self.current_bankslot = '0-0'
self.shader_layer = 0
### persisted data (use default if doesnt exits):
if not os.path.isfile(self.PATH_TO_CONJUR_DATA):
self.try_remove_file(self.PATH_TO_DATA_OBJECTS + self.SETTINGS_JSON ) # keep the, in sync
self.try_remove_file(self.PATH_TO_DATA_OBJECTS + self.SETTINGS_JSON) # keep the, in sync
copyfile(self.PATH_TO_DEFAULT_CONJUR_DATA, self.PATH_TO_CONJUR_DATA)
self.bank_data = [self.create_empty_bank()]
@@ -99,7 +98,7 @@ class Data(object):
if os.path.isfile(self.PATH_TO_DATA_OBJECTS + self.SETTINGS_JSON):
self.settings = self._read_json(self.SETTINGS_JSON)
self.settings['user_input'].setdefault('REMOTE_SERVER',
self.default_settings['user_input']['REMOTE_SERVER'])['value'] = 'disabled' # remote server off at boot
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.osc_mappings = self._read_json(self.OSC_MAPPING_JSON)
@@ -113,15 +112,15 @@ class Data(object):
docs.generate_mappings_doc("OSC mappings", self.osc_mappings, column_one_header="OSC address")
docs.generate_mappings_doc("Analog mappings", self.analog_mappings, column_one_header="Analogue input")
docs.generate_mappings_doc("Key mappings", self.key_mappings, column_one_header="Key mappings")
#quit()
# quit()
def initialise_plugins(self):
#initialise plugin manager
# initialise plugin manager
self.plugins = plugin_collection.PluginCollection("plugins", self.message_handler, self)
self.compare_plugins_list()
def get_enabled_plugin_class_names(self):
return [k for k,v in self.enabled_plugins.items() if v is True]
return [k for k, v in self.enabled_plugins.items() if v is True]
def compare_plugins_list(self):
current_plugins = [type(plugin).__name__ for plugin in self.plugins.get_plugins(include_disabled=True)]
@@ -131,9 +130,9 @@ class Data(object):
self.enabled_plugins.pop(k, None)
for k in plugins_to_add:
self.enabled_plugins[k] = False
#switch off all plugins if disabled ...
# switch off all plugins if disabled ...
if self.settings['system']['USE_PLUGINS']['value'] == 'disabled':
self.enabled_plugins = {x:False for x in self.enabled_plugins}
self.enabled_plugins = {x: False for x in self.enabled_plugins}
def update_enabled_plugins(self, key, value):
self.enabled_plugins[key] = value
@@ -141,16 +140,16 @@ class Data(object):
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)
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))
print ("loaded custom midi mapping for %s" % custom_file)
print("loaded custom midi mapping for %s" % custom_file)
else:
print ("loading default midi mapping for %s" % (device_name))
print("loading default midi mapping for %s" % (device_name))
self.midi_mappings = self._read_json(self.MIDI_MAPPING_JSON)
return self.midi_mappings
def get_ip_address(self):
ip_list = subprocess.check_output(['hostname', '-I']).decode('utf-8').split()
if len(ip_list) > 0:
@@ -163,7 +162,7 @@ class Data(object):
return '127.0.0.1'
else:
return self.get_ip_address()
@staticmethod
def create_empty_bank():
empty_slot = dict(name='', location='', length=-1, start=-1, end=-1, rate=1)
@@ -173,7 +172,7 @@ class Data(object):
def create_empty_shader_bank():
empty_slot = dict(name='', path='', param_number=4, shad_type='-')
return [empty_slot for i in range(10)]
def _read_json(self, file_name):
with open(self.PATH_TO_DATA_OBJECTS + file_name) as data_file:
data = json.load(data_file)
@@ -187,15 +186,15 @@ class Data(object):
for path in self.PATHS_TO_PLUGIN_DATA:
print("loading plugin data %s" % path)
try:
with open("%s/%s" % (path,file_name)) as data_file:
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)
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:
# 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()
@@ -220,12 +219,12 @@ class Data(object):
tree.write(self.PATH_TO_CONJUR_DATA)
def get_setting_and_folder_from_name(self, setting_name):
for folder_key , folder_item in self.settings.items():
for folder_key, folder_item in self.settings.items():
for setting_key, setting_item in folder_item.items():
if setting_key == setting_name:
return folder_key, setting_key, setting_item
##### setting and adding to sample mapping ######
##### setting and adding to sample mapping ######
def create_new_slot_mapping_in_first_open(self, file_name):
######## used for mapping current video to next available slot ########
@@ -238,7 +237,7 @@ class Data(object):
def create_new_slot_mapping(self, slot_number, file_name):
######## used for mapping current video to a specific slot ########
has_location, location = self._get_path_for_file(file_name)
print('file_name:{},has_location:{}, location:{}'.format(file_name,has_location, location))
print('file_name:{},has_location:{}, location:{}'.format(file_name, has_location, location))
length = self._get_length_for_file(location)
if length:
new_slot = dict(name=file_name, location=location, length=length, start=-1, end=-1, rate=1)
@@ -250,15 +249,15 @@ class Data(object):
def update_bank_number_by_amount(self, amount):
empty_bank = self.create_empty_bank()
if(self.bank_data[-1] != empty_bank):
if (self.bank_data[-1] != empty_bank):
self.bank_data.append(empty_bank)
elif(len(self.bank_data) > 1):
elif (len(self.bank_data) > 1):
if self.bank_data[-2] == empty_bank:
self.bank_data.pop()
self._update_json(self.BANK_DATA_JSON, self.bank_data)
self.bank_number = (self.bank_number+amount)%(len(self.bank_data))
def update_next_slot_number(self, new_value, is_current=False):
self.bank_number = (self.bank_number + amount) % (len(self.bank_data))
def update_next_slot_number(self, new_value, is_current=False):
if self.bank_data[self.bank_number][new_value]['location'] == '':
self.message_handler.set_message('INFO', 'the slot you pressed is empty')
return False
@@ -266,14 +265,13 @@ class Data(object):
self.message_handler.set_message('INFO', 'no device found for this slot')
return False
elif is_current:
self.current_bankslot = '{}-{}'.format(self.bank_number,new_value)
self.current_bankslot = '{}-{}'.format(self.bank_number, new_value)
return True
else:
self.next_bankslot = '{}-{}'.format(self.bank_number,new_value)
self.next_bankslot = '{}-{}'.format(self.bank_number, new_value)
return True
######## setting and adding to shader mapping
######## setting and adding to shader mapping
def create_new_shader_mapping_in_first_open(self, file_name):
######## used for mapping current shader to next available slot ########
@@ -286,7 +284,7 @@ class Data(object):
def create_new_shader_mapping(self, slot_number, file_name):
######## used for mapping current shader to a specific slot ########
has_location, location = self._get_path_for_file(file_name)
print('file_name:{},has_location:{}, location:{}'.format(file_name,has_location, location))
print('file_name:{},has_location:{}, location:{}'.format(file_name, has_location, location))
new_slot = dict(name=file_name, path=location, shad_type='-', param_number=4)
self._update_a_shader_slots_data(slot_number, new_slot)
@@ -295,28 +293,26 @@ class Data(object):
self._update_json(self.SHADER_BANK_DATA_JSON, self.shader_bank_data)
def update_shader_layer_by_amount(self, amount):
self.shader_layer = (self.shader_layer + amount) % len(self.shader_bank_data)
self.shader_layer = (self.shader_layer + amount) % len(self.shader_bank_data)
def update_setting_value(self, setting_folder, setting_name, setting_value):
self.settings[setting_folder][setting_name]['value'] = setting_value
self._update_json(self.SETTINGS_JSON, self.settings)
return self.settings[setting_folder][setting_name]
@classmethod
def split_bankslot_number(cls, bankslot_number):
split = bankslot_number.split('-')
is_bank_num_int , converted_bank_number = cls.try_convert_string_to_int(split[0])
is_slot_num_int , converted_slot_number = cls.try_convert_string_to_int(split[1])
is_bank_num_int, converted_bank_number = cls.try_convert_string_to_int(split[0])
is_slot_num_int, converted_slot_number = cls.try_convert_string_to_int(split[1])
return converted_bank_number, converted_slot_number
@staticmethod
def try_convert_string_to_int(string_input):
try:
return True , int(string_input)
return True, int(string_input)
except ValueError:
return False , '*'
return False, '*'
def get_next_context(self, is_current=False):
######## loads the slot details, uses settings to modify them and then set next slot number ########
@@ -324,14 +320,14 @@ class Data(object):
bankslot_number = self.current_bankslot
else:
bankslot_number = self.next_bankslot
bank_num , slot_num = self.split_bankslot_number(bankslot_number)
bank_num, slot_num = self.split_bankslot_number(bankslot_number)
next_slot_details = self.bank_data[bank_num][slot_num]
start_value = next_slot_details['start']
end_value = next_slot_details['end']
length = next_slot_details['length']
start_value, end_value = self._overwrite_values_with_sampler_settings(start_value, end_value, length)
start_value, end_value = self._overwrite_values_with_sampler_settings(start_value, end_value, length)
context = dict(location=next_slot_details['location'], name=next_slot_details['name'],
length=next_slot_details['length'], rate=next_slot_details['rate'], start=start_value, end=end_value,
@@ -347,22 +343,22 @@ class Data(object):
fixed_length_multiply = self.settings['sampler']['FIXED_LENGTH_MULTIPLY']['value']
total_fixed_length = fixed_length_value * fixed_length_multiply
if start == -1:
start = 0
start = 0
if end == -1:
end = length
end = length
new_end = end
new_start = start
if use_fixed_length and use_rand_start:
max_increase = int(max(end - start - max(total_fixed_length, 4),0))
random_increase = randint(0,max_increase)
max_increase = int(max(end - start - max(total_fixed_length, 4), 0))
random_increase = randint(0, max_increase)
new_start = start + random_increase
new_end = min(new_start + total_fixed_length, end)
elif use_fixed_length and not use_rand_start:
new_end = min(new_start + total_fixed_length, end)
elif not use_fixed_length and use_rand_start:
max_increase = int(max(end - start - 4,0))
random_increase = randint(0,max_increase)
max_increase = int(max(end - start - 4, 0))
random_increase = randint(0, max_increase)
new_start = start + random_increase
return new_start, new_end
@@ -372,17 +368,17 @@ class Data(object):
loaded_slots = self._get_list_of_loaded_slots_in_current_bank()
if loaded_slots:
if next_setting == 'random':
next_slot = loaded_slots[randint(0,len(loaded_slots)-1)]
next_slot = loaded_slots[randint(0, len(loaded_slots) - 1)]
elif next_setting == 'consecutive':
next_slot = self.get_next_loaded_slot(slot_num, loaded_slots)
else:
next_slot = slot_num
if is_current:
self.current_bankslot = '{}-{}'.format(self.bank_number,next_slot)
self.current_bankslot = '{}-{}'.format(self.bank_number, next_slot)
else:
self.next_bankslot = '{}-{}'.format(self.bank_number,next_slot)
self.next_bankslot = '{}-{}'.format(self.bank_number, next_slot)
def _get_list_of_loaded_slots_in_current_bank(self):
list_of_loaded_slots = []
for index, slot in enumerate(self.bank_data[self.bank_number]):
@@ -392,9 +388,9 @@ class Data(object):
@staticmethod
def get_next_loaded_slot(current_slot, loaded_slots):
i = ( current_slot + 1 ) % len(loaded_slots)
while(i not in loaded_slots):
i = ( i + 1 ) % len(loaded_slots)
i = (current_slot + 1) % len(loaded_slots)
while (i not in loaded_slots):
i = (i + 1) % len(loaded_slots)
return i
def update_slot_start_to_this_time(self, slot_number, position):
@@ -410,7 +406,7 @@ class Data(object):
self._update_json(self.BANK_DATA_JSON, self.bank_data)
def open_omxplayer_for_reset(self):
self._get_length_for_file('/ss',no_message=True )
self._get_length_for_file('/ss', no_message=True)
def _get_length_for_file(self, path, no_message=False):
try:
@@ -419,62 +415,60 @@ class Data(object):
temp_player.quit()
return duration
except Exception as e:
print (e)
print(e)
if not no_message:
self.message_handler.set_message('INFO', 'cannot load video')
return None
def _get_path_for_file(self, file_name):
######## returns full path for a given file name ########
for path in self.PATHS_TO_BROWSER + self.PATHS_TO_SHADERS:
for path in self.PATHS_TO_BROWSER + self.PATHS_TO_SHADERS:
for root, dirs, files in os.walk(path):
if file_name in files:
return True, '{}/{}'.format(root, file_name)
return False, ''
def is_this_path_broken(self, path):
external_devices = os.listdir(self.PATH_TO_EXTERNAL_DEVICES)
has_device_in_path = self.PATH_TO_EXTERNAL_DEVICES in path
has_existing_device_in_path = any([(x in path) for x in external_devices])
if has_device_in_path and not has_existing_device_in_path:
if has_device_in_path and not has_existing_device_in_path:
return True
else:
return False
def get_background_colour(self):
colour_name = self.settings['video']['BACKGROUND_COLOUR']['value']
colour_argb = (255,0,0,0)
colour_argb = (255, 0, 0, 0)
if colour_name == "black":
colour_argb = (255,0,0,0)
colour_argb = (255, 0, 0, 0)
elif colour_name == "white":
colour_argb = (255,255,255,255)
colour_argb = (255, 255, 255, 255)
elif colour_name == "green":
colour_argb = (255,0,255,0)
colour_argb = (255, 0, 255, 0)
elif colour_name == "blue":
colour_argb = (255,0,0,255)
colour_argb = (255, 0, 0, 255)
elif colour_name == "pink":
colour_argb = (255,255,0,255)
colour_argb = (255, 255, 0, 255)
elif colour_name == "none":
colour_argb = (0,0,0,0)
colour_argb = (0, 0, 0, 0)
colour_hex = '%02x%02x%02x%02x' % colour_argb
return colour_hex
def get_display_modes_list(self, with_nav_mode=False):
display_modes = [[ "SAMPLER",'PLAYER'], ["BROWSER",'NAV_BROWSER'],["SETTINGS",'NAV_SETTINGS']]
display_modes = [["SAMPLER", 'PLAYER'], ["BROWSER", 'NAV_BROWSER'], ["SETTINGS", 'NAV_SETTINGS']]
if self.settings['video']['VIDEOPLAYER_BACKEND']['value'] != 'omxplayer' and self.settings['shader']['USE_SHADER']['value'] == 'enabled':
display_modes.append(["SHADERS",'NAV_SHADERS'])
if self.settings['shader']['USE_SHADER_BANK']['value'] == 'enabled' and ["SHADERS",'NAV_SHADERS'] in display_modes:
display_modes.append(["SHDR_BNK",'PLAY_SHADER'])
if self.settings['shader']['USE_SHADER_MOD']['value'] == 'enabled' and ["SHADERS",'NAV_SHADERS'] in display_modes:
display_modes.append(["SHDR_MOD",["NAV_MOD","PLAY_SHADER"]]) ## allow override, but fall back to PLAY_SHADER controls
display_modes.append(["SHADERS", 'NAV_SHADERS'])
if self.settings['shader']['USE_SHADER_BANK']['value'] == 'enabled' and ["SHADERS", 'NAV_SHADERS'] in display_modes:
display_modes.append(["SHDR_BNK", 'PLAY_SHADER'])
if self.settings['shader']['USE_SHADER_MOD']['value'] == 'enabled' and ["SHADERS", 'NAV_SHADERS'] in display_modes:
display_modes.append(["SHDR_MOD", ["NAV_MOD", "PLAY_SHADER"]]) ## allow override, but fall back to PLAY_SHADER controls
if self.settings['detour']['TRY_DEMO']['value'] == 'enabled':
display_modes.append(["FRAMES",'NAV_DETOUR'])
display_modes.append(["FRAMES", 'NAV_DETOUR'])
if self.settings['system'].setdefault('USE_PLUGINS',
self.default_settings.setdefault('USE_PLUGINS',{'value': 'enabled'})).get('value') == 'enabled':
display_modes.append(["PLUGINS",'NAV_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
@@ -499,7 +493,7 @@ class Data(object):
######## overwrite a given slots info with new data ########
self.shader_bank_data[self.shader_layer][slot_number] = slot_info
self._update_json(self.SHADER_BANK_DATA_JSON, self.shader_bank_data)
@staticmethod
def make_empty_if_none(input):
if input is None:
@@ -512,15 +506,13 @@ class Data(object):
if os.path.exists('/home/pi/r_e_c_u_r/Shaders/2-input'):
(_, _, filenames) = next(os.walk('/home/pi/r_e_c_u_r/Shaders/2-input'))
return filenames
#elif os.path.exists('/home/pi/r_e_c_u_r/Shaders/2-input'):
#(_, _, filenames) = next(os.walk('/home/pi/r_e_c_u_r/Shaders/2-input'))
#return filenames
# elif os.path.exists('/home/pi/r_e_c_u_r/Shaders/2-input'):
# (_, _, filenames) = next(os.walk('/home/pi/r_e_c_u_r/Shaders/2-input'))
# return filenames
else:
return []
return []
@staticmethod
def try_remove_file(path):
if os.path.exists(path):
os.remove(path)

View File

@@ -1,14 +1,15 @@
import datetime
class FixedLengthSetter(object):
DELTA_NUMBER = 2
DELTA_NUMBER = 2
def __init__(self, data):
self.data = data
self.last_time = None
self.list_of_deltas = []
def record_input(self):
if self.last_time == None:
self.last_time = datetime.datetime.now()
@@ -17,6 +18,6 @@ class FixedLengthSetter(object):
self.list_of_deltas.append(now_time - self.last_time)
self.last_time = now_time
if len(self.list_of_deltas) > self.DELTA_NUMBER:
average_delta = sum(self.list_of_deltas[-self.DELTA_NUMBER+1:], datetime.timedelta(0))/float(self.DELTA_NUMBER)
average_delta = sum(self.list_of_deltas[-self.DELTA_NUMBER + 1:], datetime.timedelta(0)) / float(self.DELTA_NUMBER)
average_seconds = round(average_delta.total_seconds(), 2)
self.data.update_setting_value('sampler', 'FIXED_LENGTH', average_seconds)

View File

@@ -9,6 +9,7 @@ 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
"""
@property
def disabled(self):
return type(self).__name__ not in self.pc.data.get_enabled_plugin_class_names()
@@ -23,9 +24,11 @@ class Plugin(object):
def start_plugin(self):
print(">>Starting plugin " + type(self).__name__)
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'
@@ -39,29 +42,32 @@ class MidiFeedbackPlugin(Plugin):
def refresh_midi_feedback(self):
raise NotImplementedError
class SequencePlugin(Plugin):
"""Base class for plugins that run constantly or on demand for eg automation"""
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 ),
( r"^set_automation_speed$", self.set_speed ),
(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),
(r"^set_automation_speed$", self.set_speed),
]
def set_speed(self, speed):
#self.speed = 2.0 * (2.0*(speed-0.5))
speed = 2.0*(speed-0.5) # adjust to range -1 to +1
negative = speed<0.0 # remember negative state cos we'll lose it in next
# self.speed = 2.0 * (2.0*(speed-0.5))
speed = 2.0 * (speed - 0.5) # adjust to range -1 to +1
negative = speed < 0.0 # remember negative state cos we'll lose it in next
self.speed = (speed * speed) * 2.0
if negative: self.speed *= -1
print ("automation speed is now %s" % self.speed)
if negative:
self.speed *= -1
print("automation speed is now %s" % self.speed)
def toggle_automation(self):
if not self.is_playing():
@@ -81,26 +87,28 @@ class SequencePlugin(Plugin):
def toggle_pause_automation(self):
self.pause_flag = not self.is_paused()
self.last_delta = -1
#self.pause_flag = self.is_paused() and self.is_playing()
if not self.is_paused() and self.is_playing(): #not self.is_playing():
# self.pause_flag = self.is_paused() and self.is_playing()
if not self.is_paused() and self.is_playing(): # not self.is_playing():
self.run_automation()
last_delta = -1
last_delta = -1
def delta(self, now):
if self.last_delta==-1:
if self.last_delta == -1:
self.last_delta = now
r = now - self.last_delta
self.last_delta = now
return r
speed = 0.25 #1.0
speed = 0.25 # 1.0
def move_delta(self, delta, speed):
self.position += delta * speed
if self.position>1.0:
self.position = 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
elif self.position < 0.0:
self.position = self.position + 1.0
self.iterations_count += 1
position = 0.0
@@ -111,12 +119,13 @@ class SequencePlugin(Plugin):
iterations_count = 0
duration = 2000
frequency = 100
def run_automation(self):
import time
now = time.time()
#print("running automation at %s!" % self.position)
# print("running automation at %s!" % self.position)
if not self.is_paused():
self.store_passed = None
delta = self.delta(now)
@@ -126,9 +135,9 @@ class SequencePlugin(Plugin):
if not self.stop_flag and not self.disabled:
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):
@@ -136,11 +145,12 @@ class SequencePlugin(Plugin):
def is_playing(self):
return not self.is_paused() or self.stop_flag
#return self.automation_start is not None
# 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)
@@ -148,7 +158,7 @@ class ActionsPlugin(Plugin):
@property
def parserlist(self):
return [
#( r"^test_plugin$", self.test_plugin )
# ( r"^test_plugin$", self.test_plugin )
]
# test if this plugin should handle the method name -- also covers if we're a DisplayPlugin
@@ -158,7 +168,7 @@ class ActionsPlugin(Plugin):
return True
for a in self.parserlist:
if (a[0]==method_name):
if (a[0] == method_name):
return True
regex = a[0]
me = a[1]
@@ -185,24 +195,28 @@ class ActionsPlugin(Plugin):
return (found_method, args)
class DisplayPlugin(Plugin):
"""Base class for plugins that want to show a user interface on the recur screen"""
def __init__(self, plugin_collection):
super().__init__(plugin_collection)
def is_handled(self, name):
raise NotImplementedError
raise NotImplementedError
def get_display_modes(self):
raise NotImplementedError
raise NotImplementedError
def show_plugin(self, display):
from tkinter import END
#display_text.insert(END, 'test from DisplayPlugin')
# display_text.insert(END, 'test from DisplayPlugin')
display.display_text.insert(END, '{} \n'.format(display.body_title))
class ModulationReceiverPlugin(Plugin):
"""Base class for plugins that want to be notified of a change to modulation values"""
def __init__(self, plugin_collection):
super().__init__(plugin_collection)
@@ -210,8 +224,10 @@ class ModulationReceiverPlugin(Plugin):
print("||||||set_modulation_value dummy!")
raise NotImplementedError
class AutomationSourcePlugin(Plugin):
"""Base class for plugins that offer things to save&playback to&from automation"""
@property
def frame_key(self):
return self.__class__.__name__
@@ -226,7 +242,7 @@ class AutomationSourcePlugin(Plugin):
raise NotImplementedError
def get_frame_summary(self, data):
line = self.__class__.name + "%s: %s"%(self.__class__.name,data)
line = self.__class__.name + "%s: %s" % (self.__class__.name, data)
return line
# these frame stubs deal with the simplest case of a frame being a dict of values
@@ -243,36 +259,36 @@ class AutomationSourcePlugin(Plugin):
return cf.copy()
diff = {}
for queue,message in cf.items():
if lf.get(queue) is None or lf.get(queue)!=message:
for queue, message in cf.items():
if lf.get(queue) is None or lf.get(queue) != message:
diff[queue] = message
#print (">>>>>> returning diff\n%s\n<<<<<" % diff)
# print (">>>>>> returning diff\n%s\n<<<<<" % diff)
return diff
def merge_data(self, data1, data2):
#print (">>>merge_data passed\n\t%s\nand\n\t%s" % (data1,data2))
# print (">>>merge_data passed\n\t%s\nand\n\t%s" % (data1,data2))
output = {}
if data1 is None:
output = data2.copy()
else:
output = data1.copy()
output.update(data2)
#print("merge_data returning\n\t%s" % output)
#print("<<<<<<")
# print("merge_data returning\n\t%s" % output)
# print("<<<<<<")
return output
def get_ignored_data(self, data, ignored):
#frame = self.f
f = data.copy() #frame.get(self.frame_key,{})
for queue,item in f.items(): #frame.get(self.frame_key,{}).items():
# frame = self.f
f = data.copy() # frame.get(self.frame_key,{})
for queue, item in f.items(): # frame.get(self.frame_key,{}).items():
if ignored.get(queue) is not None:
#print ("\tfound that should ignore %s (%s) ?" % (queue, item))
# print ("\tfound that should ignore %s (%s) ?" % (queue, item))
f[queue] = None
return f
def is_frame_data_empty(self, data):
if len(data)>0:
if len(data) > 0:
return False
return True
@@ -281,6 +297,7 @@ class AutomationSourcePlugin(Plugin):
### TODO: experimental value interpolation -- doesn't work, and is slow!
cmd_size = {}
def process_interpolate_clip(self, frames):
# loop over every frame
# for each property of each frame
@@ -290,9 +307,9 @@ class AutomationSourcePlugin(Plugin):
# else,
# store as last value
print("AutomationSourcePlugin[%s] got pre-interpolated clip: %s" % ( type(self), [ f.f for f in frames if f is not None]) )
print("AutomationSourcePlugin[%s] got pre-interpolated clip: %s" % (type(self), [f.f for f in frames if f is not None]))
#last = [ [None]*4, [None]*4, [None]*4 ]
# last = [ [None]*4, [None]*4, [None]*4 ]
last = {}
"""for findex,frame in enumerate(frames):
@@ -300,17 +317,17 @@ class AutomationSourcePlugin(Plugin):
continue"""
reproc_to = 0
queues = []# queue for queue in list(frame.f.get(self.frame_key,{}).keys()) for frame in frames ] # get all queues in all frames in clip
queues = [] # queue for queue in list(frame.f.get(self.frame_key,{}).keys()) for frame in frames ] # get all queues in all frames in clip
for frame in frames:
if frame is not None:
for queue,command in frame.f.get(self.frame_key,{}).items():
for queue, command in frame.f.get(self.frame_key, {}).items():
queues.append(queue)
if command is not None and len(command)==2:
if command is not None and len(command) == 2:
self.cmd_size[queue] = len(command[1])
if command is not None and command[1] is not None:
last[queue] = command
queues = list(set(queues))
print ("got queues %s" % queues)
print("got queues %s" % queues)
"""distance_cache = [{}]*len(frames) # list [ dict { queue: list [ distance to next arg args ] } ]
bob = {}
@@ -322,88 +339,88 @@ class AutomationSourcePlugin(Plugin):
distance_cache[i-1] = bob"""
def process(self, findex, frame):
#for queue,command in enumerate(frame.f.get(self.frame_key,[])):
data = frame.f.get(self.frame_key,None)
#if data is None:
# for queue,command in enumerate(frame.f.get(self.frame_key,[])):
data = frame.f.get(self.frame_key, None)
# if data is None:
# return
for queue in queues:
if last.get(queue) is not None:
"""if data.get(queue) is not None:
last[queue] = data.get(queue)
continue"""
for argindex,value in enumerate(last.get(queue)[1]):
#print ("findex %s: for argindex %s got last value %s" % (findex, argindex, value))
#if data is not None: print ("data queue is %s" % data.get(queue,None))
if data is not None and data.get(queue,None) is not None and len(data.get(queue))>0 and len(data.get(queue)[1])>argindex and data.get(queue)[1][argindex] is not None:
last[queue][1][argindex] = data.get(queue)[1][argindex]
continue
gap,future_value = self.get_distance_value_command(frames,findex,queue,argindex)
if gap==0 or future_value==value:
continue
#print("\tpassing %s and %s to interpolate" % (last[queue][argindex], future_value))
newvalue = self.pc.fm.interpolate(last[queue][1][argindex], future_value, gap)
if data is None:
frame.f[self.frame_key] = {}
data = frame.f[self.frame_key]
if data.get(queue) is None:
data[queue] = [last[queue][0], last[queue][1]]# [None]*self.cmd_size[queue]]
#while len(data.get(queue)[1])<argindex:
# data.get(queue)[1] += [] #.append(None)
data.get(queue)[1][argindex] = int(newvalue)
last[queue][1][argindex] = int(newvalue)
"""if data.get(queue) is not None:
last[queue] = data.get(queue)
continue"""
for argindex, value in enumerate(last.get(queue)[1]):
# print ("findex %s: for argindex %s got last value %s" % (findex, argindex, value))
# if data is not None: print ("data queue is %s" % data.get(queue,None))
if data is not None and data.get(queue, None) is not None and len(data.get(queue)) > 0 and len(data.get(queue)[1]) > argindex and data.get(queue)[1][argindex] is not None:
last[queue][1][argindex] = data.get(queue)[1][argindex]
continue
gap, future_value = self.get_distance_value_command(frames, findex, queue, argindex)
if gap == 0 or future_value == value:
continue
# print("\tpassing %s and %s to interpolate" % (last[queue][argindex], future_value))
newvalue = self.pc.fm.interpolate(last[queue][1][argindex], future_value, gap)
if data is None:
frame.f[self.frame_key] = {}
data = frame.f[self.frame_key]
if data.get(queue) is None:
data[queue] = [last[queue][0], last[queue][1]] # [None]*self.cmd_size[queue]]
# while len(data.get(queue)[1])<argindex:
# data.get(queue)[1] += [] #.append(None)
data.get(queue)[1][argindex] = int(newvalue)
last[queue][1][argindex] = int(newvalue)
elif data is not None and data.get(queue) is not None:
#print("no last[%s] already set, setting to %s" % (queue, data.get(queue)))
# print("no last[%s] already set, setting to %s" % (queue, data.get(queue)))
last[queue] = data.get(queue)
for i in range(1):
for findex,frame in enumerate(frames):
if frame is None:
continue
for findex, frame in enumerate(frames):
if frame is None:
continue
process(self,findex,frame)
process(self, findex, frame)
print("\nAutomationSourcePlugin got interpolated clip: %s" % [ f.f for f in frames if f is not None ])
print("\nAutomationSourcePlugin got interpolated clip: %s" % [f.f for f in frames if f is not None])
self.distance_cache = {}
distance_cache = {}
def get_distance_value_command(self, frames, findex, queue, argindex):
distance_cache = self.distance_cache
# check if we have a cached value that is lower than the findex
if distance_cache.get(queue) is not None and len(distance_cache.get(queue))>=(argindex+1) and distance_cache.get(queue)[argindex] is not None and distance_cache.get(queue)[argindex]['position'] >= findex:
if distance_cache.get(queue) is not None and len(distance_cache.get(queue)) >= (argindex + 1) and distance_cache.get(queue)[argindex] is not None and distance_cache.get(queue)[argindex]['position'] >= findex:
position = distance_cache.get(queue)[argindex]['position']
#return len(frames)-
return abs(position-findex), distance_cache.get(queue)[argindex]['value']
# return len(frames)-
return abs(position - findex), distance_cache.get(queue)[argindex]['value']
#print("\t\tget_distance_value_command(findex %s, queue %s, argindex %s)" %(findex,queue,argindex))
for i in range(1,len(frames)):
# print("\t\tget_distance_value_command(findex %s, queue %s, argindex %s)" %(findex,queue,argindex))
for i in range(1, len(frames)):
search_findex = i + findex
search_findex %= len(frames)
if frames[search_findex] is None:
continue
#print("\t\t\tgetting frame index %s" % search_findex)
# print("\t\t\tgetting frame index %s" % search_findex)
frame = frames[search_findex]
data = frame.f.get(self.frame_key,None)
#print("\t\t\tgot frame data %s" % data)
data = frame.f.get(self.frame_key, None)
# print("\t\t\tgot frame data %s" % data)
if data is None:
continue
command = data.get(queue,None)
command = data.get(queue, None)
if command is None:
continue
print("\t\t\tget_distance_value_command testing %s argindex %s - command looks like %s" % (queue, argindex, command))
if len(command[1])>argindex:
if command[1][argindex] is not None and findex!=i:
if len(command[1]) > argindex:
if command[1][argindex] is not None and findex != i:
print("\t\t\t\t\tgot distance %s to value for argindex %s: %s" % (i, argindex, command[1][argindex]))
if distance_cache.get(queue) is None:
distance_cache[queue] = [None]*(self.cmd_size[queue])
#while len(distance_cache[queue])<(argindex+1):
distance_cache[queue] = [None] * (self.cmd_size[queue])
# while len(distance_cache[queue])<(argindex+1):
# distance_cache[queue] += [None]
distance_cache[queue][argindex] = { 'position': i, 'value': command[1][argindex] }
distance_cache[queue][argindex] = {'position': i, 'value': command[1][argindex]}
return i, command[1][argindex]
"""if frames[search_findex] is not None and frames[search_findex].f.get(self.frame_key,{}).get(queue,[])[argindex] is not None:
return i, frames[search_findex].f.get(self.frame_key,{}).get(queue,[])[argindex]"""
return 0, None
@@ -416,6 +433,7 @@ 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 display(self):
return self.actions.display
@@ -438,9 +456,9 @@ class PluginCollection(object):
"""
self.plugin_package = plugin_package
self.message_handler = message_handler
#self.shaders = lambda: data.shaders
# self.shaders = lambda: data.shaders
self.data = data
#self.actions = message_handler.actions
# self.actions = message_handler.actions
self.reload_plugins()
# set up a FrameManager too so that plugins can use it
@@ -448,6 +466,7 @@ class PluginCollection(object):
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)
@@ -464,7 +483,8 @@ class PluginCollection(object):
def quit_plugins(self):
# tell each plugin to quit
for plugin in self.get_plugins():
if not plugin.disabled: plugin.stop_plugin()
if not plugin.disabled:
plugin.stop_plugin()
def stop_plugin_name(self, name):
for plugin in self.get_plugins(include_disabled=True):
@@ -472,15 +492,14 @@ class PluginCollection(object):
plugin.stop_plugin()
def start_plugin_name(self, name):
#print("start_plugin_name got %s"%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))
# print("looking for %s vs %s" % (type(plugin).__name__, name))
if type(plugin).__name__ == name:
#print("starting %s" %name)
# print("starting %s" %name)
plugin.start_plugin()
def get_plugins(self, clazz = None, include_disabled = False):
def get_plugins(self, clazz=None, include_disabled=False):
if clazz:
return [c for c in self.plugins if isinstance(c, clazz) and (include_disabled or not c.disabled)]
else:
@@ -488,8 +507,8 @@ class PluginCollection(object):
def get_plugin_for_class_name(self, class_name):
for plugin in self.get_plugins():
#print("got class name %s" % type(plugin).__name__==class_name)
if type(plugin).__name__==class_name == class_name:
# print("got class name %s" % type(plugin).__name__==class_name)
if type(plugin).__name__ == class_name == class_name:
return plugin
return None
@@ -505,12 +524,11 @@ class PluginCollection(object):
for (_, c) in clsmembers:
# Only add classes that are a sub class of Plugin, but NOT Plugin itself
# or one of the base classes defined in this file
ignore_list = [ Plugin, ActionsPlugin, SequencePlugin, MidiFeedbackPlugin, DisplayPlugin, ModulationReceiverPlugin, AutomationSourcePlugin ]
ignore_list = [Plugin, ActionsPlugin, SequencePlugin, MidiFeedbackPlugin, DisplayPlugin, ModulationReceiverPlugin, AutomationSourcePlugin]
if issubclass(c, Plugin) & (c not in ignore_list):
print(' Found plugin class: %s.%s' % (c.__module__,c.__name__))
print(' Found plugin class: %s.%s' % (c.__module__, c.__name__))
self.plugins.append(c(self))
# Now that we have looked at all the modules in the current package, start looking
# recursively for additional modules in sub packages
# disabled 03-2020 to try and avoid problem with subclasses-of-subclasses being listed twice..
@@ -532,7 +550,6 @@ class PluginCollection(object):
for child_pkg in child_pkgs:
self.walk_package(package + '.' + child_pkg)"""
## helpers
def get_variable(self, varname, default=0.0):
from plugins.ManipulatePlugin import ManipulatePlugin

View File

@@ -9,7 +9,7 @@ class Display(object):
MENU_HEIGHT = 10
SELECTOR_WIDTH = 0.47
ROW_OFFSET = 6.0
TITLES = ['{0} r_e_c_u_r {0}'.format('='*18), '{0} c_o_n_j_u_r {1}'.format('='*18, '='*16), '{0} d_e_t_o_u_r {1}'.format('='*18, '='*16)]
TITLES = ['{0} r_e_c_u_r {0}'.format('=' * 18), '{0} c_o_n_j_u_r {1}'.format('=' * 18, '=' * 16), '{0} d_e_t_o_u_r {1}'.format('=' * 18, '=' * 16)]
def __init__(self, tk, video_driver, shaders, message_handler, data):
self.tk = tk
@@ -18,7 +18,7 @@ class Display(object):
self.shaders = shaders
self.message_handler = message_handler
self.data = data
self.browser_menu = menu.BrowserMenu(self.data, self.message_handler, self.MENU_HEIGHT)
self.browser_menu = menu.BrowserMenu(self.data, self.message_handler, self.MENU_HEIGHT)
self.settings_menu = menu.SettingsMenu(self.data, self.message_handler, self.MENU_HEIGHT)
self.plugins_menu = menu.PluginsMenu(self.data, self.message_handler, self.MENU_HEIGHT)
self.shaders_menu = self.shaders.shaders_menu
@@ -45,13 +45,13 @@ class Display(object):
self.display_text.tag_configure("FUNCTION", background="yellow", foreground="black")
self.display_text.tag_configure("BROKEN_PATH", background="black", foreground="gray")
self.display_text.tag_configure("ZEBRA_STRIPE", background="black", foreground="khaki")
def _load_display(self):
self._load_title()
self._load_player()
self._load_display_body()
self._load_message()
#print('the number of tags are {}'.format(len(self.display_text.tag_names())))
# print('the number of tags are {}'.format(len(self.display_text.tag_names())))
self.display_text.pack()
def _load_title(self):
@@ -79,7 +79,7 @@ class Display(object):
self.display_text.insert(END, status + '\n')
self.display_text.tag_add("NOW_ALPHA", 3.0, 3.17)
self.display_text.tag_add("CAPTURE_ALPHA", 3.18, 3.29)
self.display_text.tag_add("NEXT_ALPHA", 3.29, 3.47)
self.display_text.tag_add("NEXT_ALPHA", 3.29, 3.47)
def _load_display_body(self):
self.body_title = self._generate_body_title()
@@ -106,35 +106,34 @@ class Display(object):
self._load_plugin_page(self.data.display_mode, plugin)
self.display_text.tag_add("DISPLAY_MODE", 4.19, 4.29)
self.display_text.tag_add("COLUMN_NAME", 5.0, 6.0)
def _load_plugin_page(self, display_mode, plugin):
plugin.show_plugin(self, display_mode)
def _load_sampler(self):
bank_data = self.data.bank_data[self.data.bank_number]
self.display_text.insert(END, '{} \n'.format(self.body_title))
self.display_text.insert(END, '{:>6} {:<17} {:>5} {:<5} {:<5} \n'.format(
'{}-slot'.format(self.data.bank_number), 'name', 'length', 'start', 'end'))
'{}-slot'.format(self.data.bank_number), 'name', 'length', 'start', 'end'))
for index, slot in enumerate(bank_data):
name_without_extension = slot['name'].rsplit('.',1)[0]
name_without_extension = slot['name'].rsplit('.', 1)[0]
self.display_text.insert(END, '{:^6} {:<17} {:^5} {:>5} {:<5} \n'.format(
index, name_without_extension[0:17], self.format_time_value(slot['length']),
self.format_time_value(slot['start']), self.format_time_value(slot['end'])))
index, name_without_extension[0:17], self.format_time_value(slot['length']),
self.format_time_value(slot['start']), self.format_time_value(slot['end'])))
if index % 2:
self.display_text.tag_add("ZEBRA_STRIPE", self.ROW_OFFSET + index,
self.ROW_OFFSET + self.SELECTOR_WIDTH + index)
self.ROW_OFFSET + self.SELECTOR_WIDTH + index)
if self.data.is_this_path_broken(slot['location']):
self.display_text.tag_add("BROKEN_PATH", self.ROW_OFFSET + index,
self.ROW_OFFSET + self.SELECTOR_WIDTH + index)
self.ROW_OFFSET + self.SELECTOR_WIDTH + index)
# highlight the slot of the selected player
if self.data.player_mode == 'next':
bank_slot = self.video_driver.next_player.bankslot_number
bank_slot = self.video_driver.next_player.bankslot_number
else:
bank_slot = self.video_driver.current_player.bankslot_number
current_bank , current_slot = self.data.split_bankslot_number(bank_slot)
bank_slot = self.video_driver.current_player.bankslot_number
current_bank, current_slot = self.data.split_bankslot_number(bank_slot)
if current_bank is self.data.bank_number:
self._highlight_this_row(current_slot)
@@ -142,7 +141,7 @@ class Display(object):
browser_list = self.browser_menu.menu_list
number_of_lines_displayed = 0
self.display_text.insert(END, '{} \n'.format(self.body_title))
self.display_text.insert(END, '{:40} {:5} \n'.format('path', 'slot'))
number_of_browser_items = len(browser_list)
@@ -163,7 +162,7 @@ class Display(object):
line_count = 0
settings_list = self.settings_menu.menu_list
self.display_text.insert(END, '{} \n'.format(self.body_title))
self.display_text.insert(END, '{:^23} {:^22} \n'.format('SETTING', 'VALUE'))
number_of_settings_items = len(settings_list)
for index in range(number_of_settings_items):
@@ -182,17 +181,17 @@ class Display(object):
def _load_plugins(self):
line_count = 0
self.display_text.insert(END, '{} \n'.format(self.body_title))
self.display_text.insert(END, '{:<35} {:<8} \n'.format('plugin', 'status'))
self.display_text.insert(END, '{:<35} {:<8} \n'.format('plugin', 'status'))
## showing list of plugins:
plugins_list = sorted([
(type(plugin).__name__, type(plugin).__name__ in self.data.get_enabled_plugin_class_names())\
for plugin in self.data.plugins.get_plugins(include_disabled=True)
plugins_list = sorted([
(type(plugin).__name__, type(plugin).__name__ in self.data.get_enabled_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)
for index in range(number_of_plugins):
if line_count >= self.MENU_HEIGHT :
if line_count >= self.MENU_HEIGHT:
break
if index >= self.plugins_menu.top_menu_index:
plugin_line = plugins_list[index]
@@ -200,34 +199,33 @@ class Display(object):
line_count = line_count + 1
for index in range(self.plugins_menu.top_menu_index + self.plugins_menu.menu_height - number_of_plugins):
self.display_text.insert(END, '\n')
self.display_text.insert(END, '\n')
self._highlight_this_row(self.plugins_menu.selected_list_index - self.plugins_menu.top_menu_index)
def _load_shaders(self):
line_count = 0
self.display_text.insert(END, '{} \n'.format(self.body_title))
## showing current shader info:
shader = self.shaders.selected_shader_list[self.data.shader_layer]
self.display_text.insert(END, '{:<1}{}{:<1}:{:<2} {:<16} '.format \
(self.data.shader_layer,
self.get_speed_indicator(self.shaders.selected_speed_list[self.data.shader_layer]),
self.shaders.selected_status_list[self.data.shader_layer],shader['shad_type'][0],
shader['name'].lstrip()[0:16] ))
for i in range(min(4,shader['param_number'])):
self.get_speed_indicator(self.shaders.selected_speed_list[self.data.shader_layer]),
self.shaders.selected_status_list[self.data.shader_layer], shader['shad_type'][0],
shader['name'].lstrip()[0:16]))
for i in range(min(4, shader['param_number'])):
display_param = self.format_param_value(self.shaders.selected_param_list[self.data.shader_layer][i])
if display_param == 100:
display_param == 99
self.display_text.insert(END, 'x{}:{:02d}'.format(i, display_param))
self.display_text.insert(END,'\n')
self.display_text.insert(END, '\n')
self.display_text.tag_add("COLUMN_NAME", 5.0, 6.0)
## showing list of other shaders:
shaders_list = self.shaders.shaders_menu_list
number_of_shader_items = len(shaders_list)
for index in range(number_of_shader_items):
if line_count >= self.MENU_HEIGHT :
if line_count >= self.MENU_HEIGHT:
break
if index >= self.shaders.shaders_menu.top_menu_index:
shader_line = shaders_list[index]
@@ -235,7 +233,7 @@ class Display(object):
line_count = line_count + 1
for index in range(self.shaders.shaders_menu.top_menu_index + self.shaders.shaders_menu.menu_height - number_of_shader_items):
self.display_text.insert(END, '\n')
self.display_text.insert(END, '\n')
self._highlight_this_row(self.shaders.shaders_menu.selected_list_index - self.shaders.shaders_menu.top_menu_index)
if self.data.control_mode == "SHADER_PARAM":
@@ -243,16 +241,16 @@ class Display(object):
def _load_shader_bank(self):
shader_bank_data = self.data.shader_bank_data[self.data.shader_layer]
self.display_text.insert(END, '{} \n'.format(self.body_title))
self.display_text.insert(END, '{:>6} {:<11} {:<5} '.format(
'{} {}'.format(self.data.shader_layer, self.get_speed_indicator(self.shaders.selected_speed_list[self.data.shader_layer])),
'name', 'type'))
'{} {}'.format(self.data.shader_layer, self.get_speed_indicator(self.shaders.selected_speed_list[self.data.shader_layer])),
'name', 'type'))
shader = self.shaders.selected_shader_list[self.data.shader_layer]
for i in range(min(4,shader['param_number'])):
for i in range(min(4, shader['param_number'])):
display_param = self.format_param_value(self.shaders.selected_param_list[self.data.shader_layer][i])
if display_param == 100:
display_param == 99
@@ -260,11 +258,11 @@ class Display(object):
self.display_text.insert(END, '\n')
for index, slot in enumerate(shader_bank_data):
name_without_extension = slot['name'].rsplit('.',1)[0]
name_without_extension = slot['name'].rsplit('.', 1)[0]
self.display_text.insert(END, '{:^6} {:<17} {:<5} \n'.format(index, name_without_extension[0:17], slot['shad_type']))
if index % 2:
self.display_text.tag_add("ZEBRA_STRIPE", self.ROW_OFFSET + index,
self.ROW_OFFSET + self.SELECTOR_WIDTH + index)
self.ROW_OFFSET + self.SELECTOR_WIDTH + index)
# highlight the slot of the selected player
current_slot = self.shaders.selected_shader_list[self.data.shader_layer].get('slot', None)
not_playing_tag = self.shaders.selected_status_list[self.data.shader_layer] != ''
@@ -275,15 +273,15 @@ class Display(object):
def _load_modulation_bank(self):
shader_bank_data = self.data.shader_bank_data[self.data.shader_layer]
self.display_text.insert(END, '{} \n'.format(self.body_title))
self.display_text.insert(END, '{:>6} {:<11} {:<5} '.format(
'{} {}'.format(self.data.shader_layer, self.get_speed_indicator(self.shaders.selected_speed_list[self.data.shader_layer])),
'name', 'type'))
'{} {}'.format(self.data.shader_layer, self.get_speed_indicator(self.shaders.selected_speed_list[self.data.shader_layer])),
'name', 'type'))
shader = self.shaders.selected_shader_list[self.data.shader_layer]
"""for i in range(min(4,shader['param_number'])):
display_param = self.format_param_value(self.shaders.selected_param_list[self.data.shader_layer][i])
if display_param == 100:
@@ -314,8 +312,8 @@ class Display(object):
self._highlight_this_param(self.shaders.focused_param) """
# show info about the modulation configuration
#self.display_text.insert(END, "Lyr|1a b c d|2a b c d|3a b c d|4a b c d\n")
#self.display_text.insert(END, "Lyr")
# self.display_text.insert(END, "Lyr|1a b c d|2a b c d|3a b c d|4a b c d\n")
# self.display_text.insert(END, "Lyr")
"""for i in range(4):
self.display_text.insert(END, "|%s"%i)
for i in range(4):
@@ -323,7 +321,7 @@ class Display(object):
if i==self.shaders.selected_modulation_slot:
a = a.upper()
self.display_text.insert(END, "%s "%a)"""
#self.display_text.insert(END, "\n")
# self.display_text.insert(END, "\n")
"""for layer, modulations in enumerate(self.shaders.modulation_level):
if (layer==self.data.shader_layer):
self.display_text.insert(END, '*')
@@ -343,14 +341,14 @@ class Display(object):
o += "\n Modmatrix:\t"
name = self.shaders.selected_shader_list[layer].get('name').strip()
#o = ""
# o = ""
for slot in range(4):
sl = self.get_mod_slot_label(slot)
o+= sl + ("[" if sl.isupper() else "-")
o += sl + ("[" if sl.isupper() else "-")
for param in range(4):
o += self.get_bar(self.shaders.modulation_level[layer][param][slot])
o+= ("]" if sl.isupper() else "-") + " "
self.display_text.insert(END, "%s %s:\t%s\n\n"%(">" if layer==self.data.shader_layer else " ", layer, o))
o += ("]" if sl.isupper() else "-") + " "
self.display_text.insert(END, "%s %s:\t%s\n\n" % (">" if layer == self.data.shader_layer else " ", layer, o))
self.display_text.insert(END, '\n')
# todo: this doesnt work but would be a better way to highlight the selected modulation slot/layer
"""self._highlight_this_param(
@@ -360,12 +358,11 @@ class Display(object):
column_offset = 0.1
)"""
def _load_detour(self):
line_count = 0
self.display_text.insert(END, '{} \n'.format(self.body_title))
## showing current detour info:
## showing current detour info:
self.display_text.insert(END, '{:^23} {:^22} \n'.format('SETTING', 'VALUE'))
self.display_text.insert(END, '{:>23} {:<22} \n'.format("DETOUR_ACTIVE", self.data.detour_active))
for index, (key, value) in enumerate(self.data.detour_settings.items()):
@@ -379,30 +376,30 @@ class Display(object):
def _load_message(self):
if self.message_handler.current_message[1]:
self.display_text.insert(END, '{:5} {:42} \n'.format(
self.message_handler.current_message[0], self.message_handler.current_message[1][0:38]))
self.message_handler.current_message[0], self.message_handler.current_message[1][0:38]))
self.display_text.tag_add('{}_MESSAGE'.format(
self.message_handler.current_message[0]), 16.0,16.0 + self.SELECTOR_WIDTH)
self.message_handler.current_message[0]), 16.0, 16.0 + self.SELECTOR_WIDTH)
if self.message_handler.current_message[2]:
self.message_handler.current_message[2] = False
message_length = 4000
self.tk.after(message_length, self.message_handler.clear_message)
elif self.data.function_on:
self.display_text.insert(END, '{:^47} \n'.format('< FUNCTION KEY ON >'))
self.display_text.tag_add('FUNCTION', 16.0,16.0 + self.SELECTOR_WIDTH)
self.display_text.tag_add('FUNCTION', 16.0, 16.0 + self.SELECTOR_WIDTH)
else:
feedback = ''
if self.data.feedback_active:
feedback = 'FDBCK'
self.display_text.insert(END, '{:8} {:<28} {:>5} \n'.format('CONTROL:', str(self.data.control_mode), feedback))
self.display_text.tag_add('TITLE', 16.0,16.0 + self.SELECTOR_WIDTH)
self.display_text.tag_add('TITLE', 16.0, 16.0 + self.SELECTOR_WIDTH)
def _highlight_this_row(self, row, gray=False):
highlight_tag = "SELECT"
if gray:
highlight_tag = "BROKEN_PATH"
highlight_tag = "BROKEN_PATH"
self.display_text.tag_remove("ZEBRA_STRIPE", self.ROW_OFFSET + row,
self.ROW_OFFSET + self.SELECTOR_WIDTH + row)
self.ROW_OFFSET + self.SELECTOR_WIDTH + row)
self.display_text.tag_add(highlight_tag, self.ROW_OFFSET + row,
self.ROW_OFFSET + self.SELECTOR_WIDTH + row)
@@ -410,13 +407,13 @@ class Display(object):
self.display_text.tag_remove("SELECT", self.ROW_OFFSET + row,
self.ROW_OFFSET + self.SELECTOR_WIDTH + row)
def _highlight_this_param(self, param_num, column_offset = 0.26, param_length = 0.05, param_row = None):
def _highlight_this_param(self, param_num, column_offset=0.26, param_length=0.05, param_row=None):
if param_row is None:
param_row = self.ROW_OFFSET - 1
self.display_text.tag_add("SHADER_PARAM",
round(param_row + column_offset + param_num*param_length,2),
round(param_row + column_offset + (param_num+1)*param_length, 2)
)
self.display_text.tag_add("SHADER_PARAM",
round(param_row + column_offset + param_num * param_length, 2),
round(param_row + column_offset + (param_num + 1) * param_length, 2)
)
def _get_status_for_player(self):
now_slot, now_status, now_alpha, next_slot, next_status, next_alpha = self.video_driver.get_player_info_for_status()
@@ -427,20 +424,19 @@ class Display(object):
else:
capture_status = ''
preview_alpha = 0
if preview_alpha == None:
preview_alpha = 0
#print('capture alpha is {}'.format(preview_alpha))
# print('capture alpha is {}'.format(preview_alpha))
self._set_colour_from_alpha(now_alpha, preview_alpha, next_alpha)
self._set_colour_from_alpha(now_alpha, preview_alpha, next_alpha)
now_info = 'NOW [{}] {}'.format(now_slot, now_status)
next_info = 'NEXT [{}] {}'.format(next_slot, next_status)
capture_info = '{}'.format(capture_status)
return '{:17} {:10} {:17}'.format(now_info[:17], capture_info[:10], next_info[:18])
return '{:17} {:10} {:17}'.format(now_info[:17], capture_info[:10], next_info[:18])
def _get_banner_for_player(self,player):
def _get_banner_for_player(self, player):
start, end, position = self.video_driver.get_player_info_for_banner(player)
banner = self.create_video_display_banner(start, end, position)
time_been = self.format_time_value(position - start)
@@ -448,35 +444,37 @@ class Display(object):
return ' {:5} {} {:5}'.format(time_been, banner, time_left)
def _generate_capture_status(self):
is_previewing = self.capture.is_previewing
is_previewing = self.capture.is_previewing
is_recording = self.capture.is_recording
rec_time = -1
if is_recording == True:
rec_time = self.capture.get_recording_time()
capture_status = ''
if is_previewing and is_recording == True:
capture_status = '<{}>'.format('REC'+ self.format_time_value(rec_time))
capture_status = '<{}>'.format('REC' + self.format_time_value(rec_time))
elif is_previewing and is_recording == 'saving':
capture_status = '<{}>'.format('_saving_')
elif is_previewing:
capture_status = '<{}>'.format('_preview')
elif is_recording == True:
capture_status = '[{}]'.format('REC'+ self.format_time_value(rec_time))
capture_status = '[{}]'.format('REC' + self.format_time_value(rec_time))
elif is_recording == 'saving':
capture_status = '[{}]'.format('_saving_')
capture_status = '[{}]'.format('_saving_')
else:
capture_status = ''
return capture_status
def get_bar(self, value, max_value = 1.0):
def get_bar(self, value, max_value=1.0):
if value is None:
return " "
value = abs(value / max_value) # abs() so negative values make some sense
if value>1.0: value = 1.0
elif value<0.0: value = 0.0
value = abs(value / max_value) # abs() so negative values make some sense
if value > 1.0:
value = 1.0
elif value < 0.0:
value = 0.0
bar = u"_\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588"
g = '%s'%bar[int(value*(len(bar)-1))]
g = '%s' % bar[int(value * (len(bar) - 1))]
return g
def get_mod_slot_label(self, slot):
@@ -485,35 +483,35 @@ class Display(object):
sl = sl.lower()
return sl
def get_speed_indicator(self, value, convert = True):
def get_speed_indicator(self, value, convert=True):
if convert:
value = (value * 2.0) - 1.0 # convert 0 to 1 to -1 to +1
value = (value * 2.0) - 1.0 # convert 0 to 1 to -1 to +1
output = u""
if value==0.0 or (value>=-0.02 and value<=0.02):
output+=u"\u23f9" # stopped
elif value<=-0.5:
output+=u"\u00AB" # fast reverse
elif value<0.0:
output+=u"\u2039" # reverse
elif value>=0.5:
output+=u"\u00BB" # fast forward
elif value>0.0:
output+=u"\u203A" # forward
if value == 0.0 or (value >= -0.02 and value <= 0.02):
output += u"\u23f9" # stopped
elif value <= -0.5:
output += u"\u00AB" # fast reverse
elif value < 0.0:
output += u"\u2039" # reverse
elif value >= 0.5:
output += u"\u00BB" # fast forward
elif value > 0.0:
output += u"\u203A" # forward
#output += " {:03f}".format(value)
# output += " {:03f}".format(value)
output += self.get_bar(value)
return output
def get_compact_indicators(self, inp):
step = 2
step = 2
s = ""
for i in range(0,len(inp),step): # number of shader slots per layer
for i in range(0, len(inp), step): # number of shader slots per layer
selected1 = inp[i]
if i+1 > len(inp): # catch if odd number of elements passed to us?
if i + 1 > len(inp): # catch if odd number of elements passed to us?
selected2 = False
else:
selected2 = inp[i+1]
selected2 = inp[i + 1]
if selected1 and selected2:
# full block
@@ -528,11 +526,9 @@ class Display(object):
# empty
s += "_"
#s += "#" if selected else "-"
# s += "#" if selected else "-"
return s
@staticmethod
def create_video_display_banner(start, end, position):
banner_list = ['[', '-', '-', '-', '-', '-', '-', '-', '-',
@@ -545,8 +541,8 @@ class Display(object):
banner_list[0] = '<'
elif position > end:
banner_list[max] = '>'
elif end - start != 0 and not math.isnan(position) :
#print('start value is {}, end value is {}, position is {}'.format(start, end, position))
elif end - start != 0 and not math.isnan(position):
# print('start value is {}, end value is {}, position is {}'.format(start, end, position))
marker = int(math.floor(float(position - start) /
float(end - start) * (max - 1)) + 1)
banner_list[marker] = '*'
@@ -564,18 +560,18 @@ class Display(object):
max = len(banner_list) - 1
if size == 0:
size = max
#print('start value is {}, end value is {}, position is {}'.format(start, end, position))
# print('start value is {}, end value is {}, position is {}'.format(start, end, position))
if start > 0:
start = int(math.floor(float(start) /
float(size) * (max - 1)) + 1)
float(size) * (max - 1)) + 1)
banner_list[start] = '['
if end > 0:
end = int(math.floor(float(end) /
float(size) * (max - 1)) + 1)
float(size) * (max - 1)) + 1)
banner_list[end] = ']'
position = int(math.floor(float(position) /
float(size) * (max - 1)) + 1)
if 0 <= position and position < len(banner_list):
float(size) * (max - 1)) + 1)
if 0 <= position and position < len(banner_list):
banner_list[position] = '*'
return ''.join(banner_list)
@@ -591,43 +587,43 @@ class Display(object):
else:
is_recording = False
### scale values
scaled_now = int(( now_alpha / 255 ) * (255 - upper_bound) + upper_bound)
scaled_preview = int(( preview_alpha / 255 ) * (255 - upper_bound) + upper_bound)
scaled_next = int(( next_alpha / 255 ) * (255 - upper_bound) + upper_bound)
scaled_now = int((now_alpha / 255) * (255 - upper_bound) + upper_bound)
scaled_preview = int((preview_alpha / 255) * (255 - upper_bound) + upper_bound)
scaled_next = int((next_alpha / 255) * (255 - upper_bound) + upper_bound)
### convert to hex
now_colour = self.hex_from_rgb(scaled_now, scaled_now, 0)
capture_colour = self.hex_from_rgb(255 * is_recording, 100, scaled_preview )
capture_colour = self.hex_from_rgb(255 * is_recording, 100, scaled_preview)
next_colour = self.hex_from_rgb(0, scaled_next, scaled_next)
### update the colours
self.display_text.tag_configure("NOW_ALPHA", background="black", foreground=now_colour)
self.display_text.tag_configure("CAPTURE_ALPHA", background="black", foreground=capture_colour)
self.display_text.tag_configure("NEXT_ALPHA", background="black", foreground=next_colour)
self.display_text.tag_configure("NEXT_ALPHA", background="black", foreground=next_colour)
def _generate_body_title(self):
display_modes = self.data.get_display_modes_list()
current_mode = self.data.display_mode
selected_list = []
for index, v in enumerate(display_modes):
if v == current_mode:
if v == current_mode:
while len(v) < 8:
v = v + '_'
selected_list.append('[{}]'.format(v))
selected_list_index = index
else:
selected_list.append('<{}>'.format(v[:2].lower()))
# 18 char to PURPLE : 18 - 29 ,18 after
if selected_list_index>4:
selected_list = selected_list[selected_list_index-4:len(selected_list)]
selected_list.append('<{}>'.format(v[:2].lower()))
# 18 char to PURPLE : 18 - 29 ,18 after
if selected_list_index > 4:
selected_list = selected_list[selected_list_index - 4:len(selected_list)]
selected_list = ['--'] + selected_list
selected_string = ''.join(selected_list)
#if len(selected_string)<19:
# if len(selected_string)<19:
# selected_string += '-'*(21-len(selected_string))
#selected_string = selected_string[:30]
#wid = 19 #int(2+((len(display_modes)/2)*4))
output = ('-' * ((19) - (selected_list_index * 4))) + \
selected_string + \
('-' * (18 - ((len(display_modes) - selected_list_index - 1) * 4)))
# selected_string = selected_string[:30]
# wid = 19 #int(2+((len(display_modes)/2)*4))
output = ('-' * ((19) - (selected_list_index * 4))) + \
selected_string + \
('-' * (18 - ((len(display_modes) - selected_list_index - 1) * 4)))
output = output[0:46]
return output
@@ -641,11 +637,12 @@ class Display(object):
last_refreshed = 0
REFRESH_LIMIT = 100
def refresh_display(self):
if self.data.update_screen:
if time.time()*1000 - self.last_refreshed < self.REFRESH_LIMIT:
if time.time() * 1000 - self.last_refreshed < self.REFRESH_LIMIT:
return
self.last_refreshed = time.time()*1000
self.last_refreshed = time.time() * 1000
self.display_text.configure(state='normal')
self.display_text.delete(1.0, END)
self._load_display()

View File

@@ -1,16 +1,17 @@
import os
class Menu(object):
def __init__(self, data, message_handler, menu_height):
self.data = data
self.message_handler = message_handler
self.message_handler = message_handler
self.open_folders = []
self.menu_list = []
self.menu_height = menu_height
self.top_menu_index = 0
self.selected_list_index = 0
def navigate_menu_up(self):
if self.selected_list_index != 0:
if self.selected_list_index == self.top_menu_index:
@@ -27,7 +28,7 @@ class Menu(object):
if self.top_menu_index < self.menu_height:
self.top_menu_index = 0
self.selected_list_index = 0
else:
else:
self.top_menu_index -= self.menu_height
self.selected_list_index -= self.menu_height
print('self.top_menu_index ', self.top_menu_index)
@@ -50,20 +51,19 @@ class Menu(object):
self.top_menu_index += self.menu_height
self.selected_list_index = min(self.menu_height + self.selected_list_index, len(self.menu_list) - 1)
def update_open_folders(self, folder_name):
if folder_name not in self.open_folders:
self.open_folders.append(folder_name)
else:
self.open_folders.remove(folder_name)
def _check_folder_state(self, folder_name):
######## used for displaying folders as open or closed ########
if folder_name in self.open_folders:
return True, '/'
else:
return False, '|'
@staticmethod
def extract_file_type_and_name_from_menu_format(dir_name):
# removes whitespace and folder state from display item ########
@@ -72,7 +72,8 @@ class Menu(object):
else:
return True, dir_name.lstrip()
class BrowserMenu(Menu):
class BrowserMenu(Menu):
def __init__(self, data, message_handler, menu_height):
Menu.__init__(self, data, message_handler, menu_height)
self.generate_browser_list()
@@ -82,7 +83,7 @@ class BrowserMenu(Menu):
self.menu_list = []
for path in self.data.PATHS_TO_BROWSER:
self._add_folder_to_browser_list(path, 0)
for browser_line in self.menu_list:
is_file, name = self.extract_file_type_and_name_from_menu_format(browser_line['name'])
if is_file:
@@ -116,13 +117,12 @@ class BrowserMenu(Menu):
for slot_index, slot in enumerate(bank):
print('&&&&&&&&&&&&', slot)
if file_name == slot['name']:
return True, '{}-{}'.format(bank_index,slot_index)
return True, '{}-{}'.format(bank_index, slot_index)
return False, ''
def enter_on_browser_selection(self):
is_file, name = self.extract_file_type_and_name_from_menu_format(
self.menu_list[self.selected_list_index]['name'])
self.menu_list[self.selected_list_index]['name'])
if is_file:
is_successful = self.data.create_new_slot_mapping_in_first_open(name)
if not is_successful:
@@ -133,17 +133,16 @@ class BrowserMenu(Menu):
class SettingsMenu(Menu):
FOLDER_ORDER = ['video', 'sampler', 'user_input', 'capture', 'shader', 'detour', 'system' ]
SAMPLER_ORDER = ['LOOP_TYPE', 'LOAD_NEXT', 'RAND_START_MODE', 'RESET_PLAYERS', 'FIXED_LENGTH_MODE', 'FIXED_LENGTH', 'FIXED_LENGTH_MULTIPLY' ]
FOLDER_ORDER = ['video', 'sampler', 'user_input', 'capture', 'shader', 'detour', 'system']
SAMPLER_ORDER = ['LOOP_TYPE', 'LOAD_NEXT', 'RAND_START_MODE', 'RESET_PLAYERS', 'FIXED_LENGTH_MODE', 'FIXED_LENGTH', 'FIXED_LENGTH_MULTIPLY']
VIDEO_ORDER = ['VIDEOPLAYER_BACKEND']
USER_INPUT_ORDER = ['MIDI_INPUT', 'MIDI_STATUS', 'CYCLE_MIDI_PORT', 'OSC_INPUT', 'ACCESS_POINT', 'REMOTE_SERVER', 'SHOW_IP' ]
USER_INPUT_ORDER = ['MIDI_INPUT', 'MIDI_STATUS', 'CYCLE_MIDI_PORT', 'OSC_INPUT', 'ACCESS_POINT', 'REMOTE_SERVER', 'SHOW_IP']
CAPTURE_ORDER = ['DEVICE', 'TYPE']
SHADER_ORDER = ['USER_SHADER']
DETOUR_ORDER = ['TRY_DEMO']
SYSTEM_ORDER = []
SETTINGS_TO_HIDE = ['OUTPUT' ]
SETTINGS_TO_HIDE = ['OUTPUT']
def __init__(self, data, message_handler, menu_height):
@@ -159,16 +158,16 @@ class SettingsMenu(Menu):
if setting_folder_key in self.open_folders:
self.menu_list.append(dict(name='{}/'.format(setting_folder_key), value=''))
order_list_name = '{}_ORDER'.format(setting_folder_key.upper())
ordered_value = self.order_keys_from_list(setting_folder_item, getattr(self,order_list_name))
ordered_value = self.order_keys_from_list(setting_folder_item, getattr(self, order_list_name))
for (setting_details_key, setting_details_item) in ordered_value:
if not setting_details_key in self.SETTINGS_TO_HIDE:
self.menu_list.append(dict(name=' {}'.format(setting_details_key), value=self.data.make_empty_if_none(setting_details_item['value'])))
else:
else:
self.menu_list.append(dict(name='{}|'.format(setting_folder_key), value=''))
def enter_on_setting_selection(self):
is_file, name = self.extract_file_type_and_name_from_menu_format(
self.menu_list[self.selected_list_index]['name'])
self.menu_list[self.selected_list_index]['name'])
if is_file:
folder, setting_name, setting_details = self.data.get_setting_and_folder_from_name(name)
if setting_details['value'] in setting_details['options']:
@@ -195,7 +194,7 @@ class SettingsMenu(Menu):
for order_key in order_list:
if order_key in dictionary:
ordered_tuple_list.append((order_key, dictionary[order_key]))
for other_key in sorted(dictionary):
for other_key in sorted(dictionary):
if other_key not in [i[0] for i in ordered_tuple_list]:
ordered_tuple_list.append((other_key, dictionary[other_key]))
return ordered_tuple_list
@@ -219,8 +218,8 @@ class ShadersMenu(Menu):
def __init__(self, data, message_handler, menu_height):
Menu.__init__(self, data, message_handler, menu_height)
#self.top_menu_index = 1
#self.selected_list_index = 1
# self.top_menu_index = 1
# self.selected_list_index = 1
def generate_raw_shaders_list(self):
######## starts the recursive process of listing all folders and shader files to display ########
@@ -228,11 +227,10 @@ class ShadersMenu(Menu):
for path in self.data.PATHS_TO_SHADERS:
self._add_folder_to_shaders_list(path, 0)
return self.menu_list
def _add_folder_to_shaders_list(self, current_path, current_level):
######## adds the folders and shader files at the current level to the results list. recursively recalls at deeper level if folder is open ########
root, dirs, files = next(os.walk(current_path))
indent = ' ' * 4 * (current_level)
@@ -249,8 +247,3 @@ class ShadersMenu(Menu):
split_name = os.path.splitext(f)
if (split_name[1].lower() in ['.frag', '.shader', '.glsl', '.glslf', '.fsh']):
self.menu_list.append(dict(name='{}{}'.format(indent, f), is_shader=True))

View File

@@ -1,5 +1,6 @@
import logging
class MessageHandler(object):
def __init__(self):
self.current_message = [None, None, None]

View File

@@ -12,8 +12,9 @@ def setup_osc_client(ip, port):
return udp_client.SimpleUDPClient(client_args.ip, client_args.port)
client = setup_osc_client('127.0.0.1',5433)
client = setup_osc_client('127.0.0.1', 5433)
client.send_message("/shutdown", True)
client = setup_osc_client('127.0.0.1',9000)
client = setup_osc_client('127.0.0.1', 9000)
client.send_message("/shutdown", True)

View File

@@ -3,8 +3,7 @@ import math
from data_centre.plugin_collection import ActionsPlugin, AutomationSourcePlugin, DisplayPlugin, SequencePlugin
class LFOModulationPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin, AutomationSourcePlugin):
class LFOModulationPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, AutomationSourcePlugin):
MAX_LFOS = 4
PRESET_FILE_NAME = "LFOModulationPlugin/config.json"
@@ -16,7 +15,7 @@ class LFOModulationPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin, Automation
selected_lfo = 0
# for keeping track of LFO levels
level = [0.0]*MAX_LFOS
level = [0.0] * MAX_LFOS
speed = 0.5
# TODO: enable assigning of LFOs to mod slots
@@ -26,17 +25,18 @@ class LFOModulationPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin, Automation
stop_flag = False
pause_flag = False
def __init__(self, plugin_collection):
super().__init__(plugin_collection)
#self.PRESET_FILE_NAME = "ShaderLoopRecordPlugin/frames.json"
# self.PRESET_FILE_NAME = "ShaderLoopRecordPlugin/frames.json"
self.presets = self.load_presets()
self.level = self.presets.get('levels', [0.0]*self.MAX_LFOS).copy()
self.level = self.presets.get('levels', [0.0] * self.MAX_LFOS).copy()
self.active = self.presets.get('active', False)
self.set_lfo_speed_direct(self.presets.get('speed', self.speed))
self.pc.shaders.root.after(1000, self.start_plugin)
def start_plugin(self):
super().start_plugin()
self.pc.shaders.root.after(0, self.run_automation)
@@ -47,30 +47,30 @@ class LFOModulationPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin, Automation
def load_presets(self):
print("trying load presets? %s " % self.PRESET_FILE_NAME)
return self.pc.read_json(self.PRESET_FILE_NAME) or { 'levels': [0.0]*self.MAX_LFOS, 'active': self.active }
return self.pc.read_json(self.PRESET_FILE_NAME) or {'levels': [0.0] * self.MAX_LFOS, 'active': self.active}
def save_presets(self):
#for cmd,struct in self.commands.items():
# for cmd,struct in self.commands.items():
# self.presets.setdefault('modulation_levels',{})[cmd] = struct.get('modulation',[{},{},{},{}])
self.pc.update_json(self.PRESET_FILE_NAME, { 'levels': self.level.copy(), 'active': self.active, 'speed': self.speed } )
self.pc.update_json(self.PRESET_FILE_NAME, {'levels': self.level.copy(), 'active': self.active, 'speed': self.speed})
# DisplayPlugin methods
def get_display_modes(self):
return ['LFOMODU','NAV_LFO']
return ['LFOMODU', 'NAV_LFO']
def show_plugin(self, display, display_mode):
from tkinter import END
#super(DisplayPlugin).show_plugin(display, display_mode)
# super(DisplayPlugin).show_plugin(display, display_mode)
display.display_text.insert(END, '{} \n'.format(display.body_title))
display.display_text.insert(END, "LFOModulation is ")
display.display_text.insert(END, "ACTIVE" if self.active else "not active")
display.display_text.insert(END, "\tSpeed: {:4.1f}% {}\n\n".format(self.speed*100, display.get_speed_indicator(self.speed/2.0, convert=False)))
display.display_text.insert(END, "\tSpeed: {:4.1f}% {}\n\n".format(self.speed * 100, display.get_speed_indicator(self.speed / 2.0, convert=False)))
for lfo,value in enumerate(self.level):
display.display_text.insert(END, "*" if self.selected_lfo==lfo else " ")
display.display_text.insert(END, "lfo {} level: {:4.2f}% {}\t".format(lfo,value*100,display.get_bar(value)))
for lfo, value in enumerate(self.level):
display.display_text.insert(END, "*" if self.selected_lfo == lfo else " ")
display.display_text.insert(END, "lfo {} level: {:4.2f}% {}\t".format(lfo, value * 100, display.get_bar(value)))
display.display_text.insert(END, "{}\t{}\n".format(self.last_lfo_status[lfo], display.get_bar(self.last_lfo_value[lfo])))
display.display_text.insert(END, "\tslot %s\t%s\n" % (display.get_mod_slot_label(lfo), self.formula[lfo]))
@@ -80,9 +80,9 @@ class LFOModulationPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin, Automation
# methods/vars for AutomationSourcePlugin
# a lot of the nitty-gritty handled in parent class, these are for interfacing to the plugin
def get_frame_data(self):
diff = { 'levels': self.level.copy(), 'speed': self.speed, 'active': self.active }
#self.last_record = {}
#print(">>> reporting frame data for rec\n\t%s" % diff)
diff = {'levels': self.level.copy(), 'speed': self.speed, 'active': self.active}
# self.last_record = {}
# print(">>> reporting frame data for rec\n\t%s" % diff)
return diff
def recall_frame_data(self, data):
@@ -90,7 +90,7 @@ class LFOModulationPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin, Automation
return
# print(">>>>recall from data:\n\t%s\n" %data)
if data.get('levels') is not None:
for slot,level in enumerate(data.get('levels')):
for slot, level in enumerate(data.get('levels')):
self.set_lfo_modulation_level(slot, level)
if data.get('active') is not None:
self.active = data.get('active')
@@ -108,41 +108,43 @@ class LFOModulationPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin, Automation
line += "active " if data.get('active') else 'inactive '
if data.get('speed') is not None:
line += self.pc.display.get_speed_indicator(data.get('speed'))
#print ("returning %s from %s" %(line, data))
# print ("returning %s from %s" %(line, data))
return line
# ActionsPlugin methods
@property
def parserlist(self):
return [
( r"^set_lfo_modulation_([0-3])_level$", self.set_lfo_modulation_level ),
( r"^toggle_lfo_active$", self.toggle_lfo_active ),
( r"^set_lfo_speed", self.set_lfo_speed ),
( r"^select_lfo$", self.select_lfo ),
( r"^select_previous_lfo$", self.select_previous_lfo ),
( r"^select_next_lfo$", self.select_next_lfo ),
( r"^increase_lfo_([0-3])_level$", self.increase_lfo_level ),
( r"^decrease_lfo_([0-3])_level$", self.decrease_lfo_level ),
( r"^increase_selected_lfo_level$", self.increase_selected_lfo_level ),
( r"^decrease_selected_lfo_level$", self.decrease_selected_lfo_level ),
( r"^increase_lfo_speed", self.increase_lfo_speed ),
( r"^decrease_lfo_speed", self.decrease_lfo_speed ),
# TODO: changing formulas and LFO modes
return [
(r"^set_lfo_modulation_([0-3])_level$", self.set_lfo_modulation_level),
(r"^toggle_lfo_active$", self.toggle_lfo_active),
(r"^set_lfo_speed", self.set_lfo_speed),
(r"^select_lfo$", self.select_lfo),
(r"^select_previous_lfo$", self.select_previous_lfo),
(r"^select_next_lfo$", self.select_next_lfo),
(r"^increase_lfo_([0-3])_level$", self.increase_lfo_level),
(r"^decrease_lfo_([0-3])_level$", self.decrease_lfo_level),
(r"^increase_selected_lfo_level$", self.increase_selected_lfo_level),
(r"^decrease_selected_lfo_level$", self.decrease_selected_lfo_level),
(r"^increase_lfo_speed", self.increase_lfo_speed),
(r"^decrease_lfo_speed", self.decrease_lfo_speed),
# TODO: changing formulas and LFO modes
]
def set_lfo_modulation_level(self, slot, value):
if (value<0.0): value = 0.0
if (value>1.0): value = 1.0
if (value < 0.0):
value = 0.0
if (value > 1.0):
value = 1.0
self.level[slot] = value
def set_lfo_speed(self, speed):
self.set_lfo_speed_direct(-4*(0.5-(speed)))
self.set_lfo_speed_direct(-4 * (0.5 - (speed)))
def set_lfo_speed_direct(self, speed):
self.speed = speed
if self.speed<-2.0:
if self.speed < -2.0:
self.speed = -2.0
if self.speed>2.0:
if self.speed > 2.0:
self.speed = 2.0
def toggle_lfo_active(self):
@@ -151,66 +153,73 @@ class LFOModulationPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin, Automation
def select_lfo(self, lfo):
self.selected_lfo = lfo
if self.selected_lfo>=self.MAX_LFOS:
if self.selected_lfo >= self.MAX_LFOS:
self.selected_lfo = 0
if self.selected_lfo<0:
self.selected_lfo = self.MAX_LFOS-1
if self.selected_lfo < 0:
self.selected_lfo = self.MAX_LFOS - 1
def select_next_lfo(self):
self.select_lfo(self.selected_lfo+1)
self.select_lfo(self.selected_lfo + 1)
def select_previous_lfo(self):
self.select_lfo(self.selected_lfo-1)
self.select_lfo(self.selected_lfo - 1)
level_step = 0.125
def increase_lfo_level(self, slot):
self.set_lfo_modulation_level(slot, self.level[slot] + self.level_step)
def decrease_lfo_level(self, slot):
self.set_lfo_modulation_level(slot, self.level[slot] - self.level_step)
def increase_selected_lfo_level(self):
self.increase_lfo_level(self.selected_lfo)
def decrease_selected_lfo_level(self):
self.decrease_lfo_level(self.selected_lfo)
lfo_step = 0.25
def increase_lfo_speed(self):
self.set_lfo_speed_direct ( self.speed + self.lfo_step )
if self.speed==0.0: # dont rest on 0 - set to a small amount forward
self.set_lfo_speed_direct(self.speed + self.lfo_step)
if self.speed == 0.0: # dont rest on 0 - set to a small amount forward
self.speed = 0.05
def decrease_lfo_speed(self):
self.set_lfo_speed_direct ( self.speed - self.lfo_step )
if self.speed==0.0: # dont rest on 0 - set to a small amount forward
self.set_lfo_speed_direct(self.speed - self.lfo_step)
if self.speed == 0.0: # dont rest on 0 - set to a small amount forward
self.speed = -0.05
# Formula handling for generating automation
# mapping 0-3 to match the LFO
# TODO: save & load this to config file, make editable
formula = [
"f_sin",
"f_double_cos",
"f_invert_sin",
#"f_invert_double_cos",
"f_linear"
"f_sin",
"f_double_cos",
"f_invert_sin",
# "f_invert_double_cos",
"f_linear"
]
# run the formula for the stored lfo configuration
last_lfo_status = [None]*MAX_LFOS # for displaying status
last_lfo_value = [None]*MAX_LFOS
#lfo_speed = [1.0]*MAX_LFOS
last_lfo_status = [None] * MAX_LFOS # for displaying status
last_lfo_value = [None] * MAX_LFOS
# lfo_speed = [1.0]*MAX_LFOS
def getLFO(self, position, lfo):
lfo_value = getattr(self,self.formula[lfo])(position, self.level[lfo])
lfo_value = getattr(self, self.formula[lfo])(position, self.level[lfo])
self.last_lfo_value[lfo] = lfo_value
self.last_lfo_status[lfo] = "sent {:03.1f}%".format(lfo_value*100.0)
self.last_lfo_status[lfo] = "sent {:03.1f}%".format(lfo_value * 100.0)
return lfo_value
# built-in waveshapes
# outgoing values should be between 0 and 1!!
# todo: more of the these, and better!
def f_sin(self, position, level):
#return level * (( math.sin(position*math.pi)))
# return level * (( math.sin(position*math.pi)))
value = math.sin(position * math.pi * 2) / 2
value *= level
value += 0.5 # normalise to range 0 - 1
value += 0.5 # normalise to range 0 - 1
return value
@@ -218,7 +227,7 @@ class LFOModulationPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin, Automation
return 1.0 - self.f_sin(position, level)
def f_double_cos(self, position, level):
return self.f_sin(math.cos(position*math.pi), level)
return self.f_sin(math.cos(position * math.pi), level)
def f_invert_double_cos(self, position, level):
return 1.0 - self.f_double_cos(position, level)
@@ -231,16 +240,16 @@ class LFOModulationPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin, Automation
import time
now = time.time()
if self.pc.data.plugins is None: # not initialised yet
if self.pc.data.plugins is None: # not initialised yet
return
if not self.active: # output is disabled
if not self.active: # output is disabled
return
for lfo in range(0,self.MAX_LFOS):
for lfo in range(0, self.MAX_LFOS):
# TODO: this is where would use assignable amounts and average across multiple inputs
if self.level[lfo]>0.0:
if self.level[lfo] > 0.0:
self.pc.actions.call_method_name(
"modulate_param_%s_to_amount_continuous"%lfo,
"modulate_param_%s_to_amount_continuous" % lfo,
self.getLFO(position, lfo)
)

View File

@@ -1,5 +1,6 @@
from data_centre.plugin_collection import ActionsPlugin, DisplayPlugin, ModulationReceiverPlugin#, SequencePlugin
#import math
from data_centre.plugin_collection import ActionsPlugin, DisplayPlugin, ModulationReceiverPlugin # , SequencePlugin
# import math
"""
add to midi or osc mapping
@@ -39,8 +40,8 @@ TODO: >> ?? invert|set_the_shader_param_0_layer_>>print_arguments>>set_variab
"""
class ManipulatePlugin(ActionsPlugin,DisplayPlugin,ModulationReceiverPlugin):
class ManipulatePlugin(ActionsPlugin, DisplayPlugin, ModulationReceiverPlugin):
DEBUG = False
def __init__(self, plugin_collection):
@@ -49,31 +50,32 @@ class ManipulatePlugin(ActionsPlugin,DisplayPlugin,ModulationReceiverPlugin):
# ActionsPlugin methods
@property
def parserlist(self):
return [
( r"(.*)&&(.*)", self.run_multi ), # split && first since they need to be processed separately
( r"^invert\|(.*)$", self.invert ),
( r"^f:(.*):\|(.*)$", self.formula ), # formula eg ```f:sin(x):|```
( r"^set_variable_([a-zA-Z0-9]+)$", self.set_variable ),
( r"^([A-Z0-9]+)>(.*)$", self.recall_variable ), # recall variable and pipe into righthand side eg ```VAR1>invert|set_the_shader_.....```
( r"^(.*)>\&(.*)$", self.run_multi ), # pick up piped commands that duplicate a chain of values last
return [
(r"(.*)&&(.*)", self.run_multi), # split && first since they need to be processed separately
(r"^invert\|(.*)$", self.invert),
(r"^f:(.*):\|(.*)$", self.formula), # formula eg ```f:sin(x):|```
(r"^set_variable_([a-zA-Z0-9]+)$", self.set_variable),
(r"^([A-Z0-9]+)>(.*)$", self.recall_variable), # recall variable and pipe into righthand side eg ```VAR1>invert|set_the_shader_.....```
(r"^(.*)>\&(.*)$", self.run_multi), # pick up piped commands that duplicate a chain of values last
]
# DisplayPlugin methods
def show_plugin(self, display, display_mode):
from tkinter import END
#super(DisplayPlugin).show_plugin(display, display_mode)
# super(DisplayPlugin).show_plugin(display, display_mode)
display.display_text.insert(END, '{} \n'.format(display.body_title))
display.display_text.insert(END, "test from ManipulatePlugin!\n")
for key,value in self.variables.items():
for key, value in self.variables.items():
display.display_text.insert(END, "\t" + key + "\t{:03.2f}\n".format(value))
def get_display_modes(self):
return ["MANIPULA","NAV_MANI"] #"NAV_MANIPULATE"]
return ["MANIPULA", "NAV_MANI"] # "NAV_MANIPULATE"]
# Actions
def run_multi(self, action1, action2, value):
if self.DEBUG: print("ManipulatePlugin>> multi-running '%s' and '%s' with value %s" % (action1, action2, value))
if self.DEBUG:
print("ManipulatePlugin>> multi-running '%s' and '%s' with value %s" % (action1, action2, value))
self.pc.actions.call_method_name(action1, value)
self.pc.actions.call_method_name(action2, value)
@@ -89,16 +91,19 @@ class ManipulatePlugin(ActionsPlugin,DisplayPlugin,ModulationReceiverPlugin):
def formula(self, formula, action, value):
self.variables['x'] = value
if self.DEBUG: print("ManipulatePlugin>> evaluating formula `%s` with value `%s`" % (formula, value))
if self.DEBUG:
print("ManipulatePlugin>> evaluating formula `%s` with value `%s`" % (formula, value))
value = eval(formula, globals(), self.variables)
if self.DEBUG: print("ManipulatePlugin>> got evaluated value `%s`" % value)
if self.DEBUG:
print("ManipulatePlugin>> got evaluated value `%s`" % value)
self.pc.actions.call_method_name(
action, value
)
def set_variable(self, var_name, value):
if self.DEBUG: print("ManipulatePlugin>> set_variable (%s) to %s" % (var_name, value))
if self.DEBUG:
print("ManipulatePlugin>> set_variable (%s) to %s" % (var_name, value))
self.variables[var_name] = value
def get_variable(self, var_name, default):
@@ -108,16 +113,16 @@ class ManipulatePlugin(ActionsPlugin,DisplayPlugin,ModulationReceiverPlugin):
return default
def recall_variable(self, var_name, action, *args):
if self.DEBUG: print ("ManipulatePlugin>> recall_variable (%s) as %s" % (var_name,args))
if self.DEBUG:
print("ManipulatePlugin>> recall_variable (%s) as %s" % (var_name, args))
self.pc.actions.call_method_name(
action, self.variables.get(var_name)# + list(args)
action, self.variables.get(var_name) # + list(args)
)
# ModulationReceiverPlugin methods
# methods for ModulationReceiverPlugin - receives changes to the in-built modulation levels (-1 to +1)
def set_modulation_value(self, param, value):
# take modulation value and throw it to local parameter
if self.DEBUG: print("||||| ManipulatePlugin received set_modulation_value for param %s with value %s!" % (param, value))
if self.DEBUG:
print("||||| ManipulatePlugin received set_modulation_value for param %s with value %s!" % (param, value))
self.set_variable("MODVALUE%s" % ('ABCD'[param]), value)

View File

@@ -4,7 +4,7 @@ from data_centre.plugin_collection import MidiFeedbackPlugin
class MidiFeedbackAPCKey25Plugin(MidiFeedbackPlugin):
#disabled = False
# disabled = False
status = {}
@@ -12,12 +12,12 @@ class MidiFeedbackAPCKey25Plugin(MidiFeedbackPlugin):
super().__init__(plugin_collection)
self.description = 'Outputs feedback to APC Key 25'
def get_note(self,action,default):
def get_note(self, action, default):
bind = self.pc.midi_input.find_binding_for_action(action)
if bind is not None and 'note_on' in bind:
return int(bind.split(' ')[1])
else:
print ("bind is %s, returning default" % bind)
print("bind is %s, returning default" % bind)
return default
def stop_plugin(self):
@@ -33,16 +33,16 @@ class MidiFeedbackAPCKey25Plugin(MidiFeedbackPlugin):
self.init_notes()
def init_notes(self):
self.NOTE_PLAY_SHADER = self.get_note('play_shader_0_0',32)
self.NOTE_SHADER_FEEDBACK = self.get_note('toggle_feedback',85)
self.NOTE_SCENE_LAUNCH_COLUMN = self.get_note('toggle_shader_layer_0',82)
self.NOTE_PLAY_SHADER = self.get_note('play_shader_0_0', 32)
self.NOTE_SHADER_FEEDBACK = self.get_note('toggle_feedback', 85)
self.NOTE_SCENE_LAUNCH_COLUMN = self.get_note('toggle_shader_layer_0', 82)
self.NOTE_MODULATION_COLUMN = self.get_note('select_shader_modulation_slot_0', self.NOTE_SCENE_LAUNCH_COLUMN)
self.NOTE_CAPTURE_PREVIEW = self.get_note('toggle_capture_preview', 86)
self.NOTE_CLIP_STATUS_ROW = self.get_note('toggle_automation_clip_0', 8)
self.NOTE_SHADER_PRESET_ROW = self.get_note('select_preset_0', 0)
self.NOTE_SHADER_LAYER_ON = [ #82, 83, 84
self.get_note('toggle_shader_layer_%i'%i, 82+i) for i in range(0,3)
]
self.NOTE_SHADER_LAYER_ON = [ # 82, 83, 84
self.get_note('toggle_shader_layer_%i' % i, 82 + i) for i in range(0, 3)
]
def supports_midi_feedback(self, device_name):
supported_devices = ['APC Key 25']
@@ -52,16 +52,16 @@ class MidiFeedbackAPCKey25Plugin(MidiFeedbackPlugin):
def set_status(self, command='note_on', note=None, velocity=None):
self.status[note] = {
'command': command,
'note': note,
'velocity': velocity
'command': command,
'note': note,
'velocity': velocity
}
#print("set status to %s: %s" % (note, self.status[note]))
# 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))
# print("send_command(%s, %s)" % (note, velocity))
self.midi_feedback_device.send(
mido.Message(command, note=note, velocity=velocity)
mido.Message(command, note=note, velocity=velocity)
)
def feedback_shader_feedback(self, on):
@@ -71,15 +71,16 @@ class MidiFeedbackAPCKey25Plugin(MidiFeedbackPlugin):
self.set_status(note=self.NOTE_CAPTURE_PREVIEW, velocity=int(on))
def feedback_shader_on(self, layer, slot, colour=None):
if colour is None: colour = self.COLOUR_GREEN
self.set_status(note=(self.NOTE_PLAY_SHADER-(layer)*8)+slot, velocity=int(colour))
if colour is None:
colour = self.COLOUR_GREEN
self.set_status(note=(self.NOTE_PLAY_SHADER - (layer) * 8) + slot, velocity=int(colour))
def feedback_shader_off(self, layer, slot):
self.set_status(note=(self.NOTE_PLAY_SHADER-(layer)*8)+slot, velocity=self.COLOUR_OFF)
self.set_status(note=(self.NOTE_PLAY_SHADER - (layer) * 8) + slot, velocity=self.COLOUR_OFF)
def feedback_shader_layer_on(self, layer):
self.set_status(note=self.NOTE_SHADER_LAYER_ON[layer], velocity=self.COLOUR_GREEN)
def feedback_shader_layer_off(self, layer):
self.set_status(note=self.NOTE_SHADER_LAYER_ON[layer], velocity=self.COLOUR_OFF)
@@ -87,90 +88,90 @@ class MidiFeedbackAPCKey25Plugin(MidiFeedbackPlugin):
self.set_status(note=70, velocity=layer)
def feedback_show_modulation(self, slot):
for i in range(self.NOTE_MODULATION_COLUMN,self.NOTE_MODULATION_COLUMN+4):
if slot==i-self.NOTE_MODULATION_COLUMN:
for i in range(self.NOTE_MODULATION_COLUMN, self.NOTE_MODULATION_COLUMN + 4):
if slot == i - self.NOTE_MODULATION_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 data_centre.plugin_collection import SequencePlugin
try:
from plugins.ShaderLoopRecordPlugin import ShaderLoopRecordPlugin
for plugin in self.pc.get_plugins(SequencePlugin):
if isinstance(plugin, ShaderLoopRecordPlugin):
try:
from plugins.ShaderLoopRecordPlugin import ShaderLoopRecordPlugin
for plugin in self.pc.get_plugins(SequencePlugin):
if isinstance(plugin, ShaderLoopRecordPlugin):
NOTE_PLAY_STATUS = 65
NOTE_RECORD_STATUS = 66
NOTE_OVERDUB_STATUS = 67
#NOTE_CLIP_STATUS_ROW = 8
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=self.NOTE_CLIP_STATUS_ROW+i, velocity=colour)
""" # doesnt really work well, but shows progress of clip in leds
if plugin.is_playing() and not plugin.is_paused():
for i in range(0,plugin.MAX_CLIPS):
if i==int(plugin.position*plugin.MAX_CLIPS):
self.set_status(command='note_on', note=self.NOTE_CLIP_STATUS_ROW+i, velocity=self.COLOUR_GREEN)
"""
except Exception as e:
pass
#print ("Warning: Failed when running plugin feedback for ShaderLoopRecordPlugin:\t%s" % str(e))
try:
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_OFF
if plugin.is_playing():
colour = self.COLOUR_GREEN
if plugin.selected_preset==pad:
if plugin.presets[pad] is None:
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
colour += self.BLINK
self.set_status(command='note_on', note=self.NOTE_SHADER_PRESET_ROW+pad, velocity=colour)
except Exception as e:
pass
#print ("Warning: Failed when running plugin feedback for ShaderQuickPresetPlugin:\t%s" % str(e))
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=self.NOTE_CLIP_STATUS_ROW + i, velocity=colour)
""" # doesnt really work well, but shows progress of clip in leds
if plugin.is_playing() and not plugin.is_paused():
for i in range(0,plugin.MAX_CLIPS):
if i==int(plugin.position*plugin.MAX_CLIPS):
self.set_status(command='note_on', note=self.NOTE_CLIP_STATUS_ROW+i, velocity=self.COLOUR_GREEN)
"""
except Exception as e:
pass
# print ("Warning: Failed when running plugin feedback for ShaderLoopRecordPlugin:\t%s" % str(e))
try:
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=self.NOTE_SHADER_PRESET_ROW + pad, velocity=colour)
except Exception as e:
pass
# print ("Warning: Failed when running plugin feedback for ShaderQuickPresetPlugin:\t%s" % str(e))
BLINK = 1
COLOUR_OFF = 0
@@ -189,7 +190,7 @@ class MidiFeedbackAPCKey25Plugin(MidiFeedbackPlugin):
# 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:
# 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)
@@ -204,16 +205,16 @@ class MidiFeedbackAPCKey25Plugin(MidiFeedbackPlugin):
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))
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:
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)
@@ -229,15 +230,16 @@ class MidiFeedbackAPCKey25Plugin(MidiFeedbackPlugin):
self.update_device()
#print("refresh_midi_feedback")
# 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 (i not in self.last_state or self.last_state[i]!=c):
#print("got command: %s: %s" % (i,c))
# 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 (i not in self.last_state or self.last_state[i] != c):
# print("got command: %s: %s" % (i,c))
self.send_command(**c)
self.last_state = deepcopy(self.status)

View File

@@ -1,8 +1,9 @@
import plugins
#from plugins.MidiFeedbackAPCKey25Plugin import MidiFeedbackAPCKey25Plugin
# from plugins.MidiFeedbackAPCKey25Plugin import MidiFeedbackAPCKey25Plugin
class MidiFeedbackLaunchpadPlugin(plugins.MidiFeedbackAPCKey25Plugin.MidiFeedbackAPCKey25Plugin):
status = {}
def __init__(self, plugin_collection):
@@ -10,15 +11,15 @@ class MidiFeedbackLaunchpadPlugin(plugins.MidiFeedbackAPCKey25Plugin.MidiFeedbac
self.description = 'Outputs feedback to Novation Launchpad'
def init_notes(self):
self.NOTE_PLAY_SHADER = self.get_note('play_shader_0_0',0)
self.NOTE_SHADER_FEEDBACK = self.get_note('toggle_feedback',85)
self.NOTE_SCENE_LAUNCH_COLUMN = self.get_note('toggle_shader_layer_0',82)
self.NOTE_PLAY_SHADER = self.get_note('play_shader_0_0', 0)
self.NOTE_SHADER_FEEDBACK = self.get_note('toggle_feedback', 85)
self.NOTE_SCENE_LAUNCH_COLUMN = self.get_note('toggle_shader_layer_0', 82)
self.NOTE_MODULATION_COLUMN = self.get_note('select_shader_modulation_slot_0', self.NOTE_SCENE_LAUNCH_COLUMN)
self.NOTE_CAPTURE_PREVIEW = self.get_note('toggle_capture_preview', 86)
self.NOTE_CLIP_STATUS_ROW = self.get_note('toggle_automation_clip_0', 8)
self.NOTE_SHADER_PRESET_ROW = self.get_note('select_preset_0', 112)
self.NOTE_SHADER_LAYER_ON = [
self.get_note('toggle_shader_layer_%i'%i,8+(i*16)) for i in range(0,3)
self.get_note('toggle_shader_layer_%i' % i, 8 + (i * 16)) for i in range(0, 3)
]
def supports_midi_feedback(self, device_name):
@@ -28,16 +29,17 @@ class MidiFeedbackLaunchpadPlugin(plugins.MidiFeedbackAPCKey25Plugin.MidiFeedbac
return True
def feedback_shader_on(self, layer, slot, colour=None):
if colour is None: colour = self.COLOUR_GREEN
self.set_status(note=(self.NOTE_PLAY_SHADER+(layer)*16)+slot, velocity=int(colour))
if colour is None:
colour = self.COLOUR_GREEN
self.set_status(note=(self.NOTE_PLAY_SHADER + (layer) * 16) + slot, velocity=int(colour))
def feedback_shader_off(self, layer, slot):
self.set_status(note=(self.NOTE_PLAY_SHADER+(layer)*16)+slot, velocity=self.COLOUR_OFF)
self.set_status(note=(self.NOTE_PLAY_SHADER + (layer) * 16) + slot, velocity=self.COLOUR_OFF)
# TODO: make these colours correct+sensible
BLINK = 1
COLOUR_OFF = 0
COLOUR_GREEN = 8 #1
COLOUR_GREEN = 8 # 1
COLOUR_GREEN_BLINK = 15
COLOUR_RED = 32
COLOUR_RED_BLINK = 47

View File

@@ -1,13 +1,14 @@
from data_centre.plugin_collection import ActionsPlugin
class MultiActionsPlugin(ActionsPlugin):
disabled = False # this is only a demo of very basic multi-actions plugin -- superceded by ManipulatePlugin
disabled = False # this is only a demo of very basic multi-actions plugin -- superceded by ManipulatePlugin
def __init__(self, plugin_collection):
super().__init__(plugin_collection)
try:
from plugins import ManipulatePlugin
self.disabled = True # if we've found ManipulatePlugin then disable this one
self.disabled = True # if we've found ManipulatePlugin then disable this one
except:
# if it fails, we're good to go (so long as not disabled explictly above)
pass
@@ -15,7 +16,7 @@ class MultiActionsPlugin(ActionsPlugin):
@property
def parserlist(self):
return [
( r"(.*)&&(.*)", self.run_multi ),
(r"(.*)&&(.*)", self.run_multi),
]
def run_multi(self, action1, action2, value):

View File

@@ -1,11 +1,10 @@
from data_centre.plugin_collection import ActionsPlugin, SequencePlugin, DisplayPlugin
from data_centre.plugin_collection import ActionsPlugin, DisplayPlugin, SequencePlugin
from plugins.frame_manager import Frame
class ShaderLoopRecordPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
class ShaderLoopRecordPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin):
MAX_CLIPS = 8
frames = []
frames = []
def __init__(self, plugin_collection):
super().__init__(plugin_collection)
@@ -21,25 +20,25 @@ class ShaderLoopRecordPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
self.reset_ignored()
def load_presets(self):
#try:
# try:
print("trying load presets? %s " % self.PRESET_FILE_NAME)
p = self.pc.read_json(self.PRESET_FILE_NAME)
if p:
while len(p)<self.MAX_CLIPS:
print ("adding clip ")
p += self.get_empty_clip(self.duration) #[ [None] ] #*((int(self.duration / self.frequency))-len(p)) ]
while len(p) < self.MAX_CLIPS:
print("adding clip ")
p += self.get_empty_clip(self.duration) # [ [None] ] #*((int(self.duration / self.frequency))-len(p)) ]
for i in p:
print("got automation clip of duration %s" % len(i))
if i and len(i)<(int(self.duration / self.frequency)):
if i and len(i) < (int(self.duration / self.frequency)):
print("adding more slots due to size change")
i += [None]*((int(self.duration / self.frequency))-len(i))
i += [None] * ((int(self.duration / self.frequency)) - len(i))
print("len is now %s" % len(i))
return p
elif p:
return p
else:
return self.get_factory_reset()
#except:
# except:
# return self.clear_frames()
def save_presets(self):
@@ -51,72 +50,69 @@ class ShaderLoopRecordPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
# DisplayPlugin methods
def get_display_modes(self):
return ['LOOPREC','NAV_LPRC']
return ['LOOPREC', 'NAV_LPRC']
def show_plugin(self, display, display_mode):
from tkinter import END
#super(DisplayPlugin).show_plugin(display, display_mode)
# super(DisplayPlugin).show_plugin(display, display_mode)
display.display_text.insert(END, '{} \n'.format(display.body_title))
display.display_text.insert(END, "test from ShaderLoopRecordPlugin!\n")
status = ""
status+="playing" if self.is_playing() else "stopped"
status+="\t"
status+="paused" if self.is_paused() else "unpaused"
status+="\t"
status+="REC" if self.recording else "---"
status+="*" if self.is_ignoring() else " "
status+="\t"
status+="Overdub" if self.overdub else "-------"
status+="\t"
status+="Looping" if self.looping else "Once"
status+="\n"
status += "playing" if self.is_playing() else "stopped"
status += "\t"
status += "paused" if self.is_paused() else "unpaused"
status += "\t"
status += "REC" if self.recording else "---"
status += "*" if self.is_ignoring() else " "
status += "\t"
status += "Overdub" if self.overdub else "-------"
status += "\t"
status += "Looping" if self.looping else "Once"
status += "\n"
display.display_text.insert(END, status)
display.display_text.insert(END, ("Position:\t{:3.0f}%\t[{:12s}]".format(self.position*100.0,("#"*int(self.position*12)))))
#display.display_text.insert(END, (" Speed: {:03.2f}%\n".format(self.speed*100)))
display.display_text.insert(END, (" Speed:{} {:3.0f}%\n".format(display.get_speed_indicator(self.speed/2,convert=False),self.speed*100)))
if self.speed==0.0:
display.display_text.insert(END, ("Position:\t{:3.0f}%\t[{:12s}]".format(self.position * 100.0, ("#" * int(self.position * 12)))))
# display.display_text.insert(END, (" Speed: {:03.2f}%\n".format(self.speed*100)))
display.display_text.insert(END, (" Speed:{} {:3.0f}%\n".format(display.get_speed_indicator(self.speed / 2, convert=False), self.speed * 100)))
if self.speed == 0.0:
display.display_text.insert(END, ("Duration:\tinfinity!\n"))
else:
display.display_text.insert(END, ("Duration:\t{:03.2f}s\n".format(((self.duration/1000)/self.speed)/4)))
#distance s = d/t d = s*t t = d/s
display.display_text.insert(END, ("Duration:\t{:03.2f}s\n".format(((self.duration / 1000) / self.speed) / 4)))
# distance s = d/t d = s*t t = d/s
status = "\nEnabled clips:\t"
for i in range(0,self.MAX_CLIPS):
status+="#" if i==self.selected_clip and i in self.running_clips else\
"/" if i==self.selected_clip and i not in self.running_clips else\
"=" if i in self.running_clips else\
'_'
for i in range(0, self.MAX_CLIPS):
status += "#" if i == self.selected_clip and i in self.running_clips else \
"/" if i == self.selected_clip and i not in self.running_clips else \
"=" if i in self.running_clips else \
'_'
status += "\n"
display.display_text.insert(END, status)
"""for key,value in self.variables.items():
display.display_text.insert(END, "\t" + key + "\t{:03.2f}\n".format(value))"""
@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 ),
( r"set_automation_speed", self.set_speed ),
( r"toggle_record_automation", self.toggle_record_automation ),
( r"toggle_overdub_automation", self.toggle_overdub_automation ),
( r"clear_automation", self.clear_clip ),
( r"select_automation_clip_([0-7])", self.select_clip ),
( r"toggle_automation_clip_([0-7])", self.toggle_clip ),
#( r"smooth_clip_(0-7])", self.smooth_clip ),
( r"smooth_selected_clip", self.smooth_selected_clip )
(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),
(r"set_automation_speed", self.set_speed),
(r"toggle_record_automation", self.toggle_record_automation),
(r"toggle_overdub_automation", self.toggle_overdub_automation),
(r"clear_automation", self.clear_clip),
(r"select_automation_clip_([0-7])", self.select_clip),
(r"toggle_automation_clip_([0-7])", self.toggle_clip),
# ( r"smooth_clip_(0-7])", self.smooth_clip ),
(r"smooth_selected_clip", self.smooth_selected_clip)
]
def smooth_selected_clip(self):
self.pc.fm.interpolate_clip(self.frames[self.selected_clip])
def toggle_overdub_automation(self):
self.overdub = not self.overdub
if not self.overdub:
@@ -132,36 +128,37 @@ class ShaderLoopRecordPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
self.last_saved_index = None
self.save_presets()
def get_empty_clip(self, duration = 4000):
def get_empty_clip(self, duration=4000):
return [None] * (int(duration / self.frequency))
def get_factory_reset(self):
return [ self.get_empty_clip(self.duration) for i in range(self.MAX_CLIPS) ]
return [self.get_empty_clip(self.duration) for i in range(self.MAX_CLIPS)]
def clear_clip(self,clip = None):
def clear_clip(self, clip=None):
if clip is None:
clip = self.selected_clip
self.frames[clip] = self.get_empty_clip(self.duration) * self.MAX_CLIPS
self.reset_ignored()
if self.DEBUG_FRAMES: print ("clear_frames set to %s" % (int(self.duration / self.frequency)))
if self.DEBUG_FRAMES:
print("clear_frames set to %s" % (int(self.duration / self.frequency)))
return self.frames
def toggle_clip(self,clip = None):
def toggle_clip(self, clip=None):
if clip is None:
clip = self.selected_clip
else:
self.selected_clip = clip
#self.running_clips[clip] = not self.running_clips[clip]
# self.running_clips[clip] = not self.running_clips[clip]
if clip in self.running_clips:
self.running_clips.remove(clip)
else:
self.running_clips.append(clip)
print("running clips looks like %s" %self.running_clips)
print("running clips looks like %s" % self.running_clips)
def reset_ignored(self):
# print("!!!!resetting ignored")
self.ignored = Frame(self.pc).store_copy({ 'shader_params': [[None]*4,[None]*4,[None]*4] })
self.ignored = Frame(self.pc).store_copy({'shader_params': [[None] * 4, [None] * 4, [None] * 4]})
def is_ignoring(self):
return not self.pc.fm.is_frame_empty(self.ignored)
@@ -170,81 +167,92 @@ class ShaderLoopRecordPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
self.selected_clip = clip
selected_clip = 0
running_clips = [ ] #False ] * self.MAX_CLIPS
running_clips = [] # False ] * self.MAX_CLIPS
duration = 4000
frequency = 10 #25
frequency = 10 # 25
recording = False
overdub = True
#ignored = None # set in reset_ignored in init - used for tracking what parans have changed since overdub
last_frame = None # for tracking what's changed between frames when overdubbing
last_saved_index = None # for backfilling
DEBUG_FRAMES = False#True
overdub = True
# ignored = None # set in reset_ignored in init - used for tracking what parans have changed since overdub
last_frame = None # for tracking what's changed between frames when overdubbing
last_saved_index = None # for backfilling
DEBUG_FRAMES = False # True
def run_sequence(self, position):
current_frame_index = int(position * (int(self.duration / self.frequency)))
if current_frame_index<0:
current_frame_index = (self.duration/self.frequency) - current_frame_index
if current_frame_index >= self.duration: # self.duration/self.frequency:
current_frame_index = "(self.duration/self.frequency) +""" (current_frame_index%self.duration)
if current_frame_index < 0:
current_frame_index = (self.duration / self.frequency) - current_frame_index
if current_frame_index >= self.duration: # self.duration/self.frequency:
current_frame_index = "(self.duration/self.frequency) +"""(current_frame_index % self.duration)
if self.DEBUG_FRAMES: print (">>>>>>>>>>>>>>frame at %i%%: %i" % (position*100, current_frame_index))
#print("got frame index %s" % current_frame_index)
if self.DEBUG_FRAMES:
print(">>>>>>>>>>>>>>frame at %i%%: %i" % (position * 100, current_frame_index))
# print("got frame index %s" % current_frame_index)
if self.recording:
current_frame = self.pc.fm.get_live_frame() #.copy()
current_frame = self.pc.fm.get_live_frame() # .copy()
selected_clip = self.selected_clip
if self.DEBUG_FRAMES: print("current_frame copy before recall is %s" % current_frame['shader_params'])
#print ("%s clips, looks like %s" % (len(self.frames),self.frames))
if self.DEBUG_FRAMES:
print("current_frame copy before recall is %s" % current_frame['shader_params'])
# print ("%s clips, looks like %s" % (len(self.frames),self.frames))
#print("selected_clip is %s "%selected_clip)
#clip = self.frames[selected_clip]
# print("selected_clip is %s "%selected_clip)
# clip = self.frames[selected_clip]
if self.is_playing() and self.recording and self.selected_clip not in self.running_clips:
self.running_clips += [ self.selected_clip ]
self.running_clips += [self.selected_clip]
if self.recording:
current_frame = self.pc.fm.get_live_frame() #.copy()
if self.DEBUG_FRAMES: print("current_frame copy before recall is %s" % current_frame['shader_params'])
current_frame = self.pc.fm.get_live_frame() # .copy()
if self.DEBUG_FRAMES:
print("current_frame copy before recall is %s" % current_frame['shader_params'])
for selected_clip in self.running_clips:
saved_frame = self.frames[selected_clip][current_frame_index]
if not self.recording or (selected_clip!=self.selected_clip):
self.pc.fm.recall_frame(saved_frame)
if self.recording and selected_clip==self.selected_clip:
if self.last_frame is None:
self.last_frame = current_frame
if self.DEBUG_FRAMES: print("last frame is \t\t%s" % self.last_frame['shader_params'])
if self.DEBUG_FRAMES: print("current f is \t\t%s" % current_frame['shader_params'])
diff = self.pc.fm.get_frame_diff(self.last_frame,current_frame)
if self.DEBUG_FRAMES: print("diffed frame is \t%s" % diff['shader_params'])
saved_frame = self.frames[selected_clip][current_frame_index]
if not self.recording or (selected_clip != self.selected_clip):
self.pc.fm.recall_frame(saved_frame)
if self.recording and selected_clip == self.selected_clip:
if self.last_frame is None:
self.last_frame = current_frame
if self.DEBUG_FRAMES:
print("last frame is \t\t%s" % self.last_frame['shader_params'])
if self.DEBUG_FRAMES:
print("current f is \t\t%s" % current_frame['shader_params'])
diff = self.pc.fm.get_frame_diff(self.last_frame, current_frame)
if self.DEBUG_FRAMES:
print("diffed frame is \t%s" % diff['shader_params'])
if self.overdub and saved_frame:
# add the params tweaked this frame to the params to be ignored by recall
if self.DEBUG_FRAMES: print("saved frame is \t%s" % saved_frame['shader_params'])
self.ignored = self.pc.fm.merge_frames(self.ignored, diff)
if self.DEBUG_FRAMES: print("about to call get_ignored_frames with %s\n and\n %s" % (saved_frame.f, self.ignored.f))
"""print("got self.ignored:\n\t%s\n" % self.ignored.f)
print("diff is currently:\n\t%s\n" % diff.f)
print("saved_frame is currently:\n\t%s\n" % saved_frame.f)"""
diff = self.pc.fm.merge_frames(
self.pc.fm.get_frame_ignored(saved_frame, self.ignored),
diff
)
#print("got merged:\n\t%s\n" % diff.f)
#diff = self.pc.shaders.merge_frames(self.pc.shaders.get_live_frame(), diff)
self.pc.fm.recall_frame(diff)
if self.DEBUG_FRAMES: print("after diff2 is: \t%s" % diff['shader_params'])
if self.DEBUG_FRAMES: print("||||saving frame \t%s" % (diff['shader_params']))
self.frames[selected_clip][current_frame_index] = diff #self.get_frame_diff(self.last_frame,current_frame)
#backfill frames
"""if self.last_saved_index is not None:
if self.DEBUG_FRAMES: print ("last_saved_index is %s, current_frame_index is %s" % (self.last_saved_index, current_frame_index))
for i in range(current_frame_index - (self.last_saved_index) ):
if self.DEBUG_FRAMES: print("backfilling frame %s" % ((self.last_saved_index+i+1)%len(self.frames[selected_clip])))
self.frames[selected_clip][(self.last_saved_index+i+1)%len(self.frames[selected_clip])] = diff"""
self.last_saved_index = current_frame_index
self.last_frame = self.pc.fm.get_live_frame() #diff
if self.DEBUG_FRAMES: print("<<<<<<<<<<<<<< frame at %s" % current_frame_index)
if self.overdub and saved_frame:
# add the params tweaked this frame to the params to be ignored by recall
if self.DEBUG_FRAMES:
print("saved frame is \t%s" % saved_frame['shader_params'])
self.ignored = self.pc.fm.merge_frames(self.ignored, diff)
if self.DEBUG_FRAMES:
print("about to call get_ignored_frames with %s\n and\n %s" % (saved_frame.f, self.ignored.f))
"""print("got self.ignored:\n\t%s\n" % self.ignored.f)
print("diff is currently:\n\t%s\n" % diff.f)
print("saved_frame is currently:\n\t%s\n" % saved_frame.f)"""
diff = self.pc.fm.merge_frames(
self.pc.fm.get_frame_ignored(saved_frame, self.ignored),
diff
)
# print("got merged:\n\t%s\n" % diff.f)
# diff = self.pc.shaders.merge_frames(self.pc.shaders.get_live_frame(), diff)
self.pc.fm.recall_frame(diff)
if self.DEBUG_FRAMES:
print("after diff2 is: \t%s" % diff['shader_params'])
if self.DEBUG_FRAMES:
print("||||saving frame \t%s" % (diff['shader_params']))
self.frames[selected_clip][current_frame_index] = diff # self.get_frame_diff(self.last_frame,current_frame)
# backfill frames
"""if self.last_saved_index is not None:
if self.DEBUG_FRAMES: print ("last_saved_index is %s, current_frame_index is %s" % (self.last_saved_index, current_frame_index))
for i in range(current_frame_index - (self.last_saved_index) ):
if self.DEBUG_FRAMES: print("backfilling frame %s" % ((self.last_saved_index+i+1)%len(self.frames[selected_clip])))
self.frames[selected_clip][(self.last_saved_index+i+1)%len(self.frames[selected_clip])] = diff"""
self.last_saved_index = current_frame_index
self.last_frame = self.pc.fm.get_live_frame() # diff
if self.DEBUG_FRAMES:
print("<<<<<<<<<<<<<< frame at %s" % current_frame_index)
"""def recall_frame_index(self, index):
self.pc.shaders.recall_frame_params(self.frames[index].copy())"""

View File

@@ -1,7 +1,8 @@
from data_centre.plugin_collection import ActionsPlugin, DisplayPlugin
from plugins.frame_manager import Frame
class ShaderQuickPresetPlugin(ActionsPlugin,DisplayPlugin): #,SequencePlugin):
class ShaderQuickPresetPlugin(ActionsPlugin, DisplayPlugin): # ,SequencePlugin):
MAX_PRESETS = 8
display_live_on = False
@@ -18,7 +19,7 @@ class ShaderQuickPresetPlugin(ActionsPlugin,DisplayPlugin): #,SequencePlugin):
def load_presets(self):
print("trying load presets? %s " % self.PRESET_FILE_NAME)
return [ Frame(self.pc).store_copy(x) for x in (self.pc.read_json(self.PRESET_FILE_NAME) or ([None]*self.MAX_PRESETS)) ]
return [Frame(self.pc).store_copy(x) for x in (self.pc.read_json(self.PRESET_FILE_NAME) or ([None] * self.MAX_PRESETS))]
def save_presets(self):
self.pc.update_json(self.PRESET_FILE_NAME, self.presets)
@@ -29,20 +30,20 @@ class ShaderQuickPresetPlugin(ActionsPlugin,DisplayPlugin): #,SequencePlugin):
@property
def parserlist(self):
return [
( r"load_presets", self.load_presets ),
( r"save_presets", self.save_presets ),
( r"store_next_preset", self.store_next_preset ),
( r"store_current_preset", self.store_current_preset ),
( r"switch_to_preset_([0-%i])"%self.MAX_PRESETS, self.switch_to_preset ),
( r"select_preset_([0-%i])"%self.MAX_PRESETS, self.select_preset ),
( r"clear_current_preset", self.clear_current_preset ),
( r"qksh_toggle_display_live", self.toggle_display_live ),
( r"switch_to_next_preset", self.switch_to_next_preset ),
( r"switch_to_previous_preset", self.switch_to_previous_preset ),
( r"switch_to_current_preset", self.switch_to_current_preset ),
( r"select_previous_preset", self.select_previous_preset ),
( r"select_next_preset", self.select_next_preset ),
return [
(r"load_presets", self.load_presets),
(r"save_presets", self.save_presets),
(r"store_next_preset", self.store_next_preset),
(r"store_current_preset", self.store_current_preset),
(r"switch_to_preset_([0-%i])" % self.MAX_PRESETS, self.switch_to_preset),
(r"select_preset_([0-%i])" % self.MAX_PRESETS, self.select_preset),
(r"clear_current_preset", self.clear_current_preset),
(r"qksh_toggle_display_live", self.toggle_display_live),
(r"switch_to_next_preset", self.switch_to_next_preset),
(r"switch_to_previous_preset", self.switch_to_previous_preset),
(r"switch_to_current_preset", self.switch_to_current_preset),
(r"select_previous_preset", self.select_previous_preset),
(r"select_next_preset", self.select_next_preset),
]
def toggle_display_live(self):
@@ -50,16 +51,16 @@ class ShaderQuickPresetPlugin(ActionsPlugin,DisplayPlugin): #,SequencePlugin):
# DisplayPlugin methods
def get_display_modes(self):
return ['QUIKSHDR',['NAV_QKSH','PLAY_SHADER']]
return ['QUIKSHDR', ['NAV_QKSH', 'PLAY_SHADER']]
def show_plugin(self, display, display_mode):
from tkinter import END
#super(DisplayPlugin).show_plugin(display, display_mode)
# super(DisplayPlugin).show_plugin(display, display_mode)
display.display_text.insert(END, '{} \n'.format(display.body_title))
display.display_text.insert(END, "ShaderQuickPresetPlugin")
status = "Selected: ["
#for i,preset in enumerate(self.presets):
# for i,preset in enumerate(self.presets):
for i in range(self.MAX_PRESETS):
preset = self.presets[i]
if i == self.selected_preset:
@@ -81,14 +82,14 @@ class ShaderQuickPresetPlugin(ActionsPlugin,DisplayPlugin): #,SequencePlugin):
display.display_text.insert(END, "Showing LIVE preview\n")
else:
display.display_text.insert(END, "Showing stored preset slot %s" % self.selected_preset)
if self.selected_preset==self.last_recalled:
if self.selected_preset == self.last_recalled:
display.display_text.insert(END, " [last switched]")
display.display_text.insert(END, "\n")
## show a summary of the selected preset
if self.selected_preset is not None:
# TODO: switch to display current settings
#for line in self.pc.fm.get_live_frame().get_frame_summary():
# for line in self.pc.fm.get_live_frame().get_frame_summary():
for line in (self.presets[self.selected_preset] if not self.display_live_on else self.pc.fm.get_live_frame()).get_frame_summary():
display.display_text.insert(END, "%s\n" % line)
@@ -99,7 +100,7 @@ class ShaderQuickPresetPlugin(ActionsPlugin,DisplayPlugin): #,SequencePlugin):
# didnt find an empty slot, save to current
self.store_current_preset()
self.selected_preset += 1
self.selected_preset %= self.MAX_PRESETS
self.selected_preset %= self.MAX_PRESETS
else:
# found an empty slot, save to it
self.selected_preset = res[0]
@@ -113,11 +114,12 @@ class ShaderQuickPresetPlugin(ActionsPlugin,DisplayPlugin): #,SequencePlugin):
self.save_presets()
def store_current_preset(self):
if self.selected_preset is None: self.selected_preset = 0
if self.selected_preset is None:
self.selected_preset = 0
insert_position = self.selected_preset
self.presets[insert_position] = self.pc.fm.get_live_frame()
#print ("stored %s at position %s" % (self.presets[insert_position], insert_position))
# print ("stored %s at position %s" % (self.presets[insert_position], insert_position))
self.selected_preset = insert_position
self.last_recalled = insert_position
@@ -127,18 +129,18 @@ class ShaderQuickPresetPlugin(ActionsPlugin,DisplayPlugin): #,SequencePlugin):
self.selected_preset = preset
def switch_to_preset(self, preset):
#if preset>len(self.presets):
# if preset>len(self.presets):
if self.presets[preset] is None:
self.message_handler.set_message('ERROR',"No quick shader preset in slot %s!" % preset)
self.message_handler.set_message('ERROR', "No quick shader preset in slot %s!" % preset)
self.selected_preset = preset
return
print ("switching to preset %s" % preset)
print("switching to preset %s" % preset)
self.selected_preset = preset
self.last_recalled = preset
preset = self.presets[preset]
print ("recalled preset %s" % preset)
print("recalled preset %s" % preset)
self.pc.fm.recall_frame(preset)
def switch_to_current_preset(self):
@@ -158,7 +160,7 @@ class ShaderQuickPresetPlugin(ActionsPlugin,DisplayPlugin): #,SequencePlugin):
self.selected_preset = 0
return
self.selected_preset += 1
if self.selected_preset>=self.MAX_PRESETS:
if self.selected_preset >= self.MAX_PRESETS:
self.selected_preset = 0
def select_previous_preset(self):
@@ -166,8 +168,5 @@ class ShaderQuickPresetPlugin(ActionsPlugin,DisplayPlugin): #,SequencePlugin):
self.selected_preset = self.MAX_PRESETS
return
self.selected_preset -= 1
if self.selected_preset<0:
self.selected_preset = self.MAX_PRESETS-1
if self.selected_preset < 0:
self.selected_preset = self.MAX_PRESETS - 1

View File

@@ -5,12 +5,12 @@ import pyaudio
from data_centre.plugin_collection import ActionsPlugin, DisplayPlugin, SequencePlugin
#import matplotlib.pyplot as plt
# import matplotlib.pyplot as plt
np.set_printoptions(suppress=True) # don't use scientific notationn
np.set_printoptions(suppress=True) # don't use scientific notationn
class SoundReactPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
class SoundReactPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin):
DEBUG = False
active = True
@@ -19,15 +19,15 @@ class SoundReactPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
stream = None
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
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
values = {}
levels = {
"energy": [ 0.0, 0.0, 1.0, 0.0 ],
"peakfreq": [ 0.0, 0.0, 0.0, 0.0 ]
"energy": [0.0, 0.0, 1.0, 0.0],
"peakfreq": [0.0, 0.0, 0.0, 0.0]
}
last_values = {}
display_values = {}
@@ -44,9 +44,9 @@ class SoundReactPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
self.PRESET_FILE_NAME = "SoundReactPlugin/config.json"
presets = self.load_presets()
self.config = presets.get('config',self.config)
self.levels = presets.get('levels',self.levels)
self.active = presets.get('active',self.active)
self.config = presets.get('config', self.config)
self.levels = presets.get('levels', self.levels)
self.active = presets.get('active', self.active)
if not self.disabled:
self.start_plugin()
@@ -56,7 +56,7 @@ class SoundReactPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
return self.pc.read_json(self.PRESET_FILE_NAME) or {}
def save_presets(self):
self.pc.update_json(self.PRESET_FILE_NAME, { 'config': self.config, 'levels': self.levels, 'active': self.active } )
self.pc.update_json(self.PRESET_FILE_NAME, {'config': self.config, 'levels': self.levels, 'active': self.active})
def stop_plugin(self):
super().stop_plugin()
@@ -73,9 +73,9 @@ class SoundReactPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
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)
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
@@ -96,10 +96,10 @@ class SoundReactPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
# TODO: write more interpreters
return {
"energy": self.energy,
#"low": self.low,
#"mid": self.mid,
#"high": self.high,
#"peakfreq": self.peakfreq
# "low": self.low,
# "mid": self.mid,
# "high": self.high,
# "peakfreq": self.peakfreq
}
# triggers?
@@ -107,127 +107,128 @@ class SoundReactPlugin(ActionsPlugin,SequencePlugin,DisplayPlugin):
# DisplayPlugin methods
def get_display_modes(self):
return ['SOUNDMOD','NAV_SND']
return ['SOUNDMOD', 'NAV_SND']
def show_plugin(self, display, display_mode):
from tkinter import END
#super(DisplayPlugin).show_plugin(display, display_mode)
# 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))
# display.display_text.insert(END, "\tSpeed: {:03.2f}\n\n".format(self.speed))
for sourcename in sorted(self.sources):
value = "{:8}:\t".format(sourcename)
for i,level in enumerate(self.levels[sourcename]):
g = self.pc.display.get_mod_slot_label(i)+'%s '%self.pc.display.get_bar(level)
for i, level in enumerate(self.levels[sourcename]):
g = self.pc.display.get_mod_slot_label(i) + '%s ' % self.pc.display.get_bar(level)
value += g
value += "\t"
value += self.display_values.get(sourcename) or "{:4.2f}%".format(self.values.get(sourcename,0)*100) or "None"
display.display_text.insert(END,value + "\n")
value += self.display_values.get(sourcename) or "{:4.2f}%".format(self.values.get(sourcename, 0) * 100) or "None"
display.display_text.insert(END, value + "\n")
"""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, "\nLevels:%s\n\n" % self.levels)
display.display_text.insert(END, "\n\n\n")
energy_history = []
def run_sequence(self, position):
# position is irrelvant for this plugin, we just want to run continuously
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)
data = np.fromstring(self.stream.read(self.CHUNK, exception_on_overflow=False), dtype=np.int16)
previous_value = {}
for sourcename in self.sources:
value = self.sources[sourcename](data)
self.values[sourcename] = value
if value is None:
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])
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])
previous_value[sourcename] = self.last_values.get(sourcename) or value
self.last_values[sourcename] = self.values[sourcename]
if sourcename is 'energy' and self.last_values.get('energy') is not None:
diff = abs(self.last_values.get('energy',value)-previous_value.get(sourcename,value)) #mean(self.energy_history))
if len(self.energy_history)>5: #self.duration:
meandiff = abs(diff-mean(self.energy_history[:int(len(self.energy_history)/2)]))
#print (" diff is %s, meandiff %s" % (diff, meandiff))
if meandiff>=self.config['energy'].get('triggerthreshold',0.15):
diff = abs(self.last_values.get('energy', value) - previous_value.get(sourcename, value)) # mean(self.energy_history))
if len(self.energy_history) > 5: # self.duration:
meandiff = abs(diff - mean(self.energy_history[:int(len(self.energy_history) / 2)]))
# print (" diff is %s, meandiff %s" % (diff, meandiff))
if meandiff >= self.config['energy'].get('triggerthreshold', 0.15):
self.energy_history = []
print ("\n>>>>>>Triggering dynamic change for meandiff %s?\n" % meandiff)
print("\n>>>>>>Triggering dynamic change for meandiff %s?\n" % meandiff)
# TODO: add configurable triggering - eg trigger next preset, next shader, next video..
#self.pc.actions.call_method_name("load_slot_%s_into_next_player"%randint(0,9))
self.energy_history.append(diff) #self.values.get(sourcename,0.0))
#print("logging %s" % diff) #self.values.get(sourcename,0.0))
# self.pc.actions.call_method_name("load_slot_%s_into_next_player"%randint(0,9))
self.energy_history.append(diff) # self.values.get(sourcename,0.0))
# print("logging %s" % diff) #self.values.get(sourcename,0.0))
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 this value)
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 this value)
GAIN_MULT = 1.0
def energy(self,data):
peak=np.average(np.abs(data))*2
value = (peak/2**16)/16 * 100
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:
if value < 0.0:
value = 0.0
if value>1.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))
bars = "#" * int(50 * value)
if self.DEBUG:
print("energy:\t\t%05d %s\t(converted to %s)" % (peak, bars, value))
self.display_values['energy'] = "{} gn:{} trsh:{} trg:{}".format(
self.pc.display.get_bar(value),
self.pc.display.get_bar(self.config['energy']['gain']),
self.pc.display.get_bar(self.config['energy']['threshold']),
self.pc.display.get_bar(self.config['energy'].setdefault('triggerthreshold',0.15))
)
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/2000 # ?
#value = (value**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)
self.pc.display.get_bar(value),
self.pc.display.get_bar(self.config['energy']['gain']),
self.pc.display.get_bar(self.config['energy']['threshold']),
self.pc.display.get_bar(self.config['energy'].setdefault('triggerthreshold', 0.15))
)
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 / 2000 # ?
# value = (value**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 ),
(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
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!")
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):

View File

@@ -1,6 +1,7 @@
from data_centre.plugin_collection import ActionsPlugin, SequencePlugin
class TestPlugin(ActionsPlugin,SequencePlugin):
class TestPlugin(ActionsPlugin, SequencePlugin):
disabled = True
def __init__(self, plugin_collection):
@@ -8,39 +9,41 @@ class TestPlugin(ActionsPlugin,SequencePlugin):
@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 ),
( r"^print_arguments$", self.print_arguments ),
( r"^set_the_shader_param_([0-3])_layer_offset_([0-2])_continuous_inverted_example$", self.invert_shader_param_layer )
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),
(r"^print_arguments$", self.print_arguments),
(r"^set_the_shader_param_([0-3])_layer_offset_([0-2])_continuous_inverted_example$", self.invert_shader_param_layer)
]
def test_plugin(self):
print ("TEST PLUGIN test_plugin CALLED!!")
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:
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):
for i, shader in enumerate(self.pc.message_handler.shaders.selected_shader_list):
self.pc.actions.call_method_name(
"play_shader_%s_%s" % (i, self.cycle_count), None
"play_shader_%s_%s" % (i, self.cycle_count), None
)
self.pc.actions.call_method_name(
"start_shader_layer_%s" % i, None
"start_shader_layer_%s" % i, None
)
self.cycle_count += 1
duration = 5000
frequency = 50
def run_sequence(self, position):
self.pc.actions.call_method_name(
"set_the_shader_param_3_layer_0_continuous", position
@@ -56,7 +59,7 @@ class TestPlugin(ActionsPlugin,SequencePlugin):
def invert_shader_param_layer(self, param, layer, value):
# invert the value
self.pc.actions.call_method_name(
"set_the_shader_param_%s_layer_offset_%s_continuous" % ( param, layer), 1.0 - value
"set_the_shader_param_%s_layer_offset_%s_continuous" % (param, layer), 1.0 - value
# if you were calling an action with no argument, use eg:
# "toggle_automation_pause", None
)

View File

@@ -9,6 +9,7 @@ from data_centre.plugin_collection import ActionsPlugin, AutomationSourcePlugin,
class AsyncWriter(threading.Thread):
queue = []
quit_flag = False
def __init__(self, plugin):
super().__init__()
self.plugin = plugin
@@ -17,38 +18,38 @@ class AsyncWriter(threading.Thread):
self.queue.append(data)
def ready(self):
return len(self.queue)>0
return len(self.queue) > 0
def quit(self):
self.quit_flag = True
def run(self):
while not self.quit_flag:
#print("AsyncWriter looping..")
# print("AsyncWriter looping..")
if not self.plugin.active or self.plugin.disabled:
#print("plugin active or disabled - exiting!")
# print("plugin active or disabled - exiting!")
return
if self.plugin.ser is None or not self.plugin.ser:
#print("no stream - skipping")
# print("no stream - skipping")
time.sleep(0.5)
continue
if not self.ready():
#print("not ready - skipping")
# print("not ready - skipping")
time.sleep(0.005)
continue
item = self.queue.pop(0)
if item is not None:
#print("sending %s" % item)
# print("sending %s" % item)
self.plugin.ser.write(item)
time.sleep(len(item)*0.005)
time.sleep(len(item) * 0.005)
else:
time.sleep(0.01)
if len(self.queue)>4:
if len(self.queue) > 4:
self.queue = self.queue[-4:4]
class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationReceiverPlugin, AutomationSourcePlugin):
DEBUG = False #True
DEBUG = False # True
ser = None
active = True
@@ -68,7 +69,7 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
rtscts=True, # TODO : test without this one
timeout=timeout)"""
THROTTLE = 20 # milliseconds to wait between refreshing parameters
THROTTLE = 20 # milliseconds to wait between refreshing parameters
selected_command_name = None
selected_argument_index = 0
@@ -83,24 +84,24 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
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():
for cmd, levels in self.presets['modulation_levels'].items():
self.commands[cmd]['modulation'] = levels.copy()
# build a reverse map of friendly name -> command struct 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.pc.actions.tk.after(500, self.start_plugin)
self.selected_command_name = list(sorted(self.commands.keys()))[0] # select first command
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)
return self.pc.read_json(self.PRESET_FILE_NAME) or { 'modulation_levels': {} }
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',[{},{},{},{}])
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 start_plugin(self):
@@ -113,14 +114,14 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
self.asyncwriter = None
self.save_presets()
# methods/vars for AutomationSourcePlugin
# a lot of the nitty-gritty handled in parent class, these are for interfacing to the plugin
last_record = {}
def get_frame_data(self):
diff = self.last_record.copy()
#self.last_record = {}
#print(">>> reporting frame data for rec\n\t%s" % diff)
# self.last_record = {}
# print(">>> reporting frame data for rec\n\t%s" % diff)
return diff
def recall_frame_data(self, data):
@@ -129,7 +130,7 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
# print(">>>>recall from data:\n\t%s\n" %data)
for queue, item in data.items():
if item is not None:
self.send_buffered(queue, item[0], item[1], record = False)
self.send_buffered(queue, item[0], item[1], record=False)
def get_frame_summary(self, data):
line = "WJMX: "
@@ -141,43 +142,47 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
# methods for ModulationReceiverPlugin - receives changes to the in-built modulation levels (-1 to +1)
# experimental & hardcoded !
# TODO: make this not hardcoded and configurable mapping modulation to parameters, preferably on-the-fly..
modulation_value = [0.0,0.0,0.0,0.0]
modulation_value = [0.0, 0.0, 0.0, 0.0]
def set_modulation_value(self, param, value):
self.modulation_value[param] = value ## invert so that no signal always gives a value ..
#print("storing modulation slot %s as %s" % (param,value))
self.modulation_value[param] = value ## invert so that no signal always gives a value ..
# print("storing modulation slot %s as %s" % (param,value))
# take modulation value and throw it to local parameter
if self.DEBUG: print("||||| WJSendPlugin received set_modulation_value for param %s with value %s!" % (param, value))
#v = (0.5+value)/2
if self.DEBUG:
print("||||| WJSendPlugin received set_modulation_value for param %s with value %s!" % (param, value))
# v = (0.5+value)/2
"""mapped = [
'mix',
'colour_T',
#'colour_T',
'back_colour:x'
]"""
#self.catch_all(*mapped[param].split(":")+[v])
#self.commands[
# self.catch_all(*mapped[param].split(":")+[v])
# self.commands[
# find which commands are mapped to this modulation, and trigger a send of them
# so that they update with the new modulation value
to_send = {}
for queue,cmd in sorted(self.command_by_queue.items(),reverse=True):
cmd.setdefault('modulation',[{},{},{},{}])
for queue, cmd in sorted(self.command_by_queue.items(), reverse=True):
cmd.setdefault('modulation', [{}, {}, {}, {}])
if self.DEBUG: print("\tparam %s, checking modulation %s" % (param, cmd.get('modulation')))
if len(cmd['modulation'][param])>0:
if self.DEBUG: print("\tParam %s has modulation! sending update of values? %s" %
(param, [cmd['arguments'][y] for y in cmd['arg_names'] ]))
#self.send_buffered(cmd['queue'], cmd['form'], [x for x in [ cmd['arguments'][y] for y in cmd['arg_names'] ] ], record=False)
to_send[cmd['queue']] = cmd
continue
if self.DEBUG:
print("\tparam %s, checking modulation %s" % (param, cmd.get('modulation')))
if len(cmd['modulation'][param]) > 0:
if self.DEBUG:
print("\tParam %s has modulation! sending update of values? %s" %
(param, [cmd['arguments'][y] for y in cmd['arg_names']]))
# self.send_buffered(cmd['queue'], cmd['form'], [x for x in [ cmd['arguments'][y] for y in cmd['arg_names'] ] ], record=False)
to_send[cmd['queue']] = cmd
continue
for queue,cmd in sorted(to_send.items(),reverse=True):
self.send_buffered(cmd['queue'], cmd['form'], [x for x in [ cmd['arguments'][y] for y in cmd['arg_names'] ] ], record=False)
#with self.queue_lock:
#self.send(cmd['queue'], cmd['form'], [x for x in [ cmd['arguments'][y] for y in cmd['arg_names'] ] ])
#methods for DisplayPlugin
for queue, cmd in sorted(to_send.items(), reverse=True):
self.send_buffered(cmd['queue'], cmd['form'], [x for x in [cmd['arguments'][y] for y in cmd['arg_names']]], record=False)
# with self.queue_lock:
# self.send(cmd['queue'], cmd['form'], [x for x in [ cmd['arguments'][y] for y in cmd['arg_names'] ] ])
# methods for DisplayPlugin
def show_plugin(self, display, display_mode):
from tkinter import END
display.display_text.insert(END, '{} \n'.format(display.body_title))
@@ -186,31 +191,30 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
for queue, last in sorted(self.last_modulated.items()):
is_selected = queue == self.commands[self.selected_command_name].get('queue')
indicator = " " if not is_selected else "<"
display.display_text.insert(END, "%s%s:\t%s\t%s" % (indicator,queue,self.last.get(queue)[1],self.last_modulated.get(queue)[1]))
display.display_text.insert(END, "%s%s:\t%s\t%s" % (indicator, queue, self.last.get(queue)[1], self.last_modulated.get(queue)[1]))
if is_selected:
display.display_text.insert(END, ">") # add indicator of the selected queue for param jobbies
display.display_text.insert(END, ">") # add indicator of the selected queue for param jobbies
display.display_text.insert(END, "\n")
cmd = self.commands[self.selected_command_name]
output = "\n" + "%s %s : %s\n" % (self.commands[self.selected_command_name].get('queue'), self.selected_command_name, cmd['name'])
output = "\n" + "%s %s : %s\n" % (self.commands[self.selected_command_name].get('queue'), self.selected_command_name, cmd['name'])
for arg_name in cmd['arg_names']:
is_selected = cmd['arg_names'].index(arg_name)==self.selected_argument_index
output += "\t " #Mod
is_selected = cmd['arg_names'].index(arg_name) == self.selected_argument_index
output += "\t " # Mod
indicator = " " if not is_selected else "["
output += "%s%s: "%(indicator,arg_name)
for slot,mods in enumerate(cmd.setdefault('modulation',[{},{},{},{}])):
#if arg_name in mods:
v = mods.get(arg_name,0.0)
g = '%s'%self.pc.display.get_bar(v)
output += "{}:{}|".format(self.pc.display.get_mod_slot_label(slot),g)
output += "%s%s: " % (indicator, arg_name)
for slot, mods in enumerate(cmd.setdefault('modulation', [{}, {}, {}, {}])):
# if arg_name in mods:
v = mods.get(arg_name, 0.0)
g = '%s' % self.pc.display.get_bar(v)
output += "{}:{}|".format(self.pc.display.get_mod_slot_label(slot), g)
if is_selected:
output+="]"
output += "]"
output += "\n"
display.display_text.insert(END, output+"\n")
display.display_text.insert(END, output + "\n")
def get_display_modes(self):
return ["WJMXSEND","NAV_WJMX"]
return ["WJMXSEND", "NAV_WJMX"]
# methods for SerialPlugin (TODO: if this needs generalising out!) and serial command queueing
def open_serial(self, port='/dev/ttyUSB0', baudrate=9600):
@@ -220,39 +224,40 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
return
try:
self.ser = serial.Serial(
port=port,
baudrate=baudrate,
bytesize=serial.SEVENBITS,
parity=serial.PARITY_ODD,
stopbits=serial.STOPBITS_ONE,
xonxoff=False,
rtscts=True, # TODO : test without this one
timeout=None #timeout
port=port,
baudrate=baudrate,
bytesize=serial.SEVENBITS,
parity=serial.PARITY_ODD,
stopbits=serial.STOPBITS_ONE,
xonxoff=False,
rtscts=True, # TODO : test without this one
timeout=None # timeout
)
except Exception as e:
print ("WJSendPlugin>> open_serial failed: " + str(type(e)))
print("WJSendPlugin>> open_serial failed: " + str(type(e)))
self.disabled = True
import traceback
traceback.print_exc()
import threading
serial_lock = threading.Lock()
def send_serial_string(self, string):
# TODO: thread this so can implement throttling and reduce bottleneck...
if not self.active:
return
try:
if self.DEBUG:
if self.DEBUG:
print("WJSendPlugin>> sending string %s " % string)
output = b'\2' + string.encode('ascii') + b'\3'
#with self.serial_lock:
#self.ser.write(b'\2\2\2\2\3\3\3\3')
output = b'\2' + string.encode('ascii') + b'\3'
# with self.serial_lock:
# self.ser.write(b'\2\2\2\2\3\3\3\3')
if self.asyncwriter is None:
self.asyncwriter = AsyncWriter(self)
self.asyncwriter.start()
self.asyncwriter.write(output)
#self.ser.write(output) #.encode())
# self.ser.write(output) #.encode())
# TODO: sleeping here seems to help serial response lag problem?
"""self.sleep = 0.2 #self.pc.get_variable('A')
#print ("got sleep %s" % self.sleep)
@@ -260,17 +265,18 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
#print("using sleep %s" % self.sleep)
import time
time.sleep(self.sleep/10.0)"""
#yield from self.ser.drain()
if self.DEBUG:
print("send_serial_string: sent string '%s'" % output) #.encode('ascii'))
#if 'S' in string:
# yield from self.ser.drain()
if self.DEBUG:
print("send_serial_string: sent string '%s'" % output) # .encode('ascii'))
# if 'S' in string:
# self.get_device_status()
except Exception as e:
print("\t%s: send_serial_string failed for '%s'" % (e,string))
print("\t%s: send_serial_string failed for '%s'" % (e, string))
queue = {}
import threading
queue_lock = threading.Lock()
# send the queued commands to WJMX
def refresh(self):
if not self.ser or self.ser is None:
@@ -279,11 +285,11 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
try:
# sorting the commands that are sent seems to fix jerk and lag that is otherwise pretty horrendous
with self.queue_lock:
for queue, command in sorted(self.queue.items()):
self.send_buffered(queue, command[0], command[1])
#self.queue.clear()
for queue, command in sorted(self.queue.items()):
self.send_buffered(queue, command[0], command[1])
# self.queue.clear()
except Exception:
print ("WJSendPlugin>>> !!! CAUGHT EXCEPTION running queue %s!!!" % queue)
print("WJSendPlugin>>> !!! CAUGHT EXCEPTION running queue %s!!!" % queue)
import traceback
print(traceback.format_exc())
finally:
@@ -294,61 +300,62 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
self.pc.shaders.root.after(self.THROTTLE, self.refresh)
def send(self, queue, form, args):
#self.send_buffered(queue,output)
# self.send_buffered(queue,output)
with self.queue_lock:
self.queue[queue] = (form, args) #output
self.queue[queue] = (form, args) # output
last = {}
last_modulated = {}
def send_buffered(self, queue, form, args, record = True):
def send_buffered(self, queue, form, args, record=True):
# only send if new command is different to the last one we sent
mod_args = self.modulate_arguments(self.command_by_queue.get(queue), args)
if self.last_modulated.get(queue)!=(form,mod_args):
#print("WJSendPlugin>> send_buffered attempting to parse queue\t%s with form\t'%s' and args\t%s" % (queue, form, args))
if self.last_modulated.get(queue) != (form, mod_args):
# print("WJSendPlugin>> send_buffered attempting to parse queue\t%s with form\t'%s' and args\t%s" % (queue, form, args))
# TODO: actually output modulated version of args
output = form.format(*mod_args)
self.send_serial_string(output)
else:
if self.DEBUG: print("WJSendPlugin>> skipping sending %s %s as it is similar to what was previously sent" % (form,mod_args))
if self.DEBUG:
print("WJSendPlugin>> skipping sending %s %s as it is similar to what was previously sent" % (form, mod_args))
self.last[queue] = (form,args)
self.last_modulated[queue] = (form,mod_args)
if self.last[queue]!=(form,args) and record:
self.last_record[queue] = (form,args)
self.last[queue] = (form, args)
self.last_modulated[queue] = (form, mod_args)
if self.last[queue] != (form, args) and record:
self.last_record[queue] = (form, args)
else:
pass
#print("WJSendPlugin>> found no difference between:\n\t%s\n\t%s\n?" % (self.last_modulated.get(queue), (form,mod_args)))
# print("WJSendPlugin>> found no difference between:\n\t%s\n\t%s\n?" % (self.last_modulated.get(queue), (form,mod_args)))
def send_append(self, command, value):
# append value to the command as a hex value - for sending commands that aren't preprogrammed
self.send(command.split(':')[0], "{}{:02X}", [ command, int(255*value) ])
self.send(command.split(':')[0], "{}{:02X}", [command, int(255 * value)])
def send_append_pad(self, pad, command, value):
# append value, padded to length - for sending commands that aren't preprogrammed
self.send(command.split(':')[0], "{}{:0%iX}"%pad, [ command, int(255*value) ])
self.send(command.split(':')[0], "{}{:0%iX}" % pad, [command, int(255 * value)])
# methods for ActionPlugin - preprogrammed parameters
@property
def parserlist(self):
return [
( r"^open_serial$", self.open_serial ),
( r"^wj_send_serial:([0-9a-zA-Z:]*)$", self.send_serial_string ),
#( r"^wj_set_colour:([A|B|T])_([x|y])$", self.set_colour ),
#( r"^wj_set_back_colour:([x|y|z])$", self.set_back_colour ),
#( r"^wj_set_position:([N|L])_([x|y])$", self.set_position ),
#( r"^wj_set_mix$", self.set_mix ),
( r"^wj_set_modulation_([a-zA-Z_]*)[:]?([a-zA-Z_]*)_slot_([0-3])_level$", self.set_modulation_command_argument_level),
( r"^wj_set_current_modulation_slot_([0-3])_level$", self.set_current_modulation_level ),
( r"^wj_send_append_pad:([0-9]*)_([[:0-9a-zA-Z]*)$", self.send_append_pad ),
( r"^wj_send_append:([:0-9a-zA-Z]*)$", self.send_append ),
( r"^wj_set_([a-zA-Z_]*)[:]?([a-zA-Z_]*)$", self.catch_all ),
( r"^wj_select_next_command$", self.select_next_command ),
( r"^wj_select_previous_command$", self.select_previous_command ),
( r"^wj_select_next_argument$", self.select_next_argument ),
( r"^wj_select_previous_argument$", self.select_previous_argument ),
( r"^wj_reset_modulation$", self.reset_modulation_levels ),
( r"^wj_toggle_active$", self.toggle_active )
(r"^open_serial$", self.open_serial),
(r"^wj_send_serial:([0-9a-zA-Z:]*)$", self.send_serial_string),
# ( r"^wj_set_colour:([A|B|T])_([x|y])$", self.set_colour ),
# ( r"^wj_set_back_colour:([x|y|z])$", self.set_back_colour ),
# ( r"^wj_set_position:([N|L])_([x|y])$", self.set_position ),
# ( r"^wj_set_mix$", self.set_mix ),
(r"^wj_set_modulation_([a-zA-Z_]*)[:]?([a-zA-Z_]*)_slot_([0-3])_level$", self.set_modulation_command_argument_level),
(r"^wj_set_current_modulation_slot_([0-3])_level$", self.set_current_modulation_level),
(r"^wj_send_append_pad:([0-9]*)_([[:0-9a-zA-Z]*)$", self.send_append_pad),
(r"^wj_send_append:([:0-9a-zA-Z]*)$", self.send_append),
(r"^wj_set_([a-zA-Z_]*)[:]?([a-zA-Z_]*)$", self.catch_all),
(r"^wj_select_next_command$", self.select_next_command),
(r"^wj_select_previous_command$", self.select_previous_command),
(r"^wj_select_next_argument$", self.select_next_argument),
(r"^wj_select_previous_argument$", self.select_previous_argument),
(r"^wj_reset_modulation$", self.reset_modulation_levels),
(r"^wj_toggle_active$", self.toggle_active)
]
def toggle_active(self):
@@ -357,29 +364,31 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
self.asyncwriter = None
def reset_modulation_levels(self):
for cmd,struct in self.commands.items():
struct['modulation'] = [{},{},{},{}]
for cmd, struct in self.commands.items():
struct['modulation'] = [{}, {}, {}, {}]
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 not argument_name: self.commands[command_name]['arg_names'][0] #argument_name = 'v'
if self.DEBUG:
print("set_modulation_command_argument_level(%s, %s, %s, %s)" % (command_name, argument_name, slot, level))
if not argument_name:
self.commands[command_name]['arg_names'][0] # argument_name = 'v'
self.commands[command_name].setdefault('modulation',[{},{},{},{}])[slot][argument_name] = level
self.commands[command_name].setdefault('modulation', [{}, {}, {}, {}])[slot][argument_name] = 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)
def select_previous_command(self):
selected_command_index = list(sorted(self.commands.keys())).index(self.selected_command_name)-1
if selected_command_index<0:
selected_command_index = len(self.commands.keys())-1
selected_command_index = list(sorted(self.commands.keys())).index(self.selected_command_name) - 1
if selected_command_index < 0:
selected_command_index = len(self.commands.keys()) - 1
self.selected_command_name = sorted(list(self.commands.keys()))[selected_command_index]
self.selected_argument_index = 0
def select_next_command(self):
selected_command_index = list(sorted(self.commands.keys())).index(self.selected_command_name)+1
if selected_command_index>=len(self.commands.keys()):
selected_command_index = list(sorted(self.commands.keys())).index(self.selected_command_name) + 1
if selected_command_index >= len(self.commands.keys()):
selected_command_index = 0
self.selected_command_name = sorted(list(self.commands.keys()))[selected_command_index]
@@ -387,91 +396,94 @@ class WJSendPlugin(ActionsPlugin, SequencePlugin, DisplayPlugin, ModulationRecei
def select_previous_argument(self):
self.selected_argument_index -= 1
if self.selected_argument_index<0:
self.selected_argument_index = len(self.commands[self.selected_command_name]['arg_names'])-1
if self.selected_argument_index < 0:
self.selected_argument_index = len(self.commands[self.selected_command_name]['arg_names']) - 1
def select_next_argument(self):
self.selected_argument_index += 1
if self.selected_argument_index>=len(self.commands[self.selected_command_name]['arg_names']):
if self.selected_argument_index >= len(self.commands[self.selected_command_name]['arg_names']):
self.selected_argument_index = 0
def catch_all(self, param, argument_name, value):
#print ("got catch-all %s, %s, %s" % (param, argument_name, value))
#arguments = packed_arguments.split("_") + [ value ]
#print("commands looks like %s" % self.commands)
# print ("got catch-all %s, %s, %s" % (param, argument_name, value))
# arguments = packed_arguments.split("_") + [ value ]
# print("commands looks like %s" % self.commands)
msg = self.commands[param]
if len(msg['arg_names'])==1: argument_name = msg['arg_names'][0]
msg['arguments'][argument_name] = int(value*255) # = arguments
self.send(msg['queue'], msg['form'], [ msg['arguments'][p] for p in msg['arg_names'] ] )
if len(msg['arg_names']) == 1:
argument_name = msg['arg_names'][0]
msg['arguments'][argument_name] = int(value * 255) # = arguments
self.send(msg['queue'], msg['form'], [msg['arguments'][p] for p in msg['arg_names']])
def modulate_arguments(self, command, args):
args = args.copy()
#if self.DEBUG: print("modulate_arguments passed %s and\n\t%s" % (command,args))
# if self.DEBUG: print("modulate_arguments passed %s and\n\t%s" % (command,args))
# TODO: rewrite this so that it combines multiple inputs and averages them
for slot in range(0,4):
modlevels = command.get('modulation',[{},{},{},{}])[slot]
#if self.DEBUG: print("\tfor modulate_arguments for slot %s got modlevels: %s" % (slot, modlevels))
#for i,m in enumerate(modlevels.values()):
for arg_name,m in modlevels.items():
if m>0.0:
for slot in range(0, 4):
modlevels = command.get('modulation', [{}, {}, {}, {}])[slot]
# if self.DEBUG: print("\tfor modulate_arguments for slot %s got modlevels: %s" % (slot, modlevels))
# for i,m in enumerate(modlevels.values()):
for arg_name, m in modlevels.items():
if m > 0.0:
arg_index = command.get('arg_names').index(arg_name)
if self.DEBUG: print("\t\tupdating modulation slot %s, arg is %s\n\t with modlevel '%s' * modvalue '%s'" % (arg_index, args[arg_index], m, self.modulation_value[slot]))
if self.DEBUG:
print("\t\tupdating modulation slot %s, arg is %s\n\t with modlevel '%s' * modvalue '%s'" % (arg_index, args[arg_index], m, self.modulation_value[slot]))
# amount, value, level
newvalue = self.pc.shaders.get_modulation_value(
args[arg_index]/255.0,
self.modulation_value[slot],
args[arg_index] / 255.0,
self.modulation_value[slot],
m
)
if self.DEBUG: print("\t\tnewvalue is %s" %newvalue)
args[arg_index] = int(255*newvalue)
if self.DEBUG: print("modulate_arguments returning:\n\t%s" % args)
if self.DEBUG:
print("\t\tnewvalue is %s" % newvalue)
args[arg_index] = int(255 * newvalue)
if self.DEBUG:
print("modulate_arguments returning:\n\t%s" % args)
return args
# panasonic parameters are 8 bit so go 0-255, so 127 is default of centre value
commands = {
'colour_gain_T': {
'name': 'Colour Corrector gain (both)',
'queue': 'VCG',
'form': 'VCG:T{:02X}',
'arg_names': [ 'v' ],
'arguments': { 'v': 127 }
},
'colour_T': {
'name': 'Colour Corrector (both)',
'queue': 'VCC',
'form': 'VCC:T{:02X}{:02X}',
'arg_names': [ 'x', 'y' ],
'arguments': { 'x': 127, 'y': 127 },
},
'mix': {
'name': 'Mix/wipe',
'queue': 'VMM',
'form': 'VMM:{:02X}',
'arg_names': [ 'v' ],
'arguments': { 'v': 127 },
},
'back_colour': {
'name': 'Matte colour HSV',
'queue': 'VBM',
'form': 'VBM:{:02X}{:02X}{:02X}',
'arg_names': [ 'h', 's', 'v' ],
'arguments': { 'h': 127, 's': 127, 'v': 127 },
},
'position_N': {
'name': 'Positioner joystick XY',
'queue': 'VPS',
'form': 'VPS:N{:02X}{:02X}',
'arg_names': [ 'y', 'x' ],
'arguments': { 'y': 127, 'x': 127 }
},
#'dsk_slice': { ## cant seem to find the right control code for this?!
# 'name': 'Downstream Key Slice,Slope',
# 'queue': 'VDS',
# 'form': 'VDS:{:02X}{:01X}',
# 'arg_names': [ 'slice','slope' ],
# 'arguments': { 'slice': 127, 'slope': 8 },
# 'modulation': [ {}, { 'slice': 1.0 }, {}, {} ]
#}
'colour_gain_T': {
'name': 'Colour Corrector gain (both)',
'queue': 'VCG',
'form': 'VCG:T{:02X}',
'arg_names': ['v'],
'arguments': {'v': 127}
},
'colour_T': {
'name': 'Colour Corrector (both)',
'queue': 'VCC',
'form': 'VCC:T{:02X}{:02X}',
'arg_names': ['x', 'y'],
'arguments': {'x': 127, 'y': 127},
},
'mix': {
'name': 'Mix/wipe',
'queue': 'VMM',
'form': 'VMM:{:02X}',
'arg_names': ['v'],
'arguments': {'v': 127},
},
'back_colour': {
'name': 'Matte colour HSV',
'queue': 'VBM',
'form': 'VBM:{:02X}{:02X}{:02X}',
'arg_names': ['h', 's', 'v'],
'arguments': {'h': 127, 's': 127, 'v': 127},
},
'position_N': {
'name': 'Positioner joystick XY',
'queue': 'VPS',
'form': 'VPS:N{:02X}{:02X}',
'arg_names': ['y', 'x'],
'arguments': {'y': 127, 'x': 127}
},
# 'dsk_slice': { ## cant seem to find the right control code for this?!
# 'name': 'Downstream Key Slice,Slope',
# 'queue': 'VDS',
# 'form': 'VDS:{:02X}{:01X}',
# 'arg_names': [ 'slice','slope' ],
# 'arguments': { 'slice': 127, 'slope': 8 },
# 'modulation': [ {}, { 'slice': 1.0 }, {}, {} ]
# }
}
command_by_queue = {}

View File

@@ -1,55 +1,59 @@
import copy
from json import JSONEncoder
def _default(self, obj):
if getattr(obj.__class__,'to_json'):
#return _default.default(obj.to_json())
if getattr(obj.__class__, 'to_json'):
# return _default.default(obj.to_json())
return obj.to_json()
else:
return _default.default(obj)
_default.default = JSONEncoder().default
JSONEncoder.default = _default
class Frame:
f = { 'shader_params': [[None]*4,[None]*4,[None]*4] }
f = {'shader_params': [[None] * 4, [None] * 4, [None] * 4]}
pc = None
DEBUG_FRAMES = False#True
DEBUG_FRAMES = False # True
def __init__(self, pc):
self.pc = pc
def to_json(self):
return self.f #{ 'f': self.f }
return self.f # { 'f': self.f }
def get(self, key, default=None):
return self.f.get(key,default)
return self.f.get(key, default)
def has(self, key):
return self.get(key) is not None
def store_live(self):
frame = {
#'selected_shader_slots': [ shader.get('slot',None) for shader in self.pc.shaders.selected_shader_list ],
'selected_shader': copy.deepcopy(self.pc.shaders.selected_shader_list),
'shader_params': copy.deepcopy(self.pc.shaders.selected_param_list),
'layer_active_status': copy.deepcopy(self.pc.shaders.selected_status_list),
'feedback_active': self.pc.shaders.data.feedback_active,
'x3_as_speed': self.pc.shaders.data.settings['shader']['X3_AS_SPEED']['value'],
'shader_speeds': copy.deepcopy(self.pc.shaders.selected_speed_list),
'strobe_amount': self.pc.shaders.data.settings['shader']['STROBE_AMOUNT']['value'] / 10.0,
'shader_modulation_levels': copy.deepcopy(self.pc.shaders.modulation_level)
# 'selected_shader_slots': [ shader.get('slot',None) for shader in self.pc.shaders.selected_shader_list ],
'selected_shader': copy.deepcopy(self.pc.shaders.selected_shader_list),
'shader_params': copy.deepcopy(self.pc.shaders.selected_param_list),
'layer_active_status': copy.deepcopy(self.pc.shaders.selected_status_list),
'feedback_active': self.pc.shaders.data.feedback_active,
'x3_as_speed': self.pc.shaders.data.settings['shader']['X3_AS_SPEED']['value'],
'shader_speeds': copy.deepcopy(self.pc.shaders.selected_speed_list),
'strobe_amount': self.pc.shaders.data.settings['shader']['STROBE_AMOUNT']['value'] / 10.0,
'shader_modulation_levels': copy.deepcopy(self.pc.shaders.modulation_level)
}
#print("about to call get_plugin_frame_data")
# print("about to call get_plugin_frame_data")
frame.update(self.pc.fm.get_plugin_frame_data())
self.f = frame
#print("built frame: %s" % self.f)
# print("built frame: %s" % self.f)
return self
def store_copy(self, f):
#print("told to store_copy %s" % f)
# print("told to store_copy %s" % f)
if f is not None:
if f.get('f') is not None: #isinstance(f, Frame):
if f.get('f') is not None: # isinstance(f, Frame):
f = f.get('f')
return self.store_copy(f.get('f'))
self.f = f
@@ -60,12 +64,12 @@ class Frame:
def get_active_shader_names(self):
s = ""
if self.has('selected_shader_slots'):
return ['-']*3
return ['-'] * 3
if self.has('selected_shader'):
return [ shader['name'].strip() for shader in self.get('selected_shader') ]
return [ self.pc.data.shader_bank_data[layer][x].get('name').strip() if x is not None else '-'\
for layer,x in enumerate(self.get('selected_shader_slots',[None]*3))
]
return [shader['name'].strip() for shader in self.get('selected_shader')]
return [self.pc.data.shader_bank_data[layer][x].get('name').strip() if x is not None else '-' \
for layer, x in enumerate(self.get('selected_shader_slots', [None] * 3))
]
def get_frame_summary(self):
summary = []
@@ -73,30 +77,30 @@ class Frame:
# list the recorded shader info in compact format
names = self.get_active_shader_names()
for layer in range(0,3): # number of shader layers
for layer in range(0, 3): # number of shader layers
s = self.get_shader_layer_summary(layer)
summary.append(s)
# handle summarising the rest of the recorded shader info, two-to-a-line where possible
count = 0
line = ""
for key,d in sorted(self.f.items()):
#print ("get_frame_summary: checking %s value %s" % (key,d))
if type(d) is dict and len(d)==0: # skip empty dicts
for key, d in sorted(self.f.items()):
# print ("get_frame_summary: checking %s value %s" % (key,d))
if type(d) is dict and len(d) == 0: # skip empty dicts
continue
if key in ["selected_shader","layer_active_status","shader_params","shader_speeds","selected_shader_slots"]:
if key in ["selected_shader", "layer_active_status", "shader_params", "shader_speeds", "selected_shader_slots"]:
# skip these as dealt with below
pass
elif key in ['shader_modulation_levels']:
for layer in range(3):
o = ""
for slot in range(4):
sl = self.pc.display.get_mod_slot_label(slot)
o+= sl + "["
for param in range(4):
o += self.pc.display.get_bar(d[layer][param][slot])
o+= "] "
summary.append("Shader layer %s: %s"%(layer,o))
o = ""
for slot in range(4):
sl = self.pc.display.get_mod_slot_label(slot)
o += sl + "["
for param in range(4):
o += self.pc.display.get_bar(d[layer][param][slot])
o += "] "
summary.append("Shader layer %s: %s" % (layer, o))
elif self.pc.get_plugin_for_class_name(key) is not None:
summary.append(self.pc.get_plugin_for_class_name(key).get_frame_summary(d))
"""elif key in ["WJSendPlugin"]:
@@ -105,44 +109,42 @@ class Frame:
else:
line += "%s: %s" % (key, d)
count += 1
if count%2==1:
if count % 2 == 1:
line += "\t"
elif count>0 and count%2==0:
elif count > 0 and count % 2 == 0:
summary.append(line)
line = ""
if line != "":
summary.append(line)
# add 'not shown' items
if len(not_shown)>0:
if len(not_shown) > 0:
summary.append(','.join(not_shown.keys()))
return summary
def get_shader_layer_summary(self, layer):
s = "%s%s" % (layer, " " if layer != self.pc.data.shader_layer else ">")
s += "["
s += self.pc.display.get_compact_indicators([\
(i==self.get('selected_shader_slots',[-1]*3)[layer]) or\
(self.has('selected_shader') and self.pc.data.shader_bank_data[layer][i]['name'] == self.get('selected_shader')[layer]['name'])\
for i in range(10)\
])
s += "]"
s = "%s%s" % (layer, " " if layer != self.pc.data.shader_layer else ">")
s += "["
s += self.pc.display.get_compact_indicators([ \
(i == self.get('selected_shader_slots', [-1] * 3)[layer]) or \
(self.has('selected_shader') and self.pc.data.shader_bank_data[layer][i]['name'] == self.get('selected_shader')[layer]['name']) \
for i in range(10) \
])
s += "]"
if self.has('layer_active_status'):
s += " %s " % (self.get('layer_active_status',['-']*3)[layer])
if self.has('layer_active_status'):
s += " %s " % (self.get('layer_active_status', ['-'] * 3)[layer])
if self.get('selected_shader'):
s += "{:14.14}".format(self.get('selected_shader')[layer].get('name').replace('.frag','').strip())
if self.get('selected_shader'):
s += "{:14.14}".format(self.get('selected_shader')[layer].get('name').replace('.frag', '').strip())
s += " " + self.get_shader_param_summary(layer) + " "
if self.has('shader_speeds'):
s += self.pc.display.get_speed_indicator(self.get('shader_speeds',[0.0]*3)[layer])
return s
s += " " + self.get_shader_param_summary(layer) + " "
if self.has('shader_speeds'):
s += self.pc.display.get_speed_indicator(self.get('shader_speeds', [0.0] * 3)[layer])
return s
def get_shader_param_summary(self, layer):
if self.get('shader_params') is None:
@@ -164,17 +166,17 @@ class Frame:
self.recall_frame_params()
for layer in range(3):
if preset.has('selected_shader_slots'): # deprecated/compatibility
if preset.has('selected_shader_slots'): # deprecated/compatibility
self.pc.actions.call_method_name('play_shader_%s_%s' % (layer, preset.get('selected_shader_slots')[layer]))
elif preset.has('selected_shader') and preset.get('selected_shader')[layer] is not None:
# match selected shader to a slot and call that back if it exists
found = False
for slot,shader in enumerate(self.pc.data.shader_bank_data[layer]):
for slot, shader in enumerate(self.pc.data.shader_bank_data[layer]):
if shader['name'] == preset.get('selected_shader')[layer]['name']:
self.pc.actions.call_method_name('play_shader_%s_%s' % (layer, slot))
found = True
break
if not found: # otherwise fall back to loading it separately
if not found: # otherwise fall back to loading it separately
self.pc.shaders.selected_shader_list[self.pc.data.shader_layer] = preset.get('selected_shader')[layer].copy()
self.pc.shaders.load_selected_shader()
@@ -185,40 +187,40 @@ class Frame:
level = preset.get('shader_modulation_levels')[layer][param][slot]
self.pc.shaders.set_param_layer_slot_modulation_level(param, layer, slot, level)
for (layer, active) in enumerate(preset.get('layer_active_status',[])):
for (layer, active) in enumerate(preset.get('layer_active_status', [])):
# print ("got %s layer with status %s " % (layer,active))
if active=='':
if active == '':
self.pc.actions.call_method_name('start_shader_layer_%s' % layer)
else:
self.pc.actions.call_method_name('stop_shader_layer_%s' % layer)
def recall_frame_params(self):
#print("recall_frame_params got: %s" % preset.get('shader_params'))
for (layer, param_list) in enumerate(self.get('shader_params',[])):
# print("recall_frame_params got: %s" % preset.get('shader_params'))
for (layer, param_list) in enumerate(self.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):
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.pc.actions.call_method_name('set_the_shader_param_%s_layer_%s_continuous' % (param,layer), value)
# print("recalling layer %s param %s: value %s" % (layer,param,value))
self.pc.actions.call_method_name('set_the_shader_param_%s_layer_%s_continuous' % (param, layer), value)
if self.has('feedback_active'):
self.pc.data.feedback_active = self.get('feedback_active',self.pc.data.feedback_active)
self.pc.data.feedback_active = self.get('feedback_active', self.pc.data.feedback_active)
if self.pc.data.feedback_active:
self.pc.actions.call_method_name('enable_feedback')
else:
self.pc.actions.call_method_name('disable_feedback')
if self.has('x3_as_speed'):
self.pc.data.settings['shader']['X3_AS_SPEED']['value'] = self.get('x3_as_speed',self.pc.data.settings['shader']['X3_AS_SPEED']['value'])
self.pc.data.settings['shader']['X3_AS_SPEED']['value'] = self.get('x3_as_speed', self.pc.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(self.get('shader_speeds',[])):
for (layer, speed) in enumerate(self.get('shader_speeds', [])):
if speed is not None:
self.pc.actions.call_method_name('set_shader_speed_layer_%s_amount' % layer, speed)
@@ -227,19 +229,19 @@ class Frame:
from data_centre.plugin_collection import AutomationSourcePlugin
for plugin in self.pc.get_plugins(AutomationSourcePlugin):
#print("recalling for plugin %s with data %s" % (plugin, self.get(plugin.frame_key)))
# print("recalling for plugin %s with data %s" % (plugin, self.get(plugin.frame_key)))
plugin.recall_frame_data(self.get(plugin.frame_key))
def merge(self, frame2):
from copy import deepcopy
f = deepcopy(self.f) #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.get('shader_params')):
for i2,p in enumerate(f2):
f = deepcopy(self.f) # 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.get('shader_params')):
for i2, p in enumerate(f2):
if p is not None:
if 'shader_params' not in f:
f['shader_params'] = [[None]*4,[None]*4,[None]*4]
f['shader_params'] = [[None] * 4, [None] * 4, [None] * 4]
f['shader_params'][i][i2] = p
if frame2.has('feedback_active'):
@@ -252,7 +254,7 @@ class Frame:
if 'shader_speeds' in frame2.f:
f['shader_speeds'] = frame2.get('shader_speeds')
else:
for i,s in enumerate(frame2.get('shader_speeds')):
for i, s in enumerate(frame2.get('shader_speeds')):
if s is not None:
f['shader_speeds'][i] = s
@@ -261,19 +263,21 @@ class Frame:
from data_centre.plugin_collection import AutomationSourcePlugin
for plugin in self.pc.get_plugins(AutomationSourcePlugin):
f[plugin.frame_key] = plugin.merge_data(f.get(plugin.frame_key),frame2.get(plugin.frame_key))
f[plugin.frame_key] = plugin.merge_data(f.get(plugin.frame_key), frame2.get(plugin.frame_key))
if self.DEBUG_FRAMES: print("merge_frames: got return\t%s" % f)
if self.DEBUG_FRAMES:
print("merge_frames: got return\t%s" % f)
return Frame(self.pc).store_copy(f)
def get_ignored(self, ignored):
from copy import deepcopy
f = deepcopy(self.f) #frame1.copy()
f = deepcopy(self.f) # frame1.copy()
frame = self.f
ignored = ignored.f
if self.DEBUG_FRAMES: print("get_frame_ignored: got frame\t%s" % self.f)
for i,f2 in enumerate(frame.get('shader_params',[])):
for i2,p in enumerate(f2):
if self.DEBUG_FRAMES:
print("get_frame_ignored: got frame\t%s" % self.f)
for i, f2 in enumerate(frame.get('shader_params', [])):
for i2, p in enumerate(f2):
if ignored['shader_params'][i][i2] is not None:
f['shader_params'][i][i2] = None
if 'feedback_active' in ignored:
@@ -281,26 +285,28 @@ class Frame:
if 'x3_as_speed' in ignored:
f['x3_as_speed'] = None
if 'shader_speeds' in ignored and 'shader_speeds' in frame:
for i,s in enumerate(frame.get('shader_speeds')):
if ignored['shader_speeds'][i] is not None:
f['shader_speeds'][i] = None
for i, s in enumerate(frame.get('shader_speeds')):
if ignored['shader_speeds'][i] is not None:
f['shader_speeds'][i] = None
if 'strobe_amount' in ignored:
f['strobe_amount'] = None
from data_centre.plugin_collection import AutomationSourcePlugin
for plugin in self.pc.get_plugins(AutomationSourcePlugin):
if ignored.get(plugin.frame_key) is not None:
#print("ignoring for %s:\n\t%s\n" % (plugin.frame_key, ignored.get(plugin.frame_key)))
f[plugin.frame_key] = plugin.get_ignored_data(f.get(plugin.frame_key,{}),ignored.get(plugin.frame_key,{}))
# print("ignoring for %s:\n\t%s\n" % (plugin.frame_key, ignored.get(plugin.frame_key)))
f[plugin.frame_key] = plugin.get_ignored_data(f.get(plugin.frame_key, {}), ignored.get(plugin.frame_key, {}))
if self.DEBUG_FRAMES: print("get_frame_ignored: got return\t%s" % f)
if self.DEBUG_FRAMES:
print("get_frame_ignored: got return\t%s" % f)
return Frame(self.pc).store_copy(f)
def is_empty(self):
#from copy import deepcopy
#f = deepcopy(frame) #frame1.copy()
# from copy import deepcopy
# f = deepcopy(frame) #frame1.copy()
frame = self.f
if self.DEBUG_FRAMES: print("is_frame_empty: got frame\t%s" % frame)
if self.DEBUG_FRAMES:
print("is_frame_empty: got frame\t%s" % frame)
if self.has('feedback_active'):
return False
@@ -309,15 +315,15 @@ class Frame:
if self.has('strobe_amount'):
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:
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 self.has('shader_speeds'):
for i,f in enumerate(frame['shader_speeds']):
if f is not None:
return False
for i, f in enumerate(frame['shader_speeds']):
if f is not None:
return False
from data_centre.plugin_collection import AutomationSourcePlugin
for plugin in self.pc.get_plugins(AutomationSourcePlugin):
@@ -326,11 +332,12 @@ class Frame:
if not plugin.is_frame_data_empty(frame.get(plugin.frame_key)):
return False
if self.DEBUG_FRAMES: print("is_frame_empty: got return true")
if self.DEBUG_FRAMES:
print("is_frame_empty: got return true")
return True
def get_diff(self, current_frame):
#if not last_frame: return current_frame
# if not last_frame: return current_frame
current_frame = current_frame.f
last_frame = self.f
@@ -339,12 +346,13 @@ class Frame:
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):
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))
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']:
@@ -357,8 +365,8 @@ class Frame:
else:
x3_as_speed = None
speed_values = [None]*3
for layer,param in enumerate(current_frame.get('shader_speeds',[None]*3)):
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
@@ -378,21 +386,19 @@ class Frame:
plugin_data[plugin.frame_key] = plugin.get_frame_diff(last_frame, current_frame)
diff = {
'shader_params': param_values,
'feedback_active': feedback_active,
'x3_as_speed': x3_as_speed,
'shader_speeds': speed_values,
'strobe_amount': strobe_amount,
'shader_params': param_values,
'feedback_active': feedback_active,
'x3_as_speed': x3_as_speed,
'shader_speeds': speed_values,
'strobe_amount': strobe_amount,
}
diff.update(plugin_data)
if self.DEBUG_FRAMES: print("returning\t%s\n^^^^" % diff['shader_params'])
if self.DEBUG_FRAMES:
print("returning\t%s\n^^^^" % diff['shader_params'])
return Frame(self.pc).store_copy(diff)
class FrameManager:
pc = None
@@ -430,9 +436,9 @@ class FrameManager:
from data_centre.plugin_collection import AutomationSourcePlugin
for plugin in self.pc.get_plugins(AutomationSourcePlugin):
data[plugin.frame_key] = plugin.get_frame_data()
#plugin.clear_recorded_frame()
# plugin.clear_recorded_frame()
#print("get_plugin_frame_data looks like %s" % data)
# print("get_plugin_frame_data looks like %s" % data)
return data
def interpolate_clip(self, frames):
@@ -444,9 +450,9 @@ class FrameManager:
# else,
# store as last value
print("got pre-interpolated clip: %s" % [ f.f for f in frames if f is not None])
print("got pre-interpolated clip: %s" % [f.f for f in frames if f is not None])
last = [ [None]*4, [None]*4, [None]*4 ]
last = [[None] * 4, [None] * 4, [None] * 4]
"""for findex,frame in enumerate(frames):
if frame is None:
@@ -455,18 +461,18 @@ class FrameManager:
reproc_to = 0
def process(self, findex, frame):
for layer,params in enumerate(frame.get('shader_params',[])):
for param,value in enumerate(params):
for layer, params in enumerate(frame.get('shader_params', [])):
for param, value in enumerate(params):
if value is None and last[layer][param] is not None:
# find distance to when this value changes again
gap,future_value = self.get_distance_value_layer_param(frames,findex,layer,param)
if gap==0 or future_value==value: # if doesnt change again, do nothing
gap, future_value = self.get_distance_value_layer_param(frames, findex, layer, param)
if gap == 0 or future_value == value: # if doesnt change again, do nothing
continue
newvalue = self.interpolate(last[layer][param], future_value, gap)
params[param] = newvalue
print("findex %s: updating interpolated value to %s - should be between %s and %s over gap %s" % (findex, newvalue, last[layer][param], future_value, gap))
last[layer][param] = newvalue
#elif last[layer][param] is None:
# elif last[layer][param] is None:
# reproc_to = findex
elif value is not None:
last[layer][param] = value
@@ -474,13 +480,13 @@ class FrameManager:
from data_centre.plugin_collection import AutomationSourcePlugin
for plugin in self.pc.get_plugins(AutomationSourcePlugin):
plugin.process_interpolate_clip(frames)
for i in range(2):
for findex,frame in enumerate(frames):
if frame is None:
continue
process(self,findex,frame)
for i in range(2):
for findex, frame in enumerate(frames):
if frame is None:
continue
process(self, findex, frame)
"""for findex in range(reproc_to):
if frames[findex] is None:
@@ -488,23 +494,23 @@ class FrameManager:
process(self,findex,frames[findex])"""
print("got interpolated clip: %s" % [ f.f for f in frames if f is not None ])
print("got interpolated clip: %s" % [f.f for f in frames if f is not None])
def get_distance_value_layer_param(self, frames, findex, layer, param):
for i in range(1,len(frames)):
for i in range(1, len(frames)):
search_findex = i + findex
search_findex %= len(frames)
if frames[search_findex] is not None and frames[search_findex].get('shader_params',[ [None]*4, [None]*4, [None]*4 ])[layer][param] is not None:
if frames[search_findex] is not None and frames[search_findex].get('shader_params', [[None] * 4, [None] * 4, [None] * 4])[layer][param] is not None:
return i, frames[search_findex].get('shader_params')[layer][param]
return 0, None
def interpolate(self, value1, value2, total_steps):
diff = max(value1,value2)-min(value1,value2)
diff = max(value1, value2) - min(value1, value2)
sl = diff / total_steps
if value1>value2:
v = value1-sl
if value1 > value2:
v = value1 - sl
else:
v = value1+sl
v = value1 + sl
print("interpolate between\t%s and\t%s over\t%s steps, got sl\t%s and value\t%s" % (value1,value2,total_steps, sl, v))
print("interpolate between\t%s and\t%s over\t%s steps, got sl\t%s and value\t%s" % (value1, value2, total_steps, sl, v))
return v

View File

@@ -29,6 +29,7 @@ message_handler = MessageHandler()
data = Data(message_handler)
def setup_osc_client():
client_parser = argparse.ArgumentParser()
client_parser.add_argument("--ip", default="127.0.0.1", help="the ip")
@@ -38,10 +39,11 @@ def setup_osc_client():
return udp_client.SimpleUDPClient(client_args.ip, client_args.port)
osc_client = setup_osc_client()
# setup the video driver
video_driver = VideoDriver(tk, osc_client, message_handler, data)
#capture = Capture(tk, osc_client, message_handler, data)
# capture = Capture(tk, osc_client, message_handler, data)
shaders = Shaders(tk, osc_client, message_handler, data)
# setup the display
@@ -67,14 +69,12 @@ actions.toggle_x_autorepeat()
frame.pack()
tk.attributes("-fullscreen", True)
def handle_error(exc, val, tb):
print('traceback for error : {}'.format(traceback.format_exc()))
message_handler.set_message('ERROR', val, traceback.format_exc())
tk.report_callback_exception = handle_error
tk.mainloop()

View File

@@ -1,5 +1,6 @@
import Adafruit_MCP3008
class AnalogInput(object):
def __init__(self, root, message_handler, display, actions, data):
self.root = root
@@ -9,23 +10,22 @@ class AnalogInput(object):
self.data = data
self.analog_mappings = data.analog_mappings
self.analog_delay = 50
self.last_readings = [0,0,0,0,0,0,0,0]
self.last_readings = [0, 0, 0, 0, 0, 0, 0, 0]
self.analog_input = None
self.check_if_listening_enabled()
def check_if_listening_enabled(self):
if self.data.settings['user_input']['ANALOG_INPUT']['value'] == 'enabled':
if not self.analog_input:
try:
## note - using software spi for now although on the same pins as the hardware spi described below because hardware spi wasnt working with lcd display
#SPI_PORT = 1
#SPI_DEVICE = 2
#self.analog_input = Adafruit_MCP3008.MCP3008(spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE))
CLK = 21
# SPI_PORT = 1
# SPI_DEVICE = 2
# self.analog_input = Adafruit_MCP3008.MCP3008(spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE))
CLK = 21
MISO = 19
MOSI = 20
CS = 16
CS = 16
self.analog_input = Adafruit_MCP3008.MCP3008(clk=CLK, cs=CS, miso=MISO, mosi=MOSI)
except:
@@ -37,12 +37,12 @@ class AnalogInput(object):
def poll_analog_inputs(self):
if self.data.settings['user_input']['ANALOG_INPUT']['value'] == 'enabled':
for i in range(0,8):
for i in range(0, 8):
if str(i) in self.analog_mappings:
this_reading = self.analog_input.read_adc(i)
#print(str(this_reading))
# print(str(this_reading))
if abs(this_reading - self.last_readings[i]) > 10:
#print('the diff is {}'.format(this_reading - self.last_readings[i]))
# print('the diff is {}'.format(this_reading - self.last_readings[i]))
self.run_action_for_mapped_channel(i, this_reading)
self.last_readings[i] = this_reading
self.root.after(self.analog_delay, self.poll_analog_inputs)
@@ -69,14 +69,12 @@ class AnalogInput(object):
method_name = this_mapping[mode][0]
if channel_value is not None:
norm_channel_value = channel_value/1023
norm_channel_value = channel_value / 1023
else:
norm_channel_value = None
print('the action being called is {}'.format(method_name))
self.actions.call_method_name(method_name, norm_channel_value)
## not sure whether we want to update the screen in general; here - probably not most of the time ...
#if 'cc' not in message_name:
# self.display.refresh_display()
# if 'cc' not in message_name:
# self.display.refresh_display()

View File

@@ -18,10 +18,10 @@ class MidiInput(object):
self.try_open_port()
def try_open_port(self):
#self.data.midi_status = 'disconnected'
# self.data.midi_status = 'disconnected'
self.midi_setting = self.data.settings['user_input']['MIDI_INPUT']['value']
self.port_index = self.data.midi_port_index
#print('try open port : midi setting is {}'.format(midi_setting))
# print('try open port : midi setting is {}'.format(midi_setting))
if self.midi_setting == 'usb':
self.actions.stop_serial_port_process()
self.open_this_port_and_start_listening('20')
@@ -29,7 +29,7 @@ class MidiInput(object):
self.actions.create_serial_port_process()
self.open_this_port_and_start_listening('serial')
else:
self.actions.stop_serial_port_process()
self.actions.stop_serial_port_process()
self.data.midi_status = 'disconnected'
self.root.after(1000, self.try_open_port)
@@ -40,7 +40,7 @@ class MidiInput(object):
midi_devices = [s for s in midi_devices if port_phrase in s]
if midi_devices:
if self.data.midi_status == 'disconnected':
subport_index = self.port_index % len(midi_devices)
subport_index = self.port_index % len(midi_devices)
self.midi_device = mido.open_input(midi_devices[subport_index])
self.data.midi_status = 'connected'
self.data.midi_device_name = self.midi_device.name
@@ -48,7 +48,7 @@ class MidiInput(object):
self.midi_mappings = self.data.load_midi_mapping_for_device(self.midi_device.name.split(":")[0])
self.midi_output = self.find_output_plugin(midi_devices[subport_index])
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.poll_midi_input()
elif self.data.midi_status == 'connected':
@@ -62,7 +62,7 @@ class MidiInput(object):
current_message_buffer = [i.dict() for i in self.midi_device.iter_pending()]
refined_buffer = []
#refine buffer from lastest messages first
# refine buffer from lastest messages first
current_message_buffer.reverse()
for message in current_message_buffer:
# discard notes from wrong channel
@@ -81,7 +81,7 @@ class MidiInput(object):
for message in refined_buffer:
self.on_midi_message(message)
#print('the number processed {}'.format(i))
# print('the number processed {}'.format(i))
if self.data.settings['user_input']['MIDI_INPUT']['value'] == self.midi_setting and self.data.midi_port_index == self.port_index:
self.root.after(self.midi_delay, self.poll_midi_input)
else:
@@ -94,9 +94,9 @@ class MidiInput(object):
mapped_message_name = message_dict['type']
mapped_message_value = None
if 'note' in message_dict:
mapped_message_name = '{} {}'.format(mapped_message_name,message_dict['note'])
mapped_message_name = '{} {}'.format(mapped_message_name, message_dict['note'])
if 'control' in message_dict:
mapped_message_name = '{} {}'.format(mapped_message_name,message_dict['control'])
mapped_message_name = '{} {}'.format(mapped_message_name, message_dict['control'])
mapped_message_value = message_dict['value']
if mapped_message_name in self.midi_mappings.keys():
@@ -119,23 +119,23 @@ class MidiInput(object):
if self.data.function_on and len(this_mapping[mode]) > 1:
method_name = this_mapping[mode][1]
#self.data.function_on = False
# self.data.function_on = False
else:
method_name = this_mapping[mode][0]
#print('[][][][][ in mode {}, the action being called is {} from message_name {} in control_mode {}'
# print('[][][][][ in mode {}, the action being called is {} from message_name {} in control_mode {}'
# .format(mode, method_name, message_name, self.data.control_mode))
if mapped_message_value is not None:
norm_message_value = mapped_message_value/127
norm_message_value = mapped_message_value / 127
else:
norm_message_value = None
self.actions.call_method_name(method_name, norm_message_value)
## only update screen if not continuous - seeing if cc can respond faster if not refreshing screen on every action
if 'continuous' not in message_name:
self.display.refresh_display()
#self.refresh_midi_feedback()
# self.refresh_midi_feedback()
# Plugins to support MIDI feedback
@@ -143,31 +143,29 @@ class MidiInput(object):
# loop over the plugins
# find one that self.supports_midi_feedback(self.midi_device.name):
# open the midi device self.midi_feedback_device = mido.open_output(midi_device_on_port[subport_index])
print ("Looking for a MIDI Feedback plugin that supports %s..." % midi_device)
print("Looking for a MIDI Feedback plugin that supports %s..." % midi_device)
from data_centre.plugin_collection import MidiFeedbackPlugin
for p in self.data.plugins.get_plugins(MidiFeedbackPlugin):
if p.supports_midi_feedback(midi_device):
print ("Found one! Opening device")
print("Found one! Opening device")
p.set_midi_device(mido.open_output(midi_device))
return p
print ("Didn't find one!")
print("Didn't find one!")
def refresh_midi_feedback(self):
self.midi_output.refresh_midi_feedback()
if self.midi_output and self.data.settings['user_input']['MIDI_INPUT']['value'] == self.midi_setting and self.data.midi_port_index == self.port_index:
if self.midi_output.supports_midi_feedback(self.data.midi_device_name):
self.root.after(self.midi_delay*5, self.refresh_midi_feedback)
if self.midi_output.supports_midi_feedback(self.data.midi_device_name):
self.root.after(self.midi_delay * 5, self.refresh_midi_feedback)
def find_binding_for_action(self, action):
for bind,a in self.midi_mappings.items():
#print("looped over %s : %s " % (bind,a))
for (b,c) in a.items():
for bind, a in self.midi_mappings.items():
# print("looped over %s : %s " % (bind,a))
for (b, c) in a.items():
if action in c:
#print ("find_binding_for_action(%s) got %s" % (action, bind))
# print ("find_binding_for_action(%s) got %s" % (action, bind))
return bind

View File

@@ -23,11 +23,11 @@ class NumpadInput(object):
def on_key_press(self, event):
numpad = list(string.ascii_lowercase[0:19])
if event.char is 'h': # DISP button
#self.root.after(60, lambda:self.on_key_press_delay(event.char))
#return
if event.char is 'h': # DISP button
# self.root.after(60, lambda:self.on_key_press_delay(event.char))
# return
if self.data.is_display_held:
return # ignore spurious message if already held"""
return # ignore spurious message if already held"""
self.data.is_display_held = True
if self.in_0_event:
return
@@ -47,35 +47,35 @@ class NumpadInput(object):
print('{} is not in keypad map'.format(event.char))
def on_key_release(self, event):
numpad = list(string.ascii_lowercase[0:19])
if event.char in numpad:
self.check_key_release_settings(event.char)
numpad = list(string.ascii_lowercase[0:19])
if event.char in numpad:
self.check_key_release_settings(event.char)
##print ("--- releasing %s" % event.char)
# lag for 60ms to check that this is not a 'stream of 000' bullshit job from the keypad
if event.char is 'h' and not self.in_0_event:
self.root.after(self.KEY_000_DELAY+5, self.on_key_disp_release_delay)
#self.data.is_display_held = False
##print ("--- releasing %s" % event.char)
# lag for 60ms to check that this is not a 'stream of 000' bullshit job from the keypad
if event.char is 'h' and not self.in_0_event:
self.root.after(self.KEY_000_DELAY + 5, self.on_key_disp_release_delay)
# self.data.is_display_held = False
def on_mouse_move(self, event):
if self.data.settings['user_input'].setdefault(
'MOUSE_INPUT',
self.data.default_settings.get('MOUSE_INPUT',{'value': 'enabled'})).get('value') != 'enabled':
self.data.default_settings.get('MOUSE_INPUT', {'value': 'enabled'})).get('value') != 'enabled':
return
if event.x > 480 or event.y > 320:
return
width = 480
height = 320 # hard coded since display is fixed , and reading screen is more work
height = 320 # hard coded since display is fixed , and reading screen is more work
self.root.after(0, self.run_action_for_mapped_key, 'x_m', event.x / width)
self.root.after(0, self.run_action_for_mapped_key, 'y_m', event.y / height)
#self.run_action_for_mapped_key(event.char)
# self.run_action_for_mapped_key(event.char)
def select_display_mode_index(self, index):
if index >= len(self.data.get_display_modes_list()):
self.message_handler.set_message('ERROR', 'No page %s to display!' % index)
else:
self.actions.call_method_name("set_display_mode_%s"%self.data.get_display_modes_list()[index])
self.actions.call_method_name("set_display_mode_%s" % self.data.get_display_modes_list()[index])
def run_action_for_mapped_key(self, key, value=-1):
this_mapping = self.key_mappings[key]
@@ -101,7 +101,7 @@ class NumpadInput(object):
else:
print('the numpad action being called for \'{}\' is {} (mode is {})'.format(key, this_mapping[mode][is_function], mode))
if value != -1:
self.actions.call_method_name(this_mapping[mode][is_function],value)
self.actions.call_method_name(this_mapping[mode][is_function], value)
else:
self.actions.call_method_name(this_mapping[mode][is_function])
@@ -111,10 +111,8 @@ class NumpadInput(object):
if not value:
self.display.refresh_display()
def check_key_release_settings(self, key):
this_mapping = self.key_mappings[key]
if self.data.settings['sampler']['ACTION_GATED']['value'] == 'on':
if self.data.control_mode == 'PLAYER' and 'PLAYER' in this_mapping:
@@ -127,7 +125,7 @@ class NumpadInput(object):
self.run_action_for_mapped_key(key)
def on_key_disp_release_delay(self):
if not self.in_0_event:# and self.additional_0_in_event==0:
if not self.in_0_event: # and self.additional_0_in_event==0:
print("releasing !")
self.data.is_display_held = False
else:
@@ -140,36 +138,35 @@ class NumpadInput(object):
else:
print("ignoring press!")"""
def on_0_key_press(self) :
print ("on_0_key_press!")
if(not self.in_0_event ):
print (" first 0 received!")
self.in_0_event = True
def on_0_key_press(self):
print("on_0_key_press!")
if (not self.in_0_event):
print(" first 0 received!")
self.in_0_event = True
self.additional_0_in_event = 0
self.root.after(self.KEY_000_DELAY, self.check_event_outcome)
else:
print (" additional 0 received making %s!" % str(self.additional_0_in_event + 1))
self.additional_0_in_event = self.additional_0_in_event + 1
print(" additional 0 received making %s!" % str(self.additional_0_in_event + 1))
self.additional_0_in_event = self.additional_0_in_event + 1
def check_event_outcome(self):
if(self.additional_0_in_event == 0 ):
print (" no additional events, sending s")
self.in_0_event = False
if (self.additional_0_in_event == 0):
print(" no additional events, sending s")
self.in_0_event = False
self.run_action_for_mapped_key('s')
elif(self.additional_0_in_event > 1):
print (" %s additional events, sending n"%self.additional_0_in_event)
self.in_0_event = False
elif (self.additional_0_in_event > 1):
print(" %s additional events, sending n" % self.additional_0_in_event)
self.in_0_event = False
self.run_action_for_mapped_key('n')
elif(self.additional_0_in_event == 1):
elif (self.additional_0_in_event == 1):
print('this doesnt happen - may not be needed')
self.root.after(self.KEY_000_DELAY, self.second_check_event_outcome)
def second_check_event_outcome(self):
print("not supposed to happen?")
if(self.additional_0_in_event == 1 ):
self.in_0_event = False
if (self.additional_0_in_event == 1):
self.in_0_event = False
self.run_action_for_mapped_key('s')
elif(self.additional_0_in_event > 1):
self.in_0_event = False
elif (self.additional_0_in_event > 1):
self.in_0_event = False
self.run_action_for_mapped_key('n')

View File

@@ -14,14 +14,14 @@ class OscInput(object):
self.actions = actions
self.data = data
self.osc_mappings = data.osc_mappings
self.osc_enabled = False
self.osc_server = None
self.poll_settings_for_osc_info()
def poll_settings_for_osc_info(self):
self.data.settings['user_input'].setdefault('OSC_INPUT',
self.data.default_settings['user_input'].get('OSC_INPUT'))
self.data.default_settings['user_input'].get('OSC_INPUT'))
osc_setting_enabled = self.data.settings['user_input']['OSC_INPUT']['value'] == 'enabled'
if osc_setting_enabled and not self.osc_enabled:
self.setup_osc_server()
@@ -34,7 +34,7 @@ class OscInput(object):
def setup_osc_server(self):
ip_address = self.data.get_ip_for_osc_client()
if ip_address == 'none':
self.message_handler.set_message('INFO', 'osc failed - could not find ip')
self.message_handler.set_message('INFO', 'osc failed - could not find ip')
return
print('%%%%%%%%%%%%%%%%%%%%% setting up external_osc on ', ip_address)
server_parser = argparse.ArgumentParser()
@@ -44,15 +44,15 @@ class OscInput(object):
server_args = server_parser.parse_args()
this_dispatcher = dispatcher.Dispatcher()
# this_dispatcher.map("/keyboard/*", self.on_osc_input)
# this_dispatcher.map("/shaderparam0", self.on_param_osc_input)
# this_dispatcher.map("/shaderparam1", 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("/shutdown", self.exit_osc_server)
# this_dispatcher.map("/keyboard/*", self.on_osc_input)
# this_dispatcher.map("/shaderparam0", self.on_param_osc_input)
# this_dispatcher.map("/shaderparam1", 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("/shutdown", self.exit_osc_server)
this_dispatcher.map("/*", self.on_osc_input)
try:
osc_server.ThreadingOSCUDPServer.allow_reuse_address = True
server = osc_server.ThreadingOSCUDPServer((server_args.ip, server_args.port), this_dispatcher)
@@ -63,7 +63,6 @@ class OscInput(object):
except:
self.message_handler.set_message('INFO', 'failed to start osc listener')
def exit_osc_server(self, unused_addr, args):
print('%%%%%%%%%%%%%%%%%%%%% exiting external_osc')
try:
@@ -71,7 +70,6 @@ class OscInput(object):
self.message_handler.set_message('INFO', 'osc deactive')
except:
self.message_handler.set_message('INFO', 'osc shutdown failed')
def on_osc_input(self, addr, args):
if 'keyboard' in addr:
@@ -79,8 +77,7 @@ class OscInput(object):
elif 'shutdown' in addr:
self.exit_osc_server(addr, args)
else:
self.on_param_osc_input(addr,args)
self.on_param_osc_input(addr, args)
def on_key_osc_input(self, addr, args):
args = str(args)
@@ -98,7 +95,7 @@ class OscInput(object):
print("the address", addr)
self.run_action_for_osc_channel(addr, param_value=args)
def run_action_for_osc_channel(self, channel, param_value=None):
this_mapping = self.osc_mappings[channel]
if type(self.data.control_mode) is list:
@@ -111,16 +108,15 @@ class OscInput(object):
mode = self.data.control_mode
elif 'DEFAULT' in this_mapping:
mode = 'DEFAULT'
if self.data.function_on and len(this_mapping[mode]) > 1:
method_name = this_mapping[mode][1]
if self.data.settings['sampler']['FUNC_GATED']['value'] == 'off':
self.data.function_on = False
else:
method_name = this_mapping[mode][0]
self.actions.call_method_name(method_name, param_value)
if 'continuous' not in method_name:
self.display.refresh_display()

View File

@@ -1,23 +1,20 @@
def generate_mappings_doc(title, mappings, column_one_header="Note/CC"):
#print(mappings)
# print(mappings)
output = ""
output += "# %s\n" % title
output += "\n| %s | Mode | Action (default) | Action (with FN) | \n" % column_one_header
output += ("| --- " * 4) + " |\n"
for message, maps in sorted(mappings.items()):
#output += "| %s | " % message
# output += "| %s | " % message
for mode, actions in sorted(maps.items()):
output += "| "
output += "%s\t| " % message
output += "%s\t| " % mode
output += "%s | " % actions[0]
if len(actions)>1:
if len(actions) > 1:
output += "%s | " % actions[1]
output += "|\n"
output += "\n----\n"
print(output)

View File

@@ -1,5 +1,3 @@
class AltVideoPlayer:
def __init__(self, root, message_handler, data, osc_client, name):
self.root = root
@@ -18,15 +16,14 @@ class AltVideoPlayer:
self.load_attempts = 0
self.alpha = 0
self.show_toggle_on = True
### new stuff
### new stuff
self.client = osc_client
self.position = -1
def try_load(self, layer, is_current=False):
load_attempts = 0
while(load_attempts < 2):
while (load_attempts < 2):
load_attempts = load_attempts + 1
if self.load(layer, is_current):
print('load success')
@@ -36,7 +33,6 @@ class AltVideoPlayer:
self.message_handler.set_message('ERROR', 'failed to load')
self.status = 'ERROR'
return False
def load(self, layer, is_current=False):
self.get_context_for_player(is_current)
@@ -45,9 +41,9 @@ class AltVideoPlayer:
self.status = 'EMPTY'
return True
if(self.end is -1):
if (self.end is -1):
self.end = self.total_length
if(self.start is -1):
if (self.start is -1):
self.start = 0
self.client.send_message("/player/{}/load".format(self.name[0]), [self.location, self.start / self.total_length, self.end / self.total_length, self.rate])
self.crop_length = self.end - self.start
@@ -57,10 +53,10 @@ class AltVideoPlayer:
pass
self.set_alpha_value(0)
return True
#except (ValueError, SystemError) as e:
# print(e)
#self.message_handler.set_message('ERROR', 'load attempt fail')
#return False
# except (ValueError, SystemError) as e:
# print(e)
# self.message_handler.set_message('ERROR', 'load attempt fail')
# return False
def start_video(self):
if 'play' in self.data.settings['sampler']['ON_START']['value']:
@@ -73,9 +69,6 @@ class AltVideoPlayer:
else:
self.set_alpha_value(0)
def reload(self, layer, is_current=False):
self.exit()
self.player_running = False
@@ -131,7 +124,7 @@ class AltVideoPlayer:
new_rate = self.rate + amount
print('new rate is being set to {}'.format(new_rate))
if new_rate >= -3 and new_rate <= 3:
if new_rate >= -3 and new_rate <= 3:
self.client.send_message("/player/{}/speed".format(self.name[0]), new_rate)
self.rate = new_rate
return new_rate
@@ -149,15 +142,14 @@ class AltVideoPlayer:
self.root.after(100, self.exit)
def exit(self):
#self.last_player.exit()
# self.last_player.exit()
try:
self.client.send_message("/player/{}/quit".format(self.name[0]),True)
self.client.send_message("/player/{}/quit".format(self.name[0]), True)
self.player_running = False
except:
pass
## not sure if i am going to implement this atm
## not sure if i am going to implement this atm
def set_screen_size_for_dev_mode(self):
if self.data.settings['system']['DEV_MODE_RESET']['value'] == 'on':
##self.client.send_message("/player/{}/alpha".format(self.name[0]), amount)
@@ -165,17 +157,3 @@ class AltVideoPlayer:
else:
aspect_mode = self.data.settings['video']['SCREEN_MODE']['value']
return False, '--aspect-mode', aspect_mode

View File

@@ -13,7 +13,7 @@ class Capture(object):
self.root = root
self.message_handler = message_handler
self.data = data
self.device = None
self.is_recording = False
self.is_previewing = False
@@ -23,16 +23,15 @@ class Capture(object):
## some capture settings
def create_capture_device(self):
if self.data.settings['capture']['TYPE']['value'] != 'usb':
if self.use_capture:
if self.piCapture_with_no_source():
return False
self.update_capture_settings()
try:
self.device = picamera.PiCamera(resolution=self.resolution, framerate=self.framerate, sensor_mode = self.sensor_mode)
self.device = picamera.PiCamera(resolution=self.resolution, framerate=self.framerate, sensor_mode=self.sensor_mode)
return True
except picamera.exc.PiCameraError as e:
self.use_capture = False
@@ -60,16 +59,15 @@ class Capture(object):
if self.capture_type == "piCaptureSd1":
self.sensor_mode = 6
else:
self.sensor_mode = 0
##update current instance (device) if in use
self.sensor_mode = 0
##update current instance (device) if in use
if self.device and not self.device.closed:
self.device.image_effect = self.data.settings['capture']['IMAGE_EFFECT']['value']
self.device.shutter_speed = self.convert_shutter_value(self.data.settings['capture']['SHUTTER']['value'])
## can only update resolution and framerate if not recording
## can only update resolution and framerate if not recording
if not self.is_recording:
self.device.framerate = self.framerate
self.device.resolution = self.resolution
def start_preview(self):
if self.use_capture == False:
@@ -85,7 +83,7 @@ class Capture(object):
self.set_preview_screen_size()
self.set_capture_settings()
self.device.preview.layer = self.PREVIEW_LAYER
return True
return True
def set_capture_settings(self):
if self.capture_type == "piCaptureSd1":
@@ -95,7 +93,6 @@ class Capture(object):
self.device.exposure_mode = "off"
else:
self.sensor_mode = 0
def set_preview_screen_size(self):
if self.data.settings['system']['DEV_MODE_RESET']['value'] == 'on':
@@ -121,7 +118,7 @@ class Capture(object):
is_created = self.create_capture_device()
if self.use_capture == False or not is_created:
return
if not os.path.exists(self.video_dir):
os.makedirs(self.video_dir)
self.is_recording = True
@@ -131,7 +128,7 @@ class Capture(object):
def monitor_disk_space(self):
if self.is_recording:
if self.check_available_disk_space():
self.root.after(10000, self.monitor_disk_space)
self.root.after(10000, self.monitor_disk_space)
else:
self.stop_recording()
@@ -145,9 +142,9 @@ class Capture(object):
def stop_recording(self):
self.device.stop_recording()
#set status to saving
# set status to saving
mp4box_process, recording_name = self.convert_raw_recording()
self.is_recording = 'saving'
self.is_recording = 'saving'
self.root.after(0, self.wait_for_recording_to_save, mp4box_process, recording_name)
self.update_capture_settings()
@@ -156,23 +153,22 @@ class Capture(object):
self.device.close()
def convert_raw_recording(self):
recording_path , recording_name = self.generate_recording_path()
recording_path, recording_name = self.generate_recording_path()
try:
if self.sensor_mode == 6:
mp4box_process = subprocess.Popen(['MP4Box', '-fps', '60', '-add', self.video_dir + '/raw.h264', recording_path])
return mp4box_process , recording_name
return mp4box_process, recording_name
else:
mp4box_process = subprocess.Popen(['MP4Box', '-add', self.video_dir + '/raw.h264', recording_path])
return mp4box_process , recording_name
return mp4box_process, recording_name
except Exception as e:
print(e)
if hasattr(e, 'message'):
error_info = e.message
else:
error_info = e
self.message_handler.set_message('ERROR',error_info)
self.message_handler.set_message('ERROR', error_info)
def wait_for_recording_to_save(self, process, name):
print('the poll is {}'.format(process.poll()))
if process.poll() is not None:
@@ -188,10 +184,10 @@ class Capture(object):
os.makedirs(rec_dir)
date = datetime.datetime.now().strftime("%Y-%m-%d")
i = 0
while os.path.exists('{}/rec-{}-{}.mp4'.format(rec_dir,date, i)):
while os.path.exists('{}/rec-{}-{}.mp4'.format(rec_dir, date, i)):
i += 1
name = 'rec-{}-{}.mp4'.format(date, i)
return '{}/{}'.format(rec_dir,name), name
return '{}/{}'.format(rec_dir, name), name
def get_recording_time(self):
if not self.device or not self.device.recording or self.device.frame.timestamp == None:
@@ -209,7 +205,7 @@ class Capture(object):
error_info = e.message
else:
error_info = e
self.message_handler.set_message('ERROR',error_info)
self.message_handler.set_message('ERROR', error_info)
return 0
return 0
@@ -251,8 +247,7 @@ class Capture(object):
def close_capture(self):
if self.device is not None:
print('closing the old camera...')
self.device.close()
self.device.close()
def receive_recording_finished(self, path, value):
pass

View File

@@ -13,7 +13,7 @@ class OfCapture(object):
self.osc_client = osc_client
self.message_handler = message_handler
self.data = data
self.has_capture = False
self.is_recording = False
self.is_previewing = False
@@ -21,7 +21,7 @@ class OfCapture(object):
self.recording_start_time = 0
self.update_capture_settings()
self.of_recording_finished = True
#self.create_capture_device()
# self.create_capture_device()
def create_capture_device(self):
if self.use_capture and self.capture_type != 'usb':
@@ -31,13 +31,12 @@ class OfCapture(object):
self.update_capture_settings()
if not self.check_if_attached_with_picamera():
return
print('sending setup message !', self.capture_type)
self.osc_client.send_message("/capture/setup", self.capture_type)
self.has_capture = True
return True
def piCapture_with_no_source(self):
is_piCapture = subprocess.check_output(['pivideo', '--query', 'ready'])
if 'Video Processor was not found' not in str(is_piCapture):
@@ -57,12 +56,12 @@ class OfCapture(object):
if self.capture_type == "piCaptureSd1":
self.sensor_mode = 6
else:
self.sensor_mode = 0
self.sensor_mode = 0
def check_if_attached_with_picamera(self):
print('about to try open pcamera to check..')
try:
device = picamera.PiCamera(resolution=self.resolution, framerate=self.framerate, sensor_mode = self.sensor_mode)
device = picamera.PiCamera(resolution=self.resolution, framerate=self.framerate, sensor_mode=self.sensor_mode)
device.close()
return True
except picamera.exc.PiCameraError as e:
@@ -86,7 +85,7 @@ class OfCapture(object):
self.update_capture_settings()
self.osc_client.send_message("/capture/preview/start", True)
return True
def stop_preview(self):
self.osc_client.send_message("/capture/preview/stop", True)
self.is_previewing = False
@@ -103,20 +102,20 @@ class OfCapture(object):
if not self.check_available_disk_space():
return
if not os.path.exists(self.video_dir):
os.makedirs(self.video_dir)
self.is_recording = True
self.of_recording_finished = False
self.recording_start_time = time.time()
#self.device.start_recording(self.video_dir + '/raw.h264')
# self.device.start_recording(self.video_dir + '/raw.h264')
self.osc_client.send_message("/capture/record/start", True)
self.monitor_disk_space()
def monitor_disk_space(self):
if self.is_recording:
if self.check_available_disk_space():
self.root.after(10000, self.monitor_disk_space)
self.root.after(10000, self.monitor_disk_space)
else:
self.stop_recording()
@@ -129,22 +128,21 @@ class OfCapture(object):
return True
def stop_recording(self):
#self.device.stop_recording()
# self.device.stop_recording()
self.osc_client.send_message("/capture/record/stop", True)
self.is_recording = 'saving'
self.is_recording = 'saving'
self.wait_for_raw_file()
#set status to saving
# set status to saving
def wait_for_raw_file(self):
if os.path.exists(self.video_dir + 'raw.h264'):
mp4box_process, recording_name = self.convert_raw_recording()
self.root.after(0, self.wait_for_recording_to_save, mp4box_process, recording_name)
self.update_capture_settings()
elif os.path.exists(self.video_dir + 'raw.mp4') and self.of_recording_finished:
recording_path , recording_name = self.generate_recording_path()
os.rename(self.video_dir + 'raw.mp4', recording_path )
recording_path, recording_name = self.generate_recording_path()
os.rename(self.video_dir + 'raw.mp4', recording_path)
self.is_recording = False
self.data.create_new_slot_mapping_in_first_open(recording_name)
self.update_capture_settings()
@@ -154,22 +152,21 @@ class OfCapture(object):
def convert_raw_recording(self):
### wait for omx to finish creating video ...
if os.path.exists(self.video_dir + 'raw.h264'):
recording_path , recording_name = self.generate_recording_path()
framerate = 30 # hardcoded in openframeworks code for now
recording_path, recording_name = self.generate_recording_path()
framerate = 30 # hardcoded in openframeworks code for now
if self.capture_type == "piCaptureSd1":
framerate = framerate*2 # because picapture is interlaced
framerate = framerate * 2 # because picapture is interlaced
try:
mp4box_process = subprocess.Popen(['MP4Box', '-add', self.video_dir + 'raw.h264:fps={}'.format(framerate), recording_path])
return mp4box_process , recording_name
return mp4box_process, recording_name
except Exception as e:
print(e)
if hasattr(e, 'message'):
error_info = e.message
else:
error_info = e
self.message_handler.set_message('ERROR',error_info)
self.message_handler.set_message('ERROR', error_info)
def wait_for_recording_to_save(self, process, name):
print('the poll is {}'.format(process.poll()))
if process.poll() is not None:
@@ -185,10 +182,10 @@ class OfCapture(object):
os.makedirs(rec_dir)
date = datetime.datetime.now().strftime("%Y-%m-%d")
i = 0
while os.path.exists('{}/rec-{}-{}.mp4'.format(rec_dir,date, i)):
while os.path.exists('{}/rec-{}-{}.mp4'.format(rec_dir, date, i)):
i += 1
name = 'rec-{}-{}.mp4'.format(date, i)
return '{}/{}'.format(rec_dir,name), name
return '{}/{}'.format(rec_dir, name), name
def receive_recording_finished(self, unused_addr, position):
print('recieved recording finshed message !!!!')
@@ -196,9 +193,9 @@ class OfCapture(object):
def get_recording_time(self):
return time.time() - self.recording_start_time
#if not self.device or not self.device.recording or self.device.frame.timestamp == None:
# if not self.device or not self.device.recording or self.device.frame.timestamp == None:
# return -1
#else:
# else:
# return self.device.frame.timestamp / 1000000
def get_preview_alpha(self):
@@ -226,6 +223,3 @@ class OfCapture(object):
return int(1000000 / self.framerate)
else:
return int(fractions.Fraction(setting_value) * 1000000)

View File

@@ -7,7 +7,7 @@ from data_centre.plugin_collection import ModulationReceiverPlugin
class Shaders(object):
MENU_HEIGHT = 10
EMPTY_SHADER = dict(name='none',is_shader=True,shad_type='-',param_number=4,path='-')
EMPTY_SHADER = dict(name='none', is_shader=True, shad_type='-', param_number=4, path='-')
MAX_MOD_SLOTS = 4
@@ -17,27 +17,27 @@ class Shaders(object):
self.message_handler = message_handler
self.message_handler.shaders = self
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.focused_param = 0
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_param_list = [[0.0,0.0,0.0,0.0] for i in range(3)]
self.selected_status_list = ['-', '-', '-'] ## going to try using symbols for this : '-' means empty, '▶' means running, '■' means not running, '!' means error
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_modulation_slot = 0
#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] * self.MAX_MOD_SLOTS #,0.0,0.0,0.0]
# 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] * self.MAX_MOD_SLOTS # ,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)])
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 set_modulation_levels(self, levels):
self.data.settings['shader']['modulation_level'] = levels
@@ -51,17 +51,16 @@ class Shaders(object):
has_path, path = self.get_path_for_shader(stripped_name)
shad_type = self.determine_shader_type(path)
parameter_number = self.determine_shader_parameter_number(path)
shaders_menu_list.append(dict(name=line['name'],is_shader=True,shad_type=shad_type,param_number=parameter_number,path=path))
else:
shaders_menu_list.append(dict(name=line['name'],is_shader=False,shad_type='',param_number=None,path=None))
return shaders_menu_list
shaders_menu_list.append(dict(name=line['name'], is_shader=True, shad_type=shad_type, param_number=parameter_number, path=path))
else:
shaders_menu_list.append(dict(name=line['name'], is_shader=False, shad_type='', param_number=None, path=None))
return shaders_menu_list
def get_path_for_shader(self, file_name):
######## returns full path for a given file name ########
for path in self.data.PATHS_TO_SHADERS:
for path in self.data.PATHS_TO_SHADERS:
for root, dirs, files in os.walk(path):
if file_name in files:
return True, '{}/{}'.format(root, file_name)
@@ -69,20 +68,19 @@ class Shaders(object):
def determine_shader_type(self, path):
with open(path, 'r', errors='ignore') as selected_shader:
shader_text = selected_shader.read()
if '//0-input' in shader_text:
return '0in'
elif '//1-input' in shader_text:
return '1in'
elif '//2-input' in shader_text:
return '2in'
else:
return '-'
shader_text = selected_shader.read()
if '//0-input' in shader_text:
return '0in'
elif '//1-input' in shader_text:
return '1in'
elif '//2-input' in shader_text:
return '2in'
else:
return '-'
def determine_shader_parameter_number(self, path):
max_amount = 4
if True: # for now always assume 4 params
if True: # for now always assume 4 params
return max_amount
with open(path, 'r') as selected_shader:
shader_text = selected_shader.read()
@@ -93,9 +91,9 @@ class Shaders(object):
def load_shader_layer(self, layer):
selected_shader = self.selected_shader_list[layer]
#self.selected_param_list[self.data.shader_layer] = [0.0,0.0,0.0,0.0]
# self.selected_param_list[self.data.shader_layer] = [0.0,0.0,0.0,0.0]
print("select shader: ", selected_shader)
self.osc_client.send_message("/shader/{}/load".format(str(layer)), [selected_shader['path'],selected_shader['shad_type'] == '2in',selected_shader['param_number']])
self.osc_client.send_message("/shader/{}/load".format(str(layer)), [selected_shader['path'], selected_shader['shad_type'] == '2in', selected_shader['param_number']])
if not self.selected_status_list[layer] == '':
self.selected_status_list[layer] = ''
@@ -121,7 +119,7 @@ class Shaders(object):
def map_on_shaders_selection(self):
index = self.shaders_menu.selected_list_index
is_file, name = self.shaders_menu.extract_file_type_and_name_from_menu_format(
self.shaders_menu_list[index]['name'])
self.shaders_menu_list[index]['name'])
if is_file:
is_successful = self.data.create_new_shader_mapping_in_first_open(name)
if not is_successful:
@@ -133,7 +131,7 @@ class Shaders(object):
selected_shader = self.selected_shader_list[self.data.shader_layer]
index = self.shaders_menu.selected_list_index
is_file, name = self.shaders_menu.extract_file_type_and_name_from_menu_format(
self.shaders_menu_list[index]['name'])
self.shaders_menu_list[index]['name'])
is_selected_shader = False
if is_file and name == selected_shader['name'].lstrip():
is_selected_shader = True
@@ -152,7 +150,7 @@ class Shaders(object):
self.selected_shader_list[layer]['slot'] = slot
self.load_shader_layer(layer)
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))
def play_this_shader(self, slot):
print(self.data.shader_bank_data[self.data.shader_layer])
@@ -161,15 +159,15 @@ class Shaders(object):
def increase_this_param(self, amount_change):
param = self.focused_param
current_amount = self.selected_param_list[self.data.shader_layer][param]
amount = self.get_new_param_amount(current_amount,amount_change)
amount = self.get_new_param_amount(current_amount, amount_change)
self.set_param_to_amount(param, amount)
def decrease_this_param(self, amount_change):
param = self.focused_param
current_amount = self.selected_param_list[self.data.shader_layer][param]
amount = self.get_new_param_amount(current_amount,-amount_change)
amount = self.get_new_param_amount(current_amount, -amount_change)
self.set_param_to_amount(param, amount)
def toggle_shader_speed(self):
if self.selected_speed_list[self.data.shader_layer] > 0.62:
self.set_speed_to_amount(0.5)
@@ -190,11 +188,11 @@ class Shaders(object):
def select_previous_shader_modulation_slot(self):
self.selected_modulation_slot -= 1
if self.selected_modulation_slot < 0:
self.selected_modulation_slot = self.MAX_MOD_SLOTS-1
self.selected_modulation_slot = self.MAX_MOD_SLOTS - 1
def reset_modulation(self, slot):
for layer in self.modulation_level:
for layer,levels in enumerate(layer):
for layer, levels in enumerate(layer):
levels[slot] = 0.0
def reset_selected_modulation(self):
@@ -206,13 +204,13 @@ class Shaders(object):
return 1
elif current + change < 0:
return 0
else:
else:
return current + change
def set_param_to_amount(self, param, amount, layer_offset=None):
start_layer = self.data.shader_layer
if self.data.settings['shader']['FIX_PARAM_OFFSET_LAYER']['value'] == 'enabled':
start_layer = 0
start_layer = 0
if layer_offset is None:
start_layer = self.data.shader_layer
layer_offset = 0
@@ -222,45 +220,47 @@ class Shaders(object):
def set_param_layer_to_amount(self, param, layer, amount):
if self.data.settings['shader']['X3_AS_SPEED']['value'] == 'enabled' and param == 3:
self.set_speed_layer_to_amount(layer, amount) #layer_offset=layer-self.data.shader_layer)
else:
self.set_speed_layer_to_amount(layer, amount) # layer_offset=layer-self.data.shader_layer)
else:
self.selected_param_list[layer][param] = amount
self.update_param_layer(param,layer)
self.update_param_layer(param, layer)
def get_modulation_value_list(self, amount, values, levels):
l = []
for i,v in enumerate(values):
for i, v in enumerate(values):
l.append(self.get_modulation_value(amount, v, levels[i]))
#print ("got mean %s from amount %s with %s*%s" % (mean(l), amount, values, levels))
# print ("got mean %s from amount %s with %s*%s" % (mean(l), amount, values, levels))
return mean(l)
def get_modulation_value(self, amount, value, level):
if level==0:
if level == 0:
return amount
# TODO: read from list of input formulas, from plugins etc to modulate the value
temp_amount = amount + (value * level)
#print("from amount %s, modulation is %s, temp_amount is %s" % (amount, modulation, temp_amount))
if temp_amount < 0: temp_amount = 0 # input range is 0-1 so convert back
if temp_amount > 1: temp_amount = 1 # modulation however is -1 to +1
# print("from amount %s, modulation is %s, temp_amount is %s" % (amount, modulation, temp_amount))
if temp_amount < 0:
temp_amount = 0 # input range is 0-1 so convert back
if temp_amount > 1:
temp_amount = 1 # modulation however is -1 to +1
return temp_amount
def send_param_layer_amount_message(self, param, layer, amount):
self.osc_client.send_message("/shader/{}/param".format(str(layer)), [param, amount] )
self.osc_client.send_message("/shader/{}/param".format(str(layer)), [param, amount])
def modulate_param_to_amount(self, param, value):
# incoming data here should be in format 0 to 1; needs changing to -1 to +1
self.modulation_value[param] = (value-0.5)*2 # normalise to -1 to +1
self.modulation_value[param] = (value - 0.5) * 2 # normalise to -1 to +1
for plugin in self.data.plugins.get_plugins(ModulationReceiverPlugin):
plugin.set_modulation_value(param, self.modulation_value[param])
for layer,params in enumerate(self.selected_param_list):
for ip,p in enumerate(params):
for p2,v in enumerate(self.modulation_level[layer][ip]):
if v!=0:
self.update_param_layer(ip,layer)
break
for layer, params in enumerate(self.selected_param_list):
for ip, p in enumerate(params):
for p2, v in enumerate(self.modulation_level[layer][ip]):
if v != 0:
self.update_param_layer(ip, layer)
break
def set_param_layer_offset_modulation_level(self, param, layer, level):
layer = (self.data.shader_layer + layer) % 3
@@ -277,12 +277,12 @@ class Shaders(object):
# merge all applicable layers
self.send_param_layer_amount_message(param, layer,
self.get_modulation_value_list(
self.selected_param_list[layer][param],
self.modulation_value,#[0], #param],
self.modulation_level[layer][param]
)
)
self.get_modulation_value_list(
self.selected_param_list[layer][param],
self.modulation_value, # [0], #param],
self.modulation_level[layer][param]
)
)
def set_speed_offset_to_amount(self, layer_offset, amount):
self.set_speed_to_amount(amount, layer_offset)
@@ -290,8 +290,7 @@ class Shaders(object):
def set_speed_to_amount(self, amount, layer_offset=0):
layer = (self.data.shader_layer + layer_offset) % 3
self.set_speed_layer_to_amount(layer, amount)
def set_speed_layer_to_amount(self, layer, amount):
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

View File

@@ -3,7 +3,6 @@ from video_centre.video_player import VideoPlayer
class VideoDriver(object):
MAX_LAYER = 254
def __init__(self, root, osc_client, message_handler, data):
@@ -16,28 +15,26 @@ class VideoDriver(object):
self.in_current_playing_cycle = False
self.in_next_load_cycle = False
self.in_parallel_cycle = False
self.layer = self.MAX_LAYER
self.last_player = None
self.current_player = None
self.next_player = None
self.reset_all_players()
self.update_video_settings()
if self.loop_parallel:
self.in_parallel_cycle = True
self.root.after(self.delay, self.begin_playing_parallel)
else:
self.root.after(self.delay, self.begin_playing)
#self.print_status()
# self.print_status()
def update_video_settings(self):
self.switch_on_finish = self.data.settings['sampler']['ON_FINISH']['value'] == 'switch'
self.loop_parallel = self.data.settings['sampler']['LOOP_TYPE']['value'] == 'parallel'
def get_next_layer_value(self):
if self.layer > 0:
self.layer = self.layer - 1
@@ -49,8 +46,8 @@ class VideoDriver(object):
def print_status(self):
print('self.loop_parallel: ', self.loop_parallel, 'self.in_parallel_cycle :', self.in_parallel_cycle)
print('l({}):{}, c({}):{}, n({}):{}'.format(self.last_player.name, self.last_player.status, self.current_player.name, \
self.current_player.status, self.next_player.name, self.next_player.status,))
self.root.after(1000,self.print_status)
self.current_player.status, self.next_player.name, self.next_player.status, ))
self.root.after(1000, self.print_status)
def begin_playing(self):
if self.current_player.try_load(self.get_next_layer_value()):
@@ -68,11 +65,11 @@ class VideoDriver(object):
self.root.after(self.delay, self.wait_for_first_load)
def switch_players_and_start_video(self):
self.in_first_load_cycle = False
self.in_current_playing_cycle = False
self.in_next_load_cycle = True
self.in_first_load_cycle = False
self.in_current_playing_cycle = False
self.in_next_load_cycle = True
self.switch_players()
self.switch_players()
def switch_players(self):
temp_player = self.last_player
@@ -84,7 +81,7 @@ class VideoDriver(object):
def start_video(self):
self.current_player.start_video()
self.last_player.exit()
self.last_player.exit()
self.next_player.try_load(self.get_next_layer_value())
self.in_current_playing_cycle = True
self.wait_for_next_cycle()
@@ -115,10 +112,9 @@ class VideoDriver(object):
else:
self.in_next_load_cycle = False
def get_player_info_for_status(self):
return self.current_player.bankslot_number, self.current_player.status, self.current_player.alpha, \
self.next_player.bankslot_number, self.next_player.status, self.next_player.alpha
self.next_player.bankslot_number, self.next_player.status, self.next_player.alpha
def get_player_info_for_banner(self, player):
if player == 'now':
@@ -130,20 +126,20 @@ class VideoDriver(object):
if self.next_player:
self.next_player.exit()
if self.current_player:
self.current_player.exit()
if self. last_player:
self.current_player.exit()
if self.last_player:
self.last_player.exit()
def reset_all_players(self):
self.exit_all_players()
state = self.data.settings['video']['VIDEOPLAYER_BACKEND']['value']
if(state == 'ofvideoplayer' or state == 'ofxomxplayer'):
if (state == 'ofvideoplayer' or state == 'ofxomxplayer'):
self.last_player = AltVideoPlayer(self.root, self.message_handler, self.data, self.osc_client, 'a.a')
self.current_player = AltVideoPlayer(self.root,self.message_handler, self.data, self.osc_client, 'b.b')
self.current_player = AltVideoPlayer(self.root, self.message_handler, self.data, self.osc_client, 'b.b')
self.next_player = AltVideoPlayer(self.root, self.message_handler, self.data, self.osc_client, 'c.c')
else:
self.last_player = VideoPlayer(self.root, self.message_handler, self.data, 'a.a')
self.current_player = VideoPlayer(self.root,self.message_handler, self.data, 'b.b')
self.current_player = VideoPlayer(self.root, self.message_handler, self.data, 'b.b')
self.next_player = VideoPlayer(self.root, self.message_handler, self.data, 'c.c')
def reload_next_player(self):
@@ -154,7 +150,7 @@ class VideoDriver(object):
def receive_position(self, unused_addr, player_name, args):
for player in [self.next_player, self.current_player, self.last_player]:
if player_name[0] in player.name :
if player_name[0] in player.name:
player.position = args * player.total_length
break

View File

@@ -1,5 +1,6 @@
from omxplayer.player import OMXPlayer
class VideoPlayer:
def __init__(self, root, message_handler, data, name):
self.root = root
@@ -20,10 +21,9 @@ class VideoPlayer:
self.alpha = 0
self.show_toggle_on = False
def try_load(self, layer, is_current=False):
load_attempts = 0
while(load_attempts < 2):
while (load_attempts < 2):
load_attempts = load_attempts + 1
if self.load(layer, is_current):
print('load success')
@@ -33,10 +33,9 @@ class VideoPlayer:
self.message_handler.set_message('ERROR', 'failed to load')
self.status = 'ERROR'
return False
def load(self, layer, is_current=False):
#try:
# try:
self.get_context_for_player(is_current)
is_dev_mode, first_screen_arg, second_screen_arg = self.set_screen_size_for_dev_mode()
arguments = ['--no-osd', '--layer', str(layer), '--adev', 'local', '--alpha', '0', first_screen_arg, second_screen_arg]
@@ -49,10 +48,10 @@ class VideoPlayer:
return True
self.omx_player = OMXPlayer(self.location, args=arguments, dbus_name=self.name)
self.omx_running = True
self.total_length = self.omx_player.duration() # <-- uneeded once self.duration stores float
if(self.end is -1):
self.total_length = self.omx_player.duration() # <-- uneeded once self.duration stores float
if (self.end is -1):
self.end = self.total_length
if(self.start is -1):
if (self.start is -1):
self.start = 0
self.crop_length = self.end - self.start
print('{}: the duration is {}'.format(self.name, self.total_length))
@@ -64,14 +63,14 @@ class VideoPlayer:
self.set_alpha_value(0)
self.pause_at_start()
return True
#except (ValueError, SystemError) as e:
# print(e)
#self.message_handler.set_message('ERROR', 'load attempt fail')
#return False
# except (ValueError, SystemError) as e:
# print(e)
# self.message_handler.set_message('ERROR', 'load attempt fail')
# return False
def pause_at_start(self):
position = self.get_position()
start_threshold = round(self.start - 0.02,2)
start_threshold = round(self.start - 0.02, 2)
if position > start_threshold:
if self.status == 'LOADING':
self.status = 'LOADED'
@@ -94,12 +93,12 @@ class VideoPlayer:
def pause_at_end(self):
position = self.get_position()
end_threshold = self.end - 0.2
if(position > end_threshold):
if (position > end_threshold):
self.status = 'FINISHED'
self.omx_player.pause()
print('its paused at end!')
elif(self.omx_running):
elif (self.omx_running):
self.root.after(5, self.pause_at_end)
def reload(self, layer, is_current=False):
@@ -123,7 +122,7 @@ class VideoPlayer:
def get_context_for_player(self, is_current=False):
next_context = self.data.get_next_context(is_current)
self.location = next_context['location']
#self.total_length = next_context['length']
# self.total_length = next_context['length']
self.start = next_context['start']
self.end = next_context['end']
self.bankslot_number = next_context['bankslot_number']
@@ -152,7 +151,7 @@ class VideoPlayer:
after_seek_position = position + amount
if after_seek_position > self.start and after_seek_position < self.end:
self.set_position(after_seek_position)
#self.player.seek(amount)
# self.player.seek(amount)
else:
self.message_handler.set_message('INFO', 'can not seek outside range')
@@ -161,7 +160,7 @@ class VideoPlayer:
if (new_rate > self.omx_player.minimum_rate() and new_rate < self.omx_player.maximum_rate()):
updated_speed = self.omx_player.set_rate(new_rate)
self.rate = new_rate
print('max rate {} , min rate {} '.format(self.omx_player.maximum_rate() ,self.omx_player.minimum_rate()))
print('max rate {} , min rate {} '.format(self.omx_player.maximum_rate(), self.omx_player.minimum_rate()))
return new_rate
else:
self.message_handler.set_message('INFO', 'can not set speed outside of range')
@@ -173,7 +172,7 @@ class VideoPlayer:
def exit(self):
try:
if self.omx_player:
print('trying to exit this player ', self.location)
print('trying to exit this player ', self.location)
self.omx_player.quit()
self.status = 'EMPTY'
self.omx_running = False
@@ -187,5 +186,3 @@ class VideoPlayer:
else:
aspect_mode = self.data.settings['video']['SCREEN_MODE']['value']
return False, '--aspect-mode', aspect_mode