class Axiom_DirectLink(ControlSurface): """ Script for the M-Audio Axiom DirectLink """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self.set_pad_translations(PAD_TRANSLATIONS) self._device_selection_follows_track_selection = True self._suggested_input_port = "DirectLink" self._suggested_output_port = "DirectLink" self._waiting_for_first_response = True self._has_sliders = True self._current_midi_map = None self._display_reset_delay = -1 self._shift_pressed = False self._shift_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 13) self._master_slider = SliderElement(MIDI_CC_TYPE, 15, 41) self._next_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 111) self._prev_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 110) self._device_bank_buttons = None self._device_navigation = None self._shift_button.name = "Shift_Button" self._master_slider.name = "Master_Volume_Control" self._next_nav_button.name = "Next_Track_Button" self._prev_nav_button.name = "Prev_Track_Button" self._master_slider.add_value_listener(self._slider_value, identify_sender=True) self._shift_button.add_value_listener(self._shift_value) self._setup_mixer() self._setup_transport_and_session() self._setup_device() self._setup_display() for component in self.components: component.set_enabled(False) return def refresh_state(self): ControlSurface.refresh_state(self) self._waiting_for_first_response = True self.schedule_message(3, self._send_midi, SYSEX_START + (32, 46, 247)) def handle_sysex(self, midi_bytes): if midi_bytes[0:-2] == SYSEX_START + (32,) and midi_bytes[-2] != 0: self._has_sliders = midi_bytes[-2] & 8 != 0 if self._waiting_for_first_response: self._waiting_for_first_response = False self.schedule_message(1, self._show_startup_message) for component in self.components: component.set_enabled(True) if self._has_sliders: self._mixer.master_strip().set_volume_control(self._master_slider) self._mixer.update() else: self._mixer.master_strip().set_volume_control(None) self._mixer.selected_strip().set_volume_control(self._master_slider) self.request_rebuild_midi_map() return def disconnect(self): self._display_data_source.set_display_string(" ") self._shift_button.remove_value_listener(self._shift_value) self._inst_button.remove_value_listener(self._inst_value) for encoder in self._encoders: encoder.remove_value_listener(self._encoder_value) for slider in tuple(self._sliders) + (self._master_slider,): slider.remove_value_listener(self._slider_value) for button in tuple(self._strip_buttons) + (self._selected_mute_solo_button,): button.remove_value_listener(self._mixer_button_value) for button in self._device_bank_buttons: button.remove_value_listener(self._device_bank_value) self._encoders = None self._sliders = None self._strip_buttons = None self._master_slider = None self._current_midi_map = None self._selected_mute_solo_button = None self._inst_button = None self._shift_button = None self._device_navigation = None self._display = None ControlSurface.disconnect(self) self._send_midi(SYSEX_START + (32, 0, 247)) return def build_midi_map(self, midi_map_handle): self._current_midi_map = midi_map_handle ControlSurface.build_midi_map(self, midi_map_handle) def update_display(self): ControlSurface.update_display(self) if self._display_reset_delay >= 0: self._display_reset_delay -= 1 if self._display_reset_delay == -1: self._show_current_track_name() def _setup_mixer(self): self._selected_mute_solo_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 12) mute_solo_flip_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 57) self._strip_buttons = [] self._selected_mute_solo_button.name = "Selected_Mute_Button" mute_solo_flip_button.name = "Mute_Solo_Flip_Button" self._selected_mute_solo_button.add_value_listener(self._mixer_button_value, identify_sender=True) self._mixer = ShiftableMixerComponent(8) self._mixer.name = "Mixer" self._mixer.set_shift_button(self._shift_button) self._mixer.set_selected_mute_solo_button(self._selected_mute_solo_button) self._mixer.set_select_buttons(self._next_nav_button, self._prev_nav_button) self._mixer.selected_strip().name = "Selected_Channel_Strip" self._mixer.master_strip().name = "Master_Channel_Strip" self._mixer.master_strip().set_volume_control(self._master_slider) self._sliders = [] for index in range(8): strip = self._mixer.channel_strip(index) strip.name = "Channel_Strip_" + str(index) strip.set_invert_mute_feedback(True) self._sliders.append(SliderElement(MIDI_CC_TYPE, 15, 33 + index)) self._sliders[-1].name = str(index) + "_Volume_Control" self._sliders[-1].set_feedback_delay(-1) self._sliders[-1].add_value_listener(self._slider_value, identify_sender=True) strip.set_volume_control(self._sliders[-1]) self._strip_buttons.append(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 49 + index)) self._strip_buttons[-1].name = str(index) + "_Mute_Button" self._strip_buttons[-1].add_value_listener(self._mixer_button_value, identify_sender=True) self._mixer.set_strip_mute_solo_buttons(tuple(self._strip_buttons), mute_solo_flip_button) def _setup_transport_and_session(self): ffwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 115) rwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 114) loop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 113) play_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 117) stop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 116) rec_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 118) ffwd_button.name = "FFwd_Button" rwd_button.name = "Rwd_Button" loop_button.name = "Loop_Button" play_button.name = "Play_Button" stop_button.name = "Stop_Button" rec_button.name = "Record_Button" transport = ShiftableTransportComponent() transport.name = "Transport" transport.set_shift_button(self._shift_button) transport.set_stop_button(stop_button) transport.set_play_button(play_button) transport.set_record_button(rec_button) pads = [] for index in range(len(PAD_TRANSLATIONS)): pads.append(ButtonElement(IS_MOMENTARY, MIDI_NOTE_TYPE, 15, PAD_TRANSLATIONS[index][2])) pads[-1].name = "Pad_" + str(index) self._session = ShiftableSessionComponent(8, 0) self._session.name = "Session_Control" self._session.selected_scene().name = "Selected_Scene" self._session.set_mixer(self._mixer) self._session.set_shift_button(self._shift_button) self._session.set_clip_slot_buttons(tuple(pads)) transport_view_modes = TransportViewModeSelector(transport, self._session, ffwd_button, rwd_button, loop_button) transport_view_modes.name = "Transport_View_Modes" def _setup_device(self): self._encoders = [] for offset in range(8): self._encoders.append( PeekableEncoderElement( MIDI_CC_TYPE, 15, 17 + offset, Live.MidiMap.MapMode.relative_smooth_two_compliment ) ) self._encoders[-1].set_feedback_delay(-1) self._encoders[-1].add_value_listener(self._encoder_value, identify_sender=True) self._encoders[-1].name = "Device_Control_" + str(offset) prev_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 14) next_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 15) prev_bank_button.name = "Device_Bank_Down_Button" next_bank_button.name = "Device_Bank_Up_Button" device = BestBankDeviceComponent() device.name = "Device_Component" self.set_device_component(device) device.set_parameter_controls(tuple(self._encoders)) device.set_bank_nav_buttons(prev_bank_button, next_bank_button) self._device_bank_buttons = (prev_bank_button, next_bank_button) prev_bank_button.add_value_listener(self._device_bank_value) next_bank_button.add_value_listener(self._device_bank_value) self._inst_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 109) self._inst_button.name = "Inst_Button" self._inst_button.add_value_listener(self._inst_value) self._device_navigation = DetailViewCntrlComponent() self._device_navigation.name = "Device_Navigation_Component" def _setup_display(self): self._display = PhysicalDisplayElement(5, 1) self._display.name = "Display" self._display.set_message_parts(SYSEX_START + (17, 1, 0, 0), (247,)) self._display_data_source = DisplayDataSource() self._display.segment(0).set_data_source(self._display_data_source) def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(self) self._show_current_track_name() def _shift_value(self, value): if not value in range(128): raise AssertionError self._shift_pressed = value > 0 for encoder in self._encoders: encoder.set_peek_mode(self._shift_pressed) self._shift_pressed and self._mixer.set_select_buttons(None, None) self._session.set_track_bank_buttons(self._next_nav_button, self._prev_nav_button) self._device_component.set_bank_nav_buttons(None, None) self._device_navigation.set_device_nav_buttons(self._device_bank_buttons[0], self._device_bank_buttons[1]) else: self._session.set_track_bank_buttons(None, None) self._mixer.set_select_buttons(self._next_nav_button, self._prev_nav_button) self._device_navigation.set_device_nav_buttons(None, None) self._device_component.set_bank_nav_buttons(self._device_bank_buttons[0], self._device_bank_buttons[1]) self.request_rebuild_midi_map() return def _encoder_value(self, value, sender): if not sender in self._encoders: raise AssertionError if not value in range(128): raise AssertionError display_string = self._device_component.is_enabled() and " - " display_string = sender.mapped_parameter() != None and sender.mapped_parameter().name self._display_data_source.set_display_string(display_string) self._set_display_data_source(self._display_data_source) self._display_reset_delay = STANDARD_DISPLAY_DELAY return def _slider_value(self, value, sender): if not sender in tuple(self._sliders) + (self._master_slider,): raise AssertionError if not value in range(128): raise AssertionError if self._mixer.is_enabled(): display_string = " - " if sender.mapped_parameter() != None: master = self.song().master_track tracks = self.song().tracks returns = self.song().return_tracks track = None if sender == self._master_slider: track = self._has_sliders and master else: track = self.song().view.selected_track else: track = self._mixer.channel_strip(self._sliders.index(sender))._track display_string = track == master and "Ma" elif track in tracks: display_string = str(list(tracks).index(track) + 1) elif track in returns: display_string = str(chr(ord("A") + list(returns).index(track))) else: raise False or AssertionError display_string += " Vol" self._display_data_source.set_display_string(display_string) self._set_display_data_source(self._display_data_source) self._display_reset_delay = STANDARD_DISPLAY_DELAY return def _mixer_button_value(self, value, sender): if not sender in tuple(self._strip_buttons) + (self._selected_mute_solo_button,): raise AssertionError if not value in range(128): raise AssertionError if self._mixer.is_enabled() and value > 0: strip = None strip = sender == self._selected_mute_solo_button and self._mixer.selected_strip() else: strip = self._mixer.channel_strip(self._strip_buttons.index(sender)) strip != None and self._set_display_data_source(strip.track_name_data_source()) else: self._display_data_source.set_display_string(" - ") self._set_display_data_source(self._display_data_source) self._display_reset_delay = STANDARD_DISPLAY_DELAY return def _device_bank_value(self, value): if not value in range(128): raise AssertionError if self._device_component.is_enabled() and value > 0: data_source = self._device_component.bank_name_data_source() data_source = self._shift_pressed and self._device_component.device_name_data_source() self._set_display_data_source(data_source) self._display_reset_delay = STANDARD_DISPLAY_DELAY def _inst_value(self, value): if not value in range(128): raise AssertionError value > 0 and self._device_component.is_enabled() and self.song().view.selected_track.view.select_instrument() and self._set_display_data_source( self._device_component.device_name_data_source() ) self._display_reset_delay = STANDARD_DISPLAY_DELAY def _show_current_track_name(self): if self._display != None and self._mixer != None: self._set_display_data_source(self._mixer.selected_strip().track_name_data_source()) return def _show_startup_message(self): self._display.display_message("LIVE") self._display_reset_delay = INITIAL_DISPLAY_DELAY def _set_display_data_source(self, data_source): raise isinstance(data_source, DisplayDataSource) or AssertionError self._display.segment(0).set_data_source(data_source) data_source.update()
class Novation_Impulse(ControlSurface): """ Script for Novation's Impulse keyboards """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self.set_pad_translations(PAD_TRANSLATIONS) self._suggested_input_port = b'Impulse' self._suggested_output_port = b'Impulse' self._has_sliders = True self._current_midi_map = None self._display_reset_delay = -1 self._shift_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 39) self._preview_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 41) self._master_slider = SliderElement(MIDI_CC_TYPE, 0, 8) self._shift_button.name = b'Shift_Button' self._master_slider.name = b'Master_Volume_Control' self._master_slider.add_value_listener(self._slider_value, identify_sender=True) self._preview_button.add_value_listener(self._preview_value) self._setup_mixer() self._setup_session() self._setup_transport() self._setup_device() self._setup_name_display() device_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 1, 10) mixer_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 1, 9) device_button.name = b'Encoder_Device_Mode' mixer_button.name = b'Encoder_Mixer_Mode' self._encoder_modes = EncoderModeSelector(self._device_component, self._mixer, self._next_bank_button, self._prev_bank_button, self._encoders) self._encoder_modes.set_device_mixer_buttons( device_button, mixer_button) self._string_to_display = None for component in self.components: component.set_enabled(False) return def refresh_state(self): ControlSurface.refresh_state(self) self.schedule_message(3, self._send_midi, SYSEX_START + (6, 1, 1, 1, 247)) def handle_sysex(self, midi_bytes): if midi_bytes[0:-2] == SYSEX_START + (7, ) and midi_bytes[(-2)] != 0: self._has_sliders = midi_bytes[(-2)] != 25 self.schedule_message(1, self._show_startup_message) for control in self.controls: if isinstance(control, InputControlElement): control.clear_send_cache() for component in self.components: component.set_enabled(True) if self._has_sliders: self._mixer.master_strip().set_volume_control( self._master_slider) self._mixer.update() else: self._mixer.master_strip().set_volume_control(None) self._mixer.selected_strip().set_volume_control( self._master_slider) for index in range(len(self._sliders)): self._mixer.channel_strip(index).set_volume_control(None) slider = self._sliders[index] slider.release_parameter() if slider.value_has_listener(self._slider_value): slider.remove_value_listener(self._slider_value) self._encoder_modes.set_provide_volume_mode(not self._has_sliders) self.request_rebuild_midi_map() return def disconnect(self): self._name_display_data_source.set_display_string(b' ') for encoder in self._encoders: encoder.remove_value_listener(self._encoder_value) self._master_slider.remove_value_listener(self._slider_value) if self._has_sliders: for slider in tuple(self._sliders): slider.remove_value_listener(self._slider_value) for button in self._strip_buttons: button.remove_value_listener(self._mixer_button_value) self._preview_button.remove_value_listener(self._preview_value) ControlSurface.disconnect(self) self._encoders = None self._sliders = None self._strip_buttons = None self._master_slider = None self._current_midi_map = None self._shift_button = None self._name_display = None self._prev_bank_button = None self._next_bank_button = None self._encoder_modes = None self._transport_view_modes = None self._send_midi(SYSEX_START + (6, 0, 0, 0, 247)) return def build_midi_map(self, midi_map_handle): self._current_midi_map = midi_map_handle ControlSurface.build_midi_map(self, midi_map_handle) def update_display(self): ControlSurface.update_display(self) if self._string_to_display != None: self._name_display_data_source.set_display_string( self._string_to_display) self._string_to_display = None if self._display_reset_delay >= 0: self._display_reset_delay -= 1 if self._display_reset_delay == -1: self._show_current_track_name() return def _setup_mixer(self): mute_solo_flip_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 34) self._next_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 37) self._prev_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 38) self._strip_buttons = [] mute_solo_flip_button.name = b'Mute_Solo_Flip_Button' self._next_nav_button.name = b'Next_Track_Button' self._prev_nav_button.name = b'Prev_Track_Button' self._mixer = SpecialMixerComponent(8) self._mixer.name = b'Mixer' self._mixer.set_select_buttons(self._next_nav_button, self._prev_nav_button) self._mixer.selected_strip().name = b'Selected_Channel_Strip' self._mixer.master_strip().name = b'Master_Channel_Strip' self._mixer.master_strip().set_volume_control(self._master_slider) self._sliders = [] for index in range(8): strip = self._mixer.channel_strip(index) strip.name = b'Channel_Strip_' + str(index) strip.set_invert_mute_feedback(True) self._sliders.append(SliderElement(MIDI_CC_TYPE, 0, index)) self._sliders[(-1)].name = str(index) + b'_Volume_Control' self._sliders[(-1)].set_feedback_delay(-1) self._sliders[(-1)].add_value_listener(self._slider_value, identify_sender=True) strip.set_volume_control(self._sliders[(-1)]) self._strip_buttons.append( ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 9 + index)) self._strip_buttons[(-1)].name = str(index) + b'_Mute_Button' self._strip_buttons[(-1)].add_value_listener( self._mixer_button_value, identify_sender=True) self._mixer.master_strip().set_mute_button( ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 17)) self._mixer.set_strip_mute_solo_buttons(tuple(self._strip_buttons), mute_solo_flip_button) def _setup_session(self): num_pads = len(PAD_TRANSLATIONS) self._track_left_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 36) self._track_right_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 35) self._session = SessionComponent(8, 0) self._session.name = b'Session_Control' self._session.selected_scene().name = b'Selected_Scene' self._session.set_mixer(self._mixer) self._session.set_page_left_button(self._track_left_button) self._session.set_page_right_button(self._track_right_button) pads = [] for index in range(num_pads): pads.append( ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 60 + index)) pads[(-1)].name = b'Pad_' + str(index) clip_slot = self._session.selected_scene().clip_slot(index) clip_slot.set_triggered_to_play_value(GREEN_BLINK) clip_slot.set_triggered_to_record_value(RED_BLINK) clip_slot.set_stopped_value(AMBER_FULL) clip_slot.set_started_value(GREEN_FULL) clip_slot.set_recording_value(RED_FULL) clip_slot.set_launch_button(pads[(-1)]) clip_slot.name = str(index) + b'_Selected_Clip_Slot' def _setup_transport(self): rwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 27) ffwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 28) stop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 29) play_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 30) loop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 31) rec_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 32) ffwd_button.name = b'FFwd_Button' rwd_button.name = b'Rwd_Button' loop_button.name = b'Loop_Button' play_button.name = b'Play_Button' stop_button.name = b'Stop_Button' rec_button.name = b'Record_Button' transport = ShiftableTransportComponent() transport.name = b'Transport' transport.set_stop_button(stop_button) transport.set_play_button(play_button) transport.set_record_button(rec_button) transport.set_shift_button(self._shift_button) self._transport_view_modes = TransportViewModeSelector( transport, self._session, ffwd_button, rwd_button, loop_button) self._transport_view_modes.name = b'Transport_View_Modes' def _setup_device(self): encoders = [] for index in range(8): encoders.append( PeekableEncoderElement( MIDI_CC_TYPE, 1, index, Live.MidiMap.MapMode.relative_binary_offset)) encoders[(-1)].set_feedback_delay(-1) encoders[(-1)].add_value_listener(self._encoder_value, identify_sender=True) encoders[(-1)].name = b'Device_Control_' + str(index) self._encoders = tuple(encoders) self._prev_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 12) self._next_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 11) self._prev_bank_button.name = b'Device_Bank_Down_Button' self._next_bank_button.name = b'Device_Bank_Up_Button' device = DeviceComponent(device_selection_follows_track_selection=True) device.name = b'Device_Component' self.set_device_component(device) device.set_parameter_controls(self._encoders) device.set_bank_nav_buttons(self._prev_bank_button, self._next_bank_button) def _setup_name_display(self): self._name_display = PhysicalDisplayElement(16, 1) self._name_display.name = b'Display' self._name_display.set_message_parts(SYSEX_START + (8, ), (247, )) self._name_display_data_source = DisplayDataSource() self._name_display.segment(0).set_data_source( self._name_display_data_source) def _encoder_value(self, value, sender): assert sender in self._encoders assert value in range(128) if self._device_component.is_enabled(): display_string = b' - ' if sender.mapped_parameter() != None: display_string = sender.mapped_parameter().name self._set_string_to_display(display_string) return def _slider_value(self, value, sender): assert sender in tuple(self._sliders) + (self._master_slider, ) assert value in range(128) if self._mixer.is_enabled(): display_string = b' - ' if sender.mapped_parameter() != None: master = self.song().master_track tracks = self.song().tracks returns = self.song().return_tracks track = None if sender == self._master_slider: if self._has_sliders: track = master else: track = self.song().view.selected_track else: track = self._mixer.channel_strip( self._sliders.index(sender))._track if track == master: display_string = b'Master' elif track in tracks: display_string = str(list(tracks).index(track) + 1) elif track in returns: display_string = str( chr(ord(b'A') + list(returns).index(track))) else: assert False display_string += b' Volume' self._set_string_to_display(display_string) return def _mixer_button_value(self, value, sender): assert value in range(128) if self._mixer.is_enabled() and value > 0: strip = self._mixer.channel_strip( self._strip_buttons.index(sender)) if strip != None: self._string_to_display = None self._name_display.segment(0).set_data_source( strip.track_name_data_source()) self._name_display.update() self._display_reset_delay = STANDARD_DISPLAY_DELAY else: self._set_string_to_display(b' - ') return def _preview_value(self, value): assert value in range(128) for encoder in self._encoders: encoder.set_peek_mode(value > 0) def _show_current_track_name(self): if self._name_display != None and self._mixer != None: self._string_to_display = None self._name_display.segment(0).set_data_source( self._mixer.selected_strip().track_name_data_source()) self._name_display.update() return def _show_startup_message(self): self._name_display.display_message(b'LIVE') self._display_reset_delay = INITIAL_DISPLAY_DELAY def _set_string_to_display(self, string_to_display): assert isinstance(string_to_display, (str, unicode)) self._name_display.segment(0).set_data_source( self._name_display_data_source) self._string_to_display = string_to_display self._display_reset_delay = STANDARD_DISPLAY_DELAY def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(self) self._show_current_track_name() all_tracks = self._has_sliders or self._session.tracks_to_use() selected_track = self.song().view.selected_track num_strips = self._session.width() if selected_track in all_tracks: track_index = list(all_tracks).index(selected_track) new_offset = track_index - track_index % num_strips if not new_offset / num_strips == int(new_offset / num_strips): raise AssertionError self._session.set_offsets(new_offset, self._session.scene_offset())
class Novation_Impulse(ControlSurface): """ Script for Novation's Impulse keyboards """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self.set_pad_translations(PAD_TRANSLATIONS) self._device_selection_follows_track_selection = True self._suggested_input_port = 'Impulse' self._suggested_output_port = 'Impulse' self._has_sliders = True self._current_midi_map = None self._display_reset_delay = -1 self._shift_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 39) self._preview_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 41) self._master_slider = SliderElement(MIDI_CC_TYPE, 0, 8) self._shift_button.name = 'Shift_Button' self._master_slider.name = 'Master_Volume_Control' self._master_slider.add_value_listener(self._slider_value, identify_sender=True) self._preview_button.add_value_listener(self._preview_value) self._setup_mixer() self._setup_session() self._setup_transport() self._setup_device() self._setup_name_display() device_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 1, 10) mixer_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 1, 9) device_button.name = 'Encoder_Device_Mode' mixer_button.name = 'Encoder_Mixer_Mode' self._encoder_modes = EncoderModeSelector(self._device_component, self._mixer, self._next_bank_button, self._prev_bank_button, self._encoders) self._encoder_modes.set_device_mixer_buttons(device_button, mixer_button) self._string_to_display = None for component in self.components: component.set_enabled(False) def refresh_state(self): ControlSurface.refresh_state(self) self.schedule_message(3, self._send_midi, SYSEX_START + (6, 1, 1, 1, 247)) def handle_sysex(self, midi_bytes): if midi_bytes[0:-2] == SYSEX_START + (7,) and midi_bytes[-2] != 0: self._has_sliders = midi_bytes[-2] != 25 self.schedule_message(1, self._show_startup_message) for control in self.controls: if isinstance(control, InputControlElement): control.clear_send_cache() for component in self.components: component.set_enabled(True) if self._has_sliders: self._mixer.master_strip().set_volume_control(self._master_slider) self._mixer.update() else: self._mixer.master_strip().set_volume_control(None) self._mixer.selected_strip().set_volume_control(self._master_slider) for index in range(len(self._sliders)): self._mixer.channel_strip(index).set_volume_control(None) slider = self._sliders[index] slider.release_parameter() if slider.value_has_listener(self._slider_value): slider.remove_value_listener(self._slider_value) self._encoder_modes.set_provide_volume_mode(not self._has_sliders) self.request_rebuild_midi_map() def disconnect(self): self._name_display_data_source.set_display_string(' ') for encoder in self._encoders: encoder.remove_value_listener(self._encoder_value) self._master_slider.remove_value_listener(self._slider_value) if self._has_sliders: for slider in tuple(self._sliders): slider.remove_value_listener(self._slider_value) for button in self._strip_buttons: button.remove_value_listener(self._mixer_button_value) self._preview_button.remove_value_listener(self._preview_value) ControlSurface.disconnect(self) self._encoders = None self._sliders = None self._strip_buttons = None self._master_slider = None self._current_midi_map = None self._shift_button = None self._name_display = None self._prev_bank_button = None self._next_bank_button = None self._encoder_modes = None self._transport_view_modes = None self._send_midi(SYSEX_START + (6, 0, 0, 0, 247)) def build_midi_map(self, midi_map_handle): self._current_midi_map = midi_map_handle ControlSurface.build_midi_map(self, midi_map_handle) def update_display(self): ControlSurface.update_display(self) if self._string_to_display != None: self._name_display_data_source.set_display_string(self._string_to_display) self._string_to_display = None if self._display_reset_delay >= 0: self._display_reset_delay -= 1 if self._display_reset_delay == -1: self._show_current_track_name() def _setup_mixer(self): mute_solo_flip_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 34) self._next_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 37) self._prev_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 38) self._strip_buttons = [] mute_solo_flip_button.name = 'Mute_Solo_Flip_Button' self._next_nav_button.name = 'Next_Track_Button' self._prev_nav_button.name = 'Prev_Track_Button' self._mixer = SpecialMixerComponent(8) self._mixer.name = 'Mixer' self._mixer.set_select_buttons(self._next_nav_button, self._prev_nav_button) self._mixer.selected_strip().name = 'Selected_Channel_Strip' self._mixer.master_strip().name = 'Master_Channel_Strip' self._mixer.master_strip().set_volume_control(self._master_slider) self._sliders = [] for index in range(8): strip = self._mixer.channel_strip(index) strip.name = 'Channel_Strip_' + str(index) strip.set_invert_mute_feedback(True) self._sliders.append(SliderElement(MIDI_CC_TYPE, 0, index)) self._sliders[-1].name = str(index) + '_Volume_Control' self._sliders[-1].set_feedback_delay(-1) self._sliders[-1].add_value_listener(self._slider_value, identify_sender=True) strip.set_volume_control(self._sliders[-1]) self._strip_buttons.append(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 9 + index)) self._strip_buttons[-1].name = str(index) + '_Mute_Button' self._strip_buttons[-1].add_value_listener(self._mixer_button_value, identify_sender=True) self._mixer.master_strip().set_mute_button(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 17)) self._mixer.set_strip_mute_solo_buttons(tuple(self._strip_buttons), mute_solo_flip_button) def _setup_session(self): num_pads = len(PAD_TRANSLATIONS) self._track_left_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 36) self._track_right_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 35) self._session = SessionComponent(8, 0) self._session.name = 'Session_Control' self._session.selected_scene().name = 'Selected_Scene' self._session.set_mixer(self._mixer) self._session.set_page_left_button(self._track_left_button) self._session.set_page_right_button(self._track_right_button) pads = [] for index in range(num_pads): pads.append(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 60 + index)) pads[-1].name = 'Pad_' + str(index) clip_slot = self._session.selected_scene().clip_slot(index) clip_slot.set_triggered_to_play_value(GREEN_BLINK) clip_slot.set_triggered_to_record_value(RED_BLINK) clip_slot.set_stopped_value(AMBER_FULL) clip_slot.set_started_value(GREEN_FULL) clip_slot.set_recording_value(RED_FULL) clip_slot.set_launch_button(pads[-1]) clip_slot.name = str(index) + '_Selected_Clip_Slot' def _setup_transport(self): rwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 27) ffwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 28) stop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 29) play_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 30) loop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 31) rec_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 32) ffwd_button.name = 'FFwd_Button' rwd_button.name = 'Rwd_Button' loop_button.name = 'Loop_Button' play_button.name = 'Play_Button' stop_button.name = 'Stop_Button' rec_button.name = 'Record_Button' transport = ShiftableTransportComponent() transport.name = 'Transport' transport.set_stop_button(stop_button) transport.set_play_button(play_button) transport.set_record_button(rec_button) transport.set_shift_button(self._shift_button) self._transport_view_modes = TransportViewModeSelector(transport, self._session, ffwd_button, rwd_button, loop_button) self._transport_view_modes.name = 'Transport_View_Modes' def _setup_device(self): encoders = [] for index in range(8): encoders.append(PeekableEncoderElement(MIDI_CC_TYPE, 1, index, Live.MidiMap.MapMode.relative_binary_offset)) encoders[-1].set_feedback_delay(-1) encoders[-1].add_value_listener(self._encoder_value, identify_sender=True) encoders[-1].name = 'Device_Control_' + str(index) self._encoders = tuple(encoders) self._prev_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 12) self._next_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 11) self._prev_bank_button.name = 'Device_Bank_Down_Button' self._next_bank_button.name = 'Device_Bank_Up_Button' device = DeviceComponent() device.name = 'Device_Component' self.set_device_component(device) device.set_parameter_controls(self._encoders) device.set_bank_nav_buttons(self._prev_bank_button, self._next_bank_button) def _setup_name_display(self): self._name_display = PhysicalDisplayElement(16, 1) self._name_display.name = 'Display' self._name_display.set_message_parts(SYSEX_START + (8,), (247,)) self._name_display_data_source = DisplayDataSource() self._name_display.segment(0).set_data_source(self._name_display_data_source) def _encoder_value(self, value, sender): if not sender in self._encoders: raise AssertionError if not value in range(128): raise AssertionError display_string = self._device_component.is_enabled() and ' - ' display_string = sender.mapped_parameter() != None and sender.mapped_parameter().name self._set_string_to_display(display_string) def _slider_value(self, value, sender): if not sender in tuple(self._sliders) + (self._master_slider,): raise AssertionError if not value in range(128): raise AssertionError if self._mixer.is_enabled(): display_string = ' - ' if sender.mapped_parameter() != None: master = self.song().master_track tracks = self.song().tracks returns = self.song().return_tracks track = None if sender == self._master_slider: track = self._has_sliders and master else: track = self.song().view.selected_track else: track = self._mixer.channel_strip(self._sliders.index(sender))._track display_string = track == master and 'Master' elif track in tracks: display_string = str(list(tracks).index(track) + 1) elif track in returns: display_string = str(chr(ord('A') + list(returns).index(track))) else: raise False or AssertionError display_string += ' Volume' self._set_string_to_display(display_string) def _mixer_button_value(self, value, sender): if not value in range(128): raise AssertionError if self._mixer.is_enabled() and value > 0: strip = self._mixer.channel_strip(self._strip_buttons.index(sender)) self._string_to_display = strip != None and None self._name_display.segment(0).set_data_source(strip.track_name_data_source()) self._name_display.update() self._display_reset_delay = STANDARD_DISPLAY_DELAY else: self._set_string_to_display(' - ') def _preview_value(self, value): raise value in range(128) or AssertionError for encoder in self._encoders: encoder.set_peek_mode(value > 0) def _show_current_track_name(self): if self._name_display != None and self._mixer != None: self._string_to_display = None self._name_display.segment(0).set_data_source(self._mixer.selected_strip().track_name_data_source()) self._name_display.update() def _show_startup_message(self): self._name_display.display_message('LIVE') self._display_reset_delay = INITIAL_DISPLAY_DELAY def _set_string_to_display(self, string_to_display): raise isinstance(string_to_display, (str, unicode)) or AssertionError self._name_display.segment(0).set_data_source(self._name_display_data_source) self._string_to_display = string_to_display self._display_reset_delay = STANDARD_DISPLAY_DELAY def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(self) self._show_current_track_name() all_tracks = self._has_sliders or self._session.tracks_to_use() selected_track = self.song().view.selected_track num_strips = self._session.width() if selected_track in all_tracks: track_index = list(all_tracks).index(selected_track) new_offset = track_index - track_index % num_strips if not new_offset / num_strips == int(new_offset / num_strips): raise AssertionError self._session.set_offsets(new_offset, self._session.scene_offset())
class Axiom_DirectLink(ControlSurface): """ Script for the M-Audio Axiom DirectLink """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self.set_pad_translations(PAD_TRANSLATIONS) self._device_selection_follows_track_selection = True self._suggested_input_port = 'DirectLink' self._suggested_output_port = 'DirectLink' self._waiting_for_first_response = True self._has_sliders = True self._current_midi_map = None self._display_reset_delay = -1 self._shift_pressed = False self._shift_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 13) self._master_slider = SliderElement(MIDI_CC_TYPE, 15, 41) self._next_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 111) self._prev_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 110) self._device_bank_buttons = None self._device_navigation = None self._shift_button.name = 'Shift_Button' self._master_slider.name = 'Master_Volume_Control' self._next_nav_button.name = 'Next_Track_Button' self._prev_nav_button.name = 'Prev_Track_Button' self._master_slider.add_value_listener(self._slider_value, identify_sender=True) self._shift_button.add_value_listener(self._shift_value) self._setup_mixer() self._setup_transport_and_session() self._setup_device() self._setup_display() for component in self.components: component.set_enabled(False) def refresh_state(self): ControlSurface.refresh_state(self) self._waiting_for_first_response = True self.schedule_message(3, self._send_midi, SYSEX_START + (32, 46, 247)) def handle_sysex(self, midi_bytes): if midi_bytes[0:-2] == SYSEX_START + (32, ) and midi_bytes[-2] != 0: self._has_sliders = midi_bytes[-2] & 8 != 0 if self._waiting_for_first_response: self._waiting_for_first_response = False self.schedule_message(1, self._show_startup_message) for component in self.components: component.set_enabled(True) if self._has_sliders: self._mixer.master_strip().set_volume_control( self._master_slider) self._mixer.update() else: self._mixer.master_strip().set_volume_control(None) self._mixer.selected_strip().set_volume_control( self._master_slider) self.request_rebuild_midi_map() def disconnect(self): self._display_data_source.set_display_string(' ') self._shift_button.remove_value_listener(self._shift_value) self._inst_button.remove_value_listener(self._inst_value) for encoder in self._encoders: encoder.remove_value_listener(self._encoder_value) for slider in tuple(self._sliders) + (self._master_slider, ): slider.remove_value_listener(self._slider_value) for button in tuple( self._strip_buttons) + (self._selected_mute_solo_button, ): button.remove_value_listener(self._mixer_button_value) for button in self._device_bank_buttons: button.remove_value_listener(self._device_bank_value) self._encoders = None self._sliders = None self._strip_buttons = None self._master_slider = None self._current_midi_map = None self._selected_mute_solo_button = None self._inst_button = None self._shift_button = None self._device_navigation = None self._display = None ControlSurface.disconnect(self) self._send_midi(SYSEX_START + (32, 0, 247)) def build_midi_map(self, midi_map_handle): self._current_midi_map = midi_map_handle ControlSurface.build_midi_map(self, midi_map_handle) def update_display(self): ControlSurface.update_display(self) if self._display_reset_delay >= 0: self._display_reset_delay -= 1 if self._display_reset_delay == -1: self._show_current_track_name() def _setup_mixer(self): self._selected_mute_solo_button = ButtonElement( IS_MOMENTARY, MIDI_CC_TYPE, 15, 12) mute_solo_flip_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 57) self._strip_buttons = [] self._selected_mute_solo_button.name = 'Selected_Mute_Button' mute_solo_flip_button.name = 'Mute_Solo_Flip_Button' self._selected_mute_solo_button.add_value_listener( self._mixer_button_value, identify_sender=True) self._mixer = ShiftableMixerComponent(8) self._mixer.name = 'Mixer' self._mixer.set_shift_button(self._shift_button) self._mixer.set_selected_mute_solo_button( self._selected_mute_solo_button) self._mixer.set_select_buttons(self._next_nav_button, self._prev_nav_button) self._mixer.selected_strip().name = 'Selected_Channel_Strip' self._mixer.master_strip().name = 'Master_Channel_Strip' self._mixer.master_strip().set_volume_control(self._master_slider) self._sliders = [] for index in range(8): strip = self._mixer.channel_strip(index) strip.name = 'Channel_Strip_' + str(index) strip.set_invert_mute_feedback(True) self._sliders.append(SliderElement(MIDI_CC_TYPE, 15, 33 + index)) self._sliders[-1].name = str(index) + '_Volume_Control' self._sliders[-1].set_feedback_delay(-1) self._sliders[-1].add_value_listener(self._slider_value, identify_sender=True) strip.set_volume_control(self._sliders[-1]) self._strip_buttons.append( ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 49 + index)) self._strip_buttons[-1].name = str(index) + '_Mute_Button' self._strip_buttons[-1].add_value_listener( self._mixer_button_value, identify_sender=True) self._mixer.set_strip_mute_solo_buttons(tuple(self._strip_buttons), mute_solo_flip_button) def _setup_transport_and_session(self): ffwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 115) rwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 114) loop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 113) play_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 117) stop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 116) rec_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 118) ffwd_button.name = 'FFwd_Button' rwd_button.name = 'Rwd_Button' loop_button.name = 'Loop_Button' play_button.name = 'Play_Button' stop_button.name = 'Stop_Button' rec_button.name = 'Record_Button' transport = ShiftableTransportComponent() transport.name = 'Transport' transport.set_shift_button(self._shift_button) transport.set_stop_button(stop_button) transport.set_play_button(play_button) transport.set_record_button(rec_button) pads = [] for index in range(len(PAD_TRANSLATIONS)): pads.append( ButtonElement(IS_MOMENTARY, MIDI_NOTE_TYPE, 15, PAD_TRANSLATIONS[index][2])) pads[-1].name = 'Pad_' + str(index) self._session = ShiftableSessionComponent(8, 0) self._session.name = 'Session_Control' self._session.selected_scene().name = 'Selected_Scene' self._session.set_mixer(self._mixer) self._session.set_shift_button(self._shift_button) self._session.set_clip_slot_buttons(tuple(pads)) transport_view_modes = TransportViewModeSelector( transport, self._session, ffwd_button, rwd_button, loop_button) transport_view_modes.name = 'Transport_View_Modes' def _setup_device(self): self._encoders = [] for offset in range(8): self._encoders.append( PeekableEncoderElement( MIDI_CC_TYPE, 15, 17 + offset, Live.MidiMap.MapMode.relative_smooth_two_compliment)) self._encoders[-1].set_feedback_delay(-1) self._encoders[-1].add_value_listener(self._encoder_value, identify_sender=True) self._encoders[-1].name = 'Device_Control_' + str(offset) prev_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 14) next_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 15) prev_bank_button.name = 'Device_Bank_Down_Button' next_bank_button.name = 'Device_Bank_Up_Button' device = BestBankDeviceComponent() device.name = 'Device_Component' self.set_device_component(device) device.set_parameter_controls(tuple(self._encoders)) device.set_bank_nav_buttons(prev_bank_button, next_bank_button) self._device_bank_buttons = (prev_bank_button, next_bank_button) prev_bank_button.add_value_listener(self._device_bank_value) next_bank_button.add_value_listener(self._device_bank_value) self._inst_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 109) self._inst_button.name = 'Inst_Button' self._inst_button.add_value_listener(self._inst_value) self._device_navigation = DetailViewCntrlComponent() self._device_navigation.name = 'Device_Navigation_Component' def _setup_display(self): self._display = PhysicalDisplayElement(5, 1) self._display.name = 'Display' self._display.set_message_parts(SYSEX_START + (17, 1, 0, 0), (247, )) self._display_data_source = DisplayDataSource() self._display.segment(0).set_data_source(self._display_data_source) def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(self) self._show_current_track_name() def _shift_value(self, value): if not value in range(128): raise AssertionError self._shift_pressed = value > 0 for encoder in self._encoders: encoder.set_peek_mode(self._shift_pressed) self._shift_pressed and self._mixer.set_select_buttons(None, None) self._session.set_track_bank_buttons(self._next_nav_button, self._prev_nav_button) self._device_component.set_bank_nav_buttons(None, None) self._device_navigation.set_device_nav_buttons( self._device_bank_buttons[0], self._device_bank_buttons[1]) else: self._session.set_track_bank_buttons(None, None) self._mixer.set_select_buttons(self._next_nav_button, self._prev_nav_button) self._device_navigation.set_device_nav_buttons(None, None) self._device_component.set_bank_nav_buttons( self._device_bank_buttons[0], self._device_bank_buttons[1]) self.request_rebuild_midi_map() def _encoder_value(self, value, sender): if not sender in self._encoders: raise AssertionError if not value in range(128): raise AssertionError display_string = self._device_component.is_enabled() and ' - ' display_string = sender.mapped_parameter( ) != None and sender.mapped_parameter().name self._display_data_source.set_display_string(display_string) self._set_display_data_source(self._display_data_source) self._display_reset_delay = STANDARD_DISPLAY_DELAY def _slider_value(self, value, sender): if not sender in tuple(self._sliders) + (self._master_slider, ): raise AssertionError if not value in range(128): raise AssertionError if self._mixer.is_enabled(): display_string = ' - ' if sender.mapped_parameter() != None: master = self.song().master_track tracks = self.song().tracks returns = self.song().return_tracks track = None if sender == self._master_slider: track = self._has_sliders and master else: track = self.song().view.selected_track else: track = self._mixer.channel_strip( self._sliders.index(sender))._track display_string = track == master and 'Ma' elif track in tracks: display_string = str(list(tracks).index(track) + 1) elif track in returns: display_string = str( chr(ord('A') + list(returns).index(track))) else: raise False or AssertionError display_string += ' Vol' self._display_data_source.set_display_string(display_string) self._set_display_data_source(self._display_data_source) self._display_reset_delay = STANDARD_DISPLAY_DELAY def _mixer_button_value(self, value, sender): if not sender in tuple( self._strip_buttons) + (self._selected_mute_solo_button, ): raise AssertionError if not value in range(128): raise AssertionError if self._mixer.is_enabled() and value > 0: strip = None strip = sender == self._selected_mute_solo_button and self._mixer.selected_strip( ) else: strip = self._mixer.channel_strip( self._strip_buttons.index(sender)) strip != None and self._set_display_data_source( strip.track_name_data_source()) else: self._display_data_source.set_display_string(' - ') self._set_display_data_source(self._display_data_source) self._display_reset_delay = STANDARD_DISPLAY_DELAY def _device_bank_value(self, value): if not value in range(128): raise AssertionError if self._device_component.is_enabled() and value > 0: data_source = self._device_component.bank_name_data_source() data_source = self._shift_pressed and self._device_component.device_name_data_source( ) self._set_display_data_source(data_source) self._display_reset_delay = STANDARD_DISPLAY_DELAY def _inst_value(self, value): if not value in range(128): raise AssertionError value > 0 and self._device_component.is_enabled() and self.song( ).view.selected_track.view.select_instrument( ) and self._set_display_data_source( self._device_component.device_name_data_source()) self._display_reset_delay = STANDARD_DISPLAY_DELAY def _show_current_track_name(self): if self._display != None and self._mixer != None: self._set_display_data_source( self._mixer.selected_strip().track_name_data_source()) def _show_startup_message(self): self._display.display_message('LIVE') self._display_reset_delay = INITIAL_DISPLAY_DELAY def _set_display_data_source(self, data_source): raise isinstance(data_source, DisplayDataSource) or AssertionError self._display.segment(0).set_data_source(data_source) data_source.update()
class MainKnobControl: __module__ = __name__ __doc__ = 'Mk2 Module for Controlling Parameters with Master Knob' def __init__(self, parent): self._parent = parent self.master_track = parent.song().master_track self.the_slider = SliderElement(MIDI_CC_TYPE, 1, 86) self.the_slider.add_value_listener(self._do_main_slider, True) self.volume_button = None self._set_volume_button(StateButton(True, MIDI_CC_TYPE, 1, 80)) self.xfade_button = None self._set_xfade_button(StateButton(True, MIDI_CC_TYPE, 1, 99)) self.swing_button = None self._set_swing_button(StateButton(True, MIDI_CC_TYPE, 1, 81)) self.mode = KN2_MODE_VOLUME self.previous_mode = -1 self.tempo_button = None self._set_tempo_button(StateButton(True, MIDI_CC_TYPE, 1, 82)) self.push_button = None self._set_push_button(StateButton(True, MIDI_CC_TYPE, 1, 87)) self.clipn_v_button = None self.clipn_h_button = None self._set_clipn_h_button(StateButton(True, MIDI_CC_TYPE, 1, 90)) self._set_clipn_v_button(StateButton(True, MIDI_CC_TYPE, 1, 91)) self.toggle_buttons = [self.volume_button, self.xfade_button, self.swing_button, self.tempo_button, self.clipn_h_button, self.clipn_v_button] self.shift_button = None self._set_shift_button(StateButton(True, MIDI_CC_TYPE, 1, 85)) self.shift_on = False self.scroll_mod_left_button = None self.scroll_mod_right_button = None self._set_scroll_mod_left_button(ButtonElement(True, MIDI_CC_TYPE, 0, 105)) self._set_scroll_mod_right_button(ButtonElement(True, MIDI_CC_TYPE, 0, 106)) self._prev_mode = KN2_MODE_VOLUME self.lrmode = LR_CONTROL_CLIP self.loop_div_index = 0 self.loop_incdex = 4.0 self.arrow_mode_button = ColorButton(True, MIDI_CC_TYPE, 30) self.arrow_mode_button.add_value_listener(self.toggle_arrow_mode) self.arrow_mode_button.send_value(1, True) self.navflags = 0 self.octave_mod_button = ButtonElement(True, MIDI_CC_TYPE, 1, 70) self.octave_mod_button.add_value_listener(self._action_octave) self.scale_mod_button = ButtonElement(True, MIDI_CC_TYPE, 1, 71) self.scale_mod_button.add_value_listener(self._action_scale) self.basenote_mod_button = ButtonElement(True, MIDI_CC_TYPE, 1, 72) self.basenote_mod_button.add_value_listener(self._action_base_note) self.pad_to_mainknob_mode = 0 self.octave_dwn_button = ButtonElement(True, MIDI_CC_TYPE, 3, 120) self.octave_upp_button = ButtonElement(True, MIDI_CC_TYPE, 3, 121) self.scale_dwn_button = ButtonElement(True, MIDI_CC_TYPE, 3, 118) self.scale_upp_button = ButtonElement(True, MIDI_CC_TYPE, 3, 119) self.basent_dwn_button = ButtonElement(True, MIDI_CC_TYPE, 3, 124) self.basent_upp_button = ButtonElement(True, MIDI_CC_TYPE, 3, 125) self.octave_dwn_button.add_value_listener(self._action_oct_down) self.octave_upp_button.add_value_listener(self._action_oct_up) self.scale_dwn_button.add_value_listener(self._action_scale_down) self.scale_upp_button.add_value_listener(self._action_scale_up) self.basent_dwn_button.add_value_listener(self._action_base_down) self.basent_upp_button.add_value_listener(self._action_base_up) self._measure_left_click = 0 self._measure_right_click = 0 self.mode_assign_map = {KN2_MODE_VOLUME: (self.chg_volume, 0, 'Master Knob controls MASTER Volume', KN2_MODE_CUE), KN2_MODE_CUE: (self.chg_cue, 0, 'Master Knob controls Cue Level', KN2_MODE_VOLUME), KN2_MODE_TEMPO_COARSE: (self.chg_tempo, 3, 'Master Knob controls TEMPO Coarse', KN2_MODE_TEMPO_FINE), KN2_MODE_TEMPO_FINE: (self.chg_tempo_fine, 3, 'Master Knob controls TEMPO Fine', KN2_MODE_TEMPO_COARSE), KN2_MODE_XFADE: (self.chg_xfade, 1, 'Master Knob controls Crossfader', -1), KN2_MODE_QUANT: (self.chg_quant, 2, 'Master Knob controls Recording Quantize', KN2_MODE_CLIP_QUANT), KN2_MODE_CLIP_QUANT: (self.chg_clip_q, 2, 'Master Knob controls Clip Start Quantize', KN2_MODE_QUANT), KN2_MODE_CLIPN_HOR: (self.nav_c_hor, 4, 'Master Knob Clip View horizontally', -1), KN2_MODE_CLIPN_VER: (self.nav_c_ver, 5, 'Master Knob Clip View vertically', -1), KN2_MODE_GENERAL: (self.chg_general, -1, None, -1), KN2_P_SCALES: (self.modify_pad_scaling, -1, None, -1)} def start_up(self): self._set_mode(KN2_MODE_VOLUME) self.arrow_mode_button.send_value(127, True) def toggle_arrow_mode(self, value): if value > 0: self.lrmode = (self.lrmode + 1) % 4 self.arrow_mode_button.send_hue(LR_MODE_HUES[self.lrmode]) self._parent.show_message('Left/Right Buttons Control: ' + L_MODE_FUNCTION[self.lrmode] + ' / ' + R_MODE_FUNCTION[self.lrmode]) def switch_to_matrix_mode(self): if self.mode != KN2_MODE_GENERAL: self.previous_mode = self.mode self._set_mode(KN2_MODE_GENERAL) def exit_matrix_mode(self): if self.mode == KN2_MODE_GENERAL: self._set_mode(self.previous_mode) self.previous_mode = -1 def update_shift(self): if self.shift_on: self.shift_button.send_value(127, True) else: self.shift_button.send_value(0, True) def _set_mode(self, mode): if not mode in range(11): raise AssertionError self.update_shift() if mode == self.mode: return self._prev_mode = mode self.mode = mode self.switch_radio_buttons(self.mode_assign_map[self.mode][1]) message = self.mode_assign_map[self.mode][2] message != None and self._parent.show_message(message) def switch_radio_buttons(self, which): for index in range(len(self.toggle_buttons)): if index == which: self.toggle_buttons[index].send_value(127, True) else: self.toggle_buttons[index].send_value(0, True) def update(self): self.switch_radio_buttons(self.mode_assign_map[self.mode][1]) self.arrow_mode_button.send_color(LR_MODE_HUES[self.lrmode]) self.arrow_mode_button.send_value(127, True) def _do_main_slider(self, value, encoder): if not value in range(128): raise AssertionError if not isinstance(encoder, EncoderElement): raise AssertionError if value == 1: delta = 1 else: delta = -1 if self.pad_to_mainknob_mode != 0: self.mode_assign_map[KN2_P_SCALES][0](delta) elif self.navflags == 0: self.mode_assign_map[self.mode][0](delta) if self.lrmode == LR_CONTROL_CLIP: self.navflags & LEFT_DOWN != 0 and self.nav_c_hor(delta) self.navflags & RIGHT_DOWN != 0 and self.nav_c_ver(delta) elif self.lrmode == LR_CONTROL_SEL: if self.navflags & LEFT_DOWN != 0: self.nav_track(delta) if self.navflags & RIGHT_DOWN != 0: self._parent.scroll_scene(delta) elif self.lrmode == LR_CONTROL_DEV: if self.navflags & LEFT_DOWN != 0: self.nav_track(delta) if self.navflags & RIGHT_DOWN != 0: self._parent.scroll_device(delta) elif self.lrmode == LR_CONTROL_LOOP: if self.navflags & LEFT_DOWN != 0: self.adjust_loop_start(delta) if self.navflags & RIGHT_DOWN != 0: self.adjust_loop_length(delta) def modify_pad_scaling(self, delta): if self.pad_to_mainknob_mode & PAD_KNOB_OCTAVE != 0: self._parent.inc_octave(delta) if self.pad_to_mainknob_mode & PAD_KNOB_SCALE != 0: self._parent.inc_scale(delta) if self.pad_to_mainknob_mode & PAD_KNOB_BASEN != 0: self._parent.inc_base_note(delta) def adjust_loop_start(self, delta): loopval = self._parent.song().loop_start loopval += self.loop_incdex * delta if loopval < 0: loopval = 0 elif loopval > 999: loopval = 999 self._parent.song().loop_start = loopval def adjust_loop_length(self, delta): loopval = self._parent.song().loop_length loopval += self.loop_incdex * delta if loopval < self.loop_incdex: loopval = self.loop_incdex elif loopval > 999: loopval = 999 self._parent.song().loop_length = loopval def chg_general(self, delta): self._parent._scenematrix.control_handler.mod_value(delta, self.shift_on) def nav_track(self, direction): if direction == 1: self._parent._a_trk_right(1) else: self._parent._a_trk_left(1) def nav_c_hor(self, direction): self._parent.move_view_horizontal(direction) def nav_c_ver(self, direction): if direction == 1: self._parent._session.bank_up() else: self._parent._session.bank_down() def chg_volume(self, diff): if self.shift_on: self.repeat(self.master_track.mixer_device.volume, diff) else: self.master_track.mixer_device.volume.value = self.calc_new_parm(self.master_track.mixer_device.volume, diff) def chg_xfade(self, diff): if self.shift_on: self.repeat(self.master_track.mixer_device.crossfader, diff) else: self.master_track.mixer_device.crossfader.value = self.calc_new_parm(self.master_track.mixer_device.crossfader, diff) def chg_cue(self, diff): if self.shift_on: self.repeat(self.master_track.mixer_device.cue_volume, diff) else: self.master_track.mixer_device.cue_volume.value = self.calc_new_parm(self.master_track.mixer_device.cue_volume, diff) def repeat(self, parm, delta): count = 0 while count < SHIFT_INC: parm.value = self.calc_new_parm(parm, delta) count += 1 def calc_new_parm(self, parm, delta): parm_range = parm.max - parm.min int_val = int((parm.value - parm.min) / parm_range * PARM_RANGE + 0.1) inc_val = min(PARM_RANGE, max(0, int_val + delta)) return float(inc_val) / float(PARM_RANGE) * parm_range + parm.min def chg_quant(self, diff): rec_quant = self._parent.song().midi_recording_quantization index = self.get_quant_index(rec_quant) new_index = index + diff if new_index >= 0 and new_index < len(QUANT_CONST): self._parent.song().midi_recording_quantization = QUANT_CONST[new_index] self._parent.show_message(QUANT_DESCR[new_index]) def chg_clip_q(self, diff): quant = self._parent.song().clip_trigger_quantization self._parent.song().clip_trigger_quantization = max(0, min(13, quant + diff)) self._parent.show_message('Clip Quantize ' + CLIQ_DESCR[self._parent.song().clip_trigger_quantization]) def chg_tempo_fine(self, diff): if diff < 0: amount = -0.01 else: amount = 0.01 self.chg_tempo(amount) def chg_tempo(self, diff): self._parent.song().tempo = max(20, min(999, self._parent.song().tempo + diff)) def get_quant_index(self, const): for index in range(len(QUANT_CONST)): if const == QUANT_CONST[index]: return index return -1 def _action_octave(self, value): if value != 0: self.pad_to_mainknob_mode |= PAD_KNOB_OCTAVE else: self.pad_to_mainknob_mode &= ~PAD_KNOB_OCTAVE def _action_scale(self, value): if value != 0: self.pad_to_mainknob_mode |= PAD_KNOB_SCALE else: self.pad_to_mainknob_mode &= ~PAD_KNOB_SCALE def _action_base_note(self, value): if value != 0: self.pad_to_mainknob_mode |= PAD_KNOB_BASEN else: self.pad_to_mainknob_mode &= ~PAD_KNOB_BASEN def _set_volume_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.volume_button != None: self.volume_button.remove_value_listener(self._action_volume) self.volume_button = button self.volume_button != None and self.volume_button.add_value_listener(self._action_volume) def _action_volume(self, value): if not self.volume_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_VOLUME and self._set_mode(KN2_MODE_VOLUME) def _set_xfade_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.xfade_button != None: self.xfade_button.remove_value_listener(self._action_xfade) self.xfade_button = button self.xfade_button != None and self.xfade_button.add_value_listener(self._action_xfade) def _action_xfade(self, value): if not self.xfade_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_XFADE and self._set_mode(KN2_MODE_XFADE) def _set_swing_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.swing_button != None: self.swing_button.remove_value_listener(self._action_swing) self.swing_button = button self.swing_button != None and self.swing_button.add_value_listener(self._action_swing) def _action_swing(self, value): if not self.swing_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_QUANT and self._set_mode(KN2_MODE_QUANT) def _set_tempo_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.tempo_button != None: self.tempo_button.remove_value_listener(self._action_tempo) self.tempo_button = button self.tempo_button != None and self.tempo_button.add_value_listener(self._action_tempo) def _action_tempo(self, value): if not self.tempo_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_TEMPO_COARSE and self._set_mode(KN2_MODE_TEMPO_COARSE) def _set_clipn_h_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.clipn_h_button != None: self.clipn_h_button.remove_value_listener(self._action_clipnh) self.clipn_h_button = button self.clipn_h_button != None and self.clipn_h_button.add_value_listener(self._action_clipnh) def _action_clipnh(self, value): if not self.clipn_h_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_CLIPN_HOR and self._set_mode(KN2_MODE_CLIPN_HOR) def _set_clipn_v_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.clipn_v_button != None: self.clipn_v_button.remove_value_listener(self._action_clipnv) self.clipn_v_button = button self.clipn_v_button != None and self.clipn_v_button.add_value_listener(self._action_clipnv) def _action_clipnv(self, value): if not self.clipn_v_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_CLIPN_VER and self._set_mode(KN2_MODE_CLIPN_VER) def _set_shift_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.shift_button != None: self.shift_button.remove_value_listener(self._action_shift) self.shift_button = button self.shift_button != None and self.shift_button.add_value_listener(self._action_shift) def _action_shift(self, value): if not self.shift_button != None: raise AssertionError raise value in range(128) or AssertionError self.shift_on = value != 0 and not self.shift_on self.update_shift() def _set_scroll_mod_left_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.scroll_mod_left_button != None: self.scroll_mod_left_button.remove_value_listener(self._action_scroll_left) self.scroll_mod_left_button = button self.scroll_mod_left_button != None and self.scroll_mod_left_button.add_value_listener(self._action_scroll_left) def _set_scroll_mod_right_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.scroll_mod_right_button != None: self.scroll_mod_right_button.remove_value_listener(self._action_scroll_right) self.scroll_mod_right_button = button self.scroll_mod_right_button != None and self.scroll_mod_right_button.add_value_listener(self._action_scroll_right) def _action_scroll_left(self, value): if not self.scroll_mod_left_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.scroll_mod_left_button.send_value(127, True) self.navflags |= LEFT_DOWN self._measure_left_click = int(round(time.time() * 1000)) else: self.scroll_mod_left_button.send_value(0, True) self.navflags &= ~LEFT_DOWN clicktime = int(round(time.time() * 1000)) - self._measure_left_click if clicktime < CLICK_TIME: if self._parent._modifier_down: self._parent.modify_track_offset(-1) elif self._parent._mode == PAD_MODE: self._do_lr_as_scale_mode(-1) elif self._parent._mode == SCENE_MODE: self._parent.modify_scene_offset(-1) elif self._parent._mode == CLIP_MODE: self._parent.move_view_horizontal(-1) elif self._parent._mode == CONTROL_MODE: self._parent.move_view_horizontal(-1) def _action_scroll_right(self, value): if not self.scroll_mod_right_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.scroll_mod_right_button.send_value(1) self.navflags |= RIGHT_DOWN self._measure_right_click = int(round(time.time() * 1000)) else: self.scroll_mod_right_button.send_value(0, True) self.navflags &= ~RIGHT_DOWN clicktime = int(round(time.time() * 1000)) - self._measure_right_click if clicktime < CLICK_TIME: if self._parent._modifier_down: self._parent.modify_track_offset(1) elif self._parent._mode == PAD_MODE: self._do_lr_as_scale_mode(1) elif self._parent._mode == SCENE_MODE: self._parent.modify_scene_offset(1) elif self._parent._mode == CLIP_MODE: self._parent.move_view_horizontal(1) elif self._parent._mode == CONTROL_MODE: self._parent.move_view_horizontal(1) def _do_lr_as_scale_mode(self, delta): if self.pad_to_mainknob_mode == PAD_KNOB_SCALE: self._parent.inc_scale(delta) elif self.pad_to_mainknob_mode == PAD_KNOB_BASEN: self._parent.inc_base_note(delta) else: self._parent.inc_octave(delta) def _action_oct_down(self, value): if value != 0: self._parent.inc_octave(-1) def _action_oct_up(self, value): if value != 0: self._parent.inc_octave(1) def _action_scale_down(self, value): if value != 0: self._parent.inc_scale(-1) def _action_scale_up(self, value): if value != 0: self._parent.inc_scale(1) def _action_base_down(self, value): if value != 0: self._parent.inc_base_note(-1) def _action_base_up(self, value): if value != 0: self._parent.inc_base_note(1) def _set_push_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.push_button != None: self.push_button.remove_value_listener(self._action_push) self.push_button = button self.push_button != None and self.push_button.add_value_listener(self._action_push) def _action_push(self, value): if not self.push_button != None: raise AssertionError if not value in range(128): raise AssertionError next_mode = self.mode_assign_map[self.mode][3] next_mode != -1 and self._set_mode(next_mode) self.loop_div_index = self.lrmode == LR_CONTROL_LOOP and self.navflags != 0 and (self.loop_div_index + 1) % len(LOOP_KNOB_DIVISION) self._parent.show_message('Loop Selection Granularity : ' + str(LOOP_KNOB_DIVISION[self.loop_div_index]) + ' beats ') self.loop_incdex = LOOP_KNOB_DIVISION[self.loop_div_index] def remove_listener(self, control, callback): if control != None and control.value_has_listener(callback): control.remove_value_listener(callback) control.disconnect() def disconnect(self): self.remove_listener(self.the_slider, self._do_main_slider) self.remove_listener(self.arrow_mode_button, self.toggle_arrow_mode) self.remove_listener(self.volume_button, self._action_volume) self.remove_listener(self.xfade_button, self._action_xfade) self.remove_listener(self.swing_button, self._action_swing) self.remove_listener(self.clipn_h_button, self._action_clipnh) self.remove_listener(self.clipn_v_button, self._action_clipnv) self.remove_listener(self.shift_button, self._action_shift) self.remove_listener(self.scroll_mod_left_button, self._action_scroll_left) self.remove_listener(self.scroll_mod_right_button, self._action_scroll_right) self.remove_listener(self.push_button, self._action_push) self.remove_listener(self.octave_mod_button, self._action_octave) self.remove_listener(self.scale_mod_button, self._action_scale) self.remove_listener(self.basenote_mod_button, self._action_base_note) self.remove_listener(self.octave_dwn_button, self._action_oct_down) self.remove_listener(self.octave_upp_button, self._action_oct_up) self.remove_listener(self.scale_dwn_button, self._action_scale_down) self.remove_listener(self.scale_upp_button, self._action_scale_up) self.remove_listener(self.basent_dwn_button, self._action_base_down) self.remove_listener(self.basent_upp_button, self._action_base_up) self._parent = None self.master_track = None self.the_slider = None self.mode_assign_map = None
def _setup_custom_controls(self): is_momentary = True select_buttons = [] encoders = [] for track in range(8): select_buttons.append(ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, select_buttons_ccs[track])) show_pot_values_button = ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, SHOW_POT_VALUES_BUTTON) for index in range(8): encoder_led_mode_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, encoder_led_mode_ccs[index]) encoder_feedback = EncoderElement(MIDI_CC_TYPE, MIDI_CHANNEL, encoder_feedback_ccs[index], Live.MidiMap.MapMode.absolute) ringed_encoder = SLEncoder(MIDI_CC_TYPE, MIDI_CHANNEL, encoder_row_ccs[index], Live.MidiMap.MapMode.relative_smooth_signed_bit) ringed_encoder.add_value_listener(self._mixer.encoder_moved) ringed_encoder.set_ring_mode_button(encoder_led_mode_button) ringed_encoder.set_led_ring_feedback(encoder_feedback) ringed_encoder.name = 'Device_Control_' + str(index) encoder_led_mode_button.name = ringed_encoder.name + '_Ring_Mode_Button' encoders.append(ringed_encoder) self._encoders = encoders self._device = SLDevice(self._mixer, self._display) self._device.name = 'Device_Component' self._device.set_parameter_controls(tuple(encoders)) self.set_device_component(self._device) self._mixer._device = self._device p1_buttons = [] p1_buttons.append(ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, P1_UP)) p1_buttons.append(ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, P1_DOWN)) self._encoder_modes = SLEncoderModeSelector(self._mixer, self._device, tuple(encoders)) self._encoder_modes.name = 'encoder_modes' self._encoder_modes.set_controls_to_translate(tuple(encoders)) #==== OLD MODES #mute_buttons = [ ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, mute_buttons_ccs[index]) for index in range(8) ] #mute_mode_button = ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, MUTE_MODE_BUTTON) #self._mute_mode = SLMuteModeSelector(mute_mode_button, tuple(mute_buttons), self._mixer) #solo_buttons = [ ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, solo_buttons_ccs[index]) for index in range(8) ] #ts_buttons = [ ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, ts_ccs[index]) for index in range(6) ] #solo_mode_button = ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, SOLO_MODE_BUTTON) #ts_lock_button = ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, TS_LOCK) #self._transport = SLTransport(self, self._display) #self._transport.name = 'Transport' #self._transport_mode = SLTransportModeSelector(ts_lock_button, tuple(ts_buttons), solo_mode_button, solo_buttons, self._transport, self._mixer) #==== NEW MODES mx_first_buttons = [ ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, mute_buttons_ccs[index]) for index in range(8) ] mx_first_row_select = ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, MUTE_MODE_BUTTON) mx_second_buttons = [ ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, solo_buttons_ccs[index]) for index in range(8) ] mx_second_row_select = ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, SOLO_MODE_BUTTON) for index in range(6): self._ts_buttons.append(ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, ts_ccs[index])) ts_lock_button = SLSpecialButton(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, TS_LOCK) self._transport = SLTransport(self, self._display) self._transport.name = 'Transport' self._button_modes = SLButtonModeSelector(self._mixer, self._session, mx_first_buttons, mx_second_buttons, self._transport, ts_lock_button, self._ts_buttons) #self._button_modes.set_mode_buttons((mx_first_row_select, mx_second_row_select)) #self._button_modes.set_mode_toggle(mx_first_row_select) #--- SLSessionModeSelector TEST --------------------- for index in range(8): self._clip_launch_buttons.append(ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, clip_launch_buttons_ccs[index])) #session_modes = SLSessionModeSelector(self._session, self._mixer, self._scene_launch_button, tuple(self._clip_launch_buttons)) #session_modes.set_mode_toggle(self._clip_launch_buttons[7]) #session_modes.set_enabled(0) pots = [] for index in range(8): pot = SliderElement(MIDI_CC_TYPE, MIDI_CHANNEL, pot_row_ccs[index]) pot.add_value_listener(self._mixer.pot_moved) pots.append(pot) self._pot_modes = SLPotModeSelector(self._mixer, tuple(pots)) self._pot_modes.set_controls_to_translate(tuple(pots)) self._pot_modes.name = 'pot_modes' self._mixer._pots = tuple(pots) #---------------------------------------------------- self._device_control = SLDeviceControl(self._device, self._display) self._shift_mode = SLShiftableSelector(tuple(select_buttons), show_pot_values_button, tuple(p1_buttons), self._scene_up_button, self._scene_down_button, self._scene_launch_button, self._session, self._mixer, self._encoder_modes, self._device, self._device_control, tuple(self._clip_launch_buttons), self._pot_modes) self._shift_mode.name = 'Shift_Modes' self._shift_mode.set_mode_toggle(self._shift_button) sliders = [] for track in range(8): slider = SliderElement(MIDI_CC_TYPE, MIDI_CHANNEL, slider_row_ccs[track]) slider.add_value_listener(self._mixer.slider_moved) sliders.append(slider) sliders[-1].name = str(track) + '_Volume_Control' mx_slider_row_select = ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, SLIDER_MODE_BUTTON) self.master_mode = SLMasterModeSelector(self._mixer, self._session, tuple(sliders), self._button_modes, self._shift_mode, self._encoder_modes, self._pot_modes) self.master_mode.set_controls_to_translate(tuple(sliders)) self.master_mode.name = 'Master_Mode' self._right_shift = SLRightShiftSelector(self._mixer, self._session, self._transport, self.master_mode, mx_slider_row_select, self._button_modes, mx_first_row_select) self._right_shift.name = 'Right_Shift_Mode' self._right_shift.set_mode_toggle(mx_second_row_select) self._transport.set_shift_button(mx_second_row_select) self._session.set_shift_button(mx_second_row_select) self._session.set_track_bank_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, P2_UP), ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, P2_DOWN)) for index in range(8): strip = self._mixer.channel_strip(index) strip.set_shift_button(mx_second_row_select)
def _setup_custom_controls(self): is_momentary = True select_buttons = [] encoders = [] for track in range(8): select_buttons.append( ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, select_buttons_ccs[track])) show_pot_values_button = ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, SHOW_POT_VALUES_BUTTON) for index in range(8): encoder_led_mode_button = ButtonElement( not is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, encoder_led_mode_ccs[index]) encoder_feedback = EncoderElement(MIDI_CC_TYPE, MIDI_CHANNEL, encoder_feedback_ccs[index], Live.MidiMap.MapMode.absolute) ringed_encoder = SLEncoder( MIDI_CC_TYPE, MIDI_CHANNEL, encoder_row_ccs[index], Live.MidiMap.MapMode.relative_smooth_signed_bit) ringed_encoder.add_value_listener(self._mixer.encoder_moved) ringed_encoder.set_ring_mode_button(encoder_led_mode_button) ringed_encoder.set_led_ring_feedback(encoder_feedback) ringed_encoder.name = 'Device_Control_' + str(index) encoder_led_mode_button.name = ringed_encoder.name + '_Ring_Mode_Button' encoders.append(ringed_encoder) self._encoders = encoders self._device = SLDevice(self._mixer, self._display) self._device.name = 'Device_Component' self._device.set_parameter_controls(tuple(encoders)) self.set_device_component(self._device) self._mixer._device = self._device self._device_appointer = DeviceAppointer( song=self.song(), appointed_device_setter=self._set_appointed_device) p1_buttons = [] p1_buttons.append( ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, P1_UP)) p1_buttons.append( ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, P1_DOWN)) self._encoder_modes = SLEncoderModeSelector(self._mixer, self._device, tuple(encoders)) self._encoder_modes.name = 'encoder_modes' self._encoder_modes.set_controls_to_translate(tuple(encoders)) #==== OLD MODES #mute_buttons = [ ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, mute_buttons_ccs[index]) for index in range(8) ] #mute_mode_button = ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, MUTE_MODE_BUTTON) #self._mute_mode = SLMuteModeSelector(mute_mode_button, tuple(mute_buttons), self._mixer) #solo_buttons = [ ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, solo_buttons_ccs[index]) for index in range(8) ] #ts_buttons = [ ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, ts_ccs[index]) for index in range(6) ] #solo_mode_button = ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, SOLO_MODE_BUTTON) #ts_lock_button = ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, TS_LOCK) #self._transport = SLTransport(self, self._display) #self._transport.name = 'Transport' #self._transport_mode = SLTransportModeSelector(ts_lock_button, tuple(ts_buttons), solo_mode_button, solo_buttons, self._transport, self._mixer) #==== NEW MODES mx_first_buttons = [ ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, mute_buttons_ccs[index]) for index in range(8) ] mx_first_row_select = ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, MUTE_MODE_BUTTON) mx_second_buttons = [ ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, solo_buttons_ccs[index]) for index in range(8) ] mx_second_row_select = ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, SOLO_MODE_BUTTON) for index in range(6): self._ts_buttons.append( ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, ts_ccs[index])) ts_lock_button = SLSpecialButton(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, TS_LOCK) self._transport = SLTransport(self, self._display) self._transport.name = 'Transport' self._button_modes = SLButtonModeSelector( self._mixer, self._session, mx_first_buttons, mx_second_buttons, self._transport, ts_lock_button, self._ts_buttons) #self._button_modes.set_mode_buttons((mx_first_row_select, mx_second_row_select)) #self._button_modes.set_mode_toggle(mx_first_row_select) #--- SLSessionModeSelector TEST --------------------- for index in range(8): self._clip_launch_buttons.append( ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, clip_launch_buttons_ccs[index])) #session_modes = SLSessionModeSelector(self._session, self._mixer, self._scene_launch_button, tuple(self._clip_launch_buttons)) #session_modes.set_mode_toggle(self._clip_launch_buttons[7]) #session_modes.set_enabled(0) pots = [] for index in range(8): pot = SliderElement(MIDI_CC_TYPE, MIDI_CHANNEL, pot_row_ccs[index]) pot.add_value_listener(self._mixer.pot_moved) pots.append(pot) self._pot_modes = SLPotModeSelector(self._mixer, tuple(pots)) self._pot_modes.set_controls_to_translate(tuple(pots)) self._pot_modes.name = 'pot_modes' self._mixer._pots = tuple(pots) #---------------------------------------------------- self._device_control = SLDeviceControl(self._device, self._display) self._shift_mode = SLShiftableSelector( tuple(select_buttons), show_pot_values_button, tuple(p1_buttons), self._scene_up_button, self._scene_down_button, self._scene_launch_button, self._session, self._mixer, self._encoder_modes, self._device, self._device_control, tuple(self._clip_launch_buttons), self._pot_modes) self._shift_mode.name = 'Shift_Modes' self._shift_mode.set_mode_toggle(self._shift_button) sliders = [] for track in range(8): slider = SliderElement(MIDI_CC_TYPE, MIDI_CHANNEL, slider_row_ccs[track]) slider.add_value_listener(self._mixer.slider_moved) sliders.append(slider) sliders[-1].name = str(track) + '_Volume_Control' mx_slider_row_select = ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, SLIDER_MODE_BUTTON) self.master_mode = SLMasterModeSelector(self._mixer, self._session, tuple(sliders), self._button_modes, self._shift_mode, self._encoder_modes, self._pot_modes) self.master_mode.set_controls_to_translate(tuple(sliders)) self.master_mode.name = 'Master_Mode' self._right_shift = SLRightShiftSelector( self._mixer, self._session, self._transport, self.master_mode, mx_slider_row_select, self._button_modes, mx_first_row_select) self._right_shift.name = 'Right_Shift_Mode' self._right_shift.set_mode_toggle(mx_second_row_select) self._transport.set_shift_button(mx_second_row_select) self._session.set_shift_button(mx_second_row_select) self._session.set_track_bank_buttons( ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, P2_UP), ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, P2_DOWN)) for index in range(8): strip = self._mixer.channel_strip(index) strip.set_shift_button(mx_second_row_select)
class MainKnobControl: __module__ = __name__ __doc__ = 'Mk2 Module for Controlling Parameters with Master Knob' def __init__(self, parent): self._parent = parent self.master_track = parent.song().master_track self.the_slider = SliderElement(MIDI_CC_TYPE, 1, 86) self.the_slider.add_value_listener(self._do_main_slider, True) self.volume_button = None self._set_volume_button(ButtonElement(True, MIDI_CC_TYPE, 1, 80)) self.xfade_button = None self._set_xfade_button(ButtonElement(True, MIDI_CC_TYPE, 1, 99)) self.swing_button = None self._set_swing_button(ButtonElement(True, MIDI_CC_TYPE, 1, 81)) self.mode = KN2_MODE_VOLUME self.previous_mode = -1 self.tempo_button = None self._set_tempo_button(ButtonElement(True, MIDI_CC_TYPE, 1, 82)) self.push_button = None self._set_push_button(ButtonElement(True, MIDI_CC_TYPE, 1, 87)) self.clipn_v_button = None self.clipn_h_button = None self._set_clipn_h_button(ButtonElement(True, MIDI_CC_TYPE, 1, 90)) self._set_clipn_v_button(ButtonElement(True, MIDI_CC_TYPE, 1, 91)) self.toggle_buttons = [self.volume_button, self.xfade_button, self.swing_button, self.tempo_button, self.clipn_h_button, self.clipn_v_button] self.shift_button = None self._set_shift_button(ButtonElement(True, MIDI_CC_TYPE, 1, 85)) self.shift_on = False self.scroll_mod_left_button = None self.scroll_mod_right_button = None self._set_scroll_mod_left_button(ButtonElement(True, MIDI_CC_TYPE, 0, 105)) self._set_scroll_mod_right_button(ButtonElement(True, MIDI_CC_TYPE, 0, 106)) self._prev_mode = KN2_MODE_VOLUME self.lrmode = LR_CONTROL_CLIP self.loop_div_index = 0 self.loop_incdex = 4.0 self.arrow_mode_button = ColorButton(True, MIDI_CC_TYPE, 30) self.arrow_mode_button.add_value_listener(self.toggle_arrow_mode) self.arrow_mode_button.send_color(LR_MODE_HUES[self.lrmode]) self.arrow_mode_button.send_value(1) self.navflags = 0 self.octave_mod_button = ButtonElement(True, MIDI_CC_TYPE, 1, 70) self.octave_mod_button.add_value_listener(self._action_octave) self.scale_mod_button = ButtonElement(True, MIDI_CC_TYPE, 1, 71) self.scale_mod_button.add_value_listener(self._action_scale) self.basenote_mod_button = ButtonElement(True, MIDI_CC_TYPE, 1, 72) self.basenote_mod_button.add_value_listener(self._action_base_note) self.pad_to_mainknob_mode = 0 self.octave_dwn_button = ButtonElement(True, MIDI_CC_TYPE, 3, 120) self.octave_upp_button = ButtonElement(True, MIDI_CC_TYPE, 3, 121) self.scale_dwn_button = ButtonElement(True, MIDI_CC_TYPE, 3, 118) self.scale_upp_button = ButtonElement(True, MIDI_CC_TYPE, 3, 119) self.basent_dwn_button = ButtonElement(True, MIDI_CC_TYPE, 3, 124) self.basent_upp_button = ButtonElement(True, MIDI_CC_TYPE, 3, 125) self.octave_dwn_button.add_value_listener(self._action_oct_down) self.octave_upp_button.add_value_listener(self._action_oct_up) self.scale_dwn_button.add_value_listener(self._action_scale_down) self.scale_upp_button.add_value_listener(self._action_scale_up) self.basent_dwn_button.add_value_listener(self._action_base_down) self.basent_upp_button.add_value_listener(self._action_base_up) self._measure_left_click = 0 self._measure_right_click = 0 self.mode_assign_map = {KN2_MODE_VOLUME: (self.chg_volume, 0, 'Master Knob controls MASTER Volume', KN2_MODE_CUE), KN2_MODE_CUE: (self.chg_cue, 0, 'Master Knob controls Cue Level', KN2_MODE_VOLUME), KN2_MODE_TEMPO_COARSE: (self.chg_tempo, 3, 'Master Knob controls TEMPO Coarse', KN2_MODE_TEMPO_FINE), KN2_MODE_TEMPO_FINE: (self.chg_tempo_fine, 3, 'Master Knob controls TEMPO Fine', KN2_MODE_TEMPO_COARSE), KN2_MODE_XFADE: (self.chg_xfade, 1, 'Master Knob controls Crossfader', -1), KN2_MODE_QUANT: (self.chg_quant, 2, 'Master Knob controls Recording Quantize', KN2_MODE_CLIP_QUANT), KN2_MODE_CLIP_QUANT: (self.chg_clip_q, 2, 'Master Knob controls Clip Start Quantize', KN2_MODE_QUANT), KN2_MODE_CLIPN_HOR: (self.nav_c_hor, 4, 'Master Knob Clip View horizontally', -1), KN2_MODE_CLIPN_VER: (self.nav_c_ver, 5, 'Master Knob Clip View vertically', -1), KN2_MODE_GENERAL: (self.chg_general, -1, None, -1), KN2_P_SCALES: (self.modify_pad_scaling, -1, None, -1)} def start_up(self): self._set_mode(KN2_MODE_VOLUME) self.arrow_mode_button.send_value(1) def toggle_arrow_mode(self, value): if value > 0: self.lrmode = (self.lrmode + 1) % 4 self.arrow_mode_button.send_hue(LR_MODE_HUES[self.lrmode]) self._parent.show_message('Left/Right Buttons Control: ' + L_MODE_FUNCTION[self.lrmode] + ' / ' + R_MODE_FUNCTION[self.lrmode]) def switch_to_matrix_mode(self): if self.mode != KN2_MODE_GENERAL: self.previous_mode = self.mode self._set_mode(KN2_MODE_GENERAL) def exit_matrix_mode(self): if self.mode == KN2_MODE_GENERAL: self._set_mode(self.previous_mode) self.previous_mode = -1 def update_shift(self): if self.shift_on: self.shift_button.send_value(1) else: self.shift_button.send_value(0) def _set_mode(self, mode): if not mode in range(11): raise AssertionError self.update_shift() if mode == self.mode: return self._prev_mode = mode self.mode = mode self.switch_radio_buttons(self.mode_assign_map[self.mode][1]) message = self.mode_assign_map[self.mode][2] message != None and self._parent.show_message(message) def switch_radio_buttons(self, which): for index in range(len(self.toggle_buttons)): if index == which: self.toggle_buttons[index].send_value(1) else: self.toggle_buttons[index].send_value(0) def update(self): self.switch_radio_buttons(self.mode_assign_map[self.mode][1]) self.arrow_mode_button.send_color(LR_MODE_HUES[self.lrmode]) self.arrow_mode_button.send_value(1) def _do_main_slider(self, value, encoder): if not value in range(128): raise AssertionError if not isinstance(encoder, EncoderElement): raise AssertionError if value == 1: delta = 1 else: delta = -1 if self.pad_to_mainknob_mode != 0: self.mode_assign_map[KN2_P_SCALES][0](delta) elif self.navflags == 0: self.mode_assign_map[self.mode][0](delta) if self.lrmode == LR_CONTROL_CLIP: self.navflags & LEFT_DOWN != 0 and self.nav_c_hor(delta) self.navflags & RIGHT_DOWN != 0 and self.nav_c_ver(delta) elif self.lrmode == LR_CONTROL_SEL: if self.navflags & LEFT_DOWN != 0: self.nav_track(delta) if self.navflags & RIGHT_DOWN != 0: self._parent.scroll_scene(delta) elif self.lrmode == LR_CONTROL_DEV: if self.navflags & LEFT_DOWN != 0: self.nav_track(delta) if self.navflags & RIGHT_DOWN != 0: self._parent.scroll_device(delta) elif self.lrmode == LR_CONTROL_LOOP: if self.navflags & LEFT_DOWN != 0: self.adjust_loop_start(delta) if self.navflags & RIGHT_DOWN != 0: self.adjust_loop_length(delta) def modify_pad_scaling(self, delta): if self.pad_to_mainknob_mode & PAD_KNOB_OCTAVE != 0: self._parent.inc_octave(delta) if self.pad_to_mainknob_mode & PAD_KNOB_SCALE != 0: self._parent.inc_scale(delta) if self.pad_to_mainknob_mode & PAD_KNOB_BASEN != 0: self._parent.inc_base_note(delta) def adjust_loop_start(self, delta): loopval = self._parent.song().loop_start loopval += self.loop_incdex * delta if loopval < 0: loopval = 0 elif loopval > 999: loopval = 999 self._parent.song().loop_start = loopval def adjust_loop_length(self, delta): loopval = self._parent.song().loop_length loopval += self.loop_incdex * delta if loopval < self.loop_incdex: loopval = self.loop_incdex elif loopval > 999: loopval = 999 self._parent.song().loop_length = loopval def chg_general(self, delta): self._parent._scenematrix.control_handler.mod_value(delta, self.shift_on) def nav_track(self, direction): if direction == 1: self._parent._a_trk_right(1) else: self._parent._a_trk_left(1) def nav_c_hor(self, direction): self._parent.move_view_horizontal(direction) def nav_c_ver(self, direction): if direction == 1: self._parent._session.bank_up() else: self._parent._session.bank_down() def chg_volume(self, diff): if self.shift_on: self.repeat(self.master_track.mixer_device.volume, diff) else: self.master_track.mixer_device.volume.value = self.calc_new_parm(self.master_track.mixer_device.volume, diff) def chg_xfade(self, diff): if self.shift_on: self.repeat(self.master_track.mixer_device.crossfader, diff) else: self.master_track.mixer_device.crossfader.value = self.calc_new_parm(self.master_track.mixer_device.crossfader, diff) def chg_cue(self, diff): if self.shift_on: self.repeat(self.master_track.mixer_device.cue_volume, diff) else: self.master_track.mixer_device.cue_volume.value = self.calc_new_parm(self.master_track.mixer_device.cue_volume, diff) def repeat(self, parm, delta): count = 0 while count < SHIFT_INC: parm.value = self.calc_new_parm(parm, delta) count += 1 def calc_new_parm(self, parm, delta): parm_range = parm.max - parm.min int_val = int((parm.value - parm.min) / parm_range * PARM_RANGE + 0.1) inc_val = min(PARM_RANGE, max(0, int_val + delta)) return float(inc_val) / float(PARM_RANGE) * parm_range + parm.min def chg_quant(self, diff): rec_quant = self._parent.song().midi_recording_quantization index = self.get_quant_index(rec_quant) new_index = index + diff if new_index >= 0 and new_index < len(QUANT_CONST): self._parent.song().midi_recording_quantization = QUANT_CONST[new_index] self._parent.show_message(QUANT_DESCR[new_index]) def chg_clip_q(self, diff): quant = self._parent.song().clip_trigger_quantization self._parent.song().clip_trigger_quantization = max(0, min(13, quant + diff)) self._parent.show_message('Clip Quantize ' + CLIQ_DESCR[self._parent.song().clip_trigger_quantization]) def chg_tempo_fine(self, diff): if diff < 0: amount = -0.01 else: amount = 0.01 self.chg_tempo(amount) def chg_tempo(self, diff): self._parent.song().tempo = max(20, min(999, self._parent.song().tempo + diff)) def get_quant_index(self, const): for index in range(len(QUANT_CONST)): if const == QUANT_CONST[index]: return index return -1 def _action_octave(self, value): if value != 0: self.pad_to_mainknob_mode |= PAD_KNOB_OCTAVE else: self.pad_to_mainknob_mode &= ~PAD_KNOB_OCTAVE def _action_scale(self, value): if value != 0: self.pad_to_mainknob_mode |= PAD_KNOB_SCALE else: self.pad_to_mainknob_mode &= ~PAD_KNOB_SCALE def _action_base_note(self, value): if value != 0: self.pad_to_mainknob_mode |= PAD_KNOB_BASEN else: self.pad_to_mainknob_mode &= ~PAD_KNOB_BASEN def _set_volume_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.volume_button != None: self.volume_button.remove_value_listener(self._action_volume) self.volume_button = button self.volume_button != None and self.volume_button.add_value_listener(self._action_volume) def _action_volume(self, value): if not self.volume_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_VOLUME and self._set_mode(KN2_MODE_VOLUME) def _set_xfade_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.xfade_button != None: self.xfade_button.remove_value_listener(self._action_xfade) self.xfade_button = button self.xfade_button != None and self.xfade_button.add_value_listener(self._action_xfade) def _action_xfade(self, value): if not self.xfade_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_XFADE and self._set_mode(KN2_MODE_XFADE) def _set_swing_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.swing_button != None: self.swing_button.remove_value_listener(self._action_swing) self.swing_button = button self.swing_button != None and self.swing_button.add_value_listener(self._action_swing) def _action_swing(self, value): if not self.swing_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_QUANT and self._set_mode(KN2_MODE_QUANT) def _set_tempo_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.tempo_button != None: self.tempo_button.remove_value_listener(self._action_tempo) self.tempo_button = button self.tempo_button != None and self.tempo_button.add_value_listener(self._action_tempo) def _action_tempo(self, value): if not self.tempo_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_TEMPO_COARSE and self._set_mode(KN2_MODE_TEMPO_COARSE) def _set_clipn_h_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.clipn_h_button != None: self.clipn_h_button.remove_value_listener(self._action_clipnh) self.clipn_h_button = button self.clipn_h_button != None and self.clipn_h_button.add_value_listener(self._action_clipnh) def _action_clipnh(self, value): if not self.clipn_h_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_CLIPN_HOR and self._set_mode(KN2_MODE_CLIPN_HOR) def _set_clipn_v_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.clipn_v_button != None: self.clipn_v_button.remove_value_listener(self._action_clipnv) self.clipn_v_button = button self.clipn_v_button != None and self.clipn_v_button.add_value_listener(self._action_clipnv) def _action_clipnv(self, value): if not self.clipn_v_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_CLIPN_VER and self._set_mode(KN2_MODE_CLIPN_VER) def _set_shift_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.shift_button != None: self.shift_button.remove_value_listener(self._action_shift) self.shift_button = button self.shift_button != None and self.shift_button.add_value_listener(self._action_shift) def _action_shift(self, value): if not self.shift_button != None: raise AssertionError raise value in range(128) or AssertionError self.shift_on = value != 0 and not self.shift_on self.update_shift() def _set_scroll_mod_left_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.scroll_mod_left_button != None: self.scroll_mod_left_button.remove_value_listener(self._action_scroll_left) self.scroll_mod_left_button = button self.scroll_mod_left_button != None and self.scroll_mod_left_button.add_value_listener(self._action_scroll_left) def _set_scroll_mod_right_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.scroll_mod_right_button != None: self.scroll_mod_right_button.remove_value_listener(self._action_scroll_right) self.scroll_mod_right_button = button self.scroll_mod_right_button != None and self.scroll_mod_right_button.add_value_listener(self._action_scroll_right) def _action_scroll_left(self, value): if not self.scroll_mod_left_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.scroll_mod_left_button.send_value(1) self.navflags |= LEFT_DOWN self._measure_left_click = int(round(time.time() * 1000)) else: self.scroll_mod_left_button.send_value(0) self.navflags &= ~LEFT_DOWN clicktime = int(round(time.time() * 1000)) - self._measure_left_click if clicktime < CLICK_TIME: if self._parent._modifier_down: self._parent.modify_track_offset(-1) elif self._parent._mode == PAD_MODE: self._do_lr_as_scale_mode(-1) elif self._parent._mode == SCENE_MODE: self._parent.modify_scene_offset(-1) elif self._parent._mode == CLIP_MODE: self._parent.move_view_horizontal(-1) elif self._parent._mode == CONTROL_MODE: self._parent.move_view_horizontal(-1) def _action_scroll_right(self, value): if not self.scroll_mod_right_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.scroll_mod_right_button.send_value(1) self.navflags |= RIGHT_DOWN self._measure_right_click = int(round(time.time() * 1000)) else: self.scroll_mod_right_button.send_value(0) self.navflags &= ~RIGHT_DOWN clicktime = int(round(time.time() * 1000)) - self._measure_right_click if clicktime < CLICK_TIME: if self._parent._modifier_down: self._parent.modify_track_offset(1) elif self._parent._mode == PAD_MODE: self._do_lr_as_scale_mode(1) elif self._parent._mode == SCENE_MODE: self._parent.modify_scene_offset(1) elif self._parent._mode == CLIP_MODE: self._parent.move_view_horizontal(1) elif self._parent._mode == CONTROL_MODE: self._parent.move_view_horizontal(1) def _do_lr_as_scale_mode(self, delta): if self.pad_to_mainknob_mode == PAD_KNOB_SCALE: self._parent.inc_scale(delta) elif self.pad_to_mainknob_mode == PAD_KNOB_BASEN: self._parent.inc_base_note(delta) else: self._parent.inc_octave(delta) def _action_oct_down(self, value): if value != 0: self._parent.inc_octave(-1) def _action_oct_up(self, value): if value != 0: self._parent.inc_octave(1) def _action_scale_down(self, value): if value != 0: self._parent.inc_scale(-1) def _action_scale_up(self, value): if value != 0: self._parent.inc_scale(1) def _action_base_down(self, value): if value != 0: self._parent.inc_base_note(-1) def _action_base_up(self, value): if value != 0: self._parent.inc_base_note(1) def _set_push_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.push_button != None: self.push_button.remove_value_listener(self._action_push) self.push_button = button self.push_button != None and self.push_button.add_value_listener(self._action_push) def _action_push(self, value): if not self.push_button != None: raise AssertionError if not value in range(128): raise AssertionError next_mode = self.mode_assign_map[self.mode][3] next_mode != -1 and self._set_mode(next_mode) self.loop_div_index = self.lrmode == LR_CONTROL_LOOP and self.navflags != 0 and (self.loop_div_index + 1) % len(LOOP_KNOB_DIVISION) self._parent.show_message('Loop Selection Granularity : ' + str(LOOP_KNOB_DIVISION[self.loop_div_index]) + ' beats ') self.loop_incdex = LOOP_KNOB_DIVISION[self.loop_div_index] def remove_listener(self, control, callback): if control != None and control.value_has_listener(callback): control.remove_value_listener(callback) control.disconnect() def disconnect(self): self.remove_listener(self.the_slider, self._do_main_slider) self.remove_listener(self.arrow_mode_button, self.toggle_arrow_mode) self.remove_listener(self.volume_button, self._action_volume) self.remove_listener(self.xfade_button, self._action_xfade) self.remove_listener(self.swing_button, self._action_swing) self.remove_listener(self.clipn_h_button, self._action_clipnh) self.remove_listener(self.clipn_v_button, self._action_clipnv) self.remove_listener(self.shift_button, self._action_shift) self.remove_listener(self.scroll_mod_left_button, self._action_scroll_left) self.remove_listener(self.scroll_mod_right_button, self._action_scroll_right) self.remove_listener(self.push_button, self._action_push) self.remove_listener(self.octave_mod_button, self._action_octave) self.remove_listener(self.scale_mod_button, self._action_scale) self.remove_listener(self.basenote_mod_button, self._action_base_note) self.remove_listener(self.octave_dwn_button, self._action_oct_down) self.remove_listener(self.octave_upp_button, self._action_oct_up) self.remove_listener(self.scale_dwn_button, self._action_scale_down) self.remove_listener(self.scale_upp_button, self._action_scale_up) self.remove_listener(self.basent_dwn_button, self._action_base_down) self.remove_listener(self.basent_upp_button, self._action_base_up) self._parent = None self.master_track = None self.the_slider = None self.mode_assign_map = None
class Novation_Impulse2(ControlSurface): """ Script for Novation's Impulse keyboards """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) self.c_instance = c_instance with self.component_guard(): self.set_pad_translations(PAD_TRANSLATIONS) self._device_selection_follows_track_selection = True self._suggested_input_port = 'Impulse' self._suggested_output_port = 'Impulse' self._has_sliders = True self._current_midi_map = None self._display_reset_delay = -1 self._string_to_display = None self.shift_pressed = False # special alternative buttons mode. for now only mixer buttons become record buttons. later we will add something more self.alternative_buttons_mode = False self._shift_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 39) self._preview_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 41) self._master_slider = SliderElement(MIDI_CC_TYPE, 0, 8) self._shift_button.name = 'Shift_Button' self._master_slider.name = 'Master_Volume_Control' self._master_slider.add_value_listener(self._slider_value, identify_sender=True) self._preview_button.add_value_listener(self._preview_value) self._setup_mixer() self._setup_session() self._setup_transport() self._setup_device() self._setup_name_display() device_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 1, 10) mixer_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 1, 9) device_button.name = 'Encoder_Device_Mode' mixer_button.name = 'Encoder_Mixer_Mode' self._encoder_modes = EncoderModeSelector(self._device_component, self._mixer, self._next_bank_button, self._prev_bank_button, self._encoders) self._encoder_modes.set_device_mixer_buttons( device_button, mixer_button) self._shift_button.add_value_listener(self._shift_button_handler) for component in self.components: component.set_enabled(False) # attributes def alternative_buttons_mode(self): return self.alternative_buttons_mode def alternative_buttons_mode(self, value): self.log('alternative_buttons_mode_value ' + str(value)) self.alternative_buttons_mode = value def shift_pressed(self): return self.shift_pressed def shift_pressed(self, value): self.log('shift_pressed value ' + str(value)) self.shift_pressed = value def refresh_state(self): ControlSurface.refresh_state(self) self.schedule_message(3, self._send_midi, SYSEX_START + (6, 1, 1, 1, 247)) def handle_sysex(self, midi_bytes): if midi_bytes[0:-2] == SYSEX_START + (7, ) and midi_bytes[-2] != 0: self._has_sliders = midi_bytes[-2] != 25 self.schedule_message(1, self._show_startup_message) for control in self.controls: if isinstance(control, InputControlElement): control.clear_send_cache() for component in self.components: component.set_enabled(True) if self._has_sliders: self._mixer.master_strip().set_volume_control( self._master_slider) self._mixer.update() else: self._mixer.master_strip().set_volume_control(None) self._mixer.selected_strip().set_volume_control( self._master_slider) for index in range(len(self._sliders)): self._mixer.channel_strip(index).set_volume_control(None) slider = self._sliders[index] slider.release_parameter() if slider.value_has_listener(self._slider_value): slider.remove_value_listener(self._slider_value) self._encoder_modes.set_provide_volume_mode(not self._has_sliders) self.request_rebuild_midi_map() def disconnect(self): self.log('starting disconnect 1') self._name_display_data_source.set_display_string(' ') for encoder in self._encoders: encoder.remove_value_listener(self._encoder_value) self._master_slider.remove_value_listener(self._slider_value) if self._has_sliders: for slider in tuple(self._sliders): slider.remove_value_listener(self._slider_value) for button in self._strip_buttons: button.remove_value_listener(self._mixer_button_value) self._preview_button.remove_value_listener(self._preview_value) self.log('starting disconnect 3') ControlSurface.disconnect(self) self.log('starting disconnect 3') self._encoders = None self._sliders = None self._strip_buttons = None self._master_slider = None self._current_midi_map = None self._name_display = None self._prev_bank_button = None self._next_bank_button = None self._encoder_modes = None self._transport_view_modes = None self.log('starting disconnect 4') self._send_midi(SYSEX_START + (6, 0, 0, 0, 247)) self.log('starting disconnect 5') if self._shift_button != None: self._shift_button.remove_value_listener( self._shift_button_handler) self._shift_button = None self.log('starting disconnect 6') def build_midi_map(self, midi_map_handle): self._current_midi_map = midi_map_handle ControlSurface.build_midi_map(self, midi_map_handle) def update_display(self): ControlSurface.update_display(self) if self._string_to_display != None: self._name_display_data_source.set_display_string( self._string_to_display) self._string_to_display = None if self._display_reset_delay >= 0: self._display_reset_delay -= 1 if self._display_reset_delay == -1: self._show_current_track_name() def _setup_mixer(self): self.log('setup mixer') mute_solo_flip_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 34) self._next_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 37) self._prev_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 38) self._strip_buttons = [] mute_solo_flip_button.name = 'Mute_Solo_Flip_Button' self._next_nav_button.name = 'Next_Track_Button' self._prev_nav_button.name = 'Prev_Track_Button' self._mixer = SpecialMixerComponent(self, 8, self.c_instance) self._mixer.name = 'Mixer' self._mixer.set_select_buttons(self._next_nav_button, self._prev_nav_button) self._mixer.selected_strip().name = 'Selected_Channel_Strip' self._mixer.master_strip().name = 'Master_Channel_Strip' self._mixer.master_strip().set_volume_control(self._master_slider) self._sliders = [] for index in range(8): strip = self._mixer.channel_strip(index) strip.name = 'Channel_Strip_' + str(index) strip.set_invert_mute_feedback(True) self._sliders.append(SliderElement(MIDI_CC_TYPE, 0, index)) self._sliders[-1].name = str(index) + '_Volume_Control' self._sliders[-1].set_feedback_delay(-1) self._sliders[-1].add_value_listener(self._slider_value, identify_sender=True) strip.set_volume_control(self._sliders[-1]) self._strip_buttons.append( ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 9 + index)) self._strip_buttons[-1].name = str(index) + '_Mute_Button' self._strip_buttons[-1].add_value_listener( self._mixer_button_value, identify_sender=True) self._mixer.master_strip().set_mute_button( ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 17)) self._mixer.set_strip_mute_solo_buttons(tuple(self._strip_buttons), mute_solo_flip_button) #self._mixer.set_shift_button(self._shift_button) self._mixer.updateMixerButtons() self._button9 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 9 + 8) def _setup_session(self): num_pads = len(PAD_TRANSLATIONS) self._session = SessionComponent(8, 0) self._session.name = 'Session_Control' self._session.selected_scene().name = 'Selected_Scene' self._session.set_mixer(self._mixer) # for ableton 9.1.1 and lower #self._session.set_track_banking_increment(num_pads) #self._session.set_track_bank_buttons(ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 35), ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 36)) # for ableton 9.1.1 and higher self._track_left_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 36) self._track_right_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 35) self._session.set_page_left_button(self._track_left_button) self._session.set_page_right_button(self._track_right_button) pads = [] for index in range(num_pads): pads.append( ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 60 + index)) pads[-1].name = 'Pad_' + str(index) clip_slot = self._session.selected_scene().clip_slot(index) clip_slot.set_triggered_to_play_value(GREEN_BLINK) clip_slot.set_triggered_to_record_value(RED_BLINK) clip_slot.set_stopped_value(AMBER_FULL) clip_slot.set_started_value(GREEN_FULL) clip_slot.set_recording_value(RED_FULL) clip_slot.set_launch_button(pads[-1]) clip_slot.name = str(index) + '_Selected_Clip_Slot' def _setup_transport(self): rwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 27) ffwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 28) stop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 29) play_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 30) loop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 31) rec_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 32) ffwd_button.name = 'FFwd_Button' rwd_button.name = 'Rwd_Button' loop_button.name = 'Loop_Button' play_button.name = 'Play_Button' stop_button.name = 'Stop_Button' rec_button.name = 'Record_Button' self._transport = ShiftableTransportComponent(self.c_instance, self._session, self, ffwd_button, rwd_button) self._transport.name = 'Transport' self._transport.set_stop_buttonOnInit(stop_button) self._transport.set_play_button(play_button) self._transport.set_record_buttonOnInit(rec_button) # self._transport.set_shift_button(self._shift_button) self._transport.set_mixer9_button(self._button9) self._transport_view_modes = TransportViewModeSelector( self, self.c_instance, self._transport, self._session, ffwd_button, rwd_button, loop_button) self._transport_view_modes.name = 'Transport_View_Modes' def _setup_device(self): encoders = [] for index in range(8): encoders.append( PeekableEncoderElement( MIDI_CC_TYPE, 1, index, Live.MidiMap.MapMode.relative_binary_offset)) encoders[-1].set_feedback_delay(-1) encoders[-1].add_value_listener(self._encoder_value, identify_sender=True) encoders[-1].name = 'Device_Control_' + str(index) self._encoders = tuple(encoders) self._prev_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 12) self._next_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 11) self._prev_bank_button.name = 'Device_Bank_Down_Button' self._next_bank_button.name = 'Device_Bank_Up_Button' device = DeviceComponent() device.name = 'Device_Component' self.set_device_component(device) device.set_parameter_controls(self._encoders) device.set_bank_nav_buttons(self._prev_bank_button, self._next_bank_button) def _setup_name_display(self): self._name_display = PhysicalDisplayElement(16, 1) self._name_display.name = 'Display' self._name_display.set_message_parts(SYSEX_START + (8, ), (247, )) self._name_display_data_source = DisplayDataSource() self._name_display.segment(0).set_data_source( self._name_display_data_source) def _encoder_value(self, value, sender): if not sender in self._encoders: raise AssertionError if not value in range(128): raise AssertionError # display_string = self._device_component.is_enabled() and ' - ' # display_string = sender.mapped_parameter() != None and sender.mapped_parameter().name display_string = '' if self._device_component.is_enabled(): # display_string = sender.name # track = self.song().view.selected_track # display_string = str(list(tracks).index(track) + 1) pass if (sender.mapped_parameter() != None): # display_string = display_string + '-' display_string = display_string + sender.mapped_parameter().name self._set_string_to_display(display_string) def _slider_value(self, value, sender): self.log('_slider_value ' + str(value) + ' ' + str(sender)) if not sender in tuple(self._sliders) + (self._master_slider, ): raise AssertionError if not value in range(128): raise AssertionError if self._mixer.is_enabled(): display_string = ' - ' master = self.song().master_track tracks = self.song().tracks returns = self.song().return_tracks track = None if sender.mapped_parameter() != None: self.log('1') if sender == self._master_slider: self.log('2') # track = self._has_sliders and master if self._has_sliders: track = master else: self.log('2.1') track = self.song().view.selected_track else: self.log('3') track = self._mixer.channel_strip( self._sliders.index(sender))._track else: self.log('4') track = self.song().view.selected_track self.log('track=' + str(track)) if track == master: display_string = 'Master' elif track in tracks: display_string = str(list(tracks).index(track) + 1) elif track in returns: display_string = str( chr(ord('A') + list(returns).index(track))) else: # raise False or AssertionError raise AssertionError display_string += ' Volume' self._set_string_to_display(display_string) def _mixer_button_value(self, value, sender): self.log('__mixer_button_value ' + str(value) + ' ' + str(sender)) if not value in range(128): raise AssertionError #if self._mixer.is_enabled() and value > 0: if self._mixer.is_enabled(): strip = self._mixer.channel_strip( self._strip_buttons.index(sender)) #self._string_to_display = strip != None and None self._name_display.segment(0).set_data_source( strip.track_name_data_source()) self._name_display.update() self._display_reset_delay = STANDARD_DISPLAY_DELAY else: self._set_string_to_display(' - ') # if shift_pressed XOR alternative_mode if self.shift_pressed <> self.alternative_buttons_mode: self.log("_mixer_button_value") self.log(str(value)) if (value == 0): self.select_armed_track_if_only_one() def select_armed_track_if_only_one(self): self.log("select_armed_track_if_only_one") song = self.song() armed_tracks = [] tracks = song.tracks self.log("select_armed_track_if_only_one 2") for track in tracks: if track.can_be_armed and track.arm: armed_tracks.append(track) self.log(str(len(armed_tracks))) if (len(armed_tracks) == 1): self.log("selecting the track") sel_track = armed_tracks[0] self.song().view.selected_track = sel_track self._mixer._selected_tracks = [] self._mixer._selected_tracks.append(sel_track) self._mixer.on_selected_track_changed() def _preview_value(self, value): if not value in range(128): raise AssertionError for encoder in self._encoders: encoder.set_peek_mode(value > 0) def _show_current_track_name(self): if self._name_display != None and self._mixer != None: self._string_to_display = None self._name_display.segment(0).set_data_source( self._mixer.selected_strip().track_name_data_source()) self._name_display.update() def _show_startup_message(self): self._name_display.display_message('LIVE') self._display_reset_delay = INITIAL_DISPLAY_DELAY def _set_string_to_display(self, string_to_display): if not isinstance(string_to_display, (str, unicode)): raise AssertionError self._name_display.segment(0).set_data_source( self._name_display_data_source) self._string_to_display = string_to_display self._display_reset_delay = STANDARD_DISPLAY_DELAY def _on_selected_track_changed(self): self.log('_on_selected_track_changed') ControlSurface._on_selected_track_changed(self) self._show_current_track_name() #all_tracks = self._has_sliders or self._session.tracks_to_use() all_tracks2 = self._session.tracks_to_use() selected_track = self.song().view.selected_track num_strips = self._session.width() if selected_track in all_tracks2: track_index = list(all_tracks2).index(selected_track) self.log('track_index ' + str(track_index)) new_offset = track_index - track_index % num_strips self.log('new_offset ' + str(new_offset)) if not new_offset / num_strips == int(new_offset / num_strips): raise AssertionError self._session.set_offsets(new_offset, self._session.scene_offset()) def _shift_button_handler(self, value): self.log("root shift handler : " + str(value)) if not self._shift_button != None: raise AssertionError if not value in range(128): raise AssertionError self.log("root shift handler 2") self.shift_pressed = value > 0 # calling other handlers self._mixer._shift_button_handler(value) self._transport._shift_button_handler(value) self._transport_view_modes._shift_button_handler(value) #clip stop self.log("root shift handler 3") num_pads = len(PAD_TRANSLATIONS) pads = [] for index in range(num_pads): pads.append( ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 60 + index)) pads[-1].name = 'Pad_' + str(index) clip_slot = self._session.selected_scene().clip_slot(index) if self.shift_pressed: clip_slot.set_launch_button(None) else: clip_slot.set_launch_button(pads[index]) if self.shift_pressed: self._session.set_stop_track_clip_buttons(tuple(pads)) else: self._session.set_stop_track_clip_buttons(None) self.log("root shift handler 4") def flipAlternativeButtonMode(self): self.alternative_buttons_mode = not self.alternative_buttons_mode self.updateAlternativeButtonMode() def updateAlternativeButtonMode(self): self._mixer.updateMixerButtons() self._transport_view_modes.update() def log(self, message): pass
class Novation_Impulse2(ControlSurface): """ Script for Novation's Impulse keyboards """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) self.c_instance = c_instance with self.component_guard(): self.set_pad_translations(PAD_TRANSLATIONS) self._device_selection_follows_track_selection = True self._suggested_input_port = 'Impulse' self._suggested_output_port = 'Impulse' self._has_sliders = True self._current_midi_map = None self._display_reset_delay = -1 self._string_to_display = None self.shift_pressed = False # special alternative buttons mode. for now only mixer buttons become record buttons. later we will add something more self.alternative_buttons_mode = False self._shift_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 39) self._preview_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 41) self._master_slider = SliderElement(MIDI_CC_TYPE, 0, 8) self._shift_button.name = 'Shift_Button' self._master_slider.name = 'Master_Volume_Control' self._master_slider.add_value_listener(self._slider_value, identify_sender=True) self._preview_button.add_value_listener(self._preview_value) self._setup_mixer() self._setup_session() self._setup_transport() self._setup_device() self._setup_name_display() device_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 1, 10) mixer_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 1, 9) device_button.name = 'Encoder_Device_Mode' mixer_button.name = 'Encoder_Mixer_Mode' self._encoder_modes = EncoderModeSelector(self._device_component, self._mixer, self._next_bank_button, self._prev_bank_button, self._encoders) self._encoder_modes.set_device_mixer_buttons(device_button, mixer_button) self._shift_button.add_value_listener(self._shift_button_handler) for component in self.components: component.set_enabled(False) # attributes def alternative_buttons_mode(self): return self.alternative_buttons_mode def alternative_buttons_mode(self,value): self.log ('alternative_buttons_mode_value ' + str(value)) self.alternative_buttons_mode = value def shift_pressed(self): return self.shift_pressed def shift_pressed(self,value): self.log ('shift_pressed value ' + str(value)) self.shift_pressed = value def refresh_state(self): ControlSurface.refresh_state(self) self.schedule_message(3, self._send_midi, SYSEX_START + (6, 1, 1, 1, 247)) def handle_sysex(self, midi_bytes): if midi_bytes[0:-2] == SYSEX_START + (7,) and midi_bytes[-2] != 0: self._has_sliders = midi_bytes[-2] != 25 self.schedule_message(1, self._show_startup_message) for control in self.controls: if isinstance(control, InputControlElement): control.clear_send_cache() for component in self.components: component.set_enabled(True) if self._has_sliders: self._mixer.master_strip().set_volume_control(self._master_slider) self._mixer.update() else: self._mixer.master_strip().set_volume_control(None) self._mixer.selected_strip().set_volume_control(self._master_slider) for index in range(len(self._sliders)): self._mixer.channel_strip(index).set_volume_control(None) slider = self._sliders[index] slider.release_parameter() if slider.value_has_listener(self._slider_value): slider.remove_value_listener(self._slider_value) self._encoder_modes.set_provide_volume_mode(not self._has_sliders) self.request_rebuild_midi_map() def disconnect(self): self.log('starting disconnect 1') self._name_display_data_source.set_display_string(' ') for encoder in self._encoders: encoder.remove_value_listener(self._encoder_value) self._master_slider.remove_value_listener(self._slider_value) if self._has_sliders: for slider in tuple(self._sliders): slider.remove_value_listener(self._slider_value) for button in self._strip_buttons: button.remove_value_listener(self._mixer_button_value) self._preview_button.remove_value_listener(self._preview_value) self.log('starting disconnect 3') ControlSurface.disconnect(self) self.log('starting disconnect 3') self._encoders = None self._sliders = None self._strip_buttons = None self._master_slider = None self._current_midi_map = None self._name_display = None self._prev_bank_button = None self._next_bank_button = None self._encoder_modes = None self._transport_view_modes = None self.log('starting disconnect 4') self._send_midi(SYSEX_START + (6, 0, 0, 0, 247)) self.log('starting disconnect 5') if self._shift_button != None: self._shift_button.remove_value_listener(self._shift_button_handler) self._shift_button = None self.log('starting disconnect 6') def build_midi_map(self, midi_map_handle): self._current_midi_map = midi_map_handle ControlSurface.build_midi_map(self, midi_map_handle) def update_display(self): ControlSurface.update_display(self) if self._string_to_display != None: self._name_display_data_source.set_display_string(self._string_to_display) self._string_to_display = None if self._display_reset_delay >= 0: self._display_reset_delay -= 1 if self._display_reset_delay == -1: self._show_current_track_name() def _setup_mixer(self): self.log('setup mixer') mute_solo_flip_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 34) self._next_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 37) self._prev_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 38) self._strip_buttons = [] mute_solo_flip_button.name = 'Mute_Solo_Flip_Button' self._next_nav_button.name = 'Next_Track_Button' self._prev_nav_button.name = 'Prev_Track_Button' self._mixer = SpecialMixerComponent(self, 8, self.c_instance) self._mixer.name = 'Mixer' self._mixer.set_select_buttons(self._next_nav_button, self._prev_nav_button) self._mixer.selected_strip().name = 'Selected_Channel_Strip' self._mixer.master_strip().name = 'Master_Channel_Strip' self._mixer.master_strip().set_volume_control(self._master_slider) self._sliders = [] for index in range(8): strip = self._mixer.channel_strip(index) strip.name = 'Channel_Strip_' + str(index) strip.set_invert_mute_feedback(True) self._sliders.append(SliderElement(MIDI_CC_TYPE, 0, index)) self._sliders[-1].name = str(index) + '_Volume_Control' self._sliders[-1].set_feedback_delay(-1) self._sliders[-1].add_value_listener(self._slider_value, identify_sender=True) strip.set_volume_control(self._sliders[-1]) self._strip_buttons.append(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 9 + index)) self._strip_buttons[-1].name = str(index) + '_Mute_Button' self._strip_buttons[-1].add_value_listener(self._mixer_button_value, identify_sender=True) self._mixer.master_strip().set_mute_button(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 17)) self._mixer.set_strip_mute_solo_buttons(tuple(self._strip_buttons), mute_solo_flip_button) #self._mixer.set_shift_button(self._shift_button) self._mixer.updateMixerButtons() self._button9 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 9 + 8) def _setup_session(self): num_pads = len(PAD_TRANSLATIONS) self._session = SessionComponent(8, 0) self._session.name = 'Session_Control' self._session.selected_scene().name = 'Selected_Scene' self._session.set_mixer(self._mixer) # for ableton 9.1.1 and lower #self._session.set_track_banking_increment(num_pads) #self._session.set_track_bank_buttons(ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 35), ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 36)) # for ableton 9.1.1 and higher self._track_left_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 36) self._track_right_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 35) self._session.set_page_left_button(self._track_left_button) self._session.set_page_right_button(self._track_right_button) pads = [] for index in range(num_pads): pads.append(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 60 + index)) pads[-1].name = 'Pad_' + str(index) clip_slot = self._session.selected_scene().clip_slot(index) clip_slot.set_triggered_to_play_value(GREEN_BLINK) clip_slot.set_triggered_to_record_value(RED_BLINK) clip_slot.set_stopped_value(AMBER_FULL) clip_slot.set_started_value(GREEN_FULL) clip_slot.set_recording_value(RED_FULL) clip_slot.set_launch_button(pads[-1]) clip_slot.name = str(index) + '_Selected_Clip_Slot' def _setup_transport(self): rwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 27) ffwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 28) stop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 29) play_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 30) loop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 31) rec_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 32) ffwd_button.name = 'FFwd_Button' rwd_button.name = 'Rwd_Button' loop_button.name = 'Loop_Button' play_button.name = 'Play_Button' stop_button.name = 'Stop_Button' rec_button.name = 'Record_Button' self._transport = ShiftableTransportComponent(self.c_instance,self._session, self, ffwd_button, rwd_button) self._transport.name = 'Transport' self._transport.set_stop_buttonOnInit(stop_button) self._transport.set_play_button(play_button) self._transport.set_record_buttonOnInit(rec_button) # self._transport.set_shift_button(self._shift_button) self._transport.set_mixer9_button(self._button9) self._transport_view_modes = TransportViewModeSelector(self,self.c_instance,self._transport, self._session, ffwd_button, rwd_button, loop_button) self._transport_view_modes.name = 'Transport_View_Modes' def _setup_device(self): encoders = [] for index in range(8): encoders.append(PeekableEncoderElement(MIDI_CC_TYPE, 1, index, Live.MidiMap.MapMode.relative_binary_offset)) encoders[-1].set_feedback_delay(-1) encoders[-1].add_value_listener(self._encoder_value, identify_sender=True) encoders[-1].name = 'Device_Control_' + str(index) self._encoders = tuple(encoders) self._prev_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 12) self._next_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 11) self._prev_bank_button.name = 'Device_Bank_Down_Button' self._next_bank_button.name = 'Device_Bank_Up_Button' device = DeviceComponent() device.name = 'Device_Component' self.set_device_component(device) device.set_parameter_controls(self._encoders) device.set_bank_nav_buttons(self._prev_bank_button, self._next_bank_button) def _setup_name_display(self): self._name_display = PhysicalDisplayElement(16, 1) self._name_display.name = 'Display' self._name_display.set_message_parts(SYSEX_START + (8,), (247,)) self._name_display_data_source = DisplayDataSource() self._name_display.segment(0).set_data_source(self._name_display_data_source) def _encoder_value(self, value, sender): if not sender in self._encoders: raise AssertionError if not value in range(128): raise AssertionError # display_string = self._device_component.is_enabled() and ' - ' # display_string = sender.mapped_parameter() != None and sender.mapped_parameter().name display_string = '' if self._device_component.is_enabled(): # display_string = sender.name # track = self.song().view.selected_track # display_string = str(list(tracks).index(track) + 1) pass if (sender.mapped_parameter() != None): # display_string = display_string + '-' display_string = display_string + sender.mapped_parameter().name self._set_string_to_display(display_string) def _slider_value(self, value, sender): self.log ('_slider_value ' + str(value) + ' ' +str(sender)) if not sender in tuple(self._sliders) + (self._master_slider,): raise AssertionError if not value in range(128): raise AssertionError if self._mixer.is_enabled(): display_string = ' - ' master = self.song().master_track tracks = self.song().tracks returns = self.song().return_tracks track = None if sender.mapped_parameter() != None: self.log ('1') if sender == self._master_slider: self.log ('2') # track = self._has_sliders and master if self._has_sliders: track = master else: self.log ('2.1') track = self.song().view.selected_track else: self.log ('3') track = self._mixer.channel_strip(self._sliders.index(sender))._track else: self.log ('4') track = self.song().view.selected_track self.log('track='+str(track)) if track == master: display_string = 'Master' elif track in tracks: display_string = str(list(tracks).index(track) + 1) elif track in returns: display_string = str(chr(ord('A') + list(returns).index(track))) else: # raise False or AssertionError raise AssertionError display_string += ' Volume' self._set_string_to_display(display_string) def _mixer_button_value(self, value, sender): self.log ('__mixer_button_value ' + str(value) + ' ' +str(sender)) if not value in range(128): raise AssertionError #if self._mixer.is_enabled() and value > 0: if self._mixer.is_enabled(): strip = self._mixer.channel_strip(self._strip_buttons.index(sender)) #self._string_to_display = strip != None and None self._name_display.segment(0).set_data_source(strip.track_name_data_source()) self._name_display.update() self._display_reset_delay = STANDARD_DISPLAY_DELAY else: self._set_string_to_display(' - ') # if shift_pressed XOR alternative_mode if self.shift_pressed <> self.alternative_buttons_mode: self.log("_mixer_button_value") self.log(str(value)) if (value == 0): self.select_armed_track_if_only_one() def select_armed_track_if_only_one(self): self.log("select_armed_track_if_only_one") song = self.song() armed_tracks = [] tracks = song.tracks self.log("select_armed_track_if_only_one 2") for track in tracks: if track.can_be_armed and track.arm: armed_tracks.append(track) self.log(str(len(armed_tracks))) if (len(armed_tracks) == 1): self.log("selecting the track") sel_track = armed_tracks[0] self.song().view.selected_track = sel_track self._mixer._selected_tracks = [] self._mixer._selected_tracks.append(sel_track) self._mixer.on_selected_track_changed() def _preview_value(self, value): if not value in range(128): raise AssertionError for encoder in self._encoders: encoder.set_peek_mode(value > 0) def _show_current_track_name(self): if self._name_display != None and self._mixer != None: self._string_to_display = None self._name_display.segment(0).set_data_source(self._mixer.selected_strip().track_name_data_source()) self._name_display.update() def _show_startup_message(self): self._name_display.display_message('LIVE') self._display_reset_delay = INITIAL_DISPLAY_DELAY def _set_string_to_display(self, string_to_display): if not isinstance(string_to_display, (str, unicode)): raise AssertionError self._name_display.segment(0).set_data_source(self._name_display_data_source) self._string_to_display = string_to_display self._display_reset_delay = STANDARD_DISPLAY_DELAY def _on_selected_track_changed(self): self.log('_on_selected_track_changed') ControlSurface._on_selected_track_changed(self) self._show_current_track_name() #all_tracks = self._has_sliders or self._session.tracks_to_use() all_tracks2 = self._session.tracks_to_use() selected_track = self.song().view.selected_track num_strips = self._session.width() if selected_track in all_tracks2: track_index = list(all_tracks2).index(selected_track) self.log('track_index '+ str(track_index)) new_offset = track_index - track_index % num_strips self.log('new_offset '+ str(new_offset)) if not new_offset / num_strips == int(new_offset / num_strips): raise AssertionError self._session.set_offsets(new_offset, self._session.scene_offset()) def _shift_button_handler(self, value): self.log("root shift handler : "+ str(value)) if not self._shift_button != None: raise AssertionError if not value in range(128): raise AssertionError self.log("root shift handler 2") self.shift_pressed = value > 0 # calling other handlers self._mixer._shift_button_handler(value) self._transport._shift_button_handler(value) self._transport_view_modes._shift_button_handler(value) #clip stop self.log("root shift handler 3") num_pads = len(PAD_TRANSLATIONS) pads = [] for index in range(num_pads): pads.append(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 60 + index)) pads[-1].name = 'Pad_' + str(index) clip_slot = self._session.selected_scene().clip_slot(index) if self.shift_pressed: clip_slot.set_launch_button(None) else: clip_slot.set_launch_button(pads[index]) if self.shift_pressed: self._session.set_stop_track_clip_buttons(tuple(pads)) else: self._session.set_stop_track_clip_buttons(None) self.log("root shift handler 4") def flipAlternativeButtonMode(self): self.alternative_buttons_mode = not self.alternative_buttons_mode self.updateAlternativeButtonMode() def updateAlternativeButtonMode(self): self._mixer.updateMixerButtons() self._transport_view_modes.update() def log(self, message): pass