Пример #1
0
class MaschineChannelStripComponent(ChannelStripComponent):

    def __init__(self):
        ChannelStripComponent.__init__(self)
        self.deleted = {}
        self.clear_mode = False
        self.touch_mode = False
        self.send_control = None
        self.clear_vol_button = None
        self.clear_pan_button = None
        self.clear_send_button = None

    def set_touch_mode(self, touchchannel):
        self.touch_mode = True
        id_vol = self._volume_control.message_identifier()
        id_pan = self._pan_control.message_identifier()
        id_send = None
        for send in self._send_controls:
            if send:
                id_send = send.message_identifier()

        self.clear_vol_button = ButtonElement(False, MIDI_CC_TYPE, touchchannel, id_vol)
        self.clear_vol_button.add_value_listener(self._do_clear_vol)
        self.clear_pan_button = ButtonElement(False, MIDI_CC_TYPE, touchchannel, id_pan)
        self.clear_pan_button.add_value_listener(self._do_clear_pan)
        self.clear_send_button = ButtonElement(False, MIDI_CC_TYPE, touchchannel, id_send)
        self.clear_send_button.add_value_listener(self._do_clear_send)
        for send in self._send_controls:
            if send:
                self.send_control = send

    def enter_clear(self):
        self.clear_mode = True
        self.deleted = {}
        if not self.touch_mode:
            self.set_enabled(False)
            self._volume_control.add_value_listener(self._do_clear_vol)
            self._pan_control.add_value_listener(self._do_clear_pan)
            for send in self._send_controls:
                if send:
                    self.send_control = send
                    send.add_value_listener(self._do_clear_send)

    def exit_clear(self):
        self.clear_mode = False
        if not self.touch_mode:
            self._volume_control.remove_value_listener(self._do_clear_vol)
            self._pan_control.remove_value_listener(self._do_clear_pan)
            for send in self._send_controls:
                if send:
                    send.remove_value_listener(self._do_clear_send)

            self.set_enabled(True)

    def _do_clear_vol(self, value):
        key = self._volume_control.message_identifier()
        if self.clear_mode:
            if key not in self.deleted:
                self.deleted[key] = True
                playing_clip = self._get_playing_clip()
                if playing_clip:
                    playing_clip.clear_envelope(self._track.mixer_device.volume)

    def _do_clear_pan(self, value):
        key = self._pan_control.message_identifier()
        if self.clear_mode:
            if key not in self.deleted:
                self.deleted[key] = True
                playing_clip = self._get_playing_clip()
                if playing_clip:
                    playing_clip.clear_envelope(self._track.mixer_device.panning)

    def _do_clear_send(self, value):
        key = self.send_control.message_identifier()
        if self.clear_mode:
            if key not in self.deleted:
                send_index = len(self._send_controls) - 1
                self.deleted[key] = True
                playing_clip = self._get_playing_clip()
                if playing_clip:
                    if send_index in range(len(self._track.mixer_device.sends)):
                        playing_clip.clear_envelope(self._track.mixer_device.sends[send_index])

    def _mute_value(self, value):
        super()._mute_value(value)
        key = self._mute_button.message_identifier()
        if self.clear_mode:
            if key not in self.deleted:
                self.deleted[key] = True
                playing_clip = self._get_playing_clip()
                if playing_clip:
                    playing_clip.clear_envelope(self._track.mixer_device.track_activator)

    def _get_playing_clip(self):
        if self._track is None:
            return
        clips_slots = self._track.clip_slots
        for cs in clips_slots:
            if cs.has_clip and cs.is_playing:
                return cs.clip

        return

    def disconnect(self):
        self.clear_pan_button = None
        self.clear_send_button = None
        if self.clear_vol_button is not None:
            self.clear_vol_button.remove_value_listener(self._do_clear_vol)
            self.clear_vol_button = None
        elif self.clear_pan_button is not None:
            self.clear_pan_button.remove_value_listener(self._do_clear_pan)
            self.clear_pan_button = None
        else:
            if self.clear_send_button is not None:
                self.clear_send_button.remove_value_listener(self._do_clear_send)
                self.clear_send_button = None
            if not self.touch_mode:
                if self.clear_mode:
                    if self.send_control is not None:
                        self.send_control.remove_value_listener(self._do_clear_send)
                        self.send_control = None
                    if self._volume_control is not None:
                        self._volume_control.remove_value_listener(self._do_clear_vol)
                        self._volume_control = None
                    if self._pan_control is not None:
                        self._pan_control.remove_value_listener(self._do_clear_pan)
                        self._pan_control = None
        super().disconnect()
class Novation_Impulse(ControlSurface):
    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
            self.set_pad_translations(PAD_TRANSLATIONS)
            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, ):
            if 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_selection_follows_track_selection=True)
        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 self._device_component.is_enabled():
            display_string = ' - '
            if sender.mapped_parameter() != None:
                display_string = sender.mapped_parameter().name
            self._set_string_to_display(display_string)

    def _slider_value(self, value, sender):
        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:
                    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 = 'Master'
                else:
                    pass
                if 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:
                    pass
                display_string += ' Volume'
            self._set_string_to_display(display_string)

    def _mixer_button_value(self, value, sender):
        if self._mixer.is_enabled():
            if 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(' - ')

    def _preview_value(self, value):
        for encoder in self._encoders:
            encoder.set_peek_mode(value > 0)

    def _show_current_track_name(self):
        if self._name_display != None:
            if 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):
        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()
        if not self._has_sliders:
            all_tracks = 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
                self._session.set_offsets(new_offset,
                                          self._session.scene_offset())
