diff --git a/actions.py b/actions.py index 658f03c..959e942 100644 --- a/actions.py +++ b/actions.py @@ -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() - diff --git a/data_centre/data.py b/data_centre/data.py index 1fd77c7..bf9fc42 100644 --- a/data_centre/data.py +++ b/data_centre/data.py @@ -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) - - diff --git a/data_centre/length_setter.py b/data_centre/length_setter.py index f59c24e..0bebe87 100644 --- a/data_centre/length_setter.py +++ b/data_centre/length_setter.py @@ -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) diff --git a/data_centre/plugin_collection.py b/data_centre/plugin_collection.py index 2cfd559..9961123 100644 --- a/data_centre/plugin_collection.py +++ b/data_centre/plugin_collection.py @@ -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]) 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+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 diff --git a/display_centre/display.py b/display_centre/display.py index 5f528b1..00771cb 100644 --- a/display_centre/display.py +++ b/display_centre/display.py @@ -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() diff --git a/display_centre/menu.py b/display_centre/menu.py index da4534f..4555a19 100644 --- a/display_centre/menu.py +++ b/display_centre/menu.py @@ -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)) - - - - - diff --git a/display_centre/messages.py b/display_centre/messages.py index 47fcf1b..3a01dd0 100644 --- a/display_centre/messages.py +++ b/display_centre/messages.py @@ -1,5 +1,6 @@ import logging + class MessageHandler(object): def __init__(self): self.current_message = [None, None, None] diff --git a/dotfiles/python_for_shutting_down_osc_server.py b/dotfiles/python_for_shutting_down_osc_server.py index 1f288fe..3c12030 100644 --- a/dotfiles/python_for_shutting_down_osc_server.py +++ b/dotfiles/python_for_shutting_down_osc_server.py @@ -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) diff --git a/plugins/LFOModulationPlugin.py b/plugins/LFOModulationPlugin.py index 07e8953..20e5e0d 100644 --- a/plugins/LFOModulationPlugin.py +++ b/plugins/LFOModulationPlugin.py @@ -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) ) diff --git a/plugins/ManipulatePlugin.py b/plugins/ManipulatePlugin.py index e2bec49..e04ef4c 100644 --- a/plugins/ManipulatePlugin.py +++ b/plugins/ManipulatePlugin.py @@ -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) - diff --git a/plugins/MidiFeedbackAPCKey25Plugin.py b/plugins/MidiFeedbackAPCKey25Plugin.py index e8d70aa..b19fe71 100644 --- a/plugins/MidiFeedbackAPCKey25Plugin.py +++ b/plugins/MidiFeedbackAPCKey25Plugin.py @@ -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) diff --git a/plugins/MidiFeedbackLaunchpadPlugin.py b/plugins/MidiFeedbackLaunchpadPlugin.py index 11c78f0..57d6d49 100644 --- a/plugins/MidiFeedbackLaunchpadPlugin.py +++ b/plugins/MidiFeedbackLaunchpadPlugin.py @@ -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 diff --git a/plugins/MultiActionsPlugin.py b/plugins/MultiActionsPlugin.py index 341a88e..21a4cc8 100644 --- a/plugins/MultiActionsPlugin.py +++ b/plugins/MultiActionsPlugin.py @@ -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): diff --git a/plugins/ShaderLoopRecordPlugin.py b/plugins/ShaderLoopRecordPlugin.py index bf0bc60..133be19 100644 --- a/plugins/ShaderLoopRecordPlugin.py +++ b/plugins/ShaderLoopRecordPlugin.py @@ -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.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())""" - diff --git a/plugins/ShaderQuickPresetPlugin.py b/plugins/ShaderQuickPresetPlugin.py index bff2916..7a5e9bf 100644 --- a/plugins/ShaderQuickPresetPlugin.py +++ b/plugins/ShaderQuickPresetPlugin.py @@ -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 diff --git a/plugins/SoundReactPlugin.py b/plugins/SoundReactPlugin.py index ce58f34..2695d06 100644 --- a/plugins/SoundReactPlugin.py +++ b/plugins/SoundReactPlugin.py @@ -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): diff --git a/plugins/TestPlugin.py b/plugins/TestPlugin.py index bd3bae9..5c03ba0 100644 --- a/plugins/TestPlugin.py +++ b/plugins/TestPlugin.py @@ -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 ) diff --git a/plugins/WJSendPlugin.py b/plugins/WJSendPlugin.py index 902370b..832276a 100644 --- a/plugins/WJSendPlugin.py +++ b/plugins/WJSendPlugin.py @@ -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 = {} - diff --git a/plugins/frame_manager.py b/plugins/frame_manager.py index c78be5a..95b0883 100644 --- a/plugins/frame_manager.py +++ b/plugins/frame_manager.py @@ -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 diff --git a/r_e_c_u_r.py b/r_e_c_u_r.py index 9a18857..0eefcbe 100755 --- a/r_e_c_u_r.py +++ b/r_e_c_u_r.py @@ -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() - diff --git a/user_input/analog_input.py b/user_input/analog_input.py index 49afb2e..0c910a9 100644 --- a/user_input/analog_input.py +++ b/user_input/analog_input.py @@ -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() diff --git a/user_input/midi_input.py b/user_input/midi_input.py index 955819d..d6efe9c 100644 --- a/user_input/midi_input.py +++ b/user_input/midi_input.py @@ -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 - diff --git a/user_input/numpad_input.py b/user_input/numpad_input.py index de90ee7..03c3efa 100644 --- a/user_input/numpad_input.py +++ b/user_input/numpad_input.py @@ -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') - diff --git a/user_input/osc_input.py b/user_input/osc_input.py index a994ef4..5d882a2 100644 --- a/user_input/osc_input.py +++ b/user_input/osc_input.py @@ -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() - diff --git a/utils/docs.py b/utils/docs.py index d7a3047..fc075ef 100644 --- a/utils/docs.py +++ b/utils/docs.py @@ -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) - diff --git a/video_centre/alt_video_player.py b/video_centre/alt_video_player.py index 37f4d1a..e7d281a 100644 --- a/video_centre/alt_video_player.py +++ b/video_centre/alt_video_player.py @@ -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 - - - - - - - - - - - - - - diff --git a/video_centre/capture.py b/video_centre/capture.py index 88fd336..2217d45 100644 --- a/video_centre/capture.py +++ b/video_centre/capture.py @@ -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 - diff --git a/video_centre/of_capture.py b/video_centre/of_capture.py index 312aa5c..4a2c7e8 100644 --- a/video_centre/of_capture.py +++ b/video_centre/of_capture.py @@ -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) - - - diff --git a/video_centre/shaders.py b/video_centre/shaders.py index 8cc9a20..29a9a72 100644 --- a/video_centre/shaders.py +++ b/video_centre/shaders.py @@ -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 - diff --git a/video_centre/video_driver.py b/video_centre/video_driver.py index 5d330e7..a8b4e57 100644 --- a/video_centre/video_driver.py +++ b/video_centre/video_driver.py @@ -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 diff --git a/video_centre/video_player.py b/video_centre/video_player.py index cb8458a..034f9ab 100644 --- a/video_centre/video_player.py +++ b/video_centre/video_player.py @@ -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 - -