示例#1
0
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()
示例#2
0
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())
示例#4
0
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)
示例#7
0
    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
示例#9
0
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