Пример #3
0
class Oxygen_3rd_Gen(ControlSurface):
    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
            is_momentary = True
            self._suggested_input_port = 'Oxygen'
            self._suggested_output_port = 'Oxygen'
            self._has_slider_section = True
            self._shift_button = ButtonElement(is_momentary, MIDI_CC_TYPE,
                                               GLOBAL_CHANNEL, 57)
            self._shift_button.add_value_listener(self._shift_value)
            self._mixer = SpecialMixerComponent(NUM_TRACKS)
            self._mute_solo_buttons = []
            self._track_up_button = ButtonElement(is_momentary, MIDI_CC_TYPE,
                                                  GLOBAL_CHANNEL, 111)
            self._track_down_button = ButtonElement(is_momentary, MIDI_CC_TYPE,
                                                    GLOBAL_CHANNEL, 110)
            self._master_slider = SliderElement(MIDI_CC_TYPE, GLOBAL_CHANNEL,
                                                41)
            for index in range(NUM_TRACKS):
                self._mute_solo_buttons.append(
                    ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL,
                                  49 + index))
                self._mixer.channel_strip(index).set_volume_control(
                    SliderElement(MIDI_CC_TYPE, GLOBAL_CHANNEL, 33 + index))

            self._shift_value(0)
            self._mixer.master_strip().set_volume_control(self._master_slider)
            self._mixer.selected_strip().set_volume_control(None)
            device = DeviceComponent(
                device_selection_follows_track_selection=True)
            device.set_parameter_controls(
                tuple([
                    EncoderElement(MIDI_CC_TYPE, GLOBAL_CHANNEL, 17 + index,
                                   Live.MidiMap.MapMode.absolute)
                    for index in range(8)
                ]))
            self.set_device_component(device)
            ffwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE,
                                        GLOBAL_CHANNEL, 115)
            rwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE,
                                       GLOBAL_CHANNEL, 114)
            loop_button = ButtonElement(is_momentary, MIDI_CC_TYPE,
                                        GLOBAL_CHANNEL, 113)
            transport = TransportComponent()
            transport.set_stop_button(
                ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 116))
            transport.set_play_button(
                ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 117))
            transport.set_record_button(
                ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 118))
            session = SessionComponent(0, 0)
            transport_view_modes = TransportViewModeSelector(
                transport, session, ffwd_button, rwd_button, loop_button)

    def disconnect(self):
        self._shift_button.remove_value_listener(self._shift_value)
        self._shift_button = None
        ControlSurface.disconnect(self)

    def refresh_state(self):
        ControlSurface.refresh_state(self)
        self.schedule_message(5, self._send_midi, IDENTITY_REQUEST)

    def handle_sysex(self, midi_bytes):
        if midi_bytes[0:5] == IDENTITY_RESPONSE:
            if midi_bytes[10] == 38:
                self._mixer.master_strip().set_volume_control(None)
                self._mixer.selected_strip().set_volume_control(
                    self._master_slider)

    def _shift_value(self, value):
        for index in range(NUM_TRACKS):
            if value == 0:
                self._mixer.channel_strip(index).set_solo_button(None)
                self._mixer.channel_strip(index).set_mute_button(
                    self._mute_solo_buttons[index])
                self._mixer.set_bank_buttons(None, None)
                self._mixer.set_select_buttons(self._track_up_button,
                                               self._track_down_button)
            else:
                self._mixer.channel_strip(index).set_mute_button(None)
                self._mixer.channel_strip(index).set_solo_button(
                    self._mute_solo_buttons[index])
                self._mixer.set_select_buttons(None, None)
                self._mixer.set_bank_buttons(self._track_up_button,
                                             self._track_down_button)
class Axiom_DirectLink(ControlSurface):
    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
            self.set_pad_translations(PAD_TRANSLATIONS)
            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, ):
            if 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_selection_follows_track_selection=True)
        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):
        self._shift_pressed = value > 0
        for encoder in self._encoders:
            encoder.set_peek_mode(self._shift_pressed)

        if self._shift_pressed:
            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 self._device_component.is_enabled():
            display_string = ' - '
            if sender.mapped_parameter() != None:
                display_string = 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 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:
                    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 = 'Ma'
                else:
                    pass
                if 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:
                    pass
                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 self._mixer.is_enabled():
            if value > 0:
                strip = None
                if sender == self._selected_mute_solo_button:
                    strip = self._mixer.selected_strip()
                else:
                    strip = self._mixer.channel_strip(
                        self._strip_buttons.index(sender))
                if strip != None:
                    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 self._device_component.is_enabled():
            if value > 0:
                data_source = self._device_component.bank_name_data_source()
                if self._shift_pressed:
                    data_source = 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 value > 0:
            if self._device_component.is_enabled():
                if self.song().view.selected_track.view.select_instrument():
                    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:
            if 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):
        self._display.segment(0).set_data_source(data_source)
        data_source.update()