示例#1
0
    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 set_touch_mode(self, touchchannel):
     self.touch_mode = True
     nr_dev_ctrl = len(self._parameter_controls)
     for ctrl in self._parameter_controls:
         touch_button = ButtonElement(False, MIDI_CC_TYPE, touchchannel, ctrl.message_identifier())
         self.del_touch_buttons.append(touch_button)
         touch_button.add_value_listener(self._clear_param, True)
示例#3
0
    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'
示例#4
0
 def createButton(ccindenfier, nr_freq):
     button = ButtonElement(True, MIDI_CC_TYPE, 1, ccindenfier)
     button.add_value_listener(self._select_value, True)
     button.active = False
     button.freq = nr_freq
     button.cfg = False
     button.hold = False
     return button
示例#5
0
 def set_touch_mode(self, touchchannel):
     self.touch_mode = True
     nr_dev_ctrl = len(self._parameter_controls)
     for ctrl in self._parameter_controls:
         touch_button = ButtonElement(False, MIDI_CC_TYPE, touchchannel,
                                      ctrl.message_identifier())
         self.del_touch_buttons.append(touch_button)
         touch_button.add_value_listener(self._clear_param, True)
 def createButton(ccindenfier, nr_freq):
     button = ButtonElement(True, MIDI_CC_TYPE, 1, ccindenfier)
     button.add_value_listener(self._select_value, True)
     button.active = False
     button.freq = nr_freq
     button.cfg = False
     button.hold = False
     return button
示例#7
0
 def createCfgButton(ccindenfier, nr_freq_idx):
     button = ButtonElement(True, MIDI_CC_TYPE, 2, ccindenfier)
     button.add_value_listener(self._select_value, True)
     button.active = False
     button.fr_idx = nr_freq_idx
     button.freq = CFG_REPEAT_FREQUENCIES[nr_freq_idx]
     button.cfg = True
     button.hold = False
     return button
 def createCfgButton(ccindenfier, nr_freq_idx):
     button = ButtonElement(True, MIDI_CC_TYPE, 2, ccindenfier)
     button.add_value_listener(self._select_value, True)
     button.active = False
     button.fr_idx = nr_freq_idx
     button.freq = CFG_REPEAT_FREQUENCIES[nr_freq_idx]
     button.cfg = True
     button.hold = False
     return button
示例#9
0
    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        self.sebukyChannel = 15
        with self.component_guard():
            self._left_button = ButtonElement(True, MIDI_CC_TYPE,
                                              self.sebukyChannel, 21)
            self._right_button = ButtonElement(True, MIDI_CC_TYPE,
                                               self.sebukyChannel, 22)
            self.lockBtn = ButtonElement(True, MIDI_CC_TYPE,
                                         self.sebukyChannel, 23)
            self.onOffBtn = ButtonElement(True, MIDI_CC_TYPE,
                                          self.sebukyChannel, 24)
            encoders = ButtonMatrixElement(rows=[[
                EncoderElement(MIDI_CC_TYPE,
                               0,
                               identifier + 70,
                               Live.MidiMap.MapMode.absolute,
                               name='Encoder_%d' % identifier)
                for identifier in xrange(4)
            ]])
            device = DeviceComponent(
                name='Device',
                is_enabled=False,
                layer=Layer(parameter_controls=encoders,
                            prev_device_button=self._left_button,
                            next_device_button=self._right_button))
            device.set_enabled(True)
            device.set_lock_button(self.lockBtn)
            device.set_on_off_button(self.onOffBtn)
            self.set_device_component(device)
            self._device_selection_follows_track_selection = True
            self._long_press = 500
            self.__c_instance = c_instance
            self.c_instance = c_instance
            self.log_message('sebas initiated')
            self.conter = 0
            Pad1 = ButtonElement(True, MIDI_CC_TYPE, 0, 64)
            Pad1.add_value_listener(self._session_record_value,
                                    identify_sender=False)

            #self.backBtn = ButtonElement(True, MIDI_CC_TYPE, 0, 105)
            #self.backBtn.add_value_listener(self.goBack, identify_sender=False)
            #self.forwardBtn = ButtonElement(True, MIDI_CC_TYPE, 0, 104)
            #self.forwardBtn.add_value_listener(
            #self.goFront, identify_sender=False)
            # mappings for registered MIDI notes/CCs
            self.midi_callbacks = {}

            # lookup object for fast lookup of cc to mode
            self.midi_cc_to_mode = {}
示例#10
0
class DeleteClip(ControlSurface):

    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
        	self.log_message("DeleteClip started")
        	self.show_message('DeleteClip started')
		self.DeleteButton = ButtonElement(IS_MOMENTARY, MIDI_NOTE_TYPE, 8, 39)
        	self.DeleteButton.add_value_listener(self._delete_clip,identify_sender= False)
    
    def _delete_clip(self, value):
        self.log_message('Deleting clip')
        CurrentSlot = self.song().view.highlighted_clip_slot
        if CurrentSlot.has_clip:
		CurrentSlot.delete_clip()
class AKF_Oxy61(ControlSurface):
    __module__ = __name__
    __doc__ = "MAudio Oxygen 61 MIDI Remote script "

    def __init__(self, c_instance):
        with self.component_guard():
            ControlSurface.__init__(self, c_instance)
            self.log_message(
                time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) +
                "+ + ========= AKF_Oxy61 log opened ========= + +")
            # Writes message into Live's main log file. This is a ControlSurface method.
            self.set_suppress_rebuild_requests(
                True
            )  # Turn off rebuild MIDI map until after we're done setting up

            #paste from Oxygen_3rd_Gen.py
            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._setup_mixer_control()  # Setup the mixer object
            self._setup_session_control()  # Setup the session object

            self.set_suppress_rebuild_requests(
                False)  # Turn rebuild back on, once we're done setting up
示例#12
0
class LaunchMod(ControlSurface):
    """ Script for Novation's Launchpad Controller """
    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
            self._monomod_version = 'b995'
            self._host_name = 'LaunchMod'
            self._color_type = 'Launchpad'
            self.hosts = []
            self._timer = 0
            self._suppress_send_midi = True
            self._suppress_session_highlight = True
            self._suppress_highlight = False
            is_momentary = True
            self._suggested_input_port = 'Launchpad'
            self._suggested_output_port = 'Launchpad'
            self._control_is_with_automap = False
            self._user_byte_write_button = ButtonElement(
                is_momentary, MIDI_CC_TYPE, 0, 16)
            self._user_byte_write_button.name = 'User_Byte_Button'
            self._user_byte_write_button.send_value(1)
            self._user_byte_write_button.add_value_listener(
                self._user_byte_value)
            self._wrote_user_byte = False
            self._challenge = Live.Application.get_random_int(
                0, 400000000) & 2139062143
            matrix = ButtonMatrixElement()
            matrix.name = 'Button_Matrix'
            for row in range(8):
                button_row = [
                    ConfigurableButtonElement(
                        is_momentary, MIDI_NOTE_TYPE, 0, ((row * 16) + column),
                        str(column) + '_Clip_' + str(row) + '_Button', self)
                    for column in range(8)
                ]
                matrix.add_row(tuple(button_row))
            self._config_button = ButtonElement(is_momentary,
                                                MIDI_CC_TYPE,
                                                0,
                                                0,
                                                optimized_send_midi=False)
            self._config_button.add_value_listener(self._config_value)
            top_button_names = [
                'Bank_Select_Up_Button', 'Bank_Select_Down_Button',
                'Bank_Select_Left_Button', 'Bank_Select_Right_Button',
                'Session_Button', 'User1_Button', 'User2_Button',
                'Mixer_Button'
            ]
            side_button_names = [
                'Vol_Button', 'Pan_Button', 'SndA_Button', 'SndB_Button',
                'Stop_Button', 'Trk_On_Button', 'Solo_Button', 'Arm_Button'
            ]
            top_buttons = [
                ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0,
                                          (104 + index),
                                          top_button_names[index], self)
                for index in range(8)
            ]
            side_buttons = [
                ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0,
                                          SIDE_NOTES[index],
                                          side_button_names[index], self)
                for index in range(8)
            ]
            self._setup_monobridge()
            self._setup_monomod()
            self._selector = MainSelectorComponent(matrix, tuple(top_buttons),
                                                   tuple(side_buttons),
                                                   self._config_button, self)
            self._selector.name = 'Main_Modes'
            for control in self.controls:
                if isinstance(control, MonoButtonElement):
                    control.add_value_listener(self._button_value)
            self.set_highlighting_session_component(
                self._selector.session_component())
            self._suppress_session_highlight = False
        self.log_message(
            "--------------= " + str(self._monomod_version) +
            " log opened =--------------")  #Create entry in log file

    def allow_updates(self, allow_updates):
        for component in self.components:
            component.set_allow_update(int(allow_updates != 0))

    def disconnect(self):
        self._suppress_send_midi = True
        for control in self.controls:
            if isinstance(control, ConfigurableButtonElement):
                control.remove_value_listener(self._button_value)

        self._selector = None
        self._user_byte_write_button.remove_value_listener(
            self._user_byte_value)
        self._config_button.remove_value_listener(self._config_value)
        ControlSurface.disconnect(self)
        self._suppress_send_midi = False
        self._config_button.send_value(32)
        self._config_button.send_value(0)
        self._config_button = None
        self._user_byte_write_button.send_value(0)
        self._user_byte_write_button = None

    def refresh_state(self):
        ControlSurface.refresh_state(self)
        self.schedule_message(5, self._update_hardware)

    def handle_sysex(self, midi_bytes):
        if len(midi_bytes) == 8:
            if midi_bytes[1:5] == (0, 32, 41, 6):
                response = long(midi_bytes[5])
                response += long(midi_bytes[6]) << 8
                if response == Live.Application.encrypt_challenge2(
                        self._challenge):
                    self._suppress_send_midi = False
                    self.set_enabled(True)

    def build_midi_map(self, midi_map_handle):
        ControlSurface.build_midi_map(self, midi_map_handle)
        if self._selector.mode_index == 1:
            new_channel = self._selector.channel_for_current_mode()
            for note in DRUM_NOTES:
                self._translate_message(MIDI_NOTE_TYPE, note, 0, note,
                                        new_channel)

    def _send_midi(self, midi_bytes, optimized=None):
        sent_successfully = False
        if not self._suppress_send_midi:
            sent_successfully = ControlSurface._send_midi(self,
                                                          midi_bytes,
                                                          optimized=optimized)
        return sent_successfully

    def _update_hardware(self):
        self._suppress_send_midi = False
        self._wrote_user_byte = True
        self._user_byte_write_button.send_value(1)
        self._suppress_send_midi = True
        self.set_enabled(False)
        self._suppress_send_midi = False
        self._send_challenge()

    def _send_challenge(self):
        for index in range(4):
            challenge_byte = self._challenge >> 8 * index & 127
            self._send_midi((176, 17 + index, challenge_byte))

    def _user_byte_value(self, value):
        assert value in range(128)
        enabled = self._wrote_user_byte or value == 1
        self._control_is_with_automap = not enabled
        self._suppress_send_midi = self._control_is_with_automap
        if not self._control_is_with_automap:
            for control in self.controls:
                if isinstance(control, MonoButtonElement):
                    control.set_force_next_value()

        self._selector.set_mode(0)
        self.set_enabled(enabled)
        self._suppress_send_midi = False

    def _button_value(self, value):
        assert value in range(128)

    def _config_value(self, value):
        assert value in range(128)

    def _set_session_highlight(self, track_offset, scene_offset, width, height,
                               include_return_tracks):
        if not self._suppress_session_highlight:
            ControlSurface._set_session_highlight(self, track_offset,
                                                  scene_offset, width, height,
                                                  include_return_tracks)

    def _setup_m4l_interface(self):
        self._m4l_interface = M4LInterfaceComponent(
            controls=self.controls, component_guard=self.component_guard)
        self.get_control_names = self._m4l_interface.get_control_names
        self.get_control = self._m4l_interface.get_control
        self.grab_control = self._m4l_interface.grab_control
        self.release_control = self._m4l_interface.release_control

    """Mono overrides and additions"""

    def _setup_monobridge(self):
        self._monobridge = MonoBridgeElement(self)
        self._monobridge.name = 'MonoBridge'

    def _setup_monomod(self):
        self._host = MonomodComponent(self)
        self._host.name = 'Monomod_Host'
        self.hosts = [self._host]

    def update_display(self):
        ControlSurface.update_display(self)
        self._timer = (self._timer + 1) % 256
        self.flash()

    def flash(self):
        if self._host.is_enabled():
            for control in self.controls:
                if isinstance(control, MonoButtonElement):
                    control.flash(self._timer)
class Launchpad(ControlSurface):
    """ Script for Novation's Launchpad Controller """

    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
            self._suppress_send_midi = True
            self._suppress_session_highlight = True
            is_momentary = True
            self._suggested_input_port = 'Launchpad'
            self._suggested_output_port = 'Launchpad'
            self._control_is_with_automap = False
            self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)
            self._user_byte_write_button.name = 'User_Byte_Button'
            self._user_byte_write_button.send_value(1)
            self._user_byte_write_button.add_value_listener(self._user_byte_value)
            self._wrote_user_byte = False
            self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143
            matrix = ButtonMatrixElement()
            matrix.name = 'Button_Matrix'
            for row in range(8):
                button_row = []
                for column in range(8):
                    button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, row * 16 + column)
                    button.name = str(column) + '_Clip_' + str(row) + '_Button'
                    button_row.append(button)

                matrix.add_row(tuple(button_row))

            self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0, optimized_send_midi=False)
            self._config_button.add_value_listener(self._config_value)
            top_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0, 104 + index) for index in range(8) ]
            side_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index]) for index in range(8) ]
            top_buttons[0].name = 'Bank_Select_Up_Button'
            top_buttons[1].name = 'Bank_Select_Down_Button'
            top_buttons[2].name = 'Bank_Select_Left_Button'
            top_buttons[3].name = 'Bank_Select_Right_Button'
            top_buttons[4].name = 'Session_Button'
            top_buttons[5].name = 'User1_Button'
            top_buttons[6].name = 'User2_Button'
            top_buttons[7].name = 'Mixer_Button'
            side_buttons[0].name = 'Vol_Button'
            side_buttons[1].name = 'Pan_Button'
            side_buttons[2].name = 'SndA_Button'
            side_buttons[3].name = 'SndB_Button'
            side_buttons[4].name = 'Stop_Button'
            side_buttons[5].name = 'Trk_On_Button'
            side_buttons[6].name = 'Solo_Button'
            side_buttons[7].name = 'Arm_Button'
            self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button)
            self._selector.name = 'Main_Modes'
            for control in self.controls:
                if isinstance(control, ConfigurableButtonElement):
                    control.add_value_listener(self._button_value)

            self.set_highlighting_session_component(self._selector.session_component())
            self._suppress_session_highlight = False

    def disconnect(self):
        self._suppress_send_midi = True
        for control in self.controls:
            if isinstance(control, ConfigurableButtonElement):
                control.remove_value_listener(self._button_value)

        self._selector = None
        self._user_byte_write_button.remove_value_listener(self._user_byte_value)
        self._config_button.remove_value_listener(self._config_value)
        ControlSurface.disconnect(self)
        self._suppress_send_midi = False
        self._config_button.send_value(32)
        self._config_button.send_value(0)
        self._config_button = None
        self._user_byte_write_button.send_value(0)
        self._user_byte_write_button = None

    def refresh_state(self):
        ControlSurface.refresh_state(self)
        self.schedule_message(5, self._update_hardware)

    def handle_sysex(self, midi_bytes):
        if len(midi_bytes) == 8:
            if midi_bytes[1:5] == (0, 32, 41, 6):
                response = long(midi_bytes[5])
                response += long(midi_bytes[6]) << 8
                if response == Live.Application.encrypt_challenge2(self._challenge):
                    self._on_handshake_successful()

    def _on_handshake_successful(self):
        self._suppress_send_midi = False
        self.set_enabled(True)

    def build_midi_map(self, midi_map_handle):
        ControlSurface.build_midi_map(self, midi_map_handle)
        if self._selector.mode_index == 1:
            new_channel = self._selector.channel_for_current_mode()
            for note in DRUM_NOTES:
                self._translate_message(MIDI_NOTE_TYPE, note, 0, note, new_channel)

    def _send_midi(self, midi_bytes, optimized = None):
        sent_successfully = False
        if not self._suppress_send_midi:
            sent_successfully = ControlSurface._send_midi(self, midi_bytes, optimized=optimized)
        return sent_successfully

    def _update_hardware(self):
        self._suppress_send_midi = False
        self._wrote_user_byte = True
        self._user_byte_write_button.send_value(1)
        self._suppress_send_midi = True
        self.set_enabled(False)
        self._suppress_send_midi = False
        self._send_challenge()

    def _send_challenge(self):
        for index in range(4):
            challenge_byte = self._challenge >> 8 * index & 127
            self._send_midi((176, 17 + index, challenge_byte))

    def _user_byte_value(self, value):
        if not value in range(128):
            raise AssertionError
            enabled = self._wrote_user_byte or value == 1
            self._control_is_with_automap = not enabled
            self._suppress_send_midi = self._control_is_with_automap
            if not self._control_is_with_automap:
                for control in self.controls:
                    if isinstance(control, ConfigurableButtonElement):
                        control.set_force_next_value()

            self._selector.set_mode(0)
            self.set_enabled(enabled)
            self._suppress_send_midi = False
        else:
            self._wrote_user_byte = False

    def _button_value(self, value):
        raise value in range(128) or AssertionError

    def _config_value(self, value):
        raise value in range(128) or AssertionError

    def _set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks):
        if not self._suppress_session_highlight:
            ControlSurface._set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks)
示例#14
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 Oxygen_3rd_Gen(ControlSurface):
    """ Script for the 3rd generation of M-Audio's Oxygen controllers """

    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._device_selection_follows_track_selection = 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.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)
        return

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

    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)
        return

    def _shift_value(self, value):
        raise value in range(128) or AssertionError
        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)

        return
示例#16
0
class midi_twister_110(ControlSurface):
    def __init__(self, c_instance):
        super(midi_twister_110, self).__init__(c_instance)
        with self.component_guard():
            global active_mode
            active_mode = "_mode1"
            self._set_active_mode()
            self.show_message("Modified by XXPW")

    def _mode1(self):
        self.show_message("_mode1 is active")
        # mixer
        global mixer
        num_tracks = 32
        num_returns = 7
        self.mixer = MixerComponent(num_tracks, num_returns)
        self.mixer.set_track_offset(0)
        self.song().view.selected_track = self.mixer.channel_strip(0)._track
        # sends
        send0_controls = (
            SliderElement(MIDI_CC_TYPE, 0, 32),
            SliderElement(MIDI_CC_TYPE, 0, 36),
            SliderElement(MIDI_CC_TYPE, 0, 40),
            None,
            None,
            None,
            None,
            None,
        )
        self.mixer.channel_strip(0).set_send_controls(tuple(send0_controls))
        self.mixer.channel_strip(0).set_volume_control(
            SliderElement(MIDI_CC_TYPE, 0, 44))
        send1_controls = (
            SliderElement(MIDI_CC_TYPE, 0, 33),
            SliderElement(MIDI_CC_TYPE, 0, 37),
            SliderElement(MIDI_CC_TYPE, 0, 41),
            None,
            None,
            None,
            None,
            None,
        )
        self.mixer.channel_strip(1).set_send_controls(tuple(send1_controls))
        self.mixer.channel_strip(1).set_volume_control(
            SliderElement(MIDI_CC_TYPE, 0, 45))

        send2_controls = (
            SliderElement(MIDI_CC_TYPE, 0, 34),
            SliderElement(MIDI_CC_TYPE, 0, 38),
            SliderElement(MIDI_CC_TYPE, 0, 42),
            None,
            None,
            None,
            None,
            None,
        )
        self.mixer.channel_strip(2).set_send_controls(tuple(send2_controls))
        self.mixer.channel_strip(2).set_volume_control(
            SliderElement(MIDI_CC_TYPE, 0, 46))
        send3_controls = (
            SliderElement(MIDI_CC_TYPE, 0, 35),
            SliderElement(MIDI_CC_TYPE, 0, 39),
            SliderElement(MIDI_CC_TYPE, 0, 43),
            None,
            None,
            None,
            None,
            None,
        )
        self.mixer.channel_strip(3).set_send_controls(tuple(send3_controls))
        self.mixer.channel_strip(3).set_volume_control(
            SliderElement(MIDI_CC_TYPE, 0, 47))
        # session
        global _session
        num_tracks = 4
        num_scenes = 3
        session_buttons = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
        self._pads = [
            ButtonElement(1, MIDI_CC_TYPE, 1, session_buttons[index])
            for index in range(num_tracks * num_scenes)
        ]
        self._grid = ButtonMatrixElement(rows=[
            self._pads[(index * num_tracks):(index * num_tracks) + num_tracks]
            for index in range(num_scenes)
        ])
        self._session = SessionComponent(num_tracks, num_scenes)
        self._session.set_clip_launch_buttons(self._grid)
        self.set_highlighting_session_component(self._session)
        # session track stop
        stop_track_buttons = [12, 13, 14, 15]
        self._track_stop_buttons = [
            ButtonElement(1, MIDI_CC_TYPE, 1, stop_track_buttons[index])
            for index in range(num_tracks)
        ]
        self._session.set_stop_track_clip_buttons(
            tuple(self._track_stop_buttons))
        # session navigation
        self.session_left = ButtonElement(1, MIDI_CC_TYPE, 3, 8)
        self._session.set_page_left_button(self.session_left)
        self.session_left.add_value_listener(self._reload_active_devices,
                                             identify_sender=False)
        self.session_right = ButtonElement(1, MIDI_CC_TYPE, 3, 11)
        self._session.set_page_right_button(self.session_right)
        self.session_right.add_value_listener(self._reload_active_devices,
                                              identify_sender=False)
        self.session_up = ButtonElement(1, MIDI_CC_TYPE, 3, 10)
        self._session.set_page_up_button(self.session_up)
        self.session_up.add_value_listener(self._reload_active_devices,
                                           identify_sender=False)
        self.session_down = ButtonElement(1, MIDI_CC_TYPE, 3, 13)
        self._session.set_page_down_button(self.session_down)
        self.session_down.add_value_listener(self._reload_active_devices,
                                             identify_sender=False)
        self._session._link()
        self._session.set_mixer(self.mixer)
        #self._session.set_mixer(self.mixer)
        self._mode1_devices()
        self.add_device_listeners()
        # button: next device
        self.next_device = ButtonElement(0, MIDI_CC_TYPE, 1, 25)
        self.next_device.add_value_listener(self._next_device_value,
                                            identify_sender=False)
        # button: prev device
        self.previous_device = ButtonElement(1, MIDI_CC_TYPE, 1, 24)
        self.previous_device.add_value_listener(self._prev_device_value,
                                                identify_sender=False)
        # transport
        global transport
        self.transport = TransportComponent()
        self.transport.name = 'Transport'
        loop_button = ButtonElement(1, MIDI_CC_TYPE, 1, 50)
        loop_button.name = 'loop_button'
        self.transport.set_loop_button(loop_button)
        stop_button = ButtonElement(1, MIDI_CC_TYPE, 1, 49)
        stop_button.name = 'stop_button'
        self.transport.set_stop_button(stop_button)
        play_button = ButtonElement(1, MIDI_CC_TYPE, 1, 48)
        play_button.name = 'play_button'
        self.transport.set_play_button(play_button)
        # button: track navigation right
        self.track_navigation_right = ButtonElement(1, MIDI_CC_TYPE, 3, 17)
        self.track_navigation_right.add_value_listener(
            self._track_navigation_right_track_nav, identify_sender=False)
        # button: track navigation left
        self.track_navigation_left = ButtonElement(1, MIDI_CC_TYPE, 3, 14)
        self.track_navigation_left.add_value_listener(
            self._track_navigation_left_track_nav, identify_sender=False)

    def _remove_mode1(self):
        # mixer
        global mixer
        self._remove_mode1_devices()
        self.remove_device_listeners()
        send0_controls = (
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
        )
        self.mixer.channel_strip(0).set_send_controls(tuple(send0_controls))
        send1_controls = (
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
        )
        self.mixer.channel_strip(1).set_send_controls(tuple(send1_controls))
        send2_controls = (
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
        )
        self.mixer.channel_strip(2).set_send_controls(tuple(send2_controls))
        send3_controls = (
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
        )
        self.mixer.channel_strip(3).set_send_controls(tuple(send3_controls))
        # session
        global _session
        self._session.set_clip_launch_buttons(None)
        self.set_highlighting_session_component(None)
        self._session.set_mixer(None)
        self._session.set_stop_all_clips_button(None)
        # session track stop
        self._track_stop_buttons = None
        self._session.set_stop_track_clip_buttons(None)
        # session scene launch
        self._scene_launch_buttons = None
        self._session.set_scene_launch_buttons(None)
        # session navigation
        self.session_left.remove_value_listener(self._reload_active_devices)
        self._session.set_page_left_button(None)
        self.session_right.remove_value_listener(self._reload_active_devices)
        self._session.set_page_right_button(None)
        self.session_up.remove_value_listener(self._reload_active_devices)
        self._session.set_page_up_button(None)
        self.session_down.remove_value_listener(self._reload_active_devices)
        self._session.set_page_down_button(None)
        self._session = None
        self.next_device.remove_value_listener(self._next_device_value)
        self.next_device = None
        self.previous_device.remove_value_listener(self._prev_device_value)
        self.previous_device = None
        # transport
        global transport
        self.transport.set_loop_button(None)
        self.transport.set_stop_button(None)
        self.transport.set_play_button(None)
        self.transport = None
        self.track_navigation_right.remove_value_listener(
            self._track_navigation_right_track_nav)
        self.track_navigation_right = None
        self.track_navigation_left.remove_value_listener(
            self._track_navigation_left_track_nav)
        self.track_navigation_left = None

    def _mode1_devices(self):
        global mixer
        global _session
        # device
        self.mixer.selected_strip().set_volume_control(
            SliderElement(MIDI_CC_TYPE, 0, 28))
        self.mixer.selected_strip().set_pan_control(
            SliderElement(MIDI_CC_TYPE, 0, 29))
        self.mixer.selected_strip().set_mute_button(
            ButtonElement(1, MIDI_CC_TYPE, 1, 28))
        self.mixer.selected_strip().set_solo_button(
            ButtonElement(1, MIDI_CC_TYPE, 1, 29))

        if (len(self.mixer.selected_strip()._track.devices) > 0):
            global device_tracktype_selected__chain_number_selected
            self.device_tracktype_selected__chain_number_selected = DeviceComponent(
            )
            device_controls = (
                SliderElement(MIDI_CC_TYPE, 0, 16),
                SliderElement(MIDI_CC_TYPE, 0, 17),
                SliderElement(MIDI_CC_TYPE, 0, 18),
                SliderElement(MIDI_CC_TYPE, 0, 19),
                SliderElement(MIDI_CC_TYPE, 0, 20),
                SliderElement(MIDI_CC_TYPE, 0, 21),
                SliderElement(MIDI_CC_TYPE, 0, 22),
                SliderElement(MIDI_CC_TYPE, 0, 23),
            )
            self.device_tracktype_selected__chain_number_selected.set_parameter_controls(
                tuple(device_controls))
            self.set_device_component(
                self.device_tracktype_selected__chain_number_selected)
            self.device_tracktype_selected__chain_number_selected.set_on_off_button(
                ButtonElement(1, MIDI_CC_TYPE, 1, 26))
            self.device_tracktype_selected__chain_number_selected.set_bank_nav_buttons(
                ButtonElement(0, MIDI_CC_TYPE, 1, 31),
                ButtonElement(1, MIDI_CC_TYPE, 1, 33))

    def _remove_mode1_devices(self):
        global mixer
        global _session
        # device
        if (hasattr(self, 'device_tracktype_selected__chain_number_selected')):
            global device_tracktype_selected__chain_number_selected
            device_controls = (
                None,
                None,
                None,
                None,
                None,
                None,
                None,
                None,
            )
            self.device_tracktype_selected__chain_number_selected.set_parameter_controls(
                tuple(device_controls))
            self.device_tracktype_selected__chain_number_selected.set_on_off_button(
                None)
            self.device_tracktype_selected__chain_number_selected.set_bank_nav_buttons(
                None, None)
            self.set_device_component(
                self.device_tracktype_selected__chain_number_selected)

    def add_device_listeners(self):
        global mixer
        num_of_tracks = len(self.song().tracks)
        value = "add device listener"
        for index in range(num_of_tracks):
            self.song().tracks[index].add_devices_listener(
                self._reload_active_devices)

    def remove_device_listeners(self):
        global mixer
        num_of_tracks = len(self.song().tracks)
        value = "remove device listener"
        for index in range(num_of_tracks):
            self.song().tracks[index].remove_devices_listener(
                self._reload_active_devices)

    def _on_selected_track_changed(self):
        ControlSurface._on_selected_track_changed(self)
        self._display_reset_delay = 0
        value = "selected track changed"
        self._reload_active_devices(value)

    def _reload_active_devices(self, value=None):
        self._remove_active_devices()
        self._set_active_devices()

    def _set_active_devices(self):
        global active_mode
        # activate mode
        if (active_mode == "_mode1") and (hasattr(self, '_mode1_devices')):
            self._mode1_devices()

    def _remove_active_devices(self):
        global active_mode
        # remove activate mode
        if (active_mode == "_mode1") and (hasattr(self, '_mode1_devices')):
            self._remove_mode1_devices()

    def _next_device_value(self, value):
        if value > 0:
            self._device = self.song().view.selected_track.view.selected_device
            if self._device is not None:
                self.song().view.select_device(
                    self.song().view.selected_track.devices[
                        self.selected_device_idx() + 1])

    def _prev_device_value(self, value):
        if value > 0:
            self._device = self.song().view.selected_track.view.selected_device
            if self._device is not None:
                self.song().view.select_device(
                    self.song().view.selected_track.devices[
                        self.selected_device_idx() - 1])

    def selected_device_idx(self):
        self._device = self.song().view.selected_track.view.selected_device
        return self.tuple_index(self.song().view.selected_track.devices,
                                self._device)

    def _track_navigation_right_track_nav(self, value):
        if value > 0:
            self.song().view.selected_track = self.song().tracks[
                self.selected_track_idx() + 1]

    def _track_navigation_left_track_nav(self, value):
        if value > 0:
            self.song().view.selected_track = self.song().tracks[
                self.selected_track_idx() - 1]

    def selected_track_idx(self):
        return self.tuple_index(self.song().tracks,
                                self.song().view.selected_track)

    def _set_active_mode(self):
        global active_mode
        # activate mode
        if active_mode == "_mode1":
            self._mode1()

    def _remove_active_mode(self):
        global active_mode
        # remove activate mode
        if active_mode == "_mode1":
            self._remove_mode1()

    def _activate_mode1(self, value):
        global active_mode
        if value > 0:
            self._remove_active_mode()
            active_mode = "_mode1"
            self._set_active_mode()

    def _activate_shift_mode1(self, value):
        global active_mode
        if value > 0:
            self._remove_active_mode()
            self._mode1()
        else:
            self._remove_mode1()
            self._set_active_mode()

    def tuple_index(self, tuple, obj):
        for i in xrange(0, len(tuple)):
            if (tuple[i] == obj):
                return i
        return (False)

    def disconnect(self):
        super(midi_twister_110, self).disconnect()
示例#17
0
class LaunchMod(ControlSurface):
    __module__ = __name__
    __doc__ = " Script for Novation's Launchpad Controller "

    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        self._monomod_version = 'b994'
        self._host_name = 'LaunchMod'
        self._color_type = 'Launchpad'
        self.hosts = []
        self._timer = 0
        self.set_suppress_rebuild_requests(True)
        self._suppress_send_midi = True
        self._suppress_session_highlight = True
        is_momentary = True
        self._suggested_input_port = 'Launchpad'
        self._suggested_output_port = 'Launchpad'
        self._wrote_user_byte = False
        self._control_is_with_automap = False
        self._challenge = (Live.Application.get_random_int(0, 400000000)
                           & 2139062143)
        matrix = ButtonMatrixElement()
        matrix.name = 'ButtonMatrix'
        for row in range(8):
            #button_row = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, ((row * 16) + column)) for column in range(8) ]
            button_row = [
                FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, 0,
                                      ((row * 16) + column),
                                      'Button_' + str(row) + '_' + str(column),
                                      self) for column in range(8)
            ]
            matrix.add_row(tuple(button_row))
        self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0)
        self._config_button.add_value_listener(self._config_value)
        top_buttons = [
            FlashingButtonElement(is_momentary, MIDI_CC_TYPE, 0, (104 + index),
                                  'Top_Button' + str(index), self)
            for index in range(8)
        ]
        side_buttons = [
            FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, 0,
                                  SIDE_NOTES[index],
                                  'Side_Button' + str(index), self)
            for index in range(8)
        ]
        self._setup_monobridge()
        self._setup_monomod()
        self._selector = MainSelectorComponent(matrix, tuple(top_buttons),
                                               tuple(side_buttons),
                                               self._config_button, self)
        self._suppress_session_highlight = False
        self._suppress_send_midi = False
        self._user_byte_write_button = ButtonElement(is_momentary,
                                                     MIDI_CC_TYPE, 0, 16)
        self._user_byte_write_button.send_value(1)
        self._user_byte_write_button.add_value_listener(self._user_byte_value)
        self._suppress_send_midi = True
        self.set_suppress_rebuild_requests(False)
        self.log_message("--------------= LaunchMod log opened =--------------"
                         )  #Create entry in log file
        self.refresh_state()

    def _setup_monobridge(self):
        self._monobridge = MonoBridgeElement(self)
        self._monobridge.name = 'MonoBridge'

    def _setup_monomod(self):
        self._host = MonomodComponent(self)
        self._host.name = 'Monomod_Host'
        self.hosts = [self._host]

    def disconnect(self):
        self._suppress_send_midi = True
        self._selector = None
        self._user_byte_write_button.remove_value_listener(
            self._user_byte_value)
        self._config_button.remove_value_listener(self._config_value)
        ControlSurface.disconnect(self)
        self._suppress_send_midi = False
        self._config_button.send_value(32)
        self._config_button.send_value(0)
        self._config_button = None
        self._user_byte_write_button.send_value(0)
        self._user_byte_write_button = None
        self.log_message("--------------= LaunchMod log closed =--------------"
                         )  #Create entry in log file

    def refresh_state(self):
        ControlSurface.refresh_state(self)
        self.schedule_message(5, self._update_hardware)

    def handle_sysex(self, midi_bytes):
        if (len(midi_bytes) == 8):
            if (midi_bytes[1:5] == (0, 32, 41, 6)):
                response = long(midi_bytes[5])
                response += (long(midi_bytes[6]) << 8)
                if (response == Live.Application.encrypt_challenge2(
                        self._challenge)):
                    self._suppress_send_midi = False
                    self.set_enabled(True)
                    #self.refresh_state()

    def _send_midi(self, midi_bytes):
        if (not self._suppress_send_midi):
            ControlSurface._send_midi(self, midi_bytes)

    def _update_hardware(self):
        self._suppress_send_midi = False
        self._config_button.send_value(40)
        self._wrote_user_byte = True
        self._user_byte_write_button.send_value(1)
        self._suppress_send_midi = True
        self.set_enabled(False)
        self._suppress_send_midi = False
        self._send_challenge()

    def _send_challenge(self):
        for index in range(4):
            challenge_byte = ((self._challenge >> (8 * index)) & 127)
            self._send_midi((176, (17 + index), challenge_byte))

    def _user_byte_value(self, value):
        assert (value in range(128))
        enabled = (value == 1)
        if enabled:
            self._config_button.send_value(40)
        self._control_is_with_automap = (not enabled)
        for control in self.controls:
            if isinstance(control, ConfigurableButtonElement):
                control.set_force_next_value()

        if (not self._wrote_user_byte):
            self._selector.set_mode(0)
            self.set_enabled(enabled)
        else:
            self._wrote_user_byte = False
        self.request_rebuild_midi_map()

    def _config_value(self, value):
        assert (value in range(128))

    def _set_session_highlight(self,
                               track_offset,
                               scene_offset,
                               width,
                               height,
                               include_returns=False):
        if (not self._suppress_session_highlight):
            ControlSurface._set_session_highlight(self, track_offset,
                                                  scene_offset, width, height,
                                                  include_returns)

    def _install_forwarding(self, control):
        result = False
        if ((not self._control_is_with_automap)
                or (control == self._user_byte_write_button)):
            result = ControlSurface._install_forwarding(self, control)
        return result

    def _translate_message(self, type, from_identifier, from_channel,
                           to_identifier, to_channel):
        if (not self._control_is_with_automap):
            ControlSurface._translate_message(self, type, from_identifier,
                                              from_channel, to_identifier,
                                              to_channel)

    def update_display(self):
        """ Live -> Script
		Aka on_timer. Called every 100 ms and should be used to update display relevant
		parts of the controller
		"""
        for message in self._scheduled_messages:
            message['Delay'] -= 1
            if (message['Delay'] == 0):
                if (message['Parameter'] != None):
                    message['Message'](message['Parameter'])
                else:
                    message['Message']()
                    del self._scheduled_messages[
                        self._scheduled_messages.index(message)]

        for callback in self._timer_callbacks:
            callback()
        self._timer = (self._timer + 1) % 256
        self.flash()

    def flash(self):
        #if(self.flash_status > 0):
        for row in range(8):
            if (self._selector._side_buttons[row]._flash_state > 0):
                self._selector._side_buttons[row].flash(self._timer)
            for column in range(8):
                button = self._selector._matrix.get_button(column, row)
                if (button._flash_state > 0):
                    button.flash(self._timer)
        for index in range(4):
            if (self._selector._nav_buttons[index]._flash_state > 0):
                self._selector._nav_buttons[index].flash(self._timer)
            if (self._selector._modes_buttons[index]._flash_state > 0):
                self._selector._modes_buttons[index].flash(self._timer)

    def allow_updates(self, allow_updates):
        for component in self.components:
            component.set_allow_update(int(allow_updates != 0))
示例#18
0
文件: sparkLE.py 项目: Raztua/SparkLE
class sparkLE(ControlSurface):
    __module__=__name__
    __doc__="Sparkle function"
    
    def __init__(self, c_instance):
        ControlSurface.__init__(self,c_instance)
        with self.component_guard():
            self.__c_instance = c_instance
            self.log_message("debut du script")
            #self.set_suppress_rebuild_requests(True) # pas de midi request lors du chargement
            #self._setup_session_control() #init session
            #self._setupsequencer_control() # init sequencer
            #creation des outils
            self.actual_song=Live.Application.get_application().get_document()
            self.cache=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
                        
            self._suggested_input_port = 'SparkLE'
            self._suggested_output_port = 'SparkLE'
            self._bank_button = ButtonElement(not IS_MOMENTARY, MIDI_NOTE_TYPE, 0, 16)
            self._patt_button = ButtonElement(not IS_MOMENTARY, MIDI_NOTE_TYPE, 0, 17)
            self._seq_button = ButtonElement(not IS_MOMENTARY, MIDI_NOTE_TYPE, 0, 18)
            self._tune_button = ButtonElement(not IS_MOMENTARY, MIDI_NOTE_TYPE, 0, 19)
            self._select_button = ButtonElement(IS_MOMENTARY, MIDI_NOTE_TYPE, 0, 20)
            self._18_916_button = ButtonElement(not IS_MOMENTARY, MIDI_NOTE_TYPE, 0, 21)            
            self._mute_button = ButtonElement(not IS_MOMENTARY, MIDI_NOTE_TYPE, 0, 22)
            self._solo_button = ButtonElement(not IS_MOMENTARY, MIDI_NOTE_TYPE, 0, 23)
            
            self._bank_button.name = 'Bank Button'
            self._patt_button.name = 'Pattern Button'
            self._seq_button.name = 'Sequencer Button'
            self._tune_button.name = 'Tune Button'
            self._select_button.name = 'Select Button'
            self._18_916_button.name = 'Pad Select 1-8 / 6-16 Button'
            self._mute_button.name = 'Mute Button'
            self._solo_button.name = 'solo Buttons'
            
            self._bank_button.status=False
            self._patt_button.status=True
            self._seq_button.status=False
            self._tune_button.status=False
            self._select_button.status=False
            self._18_916_button.status=False
            self._mute_button.status=False
            self._solo_button.status=False
            
            self._bank_button.identifier=16
            self._patt_button.identifier=17
            self._seq_button.identifier=18
            self._tune_button.identifier=19
            self._select_button.identifier=20
            self._18_916_button.identifier=21
            self._mute_button.identifier=22
            self._solo_button.identifier=23
            
            self._bank_button.add_value_listener(self._mode_buttons_value, identify_sender= True)
            self._patt_button.add_value_listener(self._mode_buttons_value, identify_sender= True)
            self._seq_button.add_value_listener(self._mode_buttons_value, identify_sender= True)
            self._tune_button.add_value_listener(self._mode_buttons_value, identify_sender= True)
            self._select_button.add_value_listener(self._select_buttons_value, identify_sender= True)
            self._18_916_button.add_value_listener(self._select_buttons_value, identify_sender= True)
            #self._mute_button.add_value_listener(self._mute_n_solo_buttons_value, identify_sender= True)
            #self._solo_button.add_value_listener(self._patt_n_solo_buttons_value, identify_sender= True)

            
            self._setup_pads() #setup the 8 pads button
            self._setup_patt() #setup the 16 pattern button
            self.actual_pattern_button=self._patt_buttons[0]
            self.active_pad=self._pads_buttons[0]
            self.active_pad.bis=False
            self.translated_channel=0
            
            #live ovject
            actual_song = Live.Application.get_application().get_document()
            
            #init leds
            self.turn_led_on( self.active_pad.identifier+8 )
            

            
        
        
                
    def build_midi_map(self, midi_map_handle):      
		ControlSurface.build_midi_map(self, midi_map_handle)

        
        
               
    def disconnect(self) :
        self._suggested_input_port = 'SparkLE'
        self._suggested_output_port = 'SparkLE'
                                
        self._bank_button = None
        self._patt_button = None
        self._seq_button = None
        self._tune_button = None
        self._select_button = None
        self._18_916_button = None            
        self._mute_button = None
        self._solo_button = None
        
        for index in range(8):
            #removing pad 
            self._pads_buttons[index].name= None
            self._pads_buttons[index].remove_value_listener(self._pads_buttons_value)
        for index in range(16):
            #remoing pattern buttons
            self._patt_buttons[index].name= None
            self._patt_buttons[index].remove_value_listener(self._patt_buttons_value)
        for index in range(127):
            self.turn_led_off(index)
        
        
##################################################setup of pads and patterns##########################################    

    def _setup_pads(self):
        """pads and led setup"""
        self._pads_buttons=[]
        self._pads_leds=[]
        for index in range(8):
            #setup pad 
            self._pads_buttons.append(ButtonElement( not IS_MOMENTARY, MIDI_NOTE_TYPE, 0, PADS_BUTTON + index))
            self._pads_buttons[-1].name= ' PAD '+ str(index+1)
            self._pads_buttons[-1].add_value_listener(self._pads_buttons_value, identify_sender= True)
            self._pads_buttons[-1].status=False
            self._pads_buttons[-1].identifier=index + PADS_BUTTON
            #update of the sequence
            
            
    def suggest_map_mode(self, cc_no,channel):
        if cc_no in range(47,55):
            return Live.MidiMap.MapMode.relative_binary_offset
        if cc_no in [58,59]:
            return Live.MidiMap.MapMode.value
            
    def _setup_patt(self):
        """1 to 16 button setup"""
        self._patt_buttons=[]
        for index in range(16):
                #setup patt button 
            self._patt_buttons.append(ButtonElement(not IS_MOMENTARY, MIDI_NOTE_TYPE, 0, PATT_BUTTON + index))
            self._patt_buttons[-1].name= ' Pattern button '+ str(index+1)
            self._patt_buttons[-1].add_value_listener(self._patt_buttons_value, identify_sender= True)
            self._patt_buttons[-1].status=False
            self._patt_buttons[-1].identifier= index +  PATT_BUTTON
            
            
##############################################midi message routing and analysis ################################            
# select and 1-8/9-16 button message received and routed trough this function
    def _select_buttons_value(self,value, sender):
        if sender==self._select_button:
            self.log_message(value)
            if value>0:
                self._select_button.status=True
                self.turn_led_on(self._select_button.identifier)
                return
            else:
                self._select_button.status=False
                self.turn_led_off(self._select_button.identifier)
                return
        if sender==self._18_916_button and value>0:
            if self._18_916_button.status==False:
                self.log_message("allumage")
                self._18_916_button.status=True
                self.turn_led_on(self._18_916_button.identifier)
                return
            if self._18_916_button.status==True:
                self.log_message("off")
                self._18_916_button.status=False
                self.turn_led_off(self._18_916_button.identifier)
                return

        
        
# pads button message received and routed trough this function
    def _pads_buttons_value(self, value , sender ):
        clipslot=self.actual_song.tracks[TRACK].clip_slots[self.actual_pattern_button.identifier-PATT_BUTTON]        
        if self._select_button.status==True:
            self.turn_led_off( self.active_pad.identifier+8)
            self.active_pad=sender
            self.turn_led_on( self.active_pad.identifier+8)
            self.active_pad.bis=self._18_916_button.status
            self.updatecache(clipslot)
            self.sequencerupdate()
            for index in range(47,55)+[58,59]:
                self._translate_message(1,index,0,index,9)
            
            

    
#pattern bar button message received and routed trough this function        
    def _patt_buttons_value(self, value , sender ):
            clipslot=self.actual_song.tracks[TRACK].clip_slots[self.actual_pattern_button.identifier-PATT_BUTTON]
            if self._bank_button.status==True:
                return
            elif self._patt_button.status==True:
                self.turn_led_off(self.actual_pattern_button.identifier)
                self.actual_pattern_button.status=False
                self.actual_pattern_button=sender
                self.actual_pattern_button.status=True
                self.turn_led_on(self.actual_pattern_button.identifier)
                self.createclip(TRACK, self.actual_pattern_button.identifier, LENGTH, clipslot)
                clipslot.clip.fire()
                self.actual_song.view.highlighted_clip_slot = clipslot
                return
            elif self._seq_button.status==True and value>0:
                _index=self._patt_buttons.index(sender)
                self.sequencer(_index,clipslot)
                return
            elif self._tune_button.status==True:
                return
    

            
            
    def _mode_buttons_value(self,value,sender):
        self._bank_button.status=False
        self._patt_button.status=False
        self._seq_button.status=False
        self._tune_button.status=False
        self.clear_pattern_button()
        for index in range(16,20):
            self.turn_led_off(index)        
        if sender.name=='Bank Button':
            self._bank_button.status=True
            self.turn_led_on(16)
        elif sender.name=='Pattern Button':
            self._patt_button.status=True
            self.turn_led_on(PATT_BUTTON+self.actual_pattern_button.identifier)
            self.turn_led_on(17)
        elif sender.name=='Sequencer Button':
            self._seq_button.status=True   
            self.log_message(self.cache)   
            self.turn_led_on(18)
            self.sequencerupdate()
        elif sender.name=='Tune Button':
            self._tune_button.status=True
            self.turn_led_on(19)
 
 
 
#turn off leds of the pattern button bar
    def clear_pattern_button(self):
        for index in range(16):
            self._patt_buttons[index].status=False
            self.turn_led_off(index + PATT_BUTTON)
            
#function used to easily turn on and off leds
    def turn_led_on(self,note):
        self._send_midi((144,note,100))
        
    def turn_led_off(self,note):
        self._send_midi((128,note,100))
    
#used to create clips
    def createclip(self,track,row,length,clipslot):
        self.cache=16*[0]
        if clipslot.clip==None:
            clipslot.create_clip(length)
        else:
            self.updatecache(clipslot)
 
 
 #used to update the cache of the active pattern pads during sequencer update           
    def updatecache(self,clipslot):
        note_tuple=clipslot.clip.get_notes(0.0,self.active_pad.identifier+8*self.active_pad.bis,LENGTH,1)
        self.cache=16*[0]
        if len(note_tuple)>0:
            for tuple in note_tuple:
                self.cache[int(4*tuple[1])]=1

    
#Sequencer funcions
    def sequencerupdate(self):
        for index in range(len(self.cache)):
            if self.cache[index]==0:
                self._patt_buttons[index].status=False
                self.turn_led_off(self._patt_buttons[index].identifier - PATT_BUTTON)
            if self.cache[index]==1:
                self._patt_buttons[index].status=True
                self.turn_led_on(self._patt_buttons[index].identifier - PATT_BUTTON)
        
    def sequencer(self, index,clipslot,track=TRACK):
        if self.cache[index]==0:
            self.cache[index]=1
            clipslot.clip.set_notes(((self.active_pad.identifier+8*self.active_pad.bis,0.25*index,0.22,100,False),))
            self._send_midi((144,self._patt_buttons[index].identifier,100))
        else:
            self.cache[index]=0
            clipslot.clip.remove_notes(0.25*index,self.active_pad.identifier+8*self.active_pad.bis,0.22,1)
            self._send_midi((128,self._patt_buttons[index].identifier,100))
示例#19
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()
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 and 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 and 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 and 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 and 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(MaschineChannelStripComponent, self)._mute_value(value)
        key = self._mute_button.message_identifier()
        if self.clear_mode and 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 == None:
            return
        clips_slots = self._track.clip_slots
        for cs in clips_slots:
            if cs.has_clip and cs.is_playing:
                return cs.clip

    def disconnect(self):
        self.clear_pan_button = None
        self.clear_send_button = None
        if self.clear_vol_button != None:
            self.clear_vol_button.remove_value_listener(self._do_clear_vol)
            self.clear_vol_button = None
        if self.clear_pan_button != None:
            self.clear_pan_button.remove_value_listener(self._do_clear_pan)
            self.clear_pan_button = None
        if self.clear_send_button != None:
            self.clear_send_button.remove_value_listener(self._do_clear_send)
            self.clear_send_button = None
        if not self.touch_mode and self.clear_mode:
            if self.send_control != None:
                self.send_control.remove_value_listener(self._do_clear_send)
                self.send_control = None
            if self._volume_control != None:
                self._volume_control.remove_value_listener(self._do_clear_vol)
                self._volume_control = None
            if self._pan_control != None:
                self._pan_control.remove_value_listener(self._do_clear_pan)
                self._pan_control = None
        super(MaschineChannelStripComponent, self).disconnect()
class NoteRepeatComponent(CompoundComponent):
    __module__ = __name__
    __doc__ = ' Noter Repeat Handler'
    _knob_handler = None

    def __init__(self, note_repeat = None, *a, **k):
        super(NoteRepeatComponent, self).__init__(*a, **k)
        self._note_repeat = note_repeat
        self._adjust_cfg_value.subject = SliderElement(MIDI_CC_TYPE, 2, 105)
        self._note_repeat_button = ButtonElement(True, MIDI_CC_TYPE, 0, 102)
        self._do_note_repeat.subject = self._note_repeat_button
        self._cfg_adjust_button = ButtonElement(True, MIDI_CC_TYPE, 2, 106)
        self._cfg_adjust_button.add_value_listener(self._do_cfg_button)
        self._cfg_down = False
        self._hold_mode = False
        self.nr_down = False
        self._current_nr_button = None
        self._do_change_nr_1.subject = SliderElement(MIDI_CC_TYPE, 1, 76)
        self._do_change_nr_2.subject = SliderElement(MIDI_CC_TYPE, 1, 77)
        self._do_change_nr_3.subject = SliderElement(MIDI_CC_TYPE, 1, 78)
        self._do_change_nr_4.subject = SliderElement(MIDI_CC_TYPE, 1, 79)

        def createButton(ccindenfier, nr_freq):
            button = ButtonElement(True, MIDI_CC_TYPE, 1, ccindenfier)
            button.add_value_listener(self._select_value, True)
            button.active = False
            button.freq = nr_freq
            button.cfg = False
            button.hold = False
            return button

        def createCfgButton(ccindenfier, nr_freq_idx):
            button = ButtonElement(True, MIDI_CC_TYPE, 2, ccindenfier)
            button.add_value_listener(self._select_value, True)
            button.active = False
            button.fr_idx = nr_freq_idx
            button.freq = CFG_REPEAT_FREQUENCIES[nr_freq_idx]
            button.cfg = True
            button.hold = False
            return button

        self._cfg_buttons = [ createCfgButton(assign[0], assign[1]) for assign in CTRL_CFG_TO_FREQ ]
        for button in self._cfg_buttons:
            button.send_value(button.active and 1 or 0, True)

        self.nr_frq = CTRL_TO_FREQ[4][1]
        self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0
        self.buttons = [ createButton(assign[0], assign[1]) for assign in CTRL_TO_FREQ ]
        self.buttons[4].active = True
        self._previous_button = self.buttons[4]
        self._last_active_button = self.buttons[4]
        for button in self.buttons:
            button.send_value(button.active and 1 or 0, True)

    def update(self):
        pass

    def store_values(self, dict):
        for button, idx in zip(self._cfg_buttons, range(len(self._cfg_buttons))):
            dict['cofig-nr-val' + str(idx)] = button.fr_idx

    def recall_values(self, dict):
        for button, idx in zip(self._cfg_buttons, range(len(self._cfg_buttons))):
            key = 'cofig-nr-val' + str(idx)
            if key in dict:
                fqidx = dict[key]
                button.fr_idx = fqidx
                button.freq = CFG_REPEAT_FREQUENCIES[fqidx]

    def registerKnobHandler(self, handler):
        self._knob_handler = handler

    def show_note_rates(self):
        rates = ''
        for button, idx in zip(self._cfg_buttons, range(len(self._cfg_buttons))):
            rates += ' ' + CFG_REPEAT_DISPLAY[button.fr_idx].ljust(5)
            if idx < 3:
                rates += '|'

        self.canonical_parent.timed_message(2, rates)

    def mod_button(self, button, inc, which):
        cindex = button.fr_idx
        maxindex = len(CFG_REPEAT_FREQUENCIES) - 1
        minindex = 0
        if self.canonical_parent.isShiftDown():
            inc *= 2
            if not (cindex % 2 == 0 and maxindex):
                maxindex = maxindex - 1
                minindex = cindex % 2
            new_idx = max(minindex, min(maxindex, cindex + inc))
            if new_idx != cindex:
                self.canonical_parent.show_message('Note Repeat Button ' + str(which) + ' : ' + CFG_REPEAT_DISPLAY[new_idx])
                button.fr_idx = new_idx
                button.freq = CFG_REPEAT_FREQUENCIES[new_idx]
                self.nr_frq = button.active and CFG_REPEAT_FREQUENCIES[new_idx]
                self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0

    @subject_slot('value')
    def _do_change_nr_1(self, value):
        self.mod_button(self._cfg_buttons[0], value == 0 and -1 or 1, 1)
        self.show_note_rates()

    @subject_slot('value')
    def _do_change_nr_2(self, value):
        self.mod_button(self._cfg_buttons[1], value == 0 and -1 or 1, 2)
        self.show_note_rates()

    @subject_slot('value')
    def _do_change_nr_3(self, value):
        self.mod_button(self._cfg_buttons[2], value == 0 and -1 or 1, 3)
        self.show_note_rates()

    @subject_slot('value')
    def _do_change_nr_4(self, value):
        self.mod_button(self._cfg_buttons[3], value == 0 and -1 or 1, 4)
        self.show_note_rates()

    def _do_cfg_button(self, value):
        if value != 0:
            self._cfg_down = True
            button = self._current_nr_button
            if button and button.cfg and button.fr_idx >= 0:
                self.canonical_parent.show_message('Note Repeat ' + CFG_REPEAT_DISPLAY[button.fr_idx])
        else:
            self._cfg_down = False
        if self._knob_handler:
            self._knob_handler.do_main_push(value)

    @subject_slot('value')
    def _adjust_cfg_value(self, value):
        button = self._current_nr_button
        if button and button.cfg and (self.nr_down or button.hold or self._hold_mode and button.active):
            if not (value == 127 and -1):
                inc = 1
                cindex = button.fr_idx
                maxindex = len(CFG_REPEAT_FREQUENCIES) - 1
                minindex = 0
                self._cfg_down and inc *= 2
                maxindex = cindex % 2 == 0 and maxindex or maxindex - 1
                minindex = cindex % 2
            new_idx = max(minindex, min(maxindex, cindex + inc))
            self.canonical_parent.show_message('Note Repeat ' + CFG_REPEAT_DISPLAY[new_idx])
            button.fr_idx = new_idx
            button.freq = CFG_REPEAT_FREQUENCIES[new_idx]
            self.nr_frq = CFG_REPEAT_FREQUENCIES[new_idx]
            self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0
        elif self._knob_handler:
            self._knob_handler.do_main(value)

    def _select_value(self, value, button):
        if value != 0:
            self._current_nr_button = button
            button.hold = True
            self.show_note_rates()
            if self._hold_mode:
                if self._previous_button == button:
                    button.send_value(0, True)
                    button.active = False
                    self._last_active_button = button
                    button.active = False
                    self._note_repeat.repeat_rate = 32.0
                    self._previous_button = None
                elif self._previous_button == None or self._previous_button != button:
                    button.send_value(1, True)
                    button.active = True
                    self.nr_frq = button.freq
                    self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0
                    if not self._note_repeat.enabled:
                        self._note_repeat.enabled = True
                    if self._previous_button != None:
                        self._previous_button.active = False
                        self._previous_button.send_value(0, True)
                    self._previous_button = button
            else:
                button.send_value(1, True)
                button.active = True
                self.nr_frq = button.freq
                self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0
                if self._previous_button != None and self._previous_button != button:
                    self._previous_button.active = False
                    self._previous_button.send_value(0, True)
                self._previous_button = button
        else:
            button.hold = False

    @subject_slot('value')
    def _do_note_repeat(self, value):
        self.nr_down = value > 0
        if self._hold_mode:
            if value > 0:
                self._note_repeat_button.send_value(0)
                self._note_repeat.enabled = False
                self._hold_mode = False
                if self._previous_button == None and self._last_active_button != None:
                    self._previous_button = self._last_active_button
                    self._last_active_button.send_value(1)
                    self._last_active_button.active = True
                    self.nr_frq = self._last_active_button.freq
                    self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0
        elif self.canonical_parent.isShiftDown() and value > 0:
            self._note_repeat_button.send_value(1)
            self._note_repeat.enabled = True
            self._hold_mode = True
            self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0
        elif value == 0:
            self._note_repeat.enabled = False
            self._note_repeat_button.send_value(0)
        else:
            self._note_repeat_button.send_value(1)
            self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0
            self._note_repeat.enabled = True

    def disconnect(self):
        super(NoteRepeatComponent, self).disconnect()
class OP1ModeSelectorComponent(ModeSelectorComponent):
    __doc__ = ' SelectorComponent that assigns buttons to functions based on the shift button '

    def __init__(self, parent, transport, mixer, session):
        ModeSelectorComponent.__init__(self)

        self._current_mode = -1
        self._mode_index = 0

        self._parent = parent
        self._transport = transport
        self._mixer = mixer
        self._session = session

        self._shift_active = False

        # creating buttons for the arrows keys
        self._left_arrow_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL,
                                                OP1_LEFT_ARROW)
        self._right_arrow_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL,
                                                 OP1_RIGHT_ARROW)

        # creating button for the shift key
        self._shift_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL,
                                           OP1_SHIFT_BUTTON)
        self._shift_button.add_value_listener(self.shift_pressed)

        # creating buttons for the note shifted keys
        self.note_keys_shifted_buttons = []
        self.note_keys_shifted_ccs = [
            77, 79, 81, 83, 84, 86, 88, 89, 91, 93, 95, 96, 98
        ]

        # creating a list of shifted note keys buttons
        for i in range(len(self.note_keys_shifted_ccs)):
            self.note_keys_shifted_buttons.append(
                ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL,
                              self.note_keys_shifted_ccs[i]))

        # creating buttons for the note keys
        self.note_keys_buttons = []
        self.note_keys_ccs = [
            53, 55, 57, 59, 60, 62, 64, 65, 67, 69, 71, 72, 74, 76
        ]

        # creating a list of note keys buttons
        for i in range(len(self.note_keys_ccs)):
            self.note_keys_buttons.append(
                ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL,
                              self.note_keys_ccs[i]))

    def disconnect(self):
        ModeSelectorComponent.disconnect(self)
        self._transport = None
        return None

    def number_of_modes(self):
        return NUM_MODES

    def shift_pressed(self, value):
        # handling shift pressed (only for transport mode)
        if (self._current_mode == OP1_MODE_TRANSPORT):
            if (value == 127):
                self._transport.set_seek_buttons(None, None)
                self._left_arrow_button.add_value_listener(
                    self.shifted_left_arrow_pressed)
                self._right_arrow_button.add_value_listener(
                    self.shifted_right_arrow_pressed)
            else:
                self._left_arrow_button.remove_value_listener(
                    self.shifted_left_arrow_pressed)
                self._right_arrow_button.remove_value_listener(
                    self.shifted_right_arrow_pressed)
                self._transport.set_seek_buttons(self._right_arrow_button,
                                                 self._left_arrow_button)

    def shifted_left_arrow_pressed(self, value):
        # handling negative loop offset behavior
        if (value == 127):
            if (self._parent.song().loop_start > 0):
                self._parent.song().loop_start -= 1

    def shifted_right_arrow_pressed(self, value):
        # handling positive loop offset behavior
        if (value == 127):
            self._parent.song().loop_start += 1

    def set_loop(self, index, set_loop_start):
        # handling set loop
        self._parent.song().loop = 1

        if (set_loop_start):
            self._parent.song().loop_start = round(
                self._parent.song().current_song_time)

        if (index == 0):
            self._parent.song().loop_length = 1
        elif (index == 1):
            self._parent.song().loop_length = 2
        elif (index == 2):
            self._parent.song().loop_length = 4
        elif (index == 3):
            self._parent.song().loop_length = 8
        elif (index == 4):
            self._parent.song().loop_length = 16
        elif (index == 5):
            self._parent.song().loop_length = 32
        elif (index == 6):
            self._parent.song().loop_length = 64
        elif (index == 7):
            self._parent.song().loop_length = 128
        elif (index == 8):
            self._parent.song().loop_length = 256
        elif (index == 9):
            self._parent.song().loop_length = 512
        elif (index == 10):
            self._parent.song().loop_length = 1024
        elif (index == 11):
            self._parent.song().loop_length = 2048
        elif (index == 12):
            self._parent.song().loop_length = 4096

    def note_key_pressed(self, value, sender):
        # determining index of note key button in list
        index = self.note_keys_buttons.index(sender)

        if (self._current_mode == OP1_MODE_MIXER):
            # if on mixer mode, use not key to select a track
            all_tracks = (
                (self.song().visible_tracks + self.song().return_tracks)) + (
                    self.song().master_track, )  #modified
            if (index < len(all_tracks)):
                self.song().view.selected_track = all_tracks[index]

        elif (self._current_mode == OP1_MODE_TRANSPORT):
            # if on transport mode, use key to set loop
            self.set_loop(index, False)

    def note_key_shifted_pressed(self, value, sender):
        # determining index of note key button in list
        index = self.note_keys_shifted_buttons.index(sender)

        if (self._current_mode == OP1_MODE_TRANSPORT):
            # if on transport mode, use key to set loop with loop start change
            self.set_loop(index, True)

    def clip_color_changed(self):
        self._parent.log("clip color changed")

    def has_clip_listener(self):
        self._parent.log("slot has clip")

    def update(self):
        # handle current mode change
        if self.is_enabled():
            # clearing last mappings
            self.clear()

            # updating current mode index
            self._current_mode = self._mode_index

            # based on current mode, perform necessay re mappings
            if (self._mode_index == OP1_MODE_PERFORM):
                # nothing is done for perform mode
                self._parent.log("PERFORM MODE")

            elif (self._mode_index == OP1_MODE_TRANSPORT):
                self._parent.log("TRANSPORT MODE")

                # settings arrows as seek buttons
                self._transport.set_seek_buttons(self._right_arrow_button,
                                                 self._left_arrow_button)

                # adding value listeners for note keys and note shifted keys

                for i in range(NUM_TRACKS):
                    self.note_keys_buttons[i].add_value_listener(
                        self.note_key_pressed, True)

                for i in range(NUM_TRACKS):
                    self.note_keys_shifted_buttons[i].add_value_listener(
                        self.note_key_shifted_pressed, True)

            elif (self._mode_index == OP1_MODE_MIXER):
                self._parent.log("MIXER MODE")

                # setting arrow butons as track select buttons
                self._mixer.set_select_buttons(self._right_arrow_button,
                                               self._left_arrow_button)

                # adding value listeners for note keys
                for i in range(NUM_TRACKS):
                    self.note_keys_buttons[i].add_value_listener(
                        self.note_key_pressed, True)

            elif (self._mode_index == OP1_MODE_CLIP):
                self._parent.log("CLIP MODE")

                # setting arrows as track bank buttons
                self._session.set_track_bank_buttons(self._right_arrow_button,
                                                     self._left_arrow_button)

                # setting last key note as stop all clip button
                self._session.set_stop_all_clips_button(
                    ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, 100))

                # setting track stop clip buttons
                self._session.set_stop_track_clip_buttons(
                    tuple(self.note_keys_shifted_buttons))

                # setting track individual clip launch button
                for i in range(NUM_TRACKS):
                    self._session.scene(0).clip_slot(i).set_launch_button(
                        self.note_keys_buttons[i])

                # setting scene launch button
                self._session.scene(0).set_launch_button(
                    self.note_keys_buttons[NUM_TRACKS])

        return None

    def clear(self):
        if (self._current_mode == OP1_MODE_PERFORM):
            self._parent.log("CLEARING PERFORM MODE")

        elif (self._current_mode == OP1_MODE_TRANSPORT):
            self._parent.log("CLEARING TRANSPORT MODE")

            # removing value listeners for note keys
            for i in range(NUM_TRACKS):
                self.note_keys_buttons[i].remove_value_listener(
                    self.note_key_pressed)

            # removing value listeners for shifted note keys
            for i in range(NUM_TRACKS):
                self.note_keys_shifted_buttons[i].remove_value_listener(
                    self.note_key_shifted_pressed)

            # clearing transport seek buttons
            self._transport.set_seek_buttons(None, None)

        elif (self._current_mode == OP1_MODE_MIXER):
            self._parent.log("CLEARING MIXER MODE")

            # removing value listeners for note key press
            for i in range(NUM_TRACKS):
                self.note_keys_buttons[i].remove_value_listener(
                    self.note_key_pressed)

            self._parent.clear_tracks_assigments()

            # clearing mixer track select buttons
            self._mixer.set_select_buttons(None, None)

        elif (self._current_mode == OP1_MODE_CLIP):
            self._parent.log("CLEARING CLIP MODE")

            # clearing session track bank buttons
            self._session.set_track_bank_buttons(None, None)

            # clearing session stop all clips button
            self._session.set_stop_all_clips_button(None)

            # clearing session track stop clip buttons
            self._session.set_stop_track_clip_buttons(None)

            # clearing individual clip launch button
            for i in range(NUM_TRACKS):
                self._session.scene(0).clip_slot(i).set_launch_button(None)

            # clearing session launch button
            self._session.scene(0).set_launch_button(None)
示例#23
0
class OP1ModeSelectorComponent(ModeSelectorComponent):
    __doc__ = ' SelectorComponent that assigns buttons to functions based on the shift button '
    
    def __init__(self, parent, transport, mixer, session):
        ModeSelectorComponent.__init__(self)

        self._current_mode = -1
        self._mode_index = 0

        self._parent = parent
        self._transport = transport
        self._mixer = mixer
        self._session = session

        self._shift_active = False;

        # creating buttons for the arrows keys
        self._left_arrow_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_LEFT_ARROW)
        self._right_arrow_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_RIGHT_ARROW)
        
        # creating button for the shift key
        self._shift_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SHIFT_BUTTON)
        self._shift_button.add_value_listener(self.shift_pressed)

        # creating buttons for the note shifted keys
        self.note_keys_shifted_buttons = []
        self.note_keys_shifted_ccs = [77, 79, 81, 83, 84, 86, 88, 89, 91, 93, 95, 96, 98]

        # creating a list of shifted note keys buttons
        for i in range(len(self.note_keys_shifted_ccs)):
            self.note_keys_shifted_buttons.append(ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, self.note_keys_shifted_ccs[i]))

        # creating buttons for the note keys
        self.note_keys_buttons = []
        self.note_keys_ccs = [53, 55, 57, 59, 60, 62, 64, 65, 67, 69, 71, 72, 74, 76]

        # creating a list of note keys buttons
        for i in range(len(self.note_keys_ccs)):
            self.note_keys_buttons.append(ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, self.note_keys_ccs[i]))

    def disconnect(self):
        ModeSelectorComponent.disconnect(self)
        self._transport = None
        return None

    def number_of_modes(self):
        return NUM_MODES

    def shift_pressed(self, value):
        # handling shift pressed (only for transport mode)
        if (self._current_mode==OP1_MODE_TRANSPORT):
            if (value==127):
                self._transport.set_seek_buttons(None, None)
                self._left_arrow_button.add_value_listener(self.shifted_left_arrow_pressed)
                self._right_arrow_button.add_value_listener(self.shifted_right_arrow_pressed)
            else:
                self._left_arrow_button.remove_value_listener(self.shifted_left_arrow_pressed)
                self._right_arrow_button.remove_value_listener(self.shifted_right_arrow_pressed)
                self._transport.set_seek_buttons(self._right_arrow_button, self._left_arrow_button)

    def shifted_left_arrow_pressed(self, value):
        # handling negative loop offset behavior
        if (value==127):
            if (self._parent.song().loop_start>0):
                self._parent.song().loop_start -= 1

    def shifted_right_arrow_pressed(self, value):
        # handling positive loop offset behavior
        if (value==127):
            self._parent.song().loop_start += 1

    def set_loop(self, index, set_loop_start):
        # handling set loop
        self._parent.song().loop = 1

        if (set_loop_start):
            self._parent.song().loop_start = round(self._parent.song().current_song_time)

        if (index==0):
            self._parent.song().loop_length = 1
        elif (index==1):
            self._parent.song().loop_length = 2
        elif (index==2):
            self._parent.song().loop_length = 4
        elif (index==3):
            self._parent.song().loop_length = 8
        elif (index==4):
            self._parent.song().loop_length = 16
        elif (index==5):
            self._parent.song().loop_length = 32
        elif (index==6):
            self._parent.song().loop_length = 64
        elif (index==7):
            self._parent.song().loop_length = 128
        elif (index==8):
            self._parent.song().loop_length = 256
        elif (index==9):
            self._parent.song().loop_length = 512
        elif (index==10):
            self._parent.song().loop_length = 1024
        elif (index==11):
            self._parent.song().loop_length = 2048
        elif (index==12):
            self._parent.song().loop_length = 4096

    def note_key_pressed(self, value, sender):
        # determining index of note key button in list
        index = self.note_keys_buttons.index(sender)

        if (self._current_mode==OP1_MODE_MIXER):
            # if on mixer mode, use not key to select a track
            all_tracks = ((self.song().visible_tracks + self.song().return_tracks)) + (self.song().master_track,) #modified
            if (index < len(all_tracks)):
                self.song().view.selected_track = all_tracks[index]

        elif (self._current_mode==OP1_MODE_TRANSPORT):
            # if on transport mode, use key to set loop
            self.set_loop(index, False)
            

    def note_key_shifted_pressed(self, value, sender):
        # determining index of note key button in list
        index = self.note_keys_shifted_buttons.index(sender)

        if (self._current_mode==OP1_MODE_TRANSPORT):
            # if on transport mode, use key to set loop with loop start change
            self.set_loop(index, True)

    def clip_color_changed(self):
        self._parent.log("clip color changed")

    def has_clip_listener(self):
        self._parent.log("slot has clip")

    def update(self):
        # handle current mode change
        if self.is_enabled():
            # clearing last mappings
            self.clear()

            # updating current mode index
            self._current_mode = self._mode_index

            # based on current mode, perform necessay re mappings
            if (self._mode_index == OP1_MODE_PERFORM):
                # nothing is done for perform mode
                self._parent.log("PERFORM MODE")

            elif (self._mode_index == OP1_MODE_TRANSPORT):
                self._parent.log("TRANSPORT MODE")
                
                # settings arrows as seek buttons
                self._transport.set_seek_buttons(self._right_arrow_button, self._left_arrow_button)

                # adding value listeners for note keys and note shifted keys

                for i in range(NUM_TRACKS):
                    self.note_keys_buttons[i].add_value_listener(self.note_key_pressed, True)

                for i in range(NUM_TRACKS):
                    self.note_keys_shifted_buttons[i].add_value_listener(self.note_key_shifted_pressed, True)
                
            elif (self._mode_index == OP1_MODE_MIXER):
                self._parent.log("MIXER MODE")

                # setting arrow butons as track select buttons
                self._mixer.set_select_buttons(self._right_arrow_button, self._left_arrow_button)

                # adding value listeners for note keys
                for i in range(NUM_TRACKS):
                    self.note_keys_buttons[i].add_value_listener(self.note_key_pressed, True)

            elif (self._mode_index == OP1_MODE_CLIP):
                self._parent.log("CLIP MODE")

                # setting arrows as track bank buttons
                self._session.set_track_bank_buttons(self._right_arrow_button, self._left_arrow_button)

                # setting last key note as stop all clip button
                self._session.set_stop_all_clips_button(ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, 100))

                # setting track stop clip buttons
                self._session.set_stop_track_clip_buttons(tuple(self.note_keys_shifted_buttons))

                # setting track individual clip launch button
                for i in range(NUM_TRACKS):
                    self._session.scene(0).clip_slot(i).set_launch_button(self.note_keys_buttons[i])
                    
                # setting scene launch button
                self._session.scene(0).set_launch_button(self.note_keys_buttons[NUM_TRACKS])                    

        return None

    def clear(self):
        if (self._current_mode == OP1_MODE_PERFORM):
            self._parent.log("CLEARING PERFORM MODE")

        elif (self._current_mode == OP1_MODE_TRANSPORT):
            self._parent.log("CLEARING TRANSPORT MODE")

            # removing value listeners for note keys
            for i in range(NUM_TRACKS):
                self.note_keys_buttons[i].remove_value_listener(self.note_key_pressed)

            # removing value listeners for shifted note keys
            for i in range(NUM_TRACKS):
                self.note_keys_shifted_buttons[i].remove_value_listener(self.note_key_shifted_pressed)

            # clearing transport seek buttons
            self._transport.set_seek_buttons(None, None)
            
        elif (self._current_mode == OP1_MODE_MIXER):
            self._parent.log("CLEARING MIXER MODE")
            
            # removing value listeners for note key press
            for i in range(NUM_TRACKS):
                self.note_keys_buttons[i].remove_value_listener(self.note_key_pressed)

            self._parent.clear_tracks_assigments()

            # clearing mixer track select buttons
            self._mixer.set_select_buttons(None, None)
            
        elif (self._current_mode == OP1_MODE_CLIP):
            self._parent.log("CLEARING CLIP MODE")

            # clearing session track bank buttons
            self._session.set_track_bank_buttons(None,None)

            # clearing session stop all clips button
            self._session.set_stop_all_clips_button(None)

            # clearing session track stop clip buttons
            self._session.set_stop_track_clip_buttons(None)
            
            # clearing individual clip launch button
            for i in range(NUM_TRACKS):
                self._session.scene(0).clip_slot(i).set_launch_button(None)

            # clearing session launch button
            self._session.scene(0).set_launch_button(None)
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
示例#25
0
class Launchpad(ControlSurface):

	""" Script for Novation's Launchpad Controller """

	def __init__(self, c_instance):
		live = Live.Application.get_application()
		self._live_major_version = live.get_major_version()
		self._live_minor_version = live.get_minor_version()
		self._live_bugfix_version = live.get_bugfix_version()
		self._mk2 = Settings.DEVICE == 'Launchpad mk2'
		if self._mk2:
			self._skin = Skin('Launchpad mk2')
			self._side_notes = (89, 79, 69, 59, 49, 39, 29, 19)
			self._drum_notes = (20, 30, 31, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126)
		else:
			self._skin = Skin('Launchpad')
			self._side_notes = (8, 24, 40, 56, 72, 88, 104, 120)
			self._drum_notes = (41, 42, 43, 44, 45, 46, 47, 57, 58, 59, 60, 61, 62, 63, 73, 74, 75, 76, 77, 78, 79, 89, 90, 91, 92, 93, 94, 95, 105, 106, 107)
			
			
		ControlSurface.__init__(self, c_instance)
	
	
		with self.component_guard():
			self._suppress_send_midi = True
			self._suppress_session_highlight = True

			is_momentary = True
			if self._mk2:
				self._suggested_input_port = 'Launchpad'
				self._suggested_output_port = 'Launchpad'
			else:
				self._suggested_input_port = 'Launchpad MK2'
				self._suggested_output_port = 'Launchpad MK2'
				
			self._control_is_with_automap = False
			self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)
			self._user_byte_write_button.name = 'User_Byte_Button'
			self._user_byte_write_button.send_value(1)
			self._user_byte_write_button.add_value_listener(self._user_byte_value)
			self._wrote_user_byte = False
			self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143
			matrix = ButtonMatrixElement()
			matrix.name = 'Button_Matrix'
			for row in range(8):
				button_row = []
				for column in range(8):
					if self._mk2:
						# for mk2 buttons are assigned "top to bottom"
 						midi_note = (81 - (10 * row)) + column
					else:
						midi_note = row * 16 + column
					button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, midi_note, self._skin.off)
					button.name = str(column) + '_Clip_' + str(row) + '_Button'
					button_row.append(button)

				matrix.add_row(tuple(button_row))

			self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0, optimized_send_midi=False)
			self._config_button.add_value_listener(self._config_value)
			top_buttons = [ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0, 104 + index, self._skin.off) for index in range(8)]
			side_buttons = [ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, self._side_notes[index], self._skin.off) for index in range(8)]
			top_buttons[0].name = 'Bank_Select_Up_Button'
			top_buttons[1].name = 'Bank_Select_Down_Button'
			top_buttons[2].name = 'Bank_Select_Left_Button'
			top_buttons[3].name = 'Bank_Select_Right_Button'
			top_buttons[4].name = 'Session_Button'
			top_buttons[5].name = 'User1_Button'
			top_buttons[6].name = 'User2_Button'
			top_buttons[7].name = 'Mixer_Button'
			side_buttons[0].name = 'Vol_Button'
			side_buttons[1].name = 'Pan_Button'
			side_buttons[2].name = 'SndA_Button'
			side_buttons[3].name = 'SndB_Button'
			side_buttons[4].name = 'Stop_Button'
			side_buttons[5].name = 'Trk_On_Button'
			side_buttons[6].name = 'Solo_Button'
			side_buttons[7].name = 'Arm_Button'
			self._osd = M4LInterface()
			self._osd.name = "OSD"
			self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button, self._osd, self, self._skin)
			self._selector.name = 'Main_Modes'
			self._do_combine()
			for control in self.controls:
				if isinstance(control, ConfigurableButtonElement):
					control.add_value_listener(self._button_value)

			self.set_highlighting_session_component(self._selector.session_component())
			self._suppress_session_highlight = False

			self.log_message("LaunchPad95 Loaded !")

	def disconnect(self):
		self._suppress_send_midi = True
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.remove_value_listener(self._button_value)
		self._do_uncombine()
		self._selector = None
		self._user_byte_write_button.remove_value_listener(self._user_byte_value)
		self._config_button.remove_value_listener(self._config_value)
		ControlSurface.disconnect(self)
		self._suppress_send_midi = False
		if self._mk2:
			self._send_midi((240, 0, 32, 41, 2, 24, 64, 247))
			# launchpad mk2 needs disconnect string sent			
		self._config_button.send_value(32)
		self._config_button.send_value(0)
		self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None

	_active_instances = []

	#def highlighting_session_component(self):
	#	" Return the session component showing the ring in Live session "
	#	return self._selector.session_component()

	def _combine_active_instances():
		support_devices = False
		for instance in Launchpad._active_instances:
			support_devices |= (instance._device_component != None)
		offset = 0
		for instance in Launchpad._active_instances:
			instance._activate_combination_mode(offset, support_devices)
			offset += instance._selector._session.width()

	_combine_active_instances = staticmethod(_combine_active_instances)

	def _activate_combination_mode(self, track_offset, support_devices):
		if(Settings.STEPSEQ__LINK_WITH_SESSION):
			self._selector._stepseq.link_with_step_offset(track_offset)
		if(Settings.SESSION__LINK):
			self._selector._session.link_with_track_offset(track_offset)

	def _do_combine(self):
		if (DO_COMBINE and (self not in Launchpad._active_instances)):
			Launchpad._active_instances.append(self)
			Launchpad._combine_active_instances()

	def _do_uncombine(self):
		if self in Launchpad._active_instances:
			Launchpad._active_instances.remove(self)
			if(Settings.SESSION__LINK):
				self._selector._session.unlink()
			if(Settings.STEPSEQ__LINK_WITH_SESSION):
				self._selector._stepseq.unlink()
			Launchpad._combine_active_instances()

	def refresh_state(self):
		ControlSurface.refresh_state(self)
		self.schedule_message(5, self._update_hardware)

	def handle_sysex(self, midi_bytes):
		if self._mk2:
			# mk2 has different challenge and params
			if len(midi_bytes) == 10:
				if midi_bytes[:7] == (240, 0, 32, 41, 2, 24, 64):
					response = long(midi_bytes[7])
					response += long(midi_bytes[8]) << 8
					if response == Live.Application.encrypt_challenge2(self._challenge):
						# self.log_message("Challenge Response ok")
						self._suppress_send_midi = False
						self.set_enabled(True)
		else:
			if len(midi_bytes) == 8:
				if midi_bytes[1:5] == (0, 32, 41, 6):
					response = long(midi_bytes[5])
					response += long(midi_bytes[6]) << 8
					if response == Live.Application.encrypt_challenge2(self._challenge):
						self._suppress_send_midi = False
						self.set_enabled(True)

	def build_midi_map(self, midi_map_handle):
		ControlSurface.build_midi_map(self, midi_map_handle)
		if self._selector.mode_index == 1:
			if self._selector._sub_mode_index[self._selector._mode_index] > 0:  # disable midi map rebuild for instrument mode to prevent light feedback errors
				new_channel = self._selector.channel_for_current_mode()
				# self.log_message(str(new_channel))
				for note in self.drum_notes:
					self._translate_message(MIDI_NOTE_TYPE, note, 0, note, new_channel)

	def _send_midi(self, midi_bytes, optimized=None):
		sent_successfully = False
		if not self._suppress_send_midi:
			sent_successfully = ControlSurface._send_midi(self, midi_bytes, optimized=optimized)
		return sent_successfully

	def _update_hardware(self):
		self._suppress_send_midi = False
		self._wrote_user_byte = True
		self._user_byte_write_button.send_value(1)
		self._suppress_send_midi = True
		self.set_enabled(False)
		self._suppress_send_midi = False
		self._send_challenge()

	def _send_challenge(self):
		if self._mk2:
			challenge_bytes = tuple([ self._challenge >> 8 * index & 127 for index in xrange(4) ])
			self._send_midi((240, 0, 32, 41, 2, 24, 64) + challenge_bytes + (247,))
		else:
			for index in range(4):
				challenge_byte = self._challenge >> 8 * index & 127
				self._send_midi((176, 17 + index, challenge_byte))
		

	def _user_byte_value(self, value):
		assert (value in range(128))
		if not self._wrote_user_byte:
			enabled = (value == 1)
			self._control_is_with_automap = not enabled
			self._suppress_send_midi = self._control_is_with_automap
			if not self._control_is_with_automap:
				for control in self.controls:
					if isinstance(control, ConfigurableButtonElement):
						control.set_force_next_value()

			self._selector.set_mode(0)
			self.set_enabled(enabled)
			self._suppress_send_midi = False
		else:
			self._wrote_user_byte = False

	def _button_value(self, value):
		assert value in range(128)

	def _config_value(self, value):
		assert value in range(128)

	def _set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks):
		if not self._suppress_session_highlight:
			ControlSurface._set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks)
示例#26
0
class NanoKontrolLP95(ControlSurface):
    __module__ = __name__
    __doc__ = " NanoKontrolLP95 controller script "

    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        #self._suppress_session_highlight = True
        self._suppress_send_midi = True  # Turn off rebuild MIDI map until after we're done setting up
        Live.Base.log(time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) + "--------------= NanoKontrolLP95 log opened =--------------") # Writes message into Live's main log file. This is a ControlSurface method.
        with self.component_guard():
            # OBJECTS
            self._session = None #session object
            self._mixer = None #mixer object
            self._transport = None #transport object
            self._last_button_time = time.time()
            self._io_list_index = 0
            
            self._setup_controls()

            self._setup_session_control()  # Setup the session object
            self._setup_mixer_control() # Setup the mixer object
            self._session.set_mixer(self._mixer) # Bind mixer to session
            self._setup_transport_control() # Setup transport object

            self._set_mode_button()
            self._set_normal_mode()
            self._track = self.song().view.selected_track
            
            self.set_highlighting_session_component(self._session)

            self._flash_counter = 0
            self._flash_on = True
            
            for component in self.components:
                component.set_enabled(True)

        self._suppress_send_midi = True # Turn rebuild back on, once we're done setting up
        Live.Base.log("NanoKontrolLP95 Loaded !")

    def disconnect(self):
        """clean things up on disconnect"""
        if self._cycle_button != None:
            self._cycle_button.remove_value_listener(self._cycle_button_value)
        self._clear_controls()
        self._transport.set_stop_button(None)
        self._transport.set_play_button(None)
        self._transport.set_rec_button(None)

        self._solo_buttons = None 
        self._mute_buttons = None 
        self._arm_buttons = None 
        self._knobs = None 
        self._faders = None 

        self._ff_button = None
        self._rwd_button = None
        self._play_button = None
        self._stop_button = None
        self._rec_button = None
        
        self._track_left_button = None
        self._track_right_button = None
        self._cycle_button = None
        
        self._set_button = None    
        self._mrk_left_button = None
        self._mrk_right_button = None
        
        self._session = None
        self._mixer = None
        self._transport = None

        ControlSurface.disconnect(self)
    
    def _setup_controls(self):
        self._track_left_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, track_left_btn)
        self._track_right_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, track_right_btn)    
        self._cycle_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, cycle_btn)
        self._cycle_button_active = False             
        
        self._set_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, set_btn)        
        self._mrk_left_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, mrk_left_btn)
        self._mrk_right_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, mrk_right_btn)

        self._ff_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, ff_btn)
        self._rwd_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, rwd_btn)        
        self._play_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, play_btn)
        self._stop_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, stop_btn)
        self._rec_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, rec_btn)
        
        self._solo_buttons = [ButtonElement(True, MIDI_CC_TYPE, CHANNEL, track_solo_cc[index]) for index in range(num_tracks)] 
        self._mute_buttons = [ButtonElement(True, MIDI_CC_TYPE, CHANNEL, track_mute_cc[index]) for index in range(num_tracks)] 
        self._arm_buttons = [ButtonElement(True, MIDI_CC_TYPE, CHANNEL, track_arm_cc[index]) for index in range(num_tracks)] 
        self._knobs = [SliderElement(MIDI_CC_TYPE, CHANNEL, mixer_knob_cc[index]) for index in range(num_tracks)] 
        self._faders = [SliderElement(MIDI_CC_TYPE, CHANNEL, mixer_fader_cc[index]) for index in range(num_tracks)] 
    
    
    def _setup_session_control(self):
        # CREATE SESSION, SET OFFSETS, BUTTONS NAVIGATION AND BUTTON MATRIX
        self._session = SpecialSessionComponent(num_tracks, num_scenes) #(num_tracks, num_scenes)
        self._session.set_offsets(0, 0)

    def _setup_mixer_control(self):
        #CREATE MIXER, SET OFFSET (SPECIALMIXERCOMPONENT USES SPECIALCHANNELSTRIP THAT ALLOWS US TO UNFOLD TRACKS WITH TRACK SELECT BUTTON)
        self._mixer = SpecialMixerComponent(self, num_tracks, 0, False, False) # 8 tracks, 2 returns, no EQ, no filters
        self._mixer.name = 'Mixer'
        self._mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left)
        self._mixer.set_select_buttons(self._track_right_button,self._track_left_button)
        self._mixer.set_knobs(self._knobs)
    def _setup_transport_control(self):
        # CREATE TRANSPORT DEVICE
        self._transport = SpecialTransportComponent(self)
        self._transport.set_stop_button(self._stop_button)
        self._transport.set_play_button(self._play_button)
        self._transport.set_rec_button(self._rec_button)
        
    def connect_script_instances(self, instanciated_scripts):
        #Live.Base.log("connect_script_instances - Start")
        #Live.Base.log("connect_script_instances - self._control_surfaces()=" + str(self._control_surfaces()))
        if(linked):
            for control_surface in self._control_surfaces():
                control_surface_type = str(control_surface)
                for sync_master in SYNC_TO_LIST:
                    if(control_surface_type.count(sync_master)>0):
                        control_surface_session = control_surface.highlighting_session_component()
                        if control_surface_session:
                            self._session.sync_to(control_surface_session)
                            self._on_track_list_changed()
                            break


    def _clear_controls(self):
            
        if (self._ff_button != None):
            self._ff_button.remove_value_listener(self._out_value)
            self._ff_button.turn_off()
    
        if (self._rwd_button != None):
            self._rwd_button.remove_value_listener(self._in_value)
            self._rwd_button.turn_off()           
            
        if (self._set_button != None):
            self._set_button.remove_value_listener(self._monitor_value)
            self._set_button.remove_value_listener(self._dup_track_value)           
            
        if (self._mrk_left_button != None):
            self._mrk_left_button.remove_value_listener(self._sub_in_value)
            self._mrk_left_button.remove_value_listener(self._new_midi_value)            
            
        if (self._mrk_right_button != None):
            self._mrk_right_button.remove_value_listener(self._sub_out_value)
            self._mrk_right_button.remove_value_listener(self._new_audio_value)            

        # SESSION
        resetsend_controls = []
        self._mixer.send_controls = []
        self._session.set_stop_track_clip_buttons(None)

        # MIXER
        self._mixer._set_send_nav(None, None)
        for track_index in range(num_tracks):
            strip = self._mixer.channel_strip(track_index)
            strip.set_solo_button(None)
            strip.set_mute_button(None)
            strip.set_arm_button(None)
            resetsend_controls.append(None)
            strip.set_select_button(None)
            for i in range(12):
                self._mixer.send_controls.append(None)
            strip.set_send_controls(tuple(self._mixer.send_controls))
        self._mixer.set_resetsend_buttons(tuple(resetsend_controls))
        self.log_message("Controls Cleared")

    def _set_mode_button(self):
        if self._cycle_button != None:
            self._cycle_button.remove_value_listener(self._cycle_button_value)
            self._cycle_button.add_value_listener(self._cycle_button_value)
            self._cycle_button.set_light(self._cycle_button_active)

    def _cycle_button_value(self, value):
        assert (value in range(128))        
        if self._cycle_button != None:
            if value is not 0:
                self._cycle_button_active = not self._cycle_button_active
                self._clear_controls()
                if self._cycle_button_active:
                    self._set_alt_mode()
                else:
                    self._set_normal_mode()
                self.update()   
            
    def _set_normal_mode(self):
        for index in range(num_tracks):
            strip = self._mixer.channel_strip(index)
            strip.set_solo_button(self._solo_buttons[index])
            strip.set_mute_button(self._mute_buttons[index])
            strip.set_arm_button(self._arm_buttons[index])
            strip.set_pan_control(self._knobs[index])
            strip.set_volume_control(self._faders[index])
        self._set_in_out_nav_listeners()    
        self.show_message("IN/OUT SETUP - MUTE SOLO ARM")
                        
    def _set_alt_mode(self):
        self._mixer._set_send_nav(self._ff_button, self._rwd_button)
        stop_track_controls = []
        resetsend_controls = []
        # SET SESSION TRACKSTOP, TRACK SELECT, RESET SEND KNOB
        for index in range(num_tracks):
            strip = self._mixer.channel_strip(index)
            strip.set_select_button(self._solo_buttons[index])
            stop_track_controls.append(self._arm_buttons[index])
            resetsend_controls.append(self._mute_buttons[index])
        self._session.set_stop_track_clip_buttons(tuple(stop_track_controls))
        self._mixer.set_resetsend_buttons(tuple(resetsend_controls))
        self._mixer._update_send_index()
        self._set_create_track_listeners()
        self.show_message("TRACK CREATE DEL DUPE - SEL STOP RESET SEND")
        
    def _set_in_out_nav_listeners(self):
        if (self._ff_button != None):
            self._ff_button.add_value_listener(self._out_value)
    
        if (self._rwd_button != None):
            self._rwd_button.add_value_listener(self._in_value)
            
        if (self._set_button != None):
            self._set_button.add_value_listener(self._monitor_value)
            
        if (self._mrk_left_button != None):
            self._mrk_left_button.add_value_listener(self._sub_in_value)
            
        if (self._mrk_right_button != None):
            self._mrk_right_button.add_value_listener(self._sub_out_value)                                                
        self.update()
           
    def _monitor_value(self, value):
        now = time.time()
        if(value is not 0):
            self._last_button_time = now
        else:
            song = self.song()
            if self._track in song.tracks:
                if now - self._last_button_time < LONG_PRESS:            
                    if not self._track.is_foldable:
                        self._track.current_monitoring_state = (self._track.current_monitoring_state + 1) % 3
                else:  
                    self._set_default_io()            

    def _set_default_io(self):
        if self._track.has_midi_input:
                self._track.input_routing_type = list(self._track.available_input_routing_types)[0]
                if self._track.has_audio_output:
                    if self._track.is_grouped:
                        self._track.output_routing_type = list(self._track.available_output_routing_types)[2]       
                    else:
                        self._track.output_routing_type = list(self._track.available_output_routing_types)[1]
                else:
                    self._track.output_routing_type = list(self._track.available_output_routing_types)[-1]
        else:
                self._track.input_routing_type = list(self._track.available_input_routing_types)[-1]
                if self._track.is_grouped:
                    self._track.output_routing_type = list(self._track.available_output_routing_types)[2]       
                else:
                    self._track.output_routing_type = list(self._track.available_output_routing_types)[1]
                    
        self._track.input_routing_channel = list(self._track.available_input_routing_channels)[0]            
        self._track.output_routing_channel = list(self._track.available_output_routing_channels)[0]  
        self.show_message("TRACK: " + str(self._track.name) + ' INPUT - OUTPUT RESET ')                             
                                     
    def _in_value(self, value):
        if(value is not 0):
            routings = list(self._track.available_input_routing_types)
            current_routing = self._track.input_routing_type
            if current_routing in routings:
                new_index = (routings.index(current_routing) + 1) % len(routings)
                self._track.input_routing_type = routings[new_index]
                route = ' INPUT: ' +  str(self._track.input_routing_type.display_name)
                self.show_message("TRACK: " + str(self._track.name) + route)
            self.update()
            
    def _out_value(self, value):
        if(value is not 0):
            routings = list(self._track.available_output_routing_types)
            current_routing = self._track.output_routing_type
            if current_routing in routings:
                new_index = (routings.index(current_routing) + 1) % len(routings)
                self._track.output_routing_type = routings[new_index]
                route = ' OUTPUT: ' +  str(self._track.output_routing_type.display_name)
                self.show_message("TRACK: " + str(self._track.name) + route)
        self.update()

    def _sub_in_value(self, value):
        if(value is not 0):
            routings = list(self._track.available_input_routing_channels)
            current_routing = self._track.input_routing_channel
            if current_routing in routings:
                new_index = (routings.index(current_routing) + 1) % len(routings)
                self._track.input_routing_channel = routings[new_index]
                route = ' SUB_INPUT: ' +  str(self._track.input_routing_channel.display_name)
                self.show_message("TRACK: " + str(self._track.name) + route)
            self.update()
     
    def _sub_out_value(self, value):
        if(value is not 0):
            routings = list(self._track.available_output_routing_channels)
            current_routing = self._track.output_routing_channel
            if current_routing in routings:
                new_index = (routings.index(current_routing) + 1) % len(routings)
                self._track.output_routing_channel = routings[new_index]
                route = ' SUB_OUTPUT: ' +  str(self._track.output_routing_channel.display_name)
                self.show_message("TRACK: " + str(self._track.name) + route)                       
            self.update()


    def _on_selected_track_changed(self):
        # ALLOWS TO GRAB THE FIRST DEVICE OF A SELECTED TRACK IF THERE'S ANY
        ControlSurface._on_selected_track_changed(self)
        self._track = self.song().view.selected_track
              
    def update(self):
        ControlSurface.update(self)
        self._cycle_button.set_light(self._cycle_button_active)
        
        
    def _set_create_track_listeners(self):
        if (self._set_button != None):
            self._set_button.add_value_listener(self._dup_track_value)
            
        if (self._mrk_left_button != None):
            self._mrk_left_button.add_value_listener(self._new_midi_value)
            
        if (self._mrk_right_button != None):
            self._mrk_right_button.add_value_listener(self._new_audio_value)                                                
        self.update()            
        
    def _dup_track_value(self, value):
        now = time.time()
        if(value is not 0):
            self._last_button_time = now
        else:
            song = self.song()
            if self._track in song.tracks:
                if now - self._last_button_time < LONG_PRESS:            
                    song.duplicate_track(list(song.tracks).index(self._track))
                else:  
                    song.delete_track(list(song.tracks).index(self._track))

    def _new_audio_value(self, value):
        if(value is not 0):
            self._add_track(self.song().create_audio_track)
            
    def _new_midi_value(self, value):
        if(value is not 0):
            self._add_track(self.song().create_midi_track)
            
    def _add_track(self, func):
        song = self.song()
        index = list(song.tracks).index(self._track) + 1
        if index < len(song.tracks) and index >0:
            track = song.tracks[index]
            if track.is_foldable or track.is_grouped:
                while index < len(song.tracks) and song.tracks[index].is_grouped:
                    index += 1
        func(index)
        
    @profile
    def update_display(self):
        super(NanoKontrolLP95, self).update_display()
        self._flash_counter = self._flash_counter + 1
        if self._cycle_button_active  == True:
            if(self._flash_counter % 2  == 0):
                if (self._flash_on == True):
                    self._cycle_button.send_value(127) 
                else:
                    self._cycle_button.send_value(0) 
                self._flash_on = not self._flash_on
                self._flash_counter = self._flash_counter % 4                                                  
class MaschineMk2(ControlSurface):
    __module__ = __name__
    __doc__ = 'Control Script for Maschine Mk2 and Maschine Mikro Mk2'

    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance, False)
        with self.component_guard():
            self._suppress_send_midi = True
            self.togglecolor = (10, 30, 50, 70, 90)
            self.toggleindex = 0
            self._c_ref = c_instance
            self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143
            self._c_inst = c_instance
            is_momentary = True
            self._active = True
            self._modifier_down = False
            self._return_mode = 0
            self._returntopad = False
            self._mode = CLIP_MODE
            self.init_slot = 0
            self.init_done = False
            self._midi_pause_count = 0
            self.nav_index = 0
            self._base_note = 0
            self._octave = 0.55
            self._scale_select_mode = MODE_PRESS_NONE
            self.send_slider_index = 0
            self._pad_mode = PM_OFF
            self._note_display_mode = ND_KEYBOARD1
            self._set_suppress_rebuild_requests(True)
            self._scenematrix = SceneMatrix(self)
            self._master_knob = Mk2KnobControl(self)
            self._device = self._set_up_device_control()
            self.show_message(str(''))
            self.request_rebuild_midi_map()
            self._set_global_buttons()
            self._set_mode_buttons()
            self._setup_transport()
            self._set_modecontrol()
            self._set_up_session()
            self._set_up_mixer()
            self._set_up_timer()
            self._set_up_machine_knobs()
            self.current_scale_index = 0
            self.assign_transpose(SCALES[self.current_scale_index])
            self.set_highlighting_session_component(self._session)
            self._navigate_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 127)
            self._navigate_button.add_value_listener(self._do_focus_navigate)
            self.display_update_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 86)
            self.display_update_button.add_value_listener(self._a_display_update)
            self._set_suppress_rebuild_requests(False)
            self.song().view.add_detail_clip_listener(self.clip_handle)
            self.song().add_visible_tracks_listener(self.clip_handle)
            self.song().add_scenes_listener(self.clip_handle)
            self.application().view.add_view_focus_changed_listener(self.focus_changed)
            self.log_message('########## LIVE 9 MASCHINE MK2 V 1.02 #############')
            self._suppress_send_midi = False

    def _set_up_mixer(self):
        is_momentary = True
        self._mixer = MixerComponent(8)
        self.send_sliders = []
        for track in range(8):
            self.send_sliders.append(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, SEND_CC_OFF + track))

        for track in range(8):
            strip = self._mixer.channel_strip(track)
            strip.set_arm_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, ARM_CC_OFF + track))
            strip.set_solo_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, SOLO_CC_OFF + track))
            strip.set_mute_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, MUTE_CC_OFF + track))
            strip.set_volume_control(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, LEVEL_CC_OFF + track))
            strip.set_pan_control(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, PAN_CC_OFF + track))
            strip.set_select_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, SELECT_CC_OFF + track))
            st = tuple([self.send_sliders[track]])
            strip.set_send_controls(st)

        self.send_slider_toggle_button = StateButton(False, MIDI_CC_TYPE, 0, 90)
        self.send_slider_toggle_button.add_value_listener(self._do_toggle_send)
        self._session.set_mixer(self._mixer)

    def _set_global_buttons(self):
        is_momentary = True
        self._undo_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 85)
        self._undo_button.add_value_listener(self._do_undo)
        self._redo_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 87)
        self._redo_button.add_value_listener(self._do_redo)
        self._armsolomode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 89)
        self._armsolomode_button.add_value_listener(self._do_armsolo_mode)
        self._fire_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 9)
        self._fire_button.add_value_listener(self._do_fire_button)
        self.track_left_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 120)
        self.track_right_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 121)
        self.track_left_button.add_value_listener(self._a_trk_left)
        self.track_right_button.add_value_listener(self._a_trk_right)
        self.test_button = StateButton(True, MIDI_CC_TYPE, 5, 60)
        self.note_repeat_button = StateButton(True, MIDI_CC_TYPE, 5, 61)
        self.test_button.add_value_listener(self.do_test)
        self.note_repeat_button.add_value_listener(self.do_note_repeat)
        self.reset_test_button = StateButton(True, MIDI_CC_TYPE, 5, 62)
        self.reset_test_button.add_value_listener(self.do_reset)

    def _set_mode_buttons(self):
        self.xfade_assign_button = StateButton(True, MIDI_CC_TYPE, 0, 116)
        self._pad_select_button = StateButton(False, MIDI_CC_TYPE, 0, 117)
        self._pad_solo_button = StateButton(False, MIDI_CC_TYPE, 0, 118)
        self._mute_button = StateButton(False, MIDI_CC_TYPE, 0, 119)
        self._pad_scale_up = GatedColorButton(True, MIDI_CC_TYPE, 83, 0)
        self._pad_scale_down = GatedColorButton(True, MIDI_CC_TYPE, 94, 16)
        self._pad_select_button.add_value_listener(self._do_pad_select_multi)
        self._mute_button.add_value_listener(self._do_mute_button)
        self._pad_solo_button.add_value_listener(self._do_pad_solo_multi)
        self.xfade_assign_button.add_value_listener(self._do_xfade_assign)
        self._pad_scale_up.add_value_listener(self._do_pad_note_up)
        self._pad_scale_down.add_value_listener(self._do_pad_note_down)

    def set_appointed_device(self, device):
        with self.component_guard():
            self._device_component.set_device(device)

    def _set_up_device_control(self):
        is_momentary = True
        device = MaschineDeviceComponent(self)
        device.set_device_changed_listener(self._handle_device_changed)
        device.set_device_parm_listener(self._hande_device_parm_changed)
        param_controls = []
        for index in range(8):
            param_controls.append(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_CC_OFF + index))

        device.set_parameter_controls(tuple(param_controls))
        device.set_on_off_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF))
        device.set_bank_nav_buttons(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF + 4), ButtonElement(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF + 5))
        self._device_nav_button_left = StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF + 6)
        self._device_nav_button_right = StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF + 7)
        self._device_nav_button_left.add_value_listener(self._nav_value_left)
        self._device_nav_button_right.add_value_listener(self._nav_value_right)
        device.name = 'Device_Component'
        self.set_device_component(device)
        return device

    def _setup_transport(self):
        is_momentary = True
        transport = TransportComponent()
        playButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 108)
        stopButton = StateButton(not is_momentary, MIDI_CC_TYPE, 0, 110)
        recordButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 109)
        overdubButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 107)
        metrononmeButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 104)
        playButton.name = 'Play'
        stopButton.name = 'Stop'
        recordButton.name = 'Record'
        overdubButton.name = 'Overdub'
        metrononmeButton.name = 'Metronome'
        transport.set_play_button(playButton)
        transport.set_stop_button(stopButton)
        transport.set_record_button(recordButton)
        transport.set_overdub_button(overdubButton)
        transport.set_metronome_button(metrononmeButton)
        transport.set_nudge_buttons(StateButton(is_momentary, MIDI_CC_TYPE, 1, 51), StateButton(is_momentary, MIDI_CC_TYPE, 1, 50))
        punchinbutton = ToggleButton(MIDI_CC_TYPE, 1, 52)
        punchoutbutton = ToggleButton(MIDI_CC_TYPE, 1, 53)
        punchinbutton.name = 'Punch In'
        punchoutbutton.name = 'Punch Out'
        transport.set_punch_buttons(punchinbutton, punchoutbutton)
        transport.set_loop_button(StateButton(is_momentary, MIDI_CC_TYPE, 1, 54))
        self.transp_ff_button = ButtonElement(True, MIDI_CC_TYPE, 1, 59)
        self.transp_rw_button = ButtonElement(True, MIDI_CC_TYPE, 1, 58)
        transport.set_seek_buttons(self.transp_ff_button, self.transp_rw_button)
        self.xfadeKnob = SliderElement(MIDI_CC_TYPE, 1, 100)
        self.xfadeKnob.connect_to(self.song().master_track.mixer_device.crossfader)
        self.tap_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 88)
        self.tap_button.add_value_listener(self._do_tap_tempo)
        self.cue_add_delete_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 55)
        self.cue_prev_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 56)
        self.cue_next_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 57)
        self.cue_add_delete_button.add_value_listener(self._do_toggle_cue)
        self.cue_prev_button.add_value_listener(self._do_toggle_prev_cue)
        self.cue_next_button.add_value_listener(self._do_toggle_next_cue)

    def _set_up_machine_knobs(self):
        master_track = self.song().master_track
        self.master_volume = SliderElement(MIDI_CC_TYPE, 0, 40)
        self.prehear = SliderElement(MIDI_CC_TYPE, 0, 41)
        self.master_volume.connect_to(master_track.mixer_device.volume)
        self.prehear.connect_to(master_track.mixer_device.cue_volume)

    def _set_up_session(self):
        is_momentary = True
        self._session = MaschineSessionComponent()
        self._session.add_offset_listener(self.notify_track_scroll)
        nhue = COLOR_HUE_NAV
        self.nav_buttons = (GatedColorButton(True, MIDI_CC_TYPE, 92, nhue),
         GatedColorButton(True, MIDI_CC_TYPE, 81, nhue),
         GatedColorButton(True, MIDI_CC_TYPE, 93, nhue),
         GatedColorButton(True, MIDI_CC_TYPE, 91, nhue))
        self._session.set_scene_bank_buttons(self.nav_buttons[0], self.nav_buttons[1])
        self._session.set_track_bank_buttons(self.nav_buttons[2], self.nav_buttons[3])
        self._session.set_stop_all_clips_button(StateButton(is_momentary, MIDI_CC_TYPE, 0, 111))
        track_stop_buttons = [ StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, index + STOP_CC_OFF) for index in range(4) ]
        self._session.set_stop_track_clip_buttons(tuple(track_stop_buttons))
        self._init_matrix()
        self._set_up_buttons()
        self._session._link()
        self._session.set_advance(STEP4)

    def _set_up_buttons(self):
        self._bmatrix = ButtonMatrixElement()
        for scene_index in range(4):
            button_row = []
            scene = self._session.scene(scene_index)
            for track_index in range(4):
                button = self._matrix[scene_index][track_index]
                clip_slot = scene.clip_slot(track_index)
                clip_slot.set_launch_button(button)
                clip_slot.set_triggered_to_play_value(1)
                clip_slot.set_triggered_to_record_value(1)
                clip_slot.set_started_value(1)
                clip_slot.set_recording_value(1)
                clip_slot.set_stopped_value(1)

            self._bmatrix.add_row(tuple(button_row))

    def _init_matrix(self):
        is_momentary = True
        self._button_sequence = []
        self._matrix = []
        for scene_index in range(4):
            button_row = []
            for track_index in range(4):
                button = VarButtonElement(is_momentary, 0, scene_index, track_index, self)
                partner = TwinButton(is_momentary, 1, button)
                partner.add_value_listener(self.ox, True)
                button_row.append(button)

            self._matrix.append(tuple(button_row))

        for scene_index in [3,
         2,
         1,
         0]:
            for track_index in range(4):
                self._button_sequence.append(self._matrix[scene_index][track_index])

        self._session.set_matrix(self._matrix)

    def set_pad_translations(self, pad_translations):
        ControlSurface.set_pad_translations(pad_translations)

    def refresh_state(self):
        ControlSurface.refresh_state(self)
        self._update_hardware()

    def ox(self, value, button):
        if not isinstance(button, TwinButton):
            raise AssertionError
            self._mode == PAD_MODE and button.fire(value)

    def _update_hardware(self):
        self._session.update()
        self._set_suppress_rebuild_requests(True)
        self._set_mode()
        self._master_knob.update()
        if self._scenematrix.soloexclusive:
            self._armsolomode_button.send_value(1, True)
        else:
            self._armsolomode_button.send_value(0, True)
        self._master_knob.start_up()
        self._pad_scale_up.activate()
        self._pad_scale_down.activate()
        self.current_scale_to_display()
        self.send_to_display(KEY_COLOR_MODES_STRINGS[self._note_display_mode], 1)
        for scene_index in range(4):
            scene = self._session.scene(scene_index)
            for track_index in range(4):
                button = self._matrix[scene_index][track_index]
                button.refresh()

        self._set_suppress_rebuild_requests(False)

    def get_color(self, value, track_index, scene_index):
        if not self._active:
            return
        if self._mode == SCENE_MODE or self._mode == CONTROL_MODE or self._pad_mode == PM_ON:
            element = self._scenematrix.get_element(scene_index, track_index)
            return element.get_color(value)
        elif self._mode == CLIP_MODE:
            scene = self._session.scene(scene_index)
            clip_slot = scene.clip_slot(track_index)._clip_slot
            cindex = 0
            if value == 0:
                cindex = 1
            if clip_slot != None:
                if clip_slot.has_clip:
                    if clip_slot.clip.is_recording or clip_slot.clip.will_record_on_start:
                        return PColor.CLIP_RECORD[cindex]
                    if clip_slot.clip.is_playing:
                        return PColor.CLIP_PLAY[cindex]
                    elif clip_slot.clip.is_triggered:
                        return PColor.CLIP_PLAY[cindex]
                    else:
                        return PColor.CLIP_STOPPED[cindex]
                elif clip_slot.will_record_on_start:
                    return PColor.CLIP_RECORD[cindex]
                elif clip_slot.is_playing:
                    return PColor.CLIP_GROUP_PLAY[cindex]
                elif clip_slot.controls_other_clips:
                    return PColor.CLIP_GROUP_CONTROL[cindex]
                elif clip_slot.is_triggered:
                    return PColor.CLIP_GROUP_TRIGGER[cindex]
        elif self._mode == PAD_MODE:
            button = self._matrix[scene_index][track_index]
            return self.get_color_by_note_mode(button.get_identifier(), value > 0)

    def step_key_color_mode(self):
        self._note_display_mode = (self._note_display_mode + 1) % len(KEY_COLOR_MODES_STRINGS)
        self.show_message('Pad Mode Key Color = ' + KEY_COLOR_MODES_STRINGS[self._note_display_mode])
        self.send_to_display('Colors: ' + KEY_COLOR_MODES_STRINGS[self._note_display_mode], 1)
        if self._mode == PAD_MODE:
            for note_index in range(16):
                button = self._button_sequence[note_index]
                button.send_color_direct(self.get_color_by_note_mode(button.get_identifier(), False))

    def get_color_by_note_mode(self, midi_note, on):
        if self._note_display_mode == ND_BASE_OTHER:
            interval = (midi_note + 12 - self._base_note) % 12
            if on:
                return INTERVAL_COLOR_MAP[interval][0]
            else:
                return INTERVAL_COLOR_MAP[interval][1]
        elif on:
            return KEY_COLOR_MAP[midi_note % 12][0]
        else:
            return KEY_COLOR_MAP[midi_note % 12][1]

    def _send_midi(self, midi_bytes, **keys):
        self._c_ref.send_midi(midi_bytes)
        if self._midi_pause_count == 2:
            time.sleep(0.002)
            self._midi_pause_count = 0
        else:
            self._midi_pause_count = self._midi_pause_count + 1
        return True

    def clip_handle(self):
        if self._mode == SCENE_MODE or self._mode == CONTROL_MODE or self._modifier_down:
            self._scenematrix.update()

    def _a_display_update(self, value):
        if not self.display_update_button != None:
            raise AssertionError
            raise value in range(128) or AssertionError
            (value != 0 or not self.display_update_button.is_momentary()) and self._update_hardware()
            self.show_message('Maschine Display Updated')

    def _set_up_timer(self):
        self.blink_state = 1

    def update_display(self):
        with self.component_guard():
            with self._is_sending_scheduled_messages():
                self._task_group.update(0.1)
            if self._mode == CLIP_MODE and not self._modifier_down:
                if self.blink_state == 0:
                    self._session.notify(1, 0)
                elif self.blink_state == 1:
                    self._session.notify(1, 1)
                elif self.blink_state == 3:
                    self._session.notify(2, 0)
                elif self.blink_state == 4:
                    self._session.notify(2, 1)
            elif self._mode == PAD_MODE:
                pass
            elif self.blink_state == 0:
                self._scenematrix.notify_scene_mode(1)
            elif self.blink_state == 2:
                self._scenematrix.notify_scene_mode(0)
            self.blink_state = (self.blink_state + 1) % 4
            self.init_slot += 1

    def _invoke_track_edit(self, mode):
        self._deassign_matrix()
        self._scenematrix.assign()
        self._scenematrix.set_mode(mode)
        self._pad_mode = PM_ON
        self.request_rebuild_midi_map()
        self._scenematrix.update()

    def _set_modecontrol(self):
        is_momentary = True
        self.scene_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 112)
        self.clip_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 113)
        self.pad_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 114)
        self.control_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 115)
        self.xfade_assign_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 116)
        self.scene_mode_button.add_value_listener(self._a_mode_scene)
        self.clip_mode_button.add_value_listener(self._a_mode_clip)
        self.pad_mode_button.add_value_listener(self._a_mode_pad)
        self.control_mode_button.add_value_listener(self._a_mode_control)

    def _set_mode(self, mode = None):
        if mode == None:
            mode = self._mode
        if mode == SCENE_MODE:
            self.clip_mode_button.send_value(OFF_VALUE, True)
            self.pad_mode_button.send_value(OFF_VALUE, True)
            self.control_mode_button.send_value(OFF_VALUE, True)
            self.scene_mode_button.send_value(ON_VALUE, True)
        elif mode == CLIP_MODE:
            self.scene_mode_button.send_value(OFF_VALUE, True)
            self.pad_mode_button.send_value(OFF_VALUE, True)
            self.control_mode_button.send_value(OFF_VALUE, True)
            self.clip_mode_button.send_value(ON_VALUE, True)
        elif mode == PAD_MODE:
            self.scene_mode_button.send_value(OFF_VALUE, True)
            self.clip_mode_button.send_value(OFF_VALUE, True)
            self.control_mode_button.send_value(OFF_VALUE, True)
            self.pad_mode_button.send_value(ON_VALUE, True)
        elif mode == CONTROL_MODE:
            self.scene_mode_button.send_value(OFF_VALUE, True)
            self.clip_mode_button.send_value(OFF_VALUE, True)
            self.pad_mode_button.send_value(OFF_VALUE, True)
            self.control_mode_button.send_value(ON_VALUE, True)

    def _reset_matrix(self):
        for scene_index in range(4):
            scene = self._session.scene(scene_index)
            for track_index in range(4):
                button = self._matrix[scene_index][track_index]
                clip_slot = scene.clip_slot(track_index)
                clip_slot.set_launch_button(button)

    def update_button_matrix(self):
        self._session.update()
        for scene_index in range(4):
            scene = self._session.scene(scene_index)
            for track_index in range(4):
                button = self._matrix[scene_index][track_index]
                clip_slot = scene.clip_slot(track_index)
                if clip_slot._clip_slot != None and clip_slot._clip_slot.clip != None:
                    button.send_value(1, True)
                else:
                    button.send_value(0, True)

    def _deassign_matrix(self):
        for scene_index in range(4):
            scene = self._session.scene(scene_index)
            for track_index in range(4):
                clip_slot = scene.clip_slot(track_index)
                clip_slot.set_launch_button(None)

    def _from_pad_mode(self, matrix_mode):
        self._mode = SCENE_MODE
        self._register_buttons()
        self._scenematrix.assign()
        self._scenematrix.set_mode(matrix_mode)
        self._set_suppress_rebuild_requests(True)
        self.request_rebuild_midi_map()
        self._scenematrix.update()
        self._set_suppress_rebuild_requests(False)

    def _enter_pad_mode(self):
        self._set_mode(PAD_MODE)
        if self._mode == CLIP_MODE:
            self._deassign_matrix()
        elif self._mode == SCENE_MODE:
            self._scenematrix.deassign()
        elif self._mode == CONTROL_MODE:
            self._scenematrix.deassign()
            self._master_knob.exit_matrix_mode()
        self._mode = PAD_MODE
        self._set_suppress_rebuild_requests(True)
        for row in range(4):
            for column in range(4):
                button = self._matrix[row][column]
                button.send_value(0, True)
                button.set_to_notemode(True)
                self._forwarding_registry[MIDI_NOTE_ON_STATUS, button.get_identifier()] = button
                self._forwarding_registry[MIDI_NOTE_OFF_STATUS, button.get_identifier()] = button

        self._set_suppress_rebuild_requests(False)

    def _register_buttons(self, update = False):
        self._set_suppress_rebuild_requests(True)
        for row in range(4):
            for column in range(4):
                button = self._matrix[row][column]
                button.set_to_notemode(False)
                if update:
                    button.send_value(127, True)
                fwkey = [MIDI_NOTE_ON_STATUS]
                fwkey.append(button.get_identifier())
                self._forwarding_registry[tuple(fwkey)] = button
                self._forwarding_registry[MIDI_NOTE_OFF_STATUS, button.get_identifier()] = button

        self._set_suppress_rebuild_requests(False)

    def _back_to_clip_mode(self):
        self._pad_mode = PM_OFF
        self._scenematrix.set_mode(SCENE_MODE_NORMAL)
        self._scenematrix.deassign()
        self._set_up_clip_matrix()

    def _set_up_clip_matrix(self):
        for row in range(4):
            for column in range(4):
                button = self._matrix[row][column]
                button.set_to_notemode(False)

        self._set_suppress_rebuild_requests(True)
        self.request_rebuild_midi_map()
        self._reset_matrix()
        self.update_button_matrix()
        self._set_suppress_rebuild_requests(False)

    def _enter_scene_mode(self):
        self._set_mode(SCENE_MODE)
        if self._mode == CLIP_MODE:
            self._deassign_matrix()
        elif self._mode == CONTROL_MODE:
            self._master_knob.exit_matrix_mode()
        elif self._mode == PAD_MODE:
            self._register_buttons()
        self._mode = SCENE_MODE
        self._scenematrix.assign()
        self._scenematrix.set_mode(SCENE_MODE_NORMAL)
        self._return_mode = SCENE_MODE_NORMAL
        self.request_rebuild_midi_map()

    def _enter_clip_mode(self):
        self._set_suppress_rebuild_requests(True)
        self._set_mode(CLIP_MODE)
        if self._mode == SCENE_MODE:
            self._scenematrix.deassign()
        elif self._mode == CONTROL_MODE:
            self._master_knob.exit_matrix_mode()
        self._mode = CLIP_MODE
        self._set_up_clip_matrix()
        self.request_rebuild_midi_map()
        self._set_suppress_rebuild_requests(False)

    def _enter_control_mode(self):
        self._set_mode(CONTROL_MODE)
        if self._mode == CLIP_MODE:
            self._deassign_matrix()
        elif self._mode == PAD_MODE:
            self._mode = CONTROL_MODE
            self._register_buttons()
        self._mode = CONTROL_MODE
        self._set_suppress_rebuild_requests(True)
        self._scenematrix.set_mode(SCENE_MODE_CONTROL)
        self._return_mode = SCENE_MODE_CONTROL
        self._scenematrix.assign()
        self._master_knob.switch_to_matrix_mode()
        self._set_suppress_rebuild_requests(False)
        self.request_rebuild_midi_map()
        self._scenematrix.update()

    def _a_mode_scene(self, value):
        if not self.scene_mode_button != None:
            raise AssertionError
            raise value in range(128) or AssertionError
            value != 0 and self.show_message('SCENE MODE')
            self._enter_scene_mode()

    def _a_mode_clip(self, value):
        if not self.clip_mode_button != None:
            raise AssertionError
            raise value in range(128) or AssertionError
            value != 0 and self.show_message('CLIP MODE')
            self._enter_clip_mode()

    def _a_mode_pad(self, value):
        if not self.pad_mode_button != None:
            raise AssertionError
            raise value in range(128) or AssertionError
            value != 0 and self.show_message('PAD MODE')
            self._enter_pad_mode()

    def _a_mode_control(self, value):
        if not self.control_mode_button != None:
            raise AssertionError
            raise value in range(128) or AssertionError
            value != 0 and self.show_message('CONTROL MODE')
            self._enter_control_mode()

    def _do_pad_select_multi(self, value):
        if not value in range(128):
            raise AssertionError
            self._modifier_down = value != 0
            if self._mode == PAD_MODE or self._returntopad:
                value != 0 and self._from_pad_mode(SCENE_MODE_SELECT)
                self._returntopad = True
            else:
                self._returntopad = False
                self._enter_pad_mode()
        elif self._mode == CLIP_MODE:
            if value != 0:
                self._invoke_track_edit(SCENE_MODE_SELECT)
            else:
                self._back_to_clip_mode()
        elif self._mode != PAD_MODE:
            if value == 0:
                self._scenematrix.set_mode(self._return_mode)
            else:
                if self._scenematrix.in_main_mode():
                    self._return_mode = self._scenematrix.mode
                self._scenematrix.set_mode(SCENE_MODE_SELECT)

    def _do_mute_button(self, value):
        if not self._mute_button != None:
            raise AssertionError
            if not value in range(128):
                raise AssertionError
                self._modifier_down = value != 0
                (self._mode == PAD_MODE or self._returntopad) and value != 0 and self._from_pad_mode(SCENE_MODE_MUTE)
                self._returntopad = True
            else:
                self._returntopad = False
                self._enter_pad_mode()
        elif self._mode == SCENE_MODE or self._mode == CONTROL_MODE:
            if value == 0:
                self._scenematrix.set_mode(self._return_mode)
                self._pad_mode = PM_OFF
            else:
                if self._scenematrix.in_main_mode():
                    self._return_mode = self._scenematrix.mode
                self._scenematrix.set_mode(SCENE_MODE_MUTE)
                self._pad_mode = PM_ON
        elif self._mode == CLIP_MODE:
            if value > 0:
                self._invoke_track_edit(SCENE_MODE_MUTE)
            else:
                self._back_to_clip_mode()
                self._pad_mode = PM_OFF

    def _do_pad_solo_multi(self, value):
        if not value in range(128):
            raise AssertionError
            self._modifier_down = value != 0
            if self._mode == PAD_MODE or self._returntopad:
                value != 0 and self._from_pad_mode(SCENE_MODE_SOLO)
                self._returntopad = True
            else:
                self._returntopad = False
                self._enter_pad_mode()
        elif self._mode == CLIP_MODE:
            if value != 0:
                self._invoke_track_edit(SCENE_MODE_SOLO)
            else:
                self._back_to_clip_mode()
        elif self._mode != PAD_MODE:
            if value == 0:
                self._scenematrix.set_mode(self._return_mode)
            else:
                if self._scenematrix.in_main_mode():
                    self._return_mode = self._scenematrix.mode
                self._scenematrix.set_mode(SCENE_MODE_SOLO)

    def _do_xfade_assign(self, value):
        if not self.xfade_assign_button != None:
            raise AssertionError
            if not value in range(128):
                raise AssertionError
                (self._mode == PAD_MODE or self._returntopad) and value != 0 and self._from_pad_mode(SCENE_MODE_XFADE)
                self._returntopad = True
            else:
                self._returntopad = False
                self._enter_pad_mode()
        elif self._mode == CLIP_MODE:
            if value != 0:
                self._invoke_track_edit(SCENE_MODE_XFADE)
            else:
                self._back_to_clip_mode()
        elif self._mode == SCENE_MODE or self._mode == CONTROL_MODE:
            if value == 0:
                self._scenematrix.set_mode(self._return_mode)
            else:
                if self._scenematrix.in_main_mode():
                    self._return_mode = self._scenematrix.mode
                self._scenematrix.set_mode(SCENE_MODE_XFADE)

    def _do_pad_note_up(self, value):
        if not self._pad_scale_up != None:
            raise AssertionError
            if not value in range(128):
                raise AssertionError
                self._pad_scale_up.send_value(value, True)
                self._modifier_down = value != 0
                (self._mode == PAD_MODE or self._returntopad) and value != 0 and self._from_pad_mode(SCENE_MODE_ARM)
                self._returntopad = True
            else:
                self._returntopad = False
                self._enter_pad_mode()
        elif self._mode == CLIP_MODE:
            self.show_message('Arm tracks with pads')
            if value != 0:
                self._invoke_track_edit(SCENE_MODE_ARM)
            else:
                self._back_to_clip_mode()
        elif self._mode == SCENE_MODE or self._mode == CONTROL_MODE:
            self.show_message('Arm tracks with pads')
            if value == 0:
                self._scenematrix.set_mode(self._return_mode)
            else:
                if self._scenematrix.in_main_mode():
                    self._return_mode = self._scenematrix.mode
                self._scenematrix.set_mode(SCENE_MODE_ARM)

    def _do_pad_note_down(self, value):
        if not self._pad_scale_down != None:
            raise AssertionError
            if not value in range(128):
                raise AssertionError
                self._pad_scale_down.send_value(value, True)
                self._modifier_down = value != 0
                (self._mode == PAD_MODE or self._returntopad) and value != 0 and self._from_pad_mode(SCENE_MODE_STOP)
                self._returntopad = True
            else:
                self._returntopad = False
                self._enter_pad_mode()
        elif self._mode == CLIP_MODE:
            self.show_message('Stop tracks with pads')
            if value != 0:
                self._invoke_track_edit(SCENE_MODE_STOP)
            else:
                self._back_to_clip_mode()
        elif self._mode == SCENE_MODE or self._mode == CONTROL_MODE:
            self.show_message('Stop tracks with pads')
            if value == 0:
                self._scenematrix.set_mode(self._return_mode)
            else:
                if self._scenematrix.in_main_mode():
                    self._return_mode = self._scenematrix.mode
                self._scenematrix.set_mode(SCENE_MODE_STOP)

    def modify_track_offset(self, delta):
        self._scenematrix.mod_track_offset(delta)

    def modify_scene_offset(self, delta):
        self._scenematrix.mod_scene_offset(delta)

    def move_view_horizontal(self, delta):
        if delta == 1:
            self._session.bank_right()
        else:
            self._session.bank_left()
        if self._mode == CONTROL_MODE:
            self._scenematrix.update()

    def inc_octave(self, inc):
        scale = SCALES[self.current_scale_index]
        octave = scale.to_octave(self._octave)
        newoctave = octave + inc
        if newoctave < 0:
            newoctave = 0
        elif newoctave > scale.octave_range:
            newoctave = scale.octave_range
        self._octave = scale.to_relative(newoctave, self._octave)
        scale = SCALES[self.current_scale_index]
        self.show_message(' OCTAVE ' + BASE_NOTE[self._base_note] + str(newoctave - 2) + ' to ' + scale.name)
        self.current_scale_to_display()

    def inc_base_note(self, inc):
        newbase = self._base_note + inc
        if newbase < 0:
            self._base_note = 0
        elif newbase > 11:
            self._base_note = 11
        else:
            self._base_note = newbase
        scale = SCALES[self.current_scale_index]
        self.show_message(' Base Note ' + BASE_NOTE[self._base_note] + ' to ' + scale.name)
        self.current_scale_to_display()

    def current_scale_to_display(self):
        scale = SCALES[self.current_scale_index]
        text = scale.name + ' ' + BASE_NOTE[self._base_note] + str(scale.to_octave(self._octave))
        self.send_to_display(text)

    def inc_scale(self, inc):
        nr_of_scales = len(SCALES)
        newindex = self.current_scale_index + inc
        if newindex < 0:
            newindex = 0
        elif newindex >= nr_of_scales:
            newindex = nr_of_scales - 1
        else:
            self.current_scale_index += inc
        newscale = SCALES[self.current_scale_index]
        self.show_message(' PAD Scale ' + newscale.name + ' ' + BASE_NOTE[self._base_note] + str(newscale.to_octave(self._octave) - 2))
        self.current_scale_to_display()

    def update_transpose(self):
        self.assign_transpose(SCALES[self.current_scale_index])
        self._set_suppress_rebuild_requests(True)
        self.request_rebuild_midi_map()
        self._set_suppress_rebuild_requests(False)

    def set_scale(self, scale):
        raise isinstance(scale, PadScale) or AssertionError
        scale_len = len(scale.notevalues)
        octave = scale.to_octave(self._octave)

    def assign_transpose(self, scale):
        raise isinstance(scale, PadScale) or AssertionError
        scale_len = len(scale.notevalues)
        octave = scale.to_octave(self._octave)
        last_note_val = None
        for note_index in range(16):
            button = self._button_sequence[note_index]
            scale_index = note_index % scale_len
            octave_offset = note_index / scale_len
            note_value = scale.notevalues[scale_index] + self._base_note + octave * 12 + octave_offset * 12
            if note_value < 128:
                last_note_val = note_value
            elif last_note_val != None:
                note_value = last_note_val
            button.set_send_note(note_value)
            if self._mode == PAD_MODE:
                button.send_color_direct(self.get_color_by_note_mode(note_value, False))

    def do_reset(self, value):
        if value == 0:
            return
        for row in range(4):
            for column in range(4):
                button = self._matrix[row][column]
                data_byte1 = button._original_identifier
                button.send_midi((MIDI_CC_STATUS + 2, data_byte1, 0))

    def do_test(self, value):
        color = self.togglecolor[self.toggleindex]
        self.toggleindex = (self.toggleindex + 1) % len(self.togglecolor)
        if value == 0:
            return
        for row in range(4):
            for column in range(4):
                button = self._matrix[row][column]
                self.schedule_message(1, self.dosend, (color,
                 127,
                 127,
                 row,
                 column))

    def dosend(self, parm = None):
        button = self._matrix[parm[3]][parm[4]]
        data_byte1 = button._original_identifier
        button.send_midi((MIDI_CC_STATUS + 0, data_byte1, parm[0]))
        button.send_midi((MIDI_CC_STATUS + 1, data_byte1, parm[1]))
        button.send_midi((MIDI_CC_STATUS + 2, data_byte1, parm[2]))

    def do_note_repeat(self, value):
        nrvalue = 0
        if value != 0:
            nrvalue = 1
        self._c_ref.set_note_repeat_state(nrvalue)

    def _do_toggle_send(self, value):
        nr_of_tracks = len(self.song().return_tracks)
        if value == 0 or nr_of_tracks < 1:
            return
        prev = self.send_slider_index
        self.send_slider_index += 1
        if self.send_slider_index >= nr_of_tracks:
            self.send_slider_index = 0
        self.show_message(' Set Send ' + str(SENDS[self.send_slider_index]))
        if prev != self.send_slider_index:
            for track in range(8):
                strip = self._mixer.channel_strip(track)
                slider_list = []
                for index in range(self.send_slider_index + 1):
                    if index < self.send_slider_index - 1:
                        slider_list.append(None)
                    else:
                        slider_list.append(self.send_sliders[track])
                    strip.set_send_controls(tuple(slider_list))

    def _do_armsolo_mode(self, value):
        if not self._armsolomode_button != None:
            raise AssertionError
            raise value in range(128) or AssertionError
            value != 0 and self._scenematrix.set_armsolo_exclusive(self._armsolomode_button)

    def _do_fire_button(self, value):
        if not self._fire_button != None:
            raise AssertionError
            if not value in range(128):
                raise AssertionError
                clip_slot = (value != 0 or not self._mute_button.is_momentary()) and self.song().view.highlighted_clip_slot
                clip_slot and clip_slot.fire()

    def _do_undo(self, value):
        if not self._undo_button != None:
            raise AssertionError
            if not value in range(128):
                raise AssertionError
                (value != 0 or not self._undo_button.is_momentary()) and self.song().can_undo == 1 and self.song().undo()
                self.show_message(str('UNDO'))

    def _do_redo(self, value):
        if not self._redo_button != None:
            raise AssertionError
            if not value in range(128):
                raise AssertionError
                (value != 0 or not self._redo_button.is_momentary()) and self.song().can_redo == 1 and self.song().redo()
                self.show_message(str('REDO'))

    def _a_trk_left(self, value):
        if not value in range(128):
            raise AssertionError
            if value != 0:
                direction = self.application().view.is_view_visible('Session') and Live.Application.Application.View.NavDirection.left
                self.application().view.scroll_view(direction, 'Session', True)

    def _a_trk_right(self, value):
        if not value in range(128):
            raise AssertionError
            if value != 0:
                direction = self.application().view.is_view_visible('Session') and Live.Application.Application.View.NavDirection.right
                self.application().view.scroll_view(direction, 'Session', True)

    def _nav_value_left(self, value):
        if not self._device_nav_button_left != None:
            raise AssertionError
            if not value in range(128):
                raise AssertionError
                modifier_pressed = True
                value > 0 and (not self.application().view.is_view_visible('Detail') or not self.application().view.is_view_visible('Detail/DeviceChain')) and self.application().view.show_view('Detail')
                self.application().view.show_view('Detail/DeviceChain')
            else:
                direction = Live.Application.Application.View.NavDirection.left
                self.application().view.scroll_view(direction, 'Detail/DeviceChain', not modifier_pressed)

    def _nav_value_right(self, value):
        if not self._device_nav_button_right != None:
            raise AssertionError
            if not value in range(128):
                raise AssertionError
                modifier_pressed = value > 0 and True
                (not self.application().view.is_view_visible('Detail') or not self.application().view.is_view_visible('Detail/DeviceChain')) and self.application().view.show_view('Detail')
                self.application().view.show_view('Detail/DeviceChain')
            else:
                direction = Live.Application.Application.View.NavDirection.right
                self.application().view.scroll_view(direction, 'Detail/DeviceChain', not modifier_pressed)

    def _do_tap_tempo(self, value):
        if not value in range(128):
            raise AssertionError
            value > 0 and self.song().tap_tempo()

    def _do_toggle_cue(self, value):
        if not value in range(128):
            raise AssertionError
            value > 0 and self.song().set_or_delete_cue()

    def _do_toggle_prev_cue(self, value):
        if not value in range(128):
            raise AssertionError
            value > 0 and self.song().jump_to_prev_cue()

    def _do_toggle_next_cue(self, value):
        if not value in range(128):
            raise AssertionError
            value > 0 and self.song().jump_to_next_cue()

    def focus_changed(self):
        pass

    def _handle_device_changed(self, device):
        pass

    def _hande_device_parm_changed(self):
        pass

    def _do_focus_navigate(self, value):
        if not self._navigate_button != None:
            raise AssertionError
            raise value in range(128) or AssertionError
            self.nav_index = value != 0 and (self.nav_index + 1) % len(VIEWS_ALL)
            self.application().view.focus_view(VIEWS_ALL[self.nav_index])
            self.show_message('Focus on : ' + str(VIEWS_ALL[self.nav_index]))

    def scroll_focus(self, delta):
        if delta == 1:
            self.nav_index = (self.nav_index + 1) % len(VIEWS_ALL)
        elif self.nav_index == 0:
            self.nav_index = len(VIEWS_ALL) - 1
        else:
            self.nav_index -= 1
        self.show_message('Focus on : ' + str(VIEWS_ALL[self.nav_index]))
        self.application().view.focus_view(VIEWS_ALL[self.nav_index])

    def scroll_device(self, delta):
        if not (delta == 1 or delta == -1):
            raise AssertionError
            direction = delta == 1 and Live.Application.Application.View.NavDirection.right
        else:
            direction = Live.Application.Application.View.NavDirection.left
        self.application().view.scroll_view(direction, 'Detail/DeviceChain', True)

    def scroll_scene(self, delta):
        if not self.track_left_button != None:
            raise AssertionError
            raise delta == 1 or delta == -1 or AssertionError
            direction = delta == 1 and Live.Application.Application.View.NavDirection.down
        else:
            direction = Live.Application.Application.View.NavDirection.up
        self.application().view.scroll_view(direction, 'Session', True)

    def index_in_strip(self, track):
        for ind in range(len(self._mixer._channel_strips)):
            strack = self._mixer._channel_strips[ind]._track
            if strack == track:
                return ind

        return -1

    def notify_track_scroll(self):
        self._scenematrix.update_control_selection()
        if self._mode == CONTROL_MODE:
            self._scenematrix.eval_matrix()
            self._scenematrix.fire_values()

    def send_to_display(self, text, grid = 0):
        if USE_DISPLAY == False:
            return
        if len(text) > 28:
            text = text[:27]
        msgsysex = [240,
         0,
         0,
         102,
         23,
         18,
         min(grid, 3) * 28]
        filled = text.ljust(28)
        for c in filled:
            msgsysex.append(ord(c))

        msgsysex.append(247)
        self._send_midi(tuple(msgsysex))

    def send_color(self, button, hue, sat, bright):
        raise isinstance(button, ButtonElement) or AssertionError
        raise hue in range(128) or AssertionError
        raise sat in range(128) or AssertionError
        raise bright in range(128) or AssertionError
        data_byte1 = button._original_identifier
        button.send_midi((MIDI_CC_STATUS + 2, data_byte1, bright))
        button.send_midi((MIDI_CC_STATUS + 1, data_byte1, sat))
        button.send_midi((MIDI_CC_STATUS + 0, data_byte1, hue))

    def turn_off_matrix(self):
        for row in range(4):
            for column in range(4):
                button = self._matrix[row][column]
                self.send_color(button, 2, 0, 0)
                button.set_to_notemode(False)

    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.turn_off_matrix()
        self.scene_mode_button.send_value(0, True)
        self.clip_mode_button.send_value(0, True)
        self.pad_mode_button.send_value(0, True)
        self.control_mode_button.send_value(0, True)
        time.sleep(0.2)
        self._active = False
        self._suppress_send_midi = True
        self.remove_listener(self.scene_mode_button, self._a_mode_scene)
        self.remove_listener(self.clip_mode_button, self._a_mode_clip)
        self.remove_listener(self.pad_mode_button, self._a_mode_pad)
        self.remove_listener(self.control_mode_button, self._a_mode_control)
        self.remove_listener(self._undo_button, self._do_undo)
        self.remove_listener(self._redo_button, self._do_redo)
        self.remove_listener(self._armsolomode_button, self._do_armsolo_mode)
        self.remove_listener(self.xfade_assign_button, self._do_xfade_assign)
        self.remove_listener(self._fire_button, self._do_fire_button)
        self._session.remove_offset_listener(self.notify_track_scroll)
        self._mixer.disconnect()
        ControlSurface.disconnect(self)
示例#28
0
class LaunchMod(ControlSurface):
	__module__ = __name__
	__doc__ = " Script for Novation's Launchpad Controller "

	def __init__(self, c_instance):
		ControlSurface.__init__(self, c_instance)
		self._monomod_version = 'b994'
		self._host_name = 'LaunchMod'
		self._color_type = 'Launchpad'
		self.hosts = []
		self._timer = 0
		self.set_suppress_rebuild_requests(True)
		self._suppress_send_midi = True
		self._suppress_session_highlight = True
		is_momentary = True
		self._suggested_input_port = 'Launchpad'
		self._suggested_output_port = 'Launchpad'
		self._wrote_user_byte = False
		self._control_is_with_automap = False
		self._challenge = (Live.Application.get_random_int(0, 400000000) & 2139062143)
		matrix = ButtonMatrixElement()
		matrix.name = 'ButtonMatrix'
		for row in range(8):
			#button_row = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, ((row * 16) + column)) for column in range(8) ]
			button_row = [ FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, ((row * 16) + column), 'Button_'+str(row)+'_'+str(column), self) for column in range(8) ]
			matrix.add_row(tuple(button_row))
		self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0)
		self._config_button.add_value_listener(self._config_value)
		top_buttons = [ FlashingButtonElement(is_momentary, MIDI_CC_TYPE, 0, (104 + index), 'Top_Button'+str(index), self) for index in range(8) ]
		side_buttons = [ FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index], 'Side_Button'+str(index), self) for index in range(8) ]
		self._setup_monobridge()
		self._setup_monomod()
		self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button, self)
		self._suppress_session_highlight = False
		self._suppress_send_midi = False
		self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)
		self._user_byte_write_button.send_value(1)
		self._user_byte_write_button.add_value_listener(self._user_byte_value)
		self._suppress_send_midi = True
		self.set_suppress_rebuild_requests(False)
		self.log_message("--------------= LaunchMod log opened =--------------") #Create entry in log file
		self.refresh_state()

	def _setup_monobridge(self):
		self._monobridge = MonoBridgeElement(self)
		self._monobridge.name = 'MonoBridge'
	

	def _setup_monomod(self):
		self._host = MonomodComponent(self)
		self._host.name = 'Monomod_Host'
		self.hosts = [self._host]
	

	def disconnect(self):
		self._suppress_send_midi = True
		self._selector = None
		self._user_byte_write_button.remove_value_listener(self._user_byte_value)
		self._config_button.remove_value_listener(self._config_value)
		ControlSurface.disconnect(self)
		self._suppress_send_midi = False
		self._config_button.send_value(32)
		self._config_button.send_value(0)
		self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None
		self.log_message("--------------= LaunchMod log closed =--------------") #Create entry in log file


	def refresh_state(self):
		ControlSurface.refresh_state(self)
		self.schedule_message(5, self._update_hardware)



	def handle_sysex(self, midi_bytes):
		if (len(midi_bytes) == 8):
			if (midi_bytes[1:5] == (0,
			 32,
			 41,
			 6)):
				response = long(midi_bytes[5])
				response += (long(midi_bytes[6]) << 8)
				if (response == Live.Application.encrypt_challenge2(self._challenge)):
					self._suppress_send_midi = False
					self.set_enabled(True)
					#self.refresh_state()



	def _send_midi(self, midi_bytes):
		if (not self._suppress_send_midi):
			ControlSurface._send_midi(self, midi_bytes)



	def _update_hardware(self):
		self._suppress_send_midi = False
		self._config_button.send_value(40)
		self._wrote_user_byte = True
		self._user_byte_write_button.send_value(1)
		self._suppress_send_midi = True
		self.set_enabled(False)
		self._suppress_send_midi = False
		self._send_challenge()



	def _send_challenge(self):
		for index in range(4):
			challenge_byte = ((self._challenge >> (8 * index)) & 127)
			self._send_midi((176,
			 (17 + index),
			 challenge_byte))




	def _user_byte_value(self, value):
		assert (value in range(128))
		enabled = (value == 1)
		if enabled:
			self._config_button.send_value(40)
		self._control_is_with_automap = (not enabled)
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.set_force_next_value()

		if (not self._wrote_user_byte):
			self._selector.set_mode(0)
			self.set_enabled(enabled)
		else:
			self._wrote_user_byte = False
		self.request_rebuild_midi_map()



	def _config_value(self, value):
		assert (value in range(128))



	def _set_session_highlight(self, track_offset, scene_offset, width, height, include_returns = False):
		if (not self._suppress_session_highlight):
			ControlSurface._set_session_highlight(self, track_offset, scene_offset, width, height, include_returns)



	def _install_forwarding(self, control):
		result = False
		if ((not self._control_is_with_automap) or (control == self._user_byte_write_button)):
			result = ControlSurface._install_forwarding(self, control)
		return result



	def _translate_message(self, type, from_identifier, from_channel, to_identifier, to_channel):
		if (not self._control_is_with_automap):
			ControlSurface._translate_message(self, type, from_identifier, from_channel, to_identifier, to_channel)


	def update_display(self):
		""" Live -> Script
		Aka on_timer. Called every 100 ms and should be used to update display relevant
		parts of the controller
		"""
		for message in self._scheduled_messages:
			message['Delay'] -= 1
			if (message['Delay'] == 0):
				if (message['Parameter'] != None):
					message['Message'](message['Parameter'])
				else:
					message['Message']()
					del self._scheduled_messages[self._scheduled_messages.index(message)]

		for callback in self._timer_callbacks:
			callback()
		self._timer = (self._timer + 1) % 256
		self.flash()
	

	def flash(self):
		#if(self.flash_status > 0):
		for row in range(8):
			if(self._selector._side_buttons[row]._flash_state > 0):
				self._selector._side_buttons[row].flash(self._timer)
			for column in range(8):
				button = self._selector._matrix.get_button(column, row)
				if(button._flash_state > 0):
					button.flash(self._timer)
		for index in range(4):
			if(self._selector._nav_buttons[index]._flash_state > 0):
				self._selector._nav_buttons[index].flash(self._timer)
			if(self._selector._modes_buttons[index]._flash_state > 0):
				self._selector._modes_buttons[index].flash(self._timer)
	

	def allow_updates(self, allow_updates):
		for component in self.components:
			component.set_allow_update(int(allow_updates!=0))
示例#29
0
class APCmini(ControlSurface):

	""" Script for Novation's Launchpad Controller """

	def __init__(self, c_instance):
		live = Live.Application.get_application()
		self._live_major_version = live.get_major_version()
		self._live_minor_version = live.get_minor_version()
		self._live_bugfix_version = live.get_bugfix_version()
		ControlSurface.__init__(self, c_instance)
		#self._device_selection_follows_track_selection = True
		with self.component_guard():
			self._suppress_send_midi = True
			self._suppress_session_highlight = True

			is_momentary = True
			self._suggested_input_port = 'Launchpad'
			self._suggested_output_port = 'Launchpad'
			self._control_is_with_automap = False
			self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)		# Apparently this CC is used to enable feedback, ie lighting up buttons that you pressed
			self._user_byte_write_button.name = 'User_Byte_Button'
			self._user_byte_write_button.send_value(1)
			self._user_byte_write_button.add_value_listener(self._user_byte_value)
			self._wrote_user_byte = False
			self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143
			matrix = ButtonMatrixElement()
			matrix.name = 'Button_Matrix'
			for row in range(8):
				button_row = []
				for column in range(8):
					button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, (7-row) * 8 + column)	# APCmini rows are in reverse order from Launchpad
					button.name = str(column) + '_Clip_' + str(row) + '_Button'
					button_row.append(button)

				matrix.add_row(tuple(button_row))

			self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0, optimized_send_midi=False)	# Control goes through here on LP, no real equivalent in APCmini (I don't think)
			self._config_button.add_value_listener(self._config_value)
			top_buttons = [ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 64 + index) for index in range(8)]
			side_buttons = [ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index]) for index in range(8)]
			top_buttons[0].name = 'Bank_Select_Up_Button'
			top_buttons[1].name = 'Bank_Select_Down_Button'
			top_buttons[2].name = 'Bank_Select_Left_Button'
			top_buttons[3].name = 'Bank_Select_Right_Button'
			top_buttons[4].name = 'Session_Button'
			top_buttons[5].name = 'User1_Button'
			top_buttons[6].name = 'User2_Button'
			top_buttons[7].name = 'Mixer_Button'
			side_buttons[0].name = 'Vol_Button'
			side_buttons[1].name = 'Pan_Button'
			side_buttons[2].name = 'SndA_Button'
			side_buttons[3].name = 'SndB_Button'
			side_buttons[4].name = 'Stop_Button'
			side_buttons[5].name = 'Trk_On_Button'
			side_buttons[6].name = 'Solo_Button'
			side_buttons[7].name = 'Arm_Button'
			self._osd = M4LInterface()
			self._osd.name = "OSD"
			self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button, self._osd, self)
			self._selector.name = 'Main_Modes'
			self._do_combine()
			for control in self.controls:
				if isinstance(control, ConfigurableButtonElement):
					control.add_value_listener(self._button_value)

			self.set_highlighting_session_component(self._selector.session_component())
			self._suppress_session_highlight = False

			self.log_message("LaunchPad95 Loaded !")

	def disconnect(self):
		self._suppress_send_midi = True
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.remove_value_listener(self._button_value)
		self._do_uncombine()
		self._selector = None
		self._user_byte_write_button.remove_value_listener(self._user_byte_value)
		self._config_button.remove_value_listener(self._config_value)
		ControlSurface.disconnect(self)
		self._suppress_send_midi = False
		self._config_button.send_value(32)
		self._config_button.send_value(0)
		self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None

	_active_instances = []

	#def highlighting_session_component(self):
	#	" Return the session component showing the ring in Live session "
	#	return self._selector.session_component()

	def _combine_active_instances():
		support_devices = False
		for instance in APCmini._active_instances:
			support_devices |= (instance._device_component != None)
		offset = 0
		for instance in APCmini._active_instances:
			instance._activate_combination_mode(offset, support_devices)
			offset += instance._selector._session.width()

	_combine_active_instances = staticmethod(_combine_active_instances)

	def _activate_combination_mode(self, track_offset, support_devices):
		if(Settings.STEPSEQ__LINK_WITH_SESSION):
			self._selector._stepseq.link_with_step_offset(track_offset)
		if(Settings.SESSION__LINK):
			self._selector._session.link_with_track_offset(track_offset)

	def _do_combine(self):
		if (DO_COMBINE and (self not in APCmini._active_instances)):
			APCmini._active_instances.append(self)
			APCmini._combine_active_instances()

	def _do_uncombine(self):
		if self in APCmini._active_instances:
			APCmini._active_instances.remove(self)
			if(Settings.SESSION__LINK):
				self._selector._session.unlink()
			if(Settings.STEPSEQ__LINK_WITH_SESSION):
				self._selector._stepseq.unlink()
			APCmini._combine_active_instances()

	def refresh_state(self):
		ControlSurface.refresh_state(self)
		self.schedule_message(5, self._update_hardware)

	def handle_sysex(self, midi_bytes):
		# if len(midi_bytes) == 8:
		# if midi_bytes[1:5] == (0, 32, 41, 6):
		# response = long(midi_bytes[5])
		# response += long(midi_bytes[6]) << 8
		# if response == Live.Application.encrypt_challenge2(self._challenge):
		self._suppress_send_midi = False
		self.set_enabled(True)

	def build_midi_map(self, midi_map_handle):
		ControlSurface.build_midi_map(self, midi_map_handle)
		if self._selector.mode_index == 1:
			if self._selector._sub_mode_index[self._selector._mode_index] > 0:  # disable midi map rebuild for instrument mode to prevent light feedback errors
				new_channel = self._selector.channel_for_current_mode()
				# self.log_message(str(new_channel))
				# for note in DRUM_NOTES:
				#	self._translate_message(MIDI_NOTE_TYPE, note, 0, note, new_channel)

	def _send_midi(self, midi_bytes, optimized=None):
		sent_successfully = False
		if not self._suppress_send_midi:
			sent_successfully = ControlSurface._send_midi(self, midi_bytes, optimized=optimized)
		return sent_successfully

	def _update_hardware(self):
		self._suppress_send_midi = False
		self._wrote_user_byte = True
		self._user_byte_write_button.send_value(1)
		self._suppress_send_midi = True
		self.set_enabled(False)
		self._suppress_send_midi = False
		# self._send_challenge()
		self.set_enabled(True)			# Enable anyways, without checking

	def _send_challenge(self):
		for index in range(4):
			challenge_byte = self._challenge >> 8 * index & 127
			self._send_midi((176, 17 + index, challenge_byte))

	def _user_byte_value(self, value):
		assert (value in range(128))
		if not self._wrote_user_byte:
			enabled = (value == 1)
			self._control_is_with_automap = not enabled
			self._suppress_send_midi = self._control_is_with_automap
			if not self._control_is_with_automap:
				for control in self.controls:
					if isinstance(control, ConfigurableButtonElement):
						control.set_force_next_value()

			self._selector.set_mode(0)
			self.set_enabled(enabled)
			self._suppress_send_midi = False
		else:
			self._wrote_user_byte = False

	def _button_value(self, value):
		assert value in range(128)

	def _config_value(self, value):
		assert value in range(128)

	def _set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks):
		if not self._suppress_session_highlight:
			ControlSurface._set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks)
示例#30
0
class BlockPad(ControlSurface):
	__module__ = __name__
	__doc__ = " Script for Novation's Launchpad Controller adapted to Livid's Block controller and Monomodular by amounra "

	def __init__(self, c_instance):
		ControlSurface.__init__(self, c_instance)
		self._monomod_version = 'b994'
		self.hosts = []
		self._host_name = 'BlockPad'
		self._color_type = 'Monochrome'
		self._timer = 0
		is_momentary = True
		self._suggested_input_port = 'block (Controls)'
		self._suggested_output_port = 'block (Controls)'
		self._wrote_user_byte = False
		matrix = ButtonMatrixElement()
		for row in range(8):
			button_row = [ FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, ((column * 8) + row), 'Button_'+str(column)+'_'+str(row), self) for column in range(8) ]
			matrix.add_row(tuple(button_row))
		knobs = [ EncoderElement(MIDI_CC_TYPE, 0, KNOB_CC[index], Live.MidiMap.MapMode.absolute) for index in range(8) ]
		sliders = [ EncoderElement(MIDI_CC_TYPE, 0, SLIDER_CC[index], Live.MidiMap.MapMode.absolute) for index in range(2) ]
		self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0)
		self._config_button.add_value_listener(self._config_value)
		top_buttons = [ FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, TOP_NOTES[index], 'Top_Button'+str(index), self) for index in range(8) ]
		side_buttons = [ FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index], 'Side_Button'+str(index), self) for index in range(8) ]
		self._setup_monobridge()
		self._setup_monomod()
		self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button, tuple(knobs), tuple(sliders), self)
		self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)
		self._user_byte_value(1)
		self._user_byte_write_button.add_value_listener(self._user_byte_value)
		self.set_enabled(True)
		self.log_message("--------------= BlockPad log opened =--------------") #Create entry in log file
		self.refresh_state()

	def _setup_monobridge(self):
		self._monobridge = MonoBridgeElement(self)
		self._monobridge.name = 'MonoBridge'
	

	def _setup_monomod(self):
		self._host = MonomodComponent(self)
		self._host.name = 'Monomod_Host'
		self.hosts = [self._host]
	

	def disconnect(self):
		self._suppress_send_midi = True
		self._selector = None
		self._user_byte_write_button.remove_value_listener(self._user_byte_value)
		self._config_button.remove_value_listener(self._config_value)
		ControlSurface.disconnect(self)
		self._suppress_send_midi = False
		self._config_button.send_value(32)
		self._config_button.send_value(0)
		self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None
		self.log_message("--------------= BlockPad log closed =--------------") #Create entry in log file


	def _user_byte_value(self, value):
		assert (value in range(128))
		enabled = (value == 1)
		if enabled:
			self._config_button.send_value(40)
		self._control_is_with_automap = (not enabled)
		for control in self.controls:
			if isinstance(control, FlashingButtonElement):
				control.set_force_next_value()

		if (not self._wrote_user_byte):
			self._selector.set_mode(0)
			self.set_enabled(enabled)
		else:
			self._wrote_user_byte = False
		self.request_rebuild_midi_map()



	def _config_value(self, value):
		assert (value in range(128))

	def update_display(self):
		""" Live -> Script
		Aka on_timer. Called every 100 ms and should be used to update display relevant
		parts of the controller
		"""
		for message in self._scheduled_messages:
			message['Delay'] -= 1
			if (message['Delay'] == 0):
				if (message['Parameter'] != None):
					message['Message'](message['Parameter'])
				else:
					message['Message']()
					del self._scheduled_messages[self._scheduled_messages.index(message)]

		for callback in self._timer_callbacks:
			callback()
		self._timer = (self._timer + 1) % 256
		if(self._timer == 0):
			self._selector._shift_pressed_timer = -12
		self.flash()
	

	def flash(self):
		for row in range(8):
			for column in range(8):
				button = self._selector._matrix.get_button(column, row)
				if(button._flash_state > 0):
					button.flash(self._timer)
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
示例#32
0
class Launchpad(ControlSurface):
    """ Script for Novation's Launchpad Controller """
    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        self.set_suppress_rebuild_requests(True)
        self._suppress_send_midi = True
        self._suppress_session_highlight = True
        is_momentary = True
        self._suggested_input_port = 'Launchpad'
        self._suggested_output_port = 'Launchpad'
        self._control_is_with_automap = False
        self._user_byte_write_button = ButtonElement(is_momentary,
                                                     MIDI_CC_TYPE, 0, 16)
        self._user_byte_write_button.name = 'User_Byte_Button'
        self._user_byte_write_button.send_value(1)
        self._user_byte_write_button.add_value_listener(self._user_byte_value)
        self._wrote_user_byte = False
        self._challenge = Live.Application.get_random_int(
            0, 400000000) & 2139062143
        matrix = ButtonMatrixElement()
        matrix.name = 'Button_Matrix'
        for row in range(8):
            button_row = []
            for column in range(8):
                button = ConfigurableButtonElement(is_momentary,
                                                   MIDI_NOTE_TYPE, 0,
                                                   row * 16 + column)
                button.name = str(column) + '_Clip_' + str(row) + '_Button'
                button_row.append(button)

            matrix.add_row(tuple(button_row))

        self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0)
        self._config_button.add_value_listener(self._config_value)
        top_buttons = [
            ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0,
                                      104 + index) for index in range(8)
        ]
        side_buttons = [
            ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0,
                                      SIDE_NOTES[index]) for index in range(8)
        ]
        top_buttons[0].name = 'Bank_Select_Up_Button'
        top_buttons[1].name = 'Bank_Select_Down_Button'
        top_buttons[2].name = 'Bank_Select_Left_Button'
        top_buttons[3].name = 'Bank_Select_Right_Button'
        top_buttons[4].name = 'Session_Button'
        top_buttons[5].name = 'User1_Button'
        top_buttons[6].name = 'User2_Button'
        top_buttons[7].name = 'Mixer_Button'
        side_buttons[0].name = 'Vol_Button'
        side_buttons[1].name = 'Pan_Button'
        side_buttons[2].name = 'SndA_Button'
        side_buttons[3].name = 'SndB_Button'
        side_buttons[4].name = 'Stop_Button'
        side_buttons[5].name = 'Trk_On_Button'
        side_buttons[6].name = 'Solo_Button'
        side_buttons[7].name = 'Arm_Button'
        self._selector = MainSelectorComponent(matrix, tuple(top_buttons),
                                               tuple(side_buttons),
                                               self._config_button, self)
        self._selector.name = 'Main_Modes'
        self._do_combine()
        for control in self.controls:
            if isinstance(control, ConfigurableButtonElement):
                control.add_value_listener(self._button_value)

        self._suppress_session_highlight = False
        self.set_suppress_rebuild_requests(False)

        self.log_message("LaunchPad85 Loaded !")

    def disconnect(self):
        self._suppress_send_midi = True
        for control in self.controls:
            if isinstance(control, ConfigurableButtonElement):
                control.remove_value_listener(self._button_value)
        self._do_uncombine()
        self._selector = None
        self._user_byte_write_button.remove_value_listener(
            self._user_byte_value)
        self._config_button.remove_value_listener(self._config_value)
        ControlSurface.disconnect(self)
        self._suppress_send_midi = False
        self._config_button.send_value(32)
        self._config_button.send_value(0)
        self._config_button = None
        self._user_byte_write_button.send_value(0)
        self._user_byte_write_button = None

    _active_instances = []

    def highlighting_session_component(self):
        " Return the session component showing the ring in Live session "
        return self._selector.session_component()

    def _combine_active_instances():
        support_devices = False
        for instance in Launchpad._active_instances:
            support_devices |= (instance._device_component != None)
        offset = 0
        for instance in Launchpad._active_instances:
            instance._activate_combination_mode(offset, support_devices)
            offset += instance._selector._session.width()

    _combine_active_instances = staticmethod(_combine_active_instances)

    def _activate_combination_mode(self, track_offset, support_devices):
        if (LINK_STEPSEQ):
            self._selector._stepseq.link_with_step_offset(track_offset)
        if (LINK_SESSION):
            self._selector._session.link_with_track_offset(track_offset)

    def _do_combine(self):
        if (DO_COMBINE and (self not in Launchpad._active_instances)):
            Launchpad._active_instances.append(self)
            Launchpad._combine_active_instances()

    def _do_uncombine(self):
        if self in Launchpad._active_instances:
            Launchpad._active_instances.remove(self)
            if (LINK_SESSION):
                self._selector._session.unlink()
            if (LINK_STEPSEQ):
                self._selector._stepseq.unlink()
            Launchpad._combine_active_instances()

    def refresh_state(self):
        ControlSurface.refresh_state(self)
        self.schedule_message(5, self._update_hardware)

    def handle_sysex(self, midi_bytes):
        if len(midi_bytes) == 8:
            if midi_bytes[1:5] == (0, 32, 41, 6):
                response = long(midi_bytes[5])
                response += long(midi_bytes[6]) << 8
                if response == Live.Application.encrypt_challenge2(
                        self._challenge):
                    self._suppress_send_midi = False
                    self.set_enabled(True)

    def build_midi_map(self, midi_map_handle):
        ControlSurface.build_midi_map(self, midi_map_handle)
        if self._selector.mode_index == 1:
            new_channel = self._selector.channel_for_current_mode()
            for note in DRUM_NOTES:
                self._translate_message(MIDI_NOTE_TYPE, note, 0, note,
                                        new_channel)

    def _send_midi(self, midi_bytes):
        sent_successfully = False
        if not self._suppress_send_midi:
            sent_successfully = ControlSurface._send_midi(self, midi_bytes)
        return sent_successfully

    def _update_hardware(self):
        self._suppress_send_midi = False
        self._wrote_user_byte = True
        self._user_byte_write_button.send_value(1)
        self._suppress_send_midi = True
        self.set_enabled(False)
        self._suppress_send_midi = False
        self._send_challenge()

    def _send_challenge(self):
        for index in range(4):
            challenge_byte = self._challenge >> 8 * index & 127
            self._send_midi((176, 17 + index, challenge_byte))

    def _user_byte_value(self, value):
        assert (value in range(128))
        if (not self._wrote_user_byte):
            enabled = (value == 1)
            self._control_is_with_automap = (not enabled)
            self._suppress_send_midi = self._control_is_with_automap
            if not self._control_is_with_automap:
                for control in self.controls:
                    if isinstance(control, ConfigurableButtonElement):
                        control.set_force_next_value()

            self._selector.set_mode(0)
            self.set_enabled(enabled)
            self._suppress_send_midi = False
        else:
            self._wrote_user_byte = False

    def _button_value(self, value):
        assert (value in range(128))

    def _config_value(self, value):
        assert (value in range(128))

    def _set_session_highlight(self, track_offset, scene_offset, width, height,
                               include_return_tracks):
        if not self._suppress_session_highlight:
            ControlSurface._set_session_highlight(self, track_offset,
                                                  scene_offset, width, height,
                                                  include_return_tracks)
class MidiFighterTwister(ControlSurface):
    __module__ = __name__
    __doc__ = "MidiFighterTwister class"

    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
            self.__c_instance = c_instance
            self.show_message('Script initiated')
            self.init()

    def init(self):
        # initialize listeners, caches and colors
        self.flush_all()
        self.mf_disable_bank_buttons()
        self.mf_init_page_config()
        self.mf_init_light_pages()

        # Start listeners to call dispatcher
        self.song().view.add_detail_clip_listener(
            self.dispatch_detail_clip_listener)
        self.song().add_current_song_time_listener(
            self.dispatch_current_song_time_listener)
        self.song().view.add_selected_track_listener(
            self.dispatch_selected_track_listener)
        self.device_listener_wrapper()

        # Initialize the sequencer buttons
        self.sequencer_init_buttons()
        self.sequencer_init_rotaries()
        self.init_clip_page()
        self.init_pad_page()
        self.init_device_params()

    def flush_all(self):
        for poti in range(64):
            for channel in range(4):
                self._send_midi((175 + channel, poti, 0))

    def mf_init_page_config(self):
        # Initialize configuration parameters
        # Sequencer configuration
        self.sequencer_page_default_color = 1
        self.sequencer_current_page_color_index = self.sequencer_page_default_color
        self.sequencer_base_default_note = 36
        self.sequencer_current_selected_note = self.sequencer_base_default_note
        self.sequencer_clip_position_16th = None

        # Midi Channels
        self.rotary_midi_channel = 175 + 1
        self.ring_midi_channel = 175 + 1
        self.switch_midi_channel = 175 + 2
        self.light_midi_channel = 175 + 2
        # Pages cc map
        self.clip_page_cc = range(0, 16)
        self.sequencer_page_cc = range(16, 32)
        self.note_page_cc = range(32, 48)
        self.control_page_cc = range(48, 64)
        # Pages init color
        self.clip_page_colors = [1] * 16
        self.sequencer_page_colors = [self.sequencer_page_default_color] * 16
        self.note_page_colors = range(1, 127, 16) * 2
        #self.note_page_colors = [0] * 16
        self.control_page_colors = [1] * 16
        # Status cache for sequencer
        self.switch_encoder_status_cache = [False] * 64
        # List to store ButtonElements in
        self.switch_encoder_buttons = [False] * 64
        # Status cache for rotaries
        self.rotary_encoder_potis = [False] * 64

    def mf_init_light_pages(self):
        sequencer_page_map = zip(self.sequencer_page_cc,
                                 self.sequencer_page_colors)
        for light_encoder_cc, light_color_cc in sequencer_page_map:
            self._mf_set_light(light_encoder_cc, light_color_cc, False)
        note_page_map = zip(self.note_page_cc,
                            self.note_page_colors)
        for light_encoder_cc, light_color_cc in note_page_map:
            self._mf_set_light(light_encoder_cc, light_color_cc, False)

    def _mf_set_light(self, light_encoder_cc, light_color_cc, status):
        # Sets color on midi channel 2 (177) end updates status cache
        # for sequencer to remember statuses
        self._send_midi((self.light_midi_channel, light_encoder_cc,
                         light_color_cc))
        self.switch_encoder_status_cache[light_encoder_cc] = status

    def mf_disable_bank_buttons(self):
        # Workaround for not sending values to track when pressing bank buttons
        self.padm0 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 4, 0)
        self.padm1 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 4, 1)
        self.padm2 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 4, 2)
        self.padm3 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 4, 3)
        self.padm0.add_value_listener(self.bank_buttons_dummy,
                                      identify_sender=True)
        self.padm1.add_value_listener(self.bank_buttons_dummy,
                                      identify_sender=True)
        self.padm2.add_value_listener(self.bank_buttons_dummy,
                                      identify_sender=True)
        self.padm3.add_value_listener(self.bank_buttons_dummy,
                                      identify_sender=True)

    def bank_buttons_dummy(self):
        pass

    def dispatch_detail_clip_listener(self):
        self.current_clip = self.song().view.highlighted_clip_slot.clip
        self.init_sequencer()
        try:
            if self.current_clip.is_midi_clip and not self.current_clip.notes_has_listener:
                # Update leds when notes are added or removed
                self.current_clip.add_notes_listener(
                    self._sequencer_update_notes_to_light)
                self.init_sequencer()
            else:
                self.sequencer_reset_colors()
        except AttributeError:
            pass

    def dispatch_current_song_time_listener(self):
        self.sequencer_light_follows_beat()

    def dispatch_selected_track_listener(self):
        self.device_auto_select()
        self.device_listener_wrapper()

    def device_listener_wrapper(self):
        selected_track = self.song().view.selected_track
        if not selected_track.devices_has_listener(self.device_auto_select):
            self.song().view.selected_track.add_devices_listener(
                self.device_auto_select)

    # Sequencer
    def init_sequencer(self):
        self.sequencer_current_selected_note = self.sequencer_base_default_note
        self.sequencer_current_page_color_index = self.sequencer_page_default_color
        self._sequencer_update_notes_to_light()

    def sequencer_init_buttons(self):
        for switch_encoder_cc in self.sequencer_page_cc:
            self.switch_encoder_buttons[switch_encoder_cc] = ButtonElement(
                IS_MOMENTARY, MIDI_CC_TYPE, 1, switch_encoder_cc)
            self.switch_encoder_buttons[switch_encoder_cc].add_value_listener(
                self.sequencer_button_press, identify_sender=True)
        self.padl14 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 14)
        self.padr17 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 17)
        self.padl16 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 16)
        self.padr19 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 19)
        self.padl14.add_value_listener(self.sequencer_side_button_press,
                                       identify_sender=True)
        self.padr17.add_value_listener(self.sequencer_side_button_press,
                                       identify_sender=True)
        self.padl16.add_value_listener(self.sequencer_side_button_press,
                                       identify_sender=True)
        self.padr19.add_value_listener(self.sequencer_side_button_press,
                                       identify_sender=True)

    def sequencer_init_rotaries(self):
        for rotary_encoder_cc in self.sequencer_page_cc:
            self.rotary_encoder_potis[rotary_encoder_cc] = EncoderElement( MIDI_CC_TYPE, 0, rotary_encoder_cc, Live.MidiMap.MapMode.absolute)
            self.rotary_encoder_potis[rotary_encoder_cc].add_value_listener(self.sequencer_rotary_change, identify_sender=True)

    def sequencer_rotary_change(self, value, sender):
        try:
            self.current_clip
        except AttributeError:
            return False
        if self.current_clip.is_midi_clip:
            cc_value = sender._msg_identifier
            if value > 0:
                if not self.switch_encoder_status_cache[cc_value]:
                    self._send_midi((self.light_midi_channel,
                                     cc_value,
                                     self.sequencer_current_light_on_color))
                    self._send_midi((
                        self.ring_midi_channel, cc_value, 100))
                    self.switch_encoder_status_cache[cc_value] = True
                self.current_clip.set_notes(((self.sequencer_current_selected_note, cc_value % 16 * 0.25, 0.25, value, False),))
            elif value == 0:
                self._send_midi((self.light_midi_channel,
                                cc_value, self.sequencer_current_page_color))
                self.current_clip.remove_notes(
                    cc_value % 16 * 0.25,
                    self.sequencer_current_selected_note,
                    0.25, 1)
                self.switch_encoder_status_cache[cc_value] = False

    def sequencer_button_press(self, value, sender):
        try:
            self.current_clip
        except AttributeError:
            return False
        if self.current_clip.is_midi_clip:
            cc_value = sender._msg_identifier
            if value > 0:
                if not self.switch_encoder_status_cache[cc_value]:
                    self._send_midi((self.light_midi_channel,
                                     cc_value,
                                     self.sequencer_current_light_on_color))
                    self.current_clip.set_notes(((
                        self.sequencer_current_selected_note, cc_value % 16 *
                        0.25, 0.25, 100, False),))
                    self.switch_encoder_status_cache[cc_value] = True
                    self._send_midi((self.ring_midi_channel, cc_value, 100))
                else:
                    self._send_midi((self.light_midi_channel,
                                     cc_value,
                                     self.sequencer_current_page_color))
                    self._send_midi((self.ring_midi_channel, cc_value, 0))
                    self.current_clip.remove_notes(
                        cc_value % 16 * 0.25,
                        self.sequencer_current_selected_note,
                        0.25, 1)
                    self.switch_encoder_status_cache[cc_value] = False

    def sequencer_side_button_press(self, value, sender):
            try:
                cc_value = sender._msg_identifier
                if value > 0:
                    # Note/clolor up/down
                    if cc_value == 14 and self.sequencer_current_selected_note > 0:
                        self.sequencer_current_selected_note = self.sequencer_current_selected_note - 1
                        self.sequencer_current_page_color_index = self.sequencer_current_page_color_index - 16
                        self._sequencer_update_notes_to_light()
                        self.sequencer_clip_position_16th = None
                        self.show_message("Selected Midi Note: "+str(self.sequencer_current_selected_note))
                    if cc_value == 17 and self.sequencer_current_selected_note < 127:
                        self.sequencer_current_selected_note = self.sequencer_current_selected_note + 1
                        self.sequencer_current_page_color_index = self.sequencer_current_page_color_index + 16
                        self._sequencer_update_notes_to_light()
                        self.sequencer_clip_position_16th = None
                        self.show_message("Selected Midi Note: "+str(self.sequencer_current_selected_note))
                    # New/duplicate clip
                    if cc_value == 16 and self.sequencer_current_selected_note > 0:
                        self.duplicate_clip()
                    if cc_value == 19 and self.sequencer_current_selected_note > 0:
                        self.session_record()
            except AttributeError:
                pass

    def sequencer_light_follows_beat(self):
        try:
            if self.current_clip.is_midi_clip:
                    if self.sequencer_clip_position_16th == None:
                        self.sequencer_clip_position_16th = int(self.current_clip.playing_position / 0.25)
                        if self.switch_encoder_status_cache[self.sequencer_page_cc[self.sequencer_clip_position_16th]]:
                            self._send_midi((177, self.sequencer_page_cc[self.sequencer_clip_position_16th], self.sequencer_current_light_on_color))
                        else:
                            self._send_midi((177, self.sequencer_page_cc[self.sequencer_clip_position_16th], self.sequencer_current_page_color))
                    elif self.sequencer_clip_position_16th != int(self.current_clip.playing_position/0.25):
                        if self.switch_encoder_status_cache[self.sequencer_page_cc[self.sequencer_clip_position_16th]]:
                            self._send_midi((177, self.sequencer_page_cc[self.sequencer_clip_position_16th], self.sequencer_current_light_on_color))
                        else:
                            self._send_midi((177, self.sequencer_page_cc[self.sequencer_clip_position_16th], self.sequencer_current_page_color))
                        self.sequencer_clip_position_16th = int(self.current_clip.playing_position/0.25)
                        self._send_midi((177, self.sequencer_page_cc[self.sequencer_clip_position_16th], self.sequencer_current_light_beat_color))
        except IndexError:
            pass

    @property
    def sequencer_current_light_on_color(self):
        # light on color to be relative to page color
        return self.sequencer_current_page_color + 32 % 128

    @property
    def sequencer_current_light_beat_color(self):
        # light on color to be relative to page color
        return self.sequencer_current_page_color + 64 % 128

    @property
    def sequencer_current_page_color(self):
        return self.sequencer_current_page_color_index % 128

    def _sequencer_get_midi_notes(self, note):
        # self.current_clip.get_notes(start, self.sequencer_current_selected_note,
        # selection_length, hight)
        try:
            return self.current_clip.get_notes(0, note, 4, 1)
        except AttributeError:
            return []

    def _sequencer_update_notes_to_light(self):
        self.sequencer_reset_colors()
        notes_for_current_selected_note = self._sequencer_get_midi_notes(
            self.sequencer_current_selected_note)
        for note in notes_for_current_selected_note:
            light_encoder_cc = int(note[1]*4+self.sequencer_page_cc[0])
            self._send_midi((self.ring_midi_channel, light_encoder_cc, note[3]))
            self._mf_set_light(light_encoder_cc,
                               self.sequencer_current_light_on_color, True)

    def sequencer_reset_colors(self):
        for light_encoder_cc in self.sequencer_page_cc:
            self._mf_set_light(light_encoder_cc,
                               self.sequencer_current_page_color, False)
            self._send_midi((self.ring_midi_channel, light_encoder_cc, 0))

    def duplicate_clip(self):
        self.log_message("duplicate clip")
        #if self._clip_slot and self._clip_slot.has_clip:
        #    slot_name = self._clip_slot.clip.name
        #    track = self._clip_slot.canonical_parent
        current_track = self.song().view.selected_track
        current_clip_slot = self.song().view.highlighted_clip_slot
        self.song().duplicate_scene(list(current_track.clip_slots).index(current_clip_slot))
        #new_clip = current_track.duplicate_clip_slot(
        #    list(current_track.clip_slots).index(current_clip_slot)+1)
        #self.log_message(new_clip)
        #selected_track = self.song().view.selected_track
        #selected_track.duplicate_clip_slot(selected_track)

    def session_record(self):
        self.log_message("session record")
        #self.song().trigger_session_record()

# Clip page setion

    def init_clip_page(self):
        num_tracks = 4
        num_scenes = 3
        self.flash_status = 1
        self.Mixer = MixerComponent(4, 3)

        # Volencoder
        self.volencoders = [None for index in range(num_tracks)]
        for index in range(num_tracks):
            self.volencoders[index] = EncoderElement(
                MIDI_CC_TYPE, 0, index, Live.MidiMap.MapMode.absolute)
            self.Mixer.channel_strip(index).set_volume_control(
                self.volencoders[index])

        # Sendencoder
        for index in range(num_tracks):
            encoder_cc_send_1 = index + num_tracks
            encoder_cc_send_2 = index + num_tracks * 2
            send1 = EncoderElement(MIDI_CC_TYPE, 0, encoder_cc_send_1,
                                   Live.MidiMap.MapMode.absolute)
            send2 = EncoderElement(MIDI_CC_TYPE, 0, encoder_cc_send_2,
                                   Live.MidiMap.MapMode.absolute)
            self.Mixer.channel_strip(index).set_send_controls((send1, send2))

        # Panencoder
        for index in range(num_tracks):
            encoder_cc_pan = index + num_tracks * 3
            pan = EncoderElement(MIDI_CC_TYPE, 0, encoder_cc_pan,
                                 Live.MidiMap.MapMode.absolute)
            self.Mixer.channel_strip(index).set_pan_control(pan)

        # Arm-/selectbuttons
        for index in range(num_tracks):
            armbutton = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1,
                                      index + 12)
            self.Mixer.channel_strip(index).set_arm_button(armbutton)
            self.Mixer.channel_strip(index).set_select_button(armbutton)

        # Navigation buttons
        self.padl11 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 11)
        self.padr8 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 8)
        self.padl10 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 10)
        self.padr13 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 13)

        self.grid = [None for index in range(num_tracks * 3)]
        for index in range(num_tracks * 3):
            self.grid[index] = ButtonElement(
                IS_MOMENTARY, MIDI_CC_TYPE, 1, index)
        self.matrix = ButtonMatrixElement()
        for row in range(num_scenes):
            button_row = []
            for column in range(num_tracks):
                button_row.append(self.grid[column+(row*4)])
                self.log_message(str(column+(row*4)))
            self.matrix.add_row(tuple(button_row))

        self.Session = SessionComponent(num_tracks, num_scenes)
        self.Session.name = "Session"
        self.Session.set_offsets(0, 0)
        self.Session.set_mixer(self.Mixer)
        self.Session._do_show_highlight()
        self.set_highlighting_session_component(self.Session)
        self.Session.set_track_bank_buttons(self.padl11, self.padr8)
        self.Session.set_scene_bank_buttons(self.padr13, self.padl10)

        self.scene = [None for index in range(num_scenes)]
        for row in range(num_scenes):
            self.scene[row] = self.Session.scene(row)
            self.scene[row].name = 'Scene_'+str(row)
            for column in range(num_tracks):
                clip_slot = self.scene[row].clip_slot(column)
                clip_slot.name = str(column)+'_Clip_Slot'+str(row)
                self.scene[row].clip_slot(column).set_triggered_to_play_value(35)
                self.scene[row].clip_slot(column).set_stopped_value(68)
                self.scene[row].clip_slot(column).set_started_value(45)
                self.scene[row].clip_slot(column).set_triggered_to_record_value(100)
                self.scene[row].clip_slot(column).set_recording_value(80)

        for column in range(num_tracks):
            for row in range(num_scenes):
                self.scene[row].clip_slot(column).set_launch_button(self.grid[column+(row*4)])
            for index in range(num_tracks*num_scenes):
                self.grid[index].clear_send_cache()

    def update_display(self):
        # Called every 100 ms
        ControlSurface.update_display(self)
        self.refresh_state()
        self.Session.set_enabled(True)
        self.Session.update()
        # Sequencer hack
        try:
            for light_encoder_cc in self.sequencer_page_cc:
                self._send_midi((self.ring_midi_channel, light_encoder_cc, 0))
            notes_for_current_selected_note = self._sequencer_get_midi_notes(
                self.sequencer_current_selected_note)
            for note in notes_for_current_selected_note:
                light_encoder_cc = int(note[1]*4+self.sequencer_page_cc[0])
                self._send_midi((self.ring_midi_channel, light_encoder_cc,
                                 note[3]))
        except AttributeError:
            pass

    # Pad Section
    def init_pad_page(self):
        self.pad_device_params()
        PAD_TRANSLATION = (
            (0, 0, 32, 1), (1, 0, 33, 1), (2, 0, 34, 1), (3, 0, 35, 1),
            (0, 1, 36, 1), (1, 1, 37, 1), (2, 1, 38, 1), (3, 1, 39, 1),
            (0, 2, 40, 1), (1, 2, 41, 1), (2, 2, 42, 1), (3, 2, 43, 1),
            (0, 3, 44, 1), (1, 3, 45, 1), (2, 3, 46, 1), (3, 3, 47, 1))
        self.set_pad_translations(PAD_TRANSLATION)
        self._device_selection_follows_track_selection = True

    def pad_device_params(self):
        device_param_controls = []
        for param in self.note_page_cc[:8]:
            self.rotary_encoder_potis[param] = EncoderElement(
                MIDI_CC_TYPE, 0, param, Live.MidiMap.MapMode.absolute)
            self.rotary_encoder_potis[param].release_parameter()
            self.rotary_encoder_potis[param].send_value(0, True)
            self.rotary_encoder_potis[param].clear_send_cache()
            device_param_controls.append(self.rotary_encoder_potis[param])

        device = DeviceComponent()
        device.name = 'Device_Component pad'
        device.set_parameter_controls(tuple(device_param_controls))
        self.set_device_component(device)

    #def scrolling(self):
    #    self.application().view.scroll_view(ndir, 'Detail/DeviceChain', True)

    # Live.Song.Song.View.selected_track
    #Live.Song.Song.View.select_device()[0]

    # Device parameter section
    def init_device_params(self):
        device_param_controls = []
        device_bank_buttons = []
        for param in self.control_page_cc[:8]:
            self.rotary_encoder_potis[param] = EncoderElement(
                MIDI_CC_TYPE, 0, param, Live.MidiMap.MapMode.absolute)
            self.switch_encoder_buttons[param] = ButtonElement(
                IS_MOMENTARY, MIDI_CC_TYPE, 1, param)
            self.rotary_encoder_potis[param].release_parameter()
            self.rotary_encoder_potis[param].send_value(0, True)
            self.rotary_encoder_potis[param].clear_send_cache()
            device_param_controls.append(self.rotary_encoder_potis[param])
            device_bank_buttons.append(self.switch_encoder_buttons[param])

        device = DeviceComponent()
        device.name = 'Device_Component'
        device.set_parameter_controls(tuple(device_param_controls))
        device.set_bank_buttons(tuple(device_bank_buttons))
        device.set_on_off_button(ButtonElement(
            IS_MOMENTARY, MIDI_CC_TYPE, 1, 56))
        self.set_device_component(device)

    def device_auto_select(self):
        # Iterates through devices within a track and assigns the first
        # DrumPad device to activate the individual drum's device.
        # Use first device in case none is a DrumPad device.
        selected_track = self.song().view.selected_track
        devices = selected_track.devices
        for device in devices:
            if device.can_have_drum_pads:
                self.current_drum_device = device
                pad_device = self.current_drum_device.view.selected_chain.devices[0]
                self.song().view.select_device(pad_device)
                if not self.current_drum_device.view.selected_drum_pad_has_listener(
                        self.device_update_current_note):
                    self.current_drum_device.view.add_selected_drum_pad_listener(
                            self.device_update_current_note)
                break
            else:
                self.song().view.select_device(devices[0])

    def device_update_current_note(self):
        current_note = self.current_drum_device.view.selected_drum_pad.note
        self.sequencer_current_selected_note = current_note

        # Update light of active pad
        #self._send_midi((self.light_midi_channel, light_encoder_cc, 63))
        try:
            self.current_clip = self.song().view.highlighted_clip_slot.clip
            self.current_clip.is_midi_clip
            self._sequencer_update_notes_to_light()
        except AttributeError:
            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
示例#35
0
class TriggerFingerMX(ControlSurface):
    def __init__(self, *a, **k):
        super(TriggerFingerMX, self).__init__(*a, **k)
        self.show_message(
            "-----------------------= TriggerFingerMX v0.5 LOADING - maxcloutier13 says hi =----------------------------------------------------------"
        )
        self.log_message(
            "-----------------------= TriggerFingerMX LOADING - maxcloutier13 says hi =----------------------------------------------------------"
        )
        with self.component_guard():
            self._init_controls()

    def _init_controls(self):
        #Define the controls in here for clarity
        #self.show_message("TFMX Debug: initControls")
        #Using channel 13 for some reason
        #Pads are set from C4 to D6
        self._Pad0 = ButtonElement(True, MIDI_NOTE_TYPE, 12, 72, name='Pad0')
        self._Pad1 = ButtonElement(True, MIDI_NOTE_TYPE, 12, 74, name='Pad1')
        self._Pad2 = ButtonElement(True, MIDI_NOTE_TYPE, 12, 76, name='Pad2')
        self._Pad3 = ButtonElement(True, MIDI_NOTE_TYPE, 12, 77, name='Pad3')
        #
        self._Pad4 = ButtonElement(True, MIDI_NOTE_TYPE, 12, 79, name='Pad4')
        self._Pad5 = ButtonElement(True, MIDI_NOTE_TYPE, 12, 81, name='Pad5')
        self._Pad6 = ButtonElement(True, MIDI_NOTE_TYPE, 12, 83, name='Pad6')
        self._Pad7 = ButtonElement(True, MIDI_NOTE_TYPE, 12, 84, name='Pad7')
        #
        self._Pad8 = ButtonElement(True, MIDI_NOTE_TYPE, 12, 86, name='Pad8')
        self._Pad9 = ButtonElement(True, MIDI_NOTE_TYPE, 12, 88, name='Pad9')
        self._Pad10 = ButtonElement(True, MIDI_NOTE_TYPE, 12, 89, name='Pad10')
        self._Pad11 = ButtonElement(True, MIDI_NOTE_TYPE, 12, 91, name='Pad11')
        #
        self._Pad12 = ButtonElement(True, MIDI_NOTE_TYPE, 12, 93, name='Pad12')
        self._Pad13 = ButtonElement(True, MIDI_NOTE_TYPE, 12, 95, name='Pad13')
        self._Pad14 = ButtonElement(True, MIDI_NOTE_TYPE, 12, 96, name='Pad14')
        self._Pad15 = ButtonElement(True, MIDI_NOTE_TYPE, 12, 98, name='Pad15')

        #Listeners on individual pads
        self._Pad0.add_value_listener(self._trig_pad0, False)
        self._Pad1.add_value_listener(self._trig_pad1, False)
        self._Pad2.add_value_listener(self._trig_pad2, False)
        self._Pad3.add_value_listener(self._trig_pad3, False)
        #
        self._Pad4.add_value_listener(self._trig_pad4, False)
        self._Pad5.add_value_listener(self._trig_pad5, False)
        self._Pad6.add_value_listener(self._trig_pad6, False)
        self._Pad7.add_value_listener(self._trig_pad7, False)
        #
        self._Pad8.add_value_listener(self._trig_pad8, False)
        self._Pad9.add_value_listener(self._trig_pad9, False)
        self._Pad10.add_value_listener(self._trig_pad10, False)
        self._Pad11.add_value_listener(self._trig_pad11, False)
        #
        self._Pad12.add_value_listener(self._trig_pad12, False)
        self._Pad13.add_value_listener(self._trig_pad13, False)
        self._Pad14.add_value_listener(self._trig_pad14, False)
        self._Pad15.add_value_listener(self._trig_pad15, False)

        self._Pads = ButtonMatrixElement(
            rows=[[self._Pad0, self._Pad1, self._Pad2, self._Pad3],
                  [self._Pad4, self._Pad5, self._Pad6, self._Pad7],
                  [self._Pad8, self._Pad9, self._Pad10, self._Pad11],
                  [self._Pad12, self._Pad13, self._Pad14, self._Pad15]])
        #Encoders to auto-map to devices -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
        self._Encoder0 = EncoderElement(MIDI_CC_TYPE,
                                        12,
                                        22,
                                        Live.MidiMap.MapMode.absolute,
                                        name='Encoder0')
        self._Encoder1 = EncoderElement(MIDI_CC_TYPE,
                                        12,
                                        23,
                                        Live.MidiMap.MapMode.absolute,
                                        name='Encoder1')
        self._Encoder2 = EncoderElement(MIDI_CC_TYPE,
                                        12,
                                        24,
                                        Live.MidiMap.MapMode.absolute,
                                        name='Encoder2')
        self._Encoder3 = EncoderElement(MIDI_CC_TYPE,
                                        12,
                                        25,
                                        Live.MidiMap.MapMode.absolute,
                                        name='Encoder3')
        self._Encoder4 = EncoderElement(MIDI_CC_TYPE,
                                        12,
                                        26,
                                        Live.MidiMap.MapMode.absolute,
                                        name='Encoder4')
        self._Encoder5 = EncoderElement(MIDI_CC_TYPE,
                                        12,
                                        27,
                                        Live.MidiMap.MapMode.absolute,
                                        name='Encoder5')
        self._Encoder6 = EncoderElement(MIDI_CC_TYPE,
                                        12,
                                        28,
                                        Live.MidiMap.MapMode.absolute,
                                        name='Encoder6')
        self._Encoder7 = EncoderElement(MIDI_CC_TYPE,
                                        12,
                                        29,
                                        Live.MidiMap.MapMode.absolute,
                                        name='Encoder7')
        self._Encoders = ButtonMatrixElement(rows=[[
            self._Encoder0, self._Encoder1, self._Encoder2, self._Encoder3,
            self._Encoder4, self._Encoder5, self._Encoder6, self._Encoder7
        ]])
        #Device -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
        self.log_message("Device component set")
        self._device = DeviceComponent(
            name='Device',
            is_enabled=False,
            layer=Layer(parameter_controls=self._Encoders),
            device_selection_follows_track_selection=True)
        self._device.set_enabled(True)
        self.set_device_component(self._device)
        self.show_message("TFMX Debug: initControls: Done")

    #--- Bottom-row
    #Record New
    def _trig_pad0(self, value):
        if value > 0:
            self._record_new()

    #Play/Pause
    def _trig_pad1(self, value):
        if value > 0:
            self._play_pause()

    #Stop
    def _trig_pad2(self, value):
        if value > 0:
            self._stop_reset()

    #Launch clip
    def _trig_pad3(self, value):
        if value > 0:
            self._launch_clip()

    #-- 2nd row
    #Set new
    def _trig_pad4(self, value):
        if value > 0:
            self._set_new()

    #-- Move left
    def _trig_pad5(self, value):
        if value > 0:
            self._move_track(1)

    #-- Move down
    def _trig_pad6(self, value):
        if value > 0:
            self._move_clipslot(0)

    #-- Move right
    def _trig_pad7(self, value):
        if value > 0:
            self._move_track(0)

    #-- 3rd-row
    #Stop new
    def _trig_pad8(self, value):
        if value > 0:
            self._stop_new()

    def _trig_pad9(self, value):
        if value > 0:
            self.show_message("TFMX Debug: Pad9 triggered")

    #-- Move Up
    def _trig_pad10(self, value):
        if value > 0:
            self._move_clipslot(1)

    def _trig_pad11(self, value):
        if value > 0:
            self.show_message("TFMX Debug: Pad11 triggered")

    #-- Top-row
    def _trig_pad12(self, value):
        if value > 0:
            self.show_message("TFMX Debug: Pad12 triggered")

    def _trig_pad13(self, value):
        if value > 0:
            self.show_message("TFMX Debug: Pad13 triggered")

    def _trig_pad14(self, value):
        if value > 0:
            self.show_message("TFMX Debug: Pad14 triggered")

    def _trig_pad15(self, value):
        if value > 0:
            self.show_message("TFMX Debug: Pad15 triggered")

    def _stop_reset(self):
        global play_flag
        if play_flag == 0:
            #Not playing, reset playing position to start
            self.song().stop_playing()
            play_flag = 1
        else:
            #Playing, stops, but tells play button to start from position next time
            self.song().stop_playing()
            play_flag = 2
        return

    def _play_pause(self):
        #Play/pause functionality
        global play_flag
        if self.song().is_playing == 0:
            #Song not playing
            if play_flag == 0:
                #Song is paused: unpause
                self.song().continue_playing()
            elif play_flag == 1:
                #Song is Stopped, play from selection start
                self.song().play_selection()
                play_flag = 0
            else:
                #Song is stopped and reset, play from start
                self.song().start_playing()
                play_flag = 0
        else:
            #Playing: pause
            self.song().stop_playing()

    def _move_clipslot(self, up):
        scene = self.song().view.selected_scene
        scenes = self.song().scenes
        max_scenes = len(scenes)
        for i in range(max_scenes):
            if scene == scenes[i]:
                #Found our guy
                if up == 1:
                    self.song().view.selected_scene = scenes[i - 1]
                    self.show_message("TFMX Debug: Up!")
                else:
                    if scene == scenes[max_scenes - 1]:
                        self.song().view.selected_scene = scenes[0]
                    else:
                        self.song().view.selected_scene = scenes[i + 1]
                    self.show_message("TFMX Debug: Down!")

    def _move_track(self, left):
        #Get track and tracks
        track = self.song().view.selected_track
        tracks = self.get_all_tracks(only_visible=True)
        max_tracks = len(tracks)
        #Iterate to find current track's index.
        for i in range(max_tracks):
            if track == tracks[i]:
                #Found our track
                if left == 1:
                    self.song().view.selected_track = tracks[i - 1]
                else:
                    if track == tracks[max_tracks - 1]:
                        self.song().view.selected_track = tracks[0]
                    else:
                        self.song().view.selected_track = tracks[i + 1]

    def get_all_tracks(self, only_visible=False):
        tracks = []
        for track in self.song().tracks:
            if not only_visible or track.is_visible:
                tracks.append(track)
        #Include the master track?
        #NOPE tracks.append(self.song().master_track)
        return tracks

    def _launch_clip(self):
        global overdub_flag
        #self.log_message("--> Track launch! -----")
        #self.song().view.highlighted_clip_slot.set_fire_button_state(True)
        _current_slot = self.song().view.highlighted_clip_slot
        if _current_slot.is_playing == 0 and _current_slot.is_recording == 0:
            self.song().view.highlighted_clip_slot.set_fire_button_state(True)
        elif _current_slot.is_playing == 1 and _current_slot.is_recording == 0:
            self.song().overdub = 1
            overdub_flag = 1
        elif _current_slot.is_playing == 1 and _current_slot.is_recording == 1 and overdub_flag == 1:
            self.song().overdub = 0
            overdub_flag = 0
        else:
            self.song().view.highlighted_clip_slot.set_fire_button_state(True)

    #Position on next valid clipslot
    def _set_new(self):
        self.show_message("TFMX Debug: SetNew")
        #Find the first empty available clipslot and set it as highlighed
        self._find_empty_slot()

    #Stop clips then Position on next valid clipslot
    def _stop_new(self):
        self.show_message("TFMX Debug: StopNew")
        self.song().view.selected_track.stop_all_clips()
        #Position on first empty cell
        self._find_empty_slot()

    #Stop clips, position on next valid clipslot and fire record
    def _record_new(self):
        self.show_message("TFMX Debug: RecordNew")
        self.song().view.selected_track.stop_all_clips()
        #Position on first empty cell
        self._find_empty_slot()
        self.song().view.highlighted_clip_slot.set_fire_button_state(True)

    def _find_empty_slot(self):
        #Find the first empty available clipslot and set it as highlighed
        for clipslot in self.song().view.selected_track.clip_slots:
            if clipslot.has_clip == 0:
                self.song().view.highlighted_clip_slot = clipslot
                return
示例#36
0
class MPK261MXLOOP(ControlSurface):

    def __init__(self, *a, **k):
        super(MPK261MXLOOP, self).__init__(*a, **k)
        self.show_message("-----------------------= MPK261MXLOOP LOADING - maxcloutier13 says hi =----------------------------------------------------------")
        self.log_message("-----------------------= MPK261MXLOOP LOADING - maxcloutier13 says hi =----------------------------------------------------------")
        with self.component_guard():
            midimap = MidiMap()
            #Sustain pedal 1 = Play/Record/Overdub switch for live looping
            self._LoopRecordButton = ButtonElement(True, MIDI_CC_TYPE, 0, 64)
            self._LoopRecordButton.add_value_listener(self._launch_clip, False)
            #Sustain pedal 2 = Sustain pour l'instant ;o)
            #self._LoopRecordButton = ButtonElement(True, MIDI_CC_TYPE, 0, 65)            
            #Control up/down/left/right using the daw controls            
            self._UpButton = ButtonElement(False, MIDI_CC_TYPE, 0, 88, name='UpButton')
            self._DownButton = ButtonElement(False, MIDI_CC_TYPE, 0, 89, name='DownButton')
            self._LeftButton = ButtonElement(False, MIDI_CC_TYPE, 0, 20, name='LeftButton')
            self._RightButton = ButtonElement(False, MIDI_CC_TYPE, 0, 21, name='RightButton')
            #Listeners for the functions
            self._UpButton.add_value_listener(self._move_up, False)
            self._DownButton.add_value_listener(self._move_down, False)
            self._LeftButton.add_value_listener(self._move_left, False)
            self._RightButton.add_value_listener(self._move_right, False)
            #Super crude manual init for the custom buttons and faders 
            #Control Bank A - Channel 1 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
            self._Encoder0 = EncoderElement(MIDI_CC_TYPE,1,22, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder0')
            self._Encoder1 = EncoderElement(MIDI_CC_TYPE,1,23, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder1')
            self._Encoder2 = EncoderElement(MIDI_CC_TYPE,1,24, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder2')
            self._Encoder3 = EncoderElement(MIDI_CC_TYPE,1,25, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder3')
            self._Encoder4 = EncoderElement(MIDI_CC_TYPE,1,26, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder4')
            self._Encoder5 = EncoderElement(MIDI_CC_TYPE,1,27, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder5')
            self._Encoder6 = EncoderElement(MIDI_CC_TYPE,1,28, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder6')
            self._Encoder7 = EncoderElement(MIDI_CC_TYPE,1,29, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder7')
            self._ArmButton0 = ButtonElement(False, MIDI_CC_TYPE, 0, 32, name='ArmButton0')
            self._ArmButton1 = ButtonElement(False, MIDI_CC_TYPE, 0, 33, name='ArmButton1')
            self._ArmButton2 = ButtonElement(False, MIDI_CC_TYPE, 0, 34, name='ArmButton2')
            self._ArmButton3 = ButtonElement(False, MIDI_CC_TYPE, 0, 35, name='ArmButton3')
            self._ArmButton4 = ButtonElement(False, MIDI_CC_TYPE, 0, 36, name='ArmButton4')
            self._ArmButton5 = ButtonElement(False, MIDI_CC_TYPE, 0, 37, name='ArmButton5')
            self._ArmButton6 = ButtonElement(False, MIDI_CC_TYPE, 0, 38, name='ArmButton6')
            self._ArmButton7 = ButtonElement(False, MIDI_CC_TYPE, 0, 39, name='ArmButton7')
            self._VolumeSlider0 = SliderElement(MIDI_CC_TYPE, 0, 12, name='VolumeSlider0')
            self._VolumeSlider1 = SliderElement(MIDI_CC_TYPE, 0, 13, name='VolumeSlider1')
            self._VolumeSlider2 = SliderElement(MIDI_CC_TYPE, 0, 14, name='VolumeSlider2')
            self._VolumeSlider3 = SliderElement(MIDI_CC_TYPE, 0, 15, name='VolumeSlider3')
            self._VolumeSlider4 = SliderElement(MIDI_CC_TYPE, 0, 16, name='VolumeSlider4')
            self._VolumeSlider5 = SliderElement(MIDI_CC_TYPE, 0, 17, name='VolumeSlider5')
            self._VolumeSlider6 = SliderElement(MIDI_CC_TYPE, 0, 18, name='VolumeSlider6')
            self._VolumeSlider7 = SliderElement(MIDI_CC_TYPE, 0, 19, name='VolumeSlider7')
            #Control Bank B - Channel 2 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
            self._Encoder8 = EncoderElement(MIDI_CC_TYPE,2,22, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder8')
            self._Encoder9 = EncoderElement(MIDI_CC_TYPE,2,23, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder9')
            self._Encoder10 = EncoderElement(MIDI_CC_TYPE,2,24, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder10')
            self._Encoder11 = EncoderElement(MIDI_CC_TYPE,2,25, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder11')
            self._Encoder12 = EncoderElement(MIDI_CC_TYPE,2,26, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder12')
            self._Encoder13 = EncoderElement(MIDI_CC_TYPE,2,27, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder13')
            self._Encoder14 = EncoderElement(MIDI_CC_TYPE,2,28, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder14')
            self._Encoder15 = EncoderElement(MIDI_CC_TYPE,2,29, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder15')
            self._ArmButton8 = ButtonElement(False, MIDI_CC_TYPE, 1, 32, name='ArmButton8')
            self._ArmButton9 = ButtonElement(False, MIDI_CC_TYPE, 1, 33, name='ArmButton9')
            self._ArmButton10 = ButtonElement(False, MIDI_CC_TYPE, 1, 34, name='ArmButton10')
            self._ArmButton11 = ButtonElement(False, MIDI_CC_TYPE, 1, 35, name='ArmButton11')
            self._ArmButton12 = ButtonElement(False, MIDI_CC_TYPE, 1, 36, name='ArmButton12')
            self._ArmButton13 = ButtonElement(False, MIDI_CC_TYPE, 1, 37, name='ArmButton13')
            self._ArmButton14 = ButtonElement(False, MIDI_CC_TYPE, 1, 38, name='ArmButton14')
            self._ArmButton15 = ButtonElement(False, MIDI_CC_TYPE, 1, 39, name='ArmButton15')
            self._VolumeSlider8 = SliderElement(MIDI_CC_TYPE, 1, 12, name='VolumeSlider8')
            self._VolumeSlider9 = SliderElement(MIDI_CC_TYPE, 1, 13, name='VolumeSlider9')
            self._VolumeSlider10 = SliderElement(MIDI_CC_TYPE, 1, 14, name='VolumeSlider10')
            self._VolumeSlider11 = SliderElement(MIDI_CC_TYPE, 1, 15, name='VolumeSlider11')
            self._VolumeSlider12 = SliderElement(MIDI_CC_TYPE, 1, 16, name='VolumeSlider12')
            self._VolumeSlider13 = SliderElement(MIDI_CC_TYPE, 1, 17, name='VolumeSlider13')
            self._VolumeSlider14 = SliderElement(MIDI_CC_TYPE, 1, 18, name='VolumeSlider14')
            self._VolumeSlider15 = SliderElement(MIDI_CC_TYPE, 1, 19, name='VolumeSlider15')
            #Control Bank C - Channel 3 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
            self._Encoder16 = EncoderElement(MIDI_CC_TYPE,3,22, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder16')
            self._Encoder17 = EncoderElement(MIDI_CC_TYPE,3,23, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder17')
            self._Encoder18 = EncoderElement(MIDI_CC_TYPE,3,24, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder18')
            self._Encoder19 = EncoderElement(MIDI_CC_TYPE,3,25, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder19')
            self._Encoder20 = EncoderElement(MIDI_CC_TYPE,3,26, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder20')
            self._Encoder21 = EncoderElement(MIDI_CC_TYPE,3,27, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder21')
            self._Encoder22 = EncoderElement(MIDI_CC_TYPE,3,28, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder22')
            self._Encoder23 = EncoderElement(MIDI_CC_TYPE,3,29, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder23')
            self._ArmButton16 = ButtonElement(False, MIDI_CC_TYPE, 2, 32, name='ArmButton16')
            self._ArmButton17 = ButtonElement(False, MIDI_CC_TYPE, 2, 33, name='ArmButton17')
            self._ArmButton18 = ButtonElement(False, MIDI_CC_TYPE, 2, 34, name='ArmButton18')
            self._ArmButton19 = ButtonElement(False, MIDI_CC_TYPE, 2, 35, name='ArmButton19')
            self._ArmButton20 = ButtonElement(False, MIDI_CC_TYPE, 2, 36, name='ArmButton20')
            self._ArmButton21 = ButtonElement(False, MIDI_CC_TYPE, 2, 37, name='ArmButton21')
            self._ArmButton22 = ButtonElement(False, MIDI_CC_TYPE, 2, 38, name='ArmButton22')
            self._ArmButton23 = ButtonElement(False, MIDI_CC_TYPE, 2, 39, name='ArmButton23')
            self._VolumeSlider16 = SliderElement(MIDI_CC_TYPE, 2, 12, name='VolumeSlider16')
            self._VolumeSlider17 = SliderElement(MIDI_CC_TYPE, 2, 13, name='VolumeSlider17')
            self._VolumeSlider18 = SliderElement(MIDI_CC_TYPE, 2, 14, name='VolumeSlider18')
            self._VolumeSlider19 = SliderElement(MIDI_CC_TYPE, 2, 15, name='VolumeSlider19')
            self._VolumeSlider20 = SliderElement(MIDI_CC_TYPE, 2, 16, name='VolumeSlider20')
            self._VolumeSlider21 = SliderElement(MIDI_CC_TYPE, 2, 17, name='VolumeSlider21')
            self._VolumeSlider22 = SliderElement(MIDI_CC_TYPE, 2, 18, name='VolumeSlider22')
            self._VolumeSlider23 = SliderElement(MIDI_CC_TYPE, 2, 19, name='VolumeSlider23')
            #Drum Bank A - Channel 4--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
            self._Pad0 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 81, name='Pad0')
            self._Pad1 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 83, name='Pad1')
            self._Pad2 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 84, name='Pad2')
            self._Pad3 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 86, name='Pad3')
            self._Pad4 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 74, name='Pad4')
            self._Pad5 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 76, name='Pad5')
            self._Pad6 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 77, name='Pad6')
            self._Pad7 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 79, name='Pad7')
            self._Pad8 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 67, name='Pad8')
            self._Pad9 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 69, name='Pad9')
            self._Pad10 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 71, name='Pad10')
            self._Pad11 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 72, name='Pad11')
            self._Pad12 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 60, name='Pad12')
            self._Pad13 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 62, name='Pad13')
            self._Pad14 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 64, name='Pad14')
            self._Pad15 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 65, name='Pad15')
            self._Pads = ButtonMatrixElement(rows=[[self._Pad0, self._Pad1, self._Pad2, self._Pad3],
                                                   [self._Pad4, self._Pad5, self._Pad6, self._Pad7], 
                                                   [self._Pad8, self._Pad9, self._Pad10, self._Pad11],
                                                   [self._Pad12, self._Pad13, self._Pad14, self._Pad15]])
            #Drum Bank B -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
            #Drum Bank C -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
            #Drum Bank D -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
            #
            #Drum rack -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
            drum_rack = DrumRackComponent(name='Drum_Rack', is_enabled=False, layer=Layer(pads=self._Pads))
            drum_rack.set_enabled(True)
            #Transport -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
            transport = TransportComponent(name='Transport', is_enabled=False, layer=Layer(play_button=midimap['Play'], record_button=midimap['Record'], stop_button=midimap['Stop'], loop_button=midimap['Loop']))
            #, seek_forward_button=midimap['Forward'], seek_backward_button=midimap['Backward']
            transport.set_enabled(True)
            #Make the Back/Fwd button just normal mapable CC senders
            self._BackButton = ButtonElement(False, MIDI_CC_TYPE, 0, 116, name='BackButton')
            self._FwdButton = ButtonElement(False, MIDI_CC_TYPE, 0, 115, name='FwdButton')
            #Device -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
            self._device = DeviceComponent(name='Device', is_enabled=False, layer=Layer(parameter_controls=midimap['Encoders']), device_selection_follows_track_selection=True)
            self._device.set_enabled(True)
            self.set_device_component(self._device)
            #Mixer -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
            mixer_size = 24
            self._mixer = MixerComponent(mixer_size, name='Mixer', is_enabled=False)
            #Super crude and repetitive mapping because after all this shit I'm not spending time learning how to loop this crap hehe
            #Bank A
            self._mixer.channel_strip(0).layer = Layer(volume_control = self._VolumeSlider0, arm_button=self._ArmButton0, pan_control=self._Encoder0)
            self._mixer.channel_strip(1).layer = Layer(volume_control = self._VolumeSlider1, arm_button=self._ArmButton1, pan_control=self._Encoder1)
            self._mixer.channel_strip(2).layer = Layer(volume_control = self._VolumeSlider2, arm_button=self._ArmButton2, pan_control=self._Encoder2)
            self._mixer.channel_strip(3).layer = Layer(volume_control = self._VolumeSlider3, arm_button=self._ArmButton3, pan_control=self._Encoder3)
            self._mixer.channel_strip(4).layer = Layer(volume_control = self._VolumeSlider4, arm_button=self._ArmButton4, pan_control=self._Encoder4)
            self._mixer.channel_strip(5).layer = Layer(volume_control = self._VolumeSlider5, arm_button=self._ArmButton5, pan_control=self._Encoder5)
            self._mixer.channel_strip(6).layer = Layer(volume_control = self._VolumeSlider6, arm_button=self._ArmButton6, pan_control=self._Encoder6)
            self._mixer.channel_strip(7).layer = Layer(volume_control = self._VolumeSlider7, arm_button=self._ArmButton7, pan_control=self._Encoder7)
            #Bank B
            self._mixer.channel_strip(8).layer = Layer(volume_control = self._VolumeSlider8, arm_button=self._ArmButton8, pan_control=self._Encoder8)
            self._mixer.channel_strip(9).layer = Layer(volume_control = self._VolumeSlider9, arm_button=self._ArmButton9, pan_control=self._Encoder9)
            self._mixer.channel_strip(10).layer = Layer(volume_control = self._VolumeSlider10, arm_button=self._ArmButton10, pan_control=self._Encoder10)
            self._mixer.channel_strip(11).layer = Layer(volume_control = self._VolumeSlider11, arm_button=self._ArmButton11, pan_control=self._Encoder11)
            self._mixer.channel_strip(12).layer = Layer(volume_control = self._VolumeSlider12, arm_button=self._ArmButton12, pan_control=self._Encoder12)
            self._mixer.channel_strip(13).layer = Layer(volume_control = self._VolumeSlider13, arm_button=self._ArmButton13, pan_control=self._Encoder13)
            self._mixer.channel_strip(14).layer = Layer(volume_control = self._VolumeSlider14, arm_button=self._ArmButton14, pan_control=self._Encoder14)
            self._mixer.channel_strip(15).layer = Layer(volume_control = self._VolumeSlider15, arm_button=self._ArmButton15, pan_control=self._Encoder15)
            #Bank C     
            self._mixer.channel_strip(16).layer = Layer(volume_control = self._VolumeSlider16, arm_button=self._ArmButton16, pan_control=self._Encoder16)
            self._mixer.channel_strip(17).layer = Layer(volume_control = self._VolumeSlider17, arm_button=self._ArmButton17, pan_control=self._Encoder17)
            self._mixer.channel_strip(18).layer = Layer(volume_control = self._VolumeSlider18, arm_button=self._ArmButton18, pan_control=self._Encoder18)
            self._mixer.channel_strip(19).layer = Layer(volume_control = self._VolumeSlider19, arm_button=self._ArmButton19, pan_control=self._Encoder19)
            self._mixer.channel_strip(20).layer = Layer(volume_control = self._VolumeSlider20, arm_button=self._ArmButton20, pan_control=self._Encoder20)
            self._mixer.channel_strip(21).layer = Layer(volume_control = self._VolumeSlider21, arm_button=self._ArmButton21, pan_control=self._Encoder21)
            self._mixer.channel_strip(22).layer = Layer(volume_control = self._VolumeSlider22, arm_button=self._ArmButton22, pan_control=self._Encoder22)
            self._mixer.channel_strip(23).layer = Layer(volume_control = self._VolumeSlider23, arm_button=self._ArmButton23, pan_control=self._Encoder23)
            self._mixer.set_enabled(True)
            #Track change listener
            self.song().view.add_selected_track_listener(self._update_selected_device)
    
    #Track changed    
    def _update_selected_device(self):
        track = self.song().view.selected_track
        #self.show_message("----- Track changed! -----")
    
    #Launch/Record/Overdub    
    def _launch_clip(self, value):
        global _overdub_flag
        #self.log_message("--> Track launch! -----")
        #self.song().view.highlighted_clip_slot.set_fire_button_state(True)
        _current_slot = self.song().view.highlighted_clip_slot 
        if _current_slot.is_playing == 0 and _current_slot.is_recording == 0:            
            self.song().view.highlighted_clip_slot.set_fire_button_state(True)
        elif _current_slot.is_playing == 1 and _current_slot.is_recording == 0:
            self.song().overdub = 1
            _overdub_flag = 1
        elif _current_slot.is_playing == 1 and _current_slot.is_recording == 1 and _overdub_flag == 1:
            self.song().overdub = 0
            _overdub_flag = 0
        else:
            self.song().view.highlighted_clip_slot.set_fire_button_state(True)
    
    #Move up/down
    def _move_clipslot(self, up):
        scene = self.song().view.selected_scene
        scenes = self.song().scenes
        max_scenes = len(scenes)
        for i in range(max_scenes):
            if scene == scenes[i]:
                #Found our guy
                if up == 1:
                    self.song().view.selected_scene = scenes[i-1]
                    self.show_message("TFMX Debug: Up!")
                else:
                    if scene == scenes[max_scenes-1]:
                        self.song().view.selected_scene = scenes[0]
                    else:
                        self.song().view.selected_scene = scenes[i+1]
                    self.show_message("TFMX Debug: Down!")
    
    #Move left/right
    def _move_track(self, left):
        #Get track and tracks
        track = self.song().view.selected_track
        tracks = self.get_all_tracks(only_visible = True)
        max_tracks = len(tracks)
        #Iterate to find current track's index.
        for i in range(max_tracks):
            if track == tracks[i]:
                #Found our track
                if left == 1:
                    self.song().view.selected_track = tracks[i-1]
                else:
                    if track == tracks[max_tracks-1]:
                        self.song().view.selected_track = tracks[0]
                    else:
                        self.song().view.selected_track = tracks[i+1]
                        
    def get_all_tracks(self, only_visible = False):
        tracks = []
        for track in self.song().tracks:
            if not only_visible or track.is_visible:
                tracks.append(track)
        #Include the master track?
        #NOPE tracks.append(self.song().master_track)
        return tracks
        
    def _move_up(self, value):
        if value > 0:
            self._move_clipslot(1)
            
    def _move_down(self, value):
        if value > 0:
            self._move_clipslot(0)
            
    def _move_left(self, value):
        if value > 0:
            self._move_track(1)
    
    def _move_right(self, value):
        if value > 0:
            self._move_track(0)
#-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
示例#37
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
        return

    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

        return

    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 and 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 and 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 and 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 and 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(MaschineChannelStripComponent, self)._mute_value(value)
        key = self._mute_button.message_identifier()
        if self.clear_mode and 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 == 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 != None:
            self.clear_vol_button.remove_value_listener(self._do_clear_vol)
            self.clear_vol_button = None
        if self.clear_pan_button != None:
            self.clear_pan_button.remove_value_listener(self._do_clear_pan)
            self.clear_pan_button = None
        if self.clear_send_button != None:
            self.clear_send_button.remove_value_listener(self._do_clear_send)
            self.clear_send_button = None
        if not self.touch_mode and self.clear_mode:
            if self.send_control != None:
                self.send_control.remove_value_listener(self._do_clear_send)
                self.send_control = None
            if self._volume_control != None:
                self._volume_control.remove_value_listener(self._do_clear_vol)
                self._volume_control = None
            if self._pan_control != None:
                self._pan_control.remove_value_listener(self._do_clear_pan)
                self._pan_control = None
        super(MaschineChannelStripComponent, self).disconnect()
        return
示例#38
0
class HyperionChan(CompoundComponent):
    def __init__(self, hyperion, mod_num, *a, **kw):
        super(HyperionChan, self).__init__(*a, **kw)

        self.hyperion = hyperion
        self.mod_num = mod_num

        self._track_selector_encoder = EncoderElement(MIDI_CC_TYPE, MIDI_MASTER_CH + 1 + mod_num, 0x15, Live.MidiMap.MapMode.relative_smooth_binary_offset) # Right encoder on Hyperion
        self._track_selector_encoder.add_value_listener(self._on_track_selector_encoder)

        self._fader = SliderElement(MIDI_CC_TYPE, MIDI_MASTER_CH + 1 + mod_num, 0x25)
        self._pots = [
            EncoderElement(MIDI_CC_TYPE, MIDI_MASTER_CH + 1 + mod_num, 0x1E + num, Live.MidiMap.MapMode.absolute, name='Pot{}'.format(num))
            for num in range(8)
        ]
        self._btns = [
            ButtonElement(True, MIDI_CC_TYPE, MIDI_MASTER_CH + 1 + mod_num, 1 + num, name='Btn{}'.format(num))
            for num in range(8)
        ]
        self._enc_right_btn = ButtonElement(True, MIDI_CC_TYPE, MIDI_MASTER_CH + 1 + mod_num, 10, name='EncRightBtn')
        self._enc_right_btn.add_value_listener(self._on_enc_right_btn)

        #self._cs = ChannelStripComponent()
        #self._cs.set_volume_control(self._fader)
        self._vu_slider = SliderElement(MIDI_CC_TYPE, MIDI_MASTER_CH + 1 + mod_num, 60)

        self._vu = VUMeter(self)

        self._track = None

        tracks = self._get_all_tracks(self.hyperion.song().tracks)
        if len(tracks) > self.mod_num:
            self._bind_to_track(tracks[self.mod_num])
        else:
            self._bind_to_track(None)

    def log(self, msg, *args):
        self.hyperion.log_message(('HyperionChan({}): ' + msg).format(self.mod_num, *args))

    def disconnect(self):
        super(HyperionChan, self).disconnect()

        self._enc_right_btn.remove_value_listener(self._on_enc_right_btn)

    def _get_parent_by_type(self, obj, parent_type):
        if not obj.canonical_parent:
            return
        if isinstance(obj.canonical_parent, parent_type):
            return obj.canonical_parent
        return self._get_parent_by_type(obj.canonical_parent, parent_type)

    def _on_enc_right_btn(self, value):
        if value and self._track:
            self.log('type {}',type(self._track))

            song = self.hyperion.song()
            if isinstance(self._track, Live.Track.Track):
                song.view.selected_track = self._track
            elif isinstance(self._track, Live.DrumChain.DrumChain):
                parent_track = self._get_parent_by_type(self._track, Live.Track.Track)

                song.view.selected_track = parent_track
                try:
                    song.view.selected_chain = self._track
                except:
                    try:
                        song.view.selected_track = parent_track
                        song.view.selected_chain = self._track.canonical_parent.canonical_parent
                        self._track.canonical_parent.view.selected_chain = self._track
                    except:
                        pass

    def _get_track_mapper_device(self, track):
        for device in track.devices:
            if device.name == 'MultiMapper16 V2.0':
                return device

    def _get_all_tracks(self, all_tracks):
        got_tracks = []

        for cur_track in all_tracks:
            if isinstance(cur_track, (Live.Track.Track, Live.DrumChain.DrumChain)):
                got_tracks.append(cur_track)

            devices = list(cur_track.devices)
            if len(devices) and isinstance(devices[0], Live.RackDevice.RackDevice):
                got_tracks.extend(self._get_all_tracks(devices[0].chains))

        return [track for track in got_tracks if self._get_track_mapper_device(track)]

    def _on_track_selector_encoder(self, value):
        direction = 1 if value > 64 else -1

        tracks = self._get_all_tracks(self.hyperion.song().tracks)

        # for t in tracks:
        #     self.log('AAAAA {}', t.name)

        try:
            cur_track_idx = tracks.index(self._track)
        except ValueError:
            self.log('track disappeared :(')
            self._bind_to_track(tracks[0])
        else:
            cur_track_idx += direction
            if cur_track_idx == len(tracks):
                cur_track_idx = 0
            if cur_track_idx == -1:
                cur_track_idx = len(tracks) - 1
            self._bind_to_track(tracks[cur_track_idx])

    def _bind_to_track(self, track):
        if self._track:
            #self._cs.set_track(None)
            self._fader.release_parameter()
            [pot.release_parameter() for pot in self._pots]
            [btn.release_parameter() for btn in self._btns]

            self._track.remove_name_listener(self._on_name_changed)

            self._track = None

        if not track:
            return

        self.log('binding to {}', track.name)
        self._track = track

        self._fader.connect_to(track.mixer_device.volume)

        mapper_dev = self._get_track_mapper_device(track)
        for num in range(8):
            self._pots[num].connect_to(mapper_dev.parameters[3 + num]) # MacroA0 MacroA1 etc
            self._btns[num].connect_to(mapper_dev.parameters[11 + num]) # MacroB0 MacroB1 etc

        # self._cs.set_track(track)

        if getattr(self._track, 'has_audio_output', False) and hasattr(self._track, 'add_output_meter_left_listener'):
            self._vu.set_vu_meter(track, self._vu_slider)
        else:
            self._vu.set_vu_meter(None, None)

        self._track.add_name_listener(self._on_name_changed)
        self._on_name_changed()

    def _on_name_changed(self):
        self.hyperion.sysex.set_title(self.mod_num, self._track.name if self._track else '-')
示例#39
0
class Oxygen_3rd_Gen(ControlSurface):
    """ Script for the 3rd generation of M-Audio's Oxygen controllers """
    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._device_selection_follows_track_selection = 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.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):
        raise value in range(128) or AssertionError
        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)
示例#40
0
class LaunchMod(ControlSurface):
	""" Script for Novation's Launchpad Controller """

	def __init__(self, c_instance):
		ControlSurface.__init__(self, c_instance)
		with self.component_guard():
			self._monomod_version = 'b995'
			self._host_name = 'LaunchMod'
			self._color_type = 'Launchpad'
			self.hosts = []
			self._timer = 0
			self._suppress_send_midi = True
			self._suppress_session_highlight = True
			self._suppress_highlight = False
			is_momentary = True
			self._suggested_input_port = 'Launchpad'
			self._suggested_output_port = 'Launchpad'
			self._control_is_with_automap = False
			self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)
			self._user_byte_write_button.name = 'User_Byte_Button'
			self._user_byte_write_button.send_value(1)
			self._user_byte_write_button.add_value_listener(self._user_byte_value)
			self._wrote_user_byte = False
			self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143
			matrix = ButtonMatrixElement()
			matrix.name = 'Button_Matrix'
			for row in range(8):
				button_row = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, ((row * 16) + column), str(column) + '_Clip_' + str(row) + '_Button', self) for column in range(8) ]
				matrix.add_row(tuple(button_row))
			self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0, optimized_send_midi=False)
			self._config_button.add_value_listener(self._config_value)
			top_button_names = ['Bank_Select_Up_Button', 'Bank_Select_Down_Button', 'Bank_Select_Left_Button', 'Bank_Select_Right_Button', 'Session_Button', 'User1_Button', 'User2_Button', 'Mixer_Button']
			side_button_names = ['Vol_Button', 'Pan_Button', 'SndA_Button',  'SndB_Button', 'Stop_Button', 'Trk_On_Button', 'Solo_Button', 'Arm_Button']
			top_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0, (104 + index), top_button_names[index], self) for index in range(8) ]
			side_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index], side_button_names[index], self) for index in range(8) ]
			self._setup_monobridge()
			self._setup_monomod()
			self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button, self)
			self._selector.name = 'Main_Modes'
			for control in self.controls:
				if isinstance(control, MonoButtonElement):
					control.add_value_listener(self._button_value)
			self.set_highlighting_session_component(self._selector.session_component())
			self._suppress_session_highlight = False
		self.log_message("--------------= " + str(self._monomod_version) + " log opened =--------------") #Create entry in log file


	

	def allow_updates(self, allow_updates):
		for component in self.components:
			component.set_allow_update(int(allow_updates!=0))

	def disconnect(self):
		self._suppress_send_midi = True
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.remove_value_listener(self._button_value)

		self._selector = None
		self._user_byte_write_button.remove_value_listener(self._user_byte_value)
		self._config_button.remove_value_listener(self._config_value)
		ControlSurface.disconnect(self)
		self._suppress_send_midi = False
		self._config_button.send_value(32)
		self._config_button.send_value(0)
		self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None

	def refresh_state(self):
		ControlSurface.refresh_state(self)
		self.schedule_message(5, self._update_hardware)

	def handle_sysex(self, midi_bytes):
		if len(midi_bytes) == 8:
			if midi_bytes[1:5] == (0, 32, 41, 6):
				response = long(midi_bytes[5])
				response += long(midi_bytes[6]) << 8
				if response == Live.Application.encrypt_challenge2(self._challenge):
					self._suppress_send_midi = False
					self.set_enabled(True)

	def build_midi_map(self, midi_map_handle):
		ControlSurface.build_midi_map(self, midi_map_handle)
		if self._selector.mode_index == 1:
			new_channel = self._selector.channel_for_current_mode()
			for note in DRUM_NOTES:
				self._translate_message(MIDI_NOTE_TYPE, note, 0, note, new_channel)

	def _send_midi(self, midi_bytes, optimized = None):
		sent_successfully = False
		if not self._suppress_send_midi:
			sent_successfully = ControlSurface._send_midi(self, midi_bytes, optimized=optimized)
		return sent_successfully

	def _update_hardware(self):
		self._suppress_send_midi = False
		self._wrote_user_byte = True
		self._user_byte_write_button.send_value(1)
		self._suppress_send_midi = True
		self.set_enabled(False)
		self._suppress_send_midi = False
		self._send_challenge()


	def _send_challenge(self):
		for index in range(4):
			challenge_byte = self._challenge >> 8 * index & 127
			self._send_midi((176, 17 + index, challenge_byte))

	def _user_byte_value(self, value):
		assert value in range(128)
		enabled = self._wrote_user_byte or value == 1
		self._control_is_with_automap = not enabled
		self._suppress_send_midi = self._control_is_with_automap
		if not self._control_is_with_automap:
			for control in self.controls:
				if isinstance(control, MonoButtonElement):
					control.set_force_next_value()

		self._selector.set_mode(0)
		self.set_enabled(enabled)
		self._suppress_send_midi = False

	def _button_value(self, value):
		assert value in range(128)

	def _config_value(self, value):
		assert value in range(128)

	def _set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks):
		if not self._suppress_session_highlight:
			ControlSurface._set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks)
	

	def _setup_m4l_interface(self):
		self._m4l_interface = M4LInterfaceComponent(controls=self.controls, component_guard=self.component_guard)
		self.get_control_names = self._m4l_interface.get_control_names
		self.get_control = self._m4l_interface.get_control
		self.grab_control = self._m4l_interface.grab_control
		self.release_control = self._m4l_interface.release_control
	

	"""Mono overrides and additions"""
	def _setup_monobridge(self):
		self._monobridge = MonoBridgeElement(self)
		self._monobridge.name = 'MonoBridge'
	

	def _setup_monomod(self):
		self._host = MonomodComponent(self)
		self._host.name = 'Monomod_Host'
		self.hosts = [self._host]
	

	def update_display(self):
		ControlSurface.update_display(self)
		self._timer = (self._timer + 1) % 256
		self.flash()
	

	def flash(self):
		if self._host.is_enabled():
			for control in self.controls:
				if isinstance(control, MonoButtonElement):
					control.flash(self._timer)
示例#41
0
class Launchpad(ControlSurface):
    u""" Script for Novation's Launchpad Controller """
    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
            self._suppress_send_midi = True
            self._suppress_session_highlight = True
            is_momentary = True
            self._suggested_input_port = 'Launchpad'
            self._suggested_output_port = 'Launchpad'
            self._control_is_with_automap = False
            self._user_byte_write_button = ButtonElement(
                is_momentary, MIDI_CC_TYPE, 0, 16)
            self._user_byte_write_button.name = 'User_Byte_Button'
            self._user_byte_write_button.send_value(1)
            self._user_byte_write_button.add_value_listener(
                self._user_byte_value)
            self._wrote_user_byte = False
            self._challenge = Live.Application.get_random_int(
                0, 400000000) & 2139062143
            matrix = ButtonMatrixElement()
            matrix.name = 'Button_Matrix'
            for row in range(8):
                button_row = []
                for column in range(8):
                    button = ConfigurableButtonElement(is_momentary,
                                                       MIDI_NOTE_TYPE, 0,
                                                       row * 16 + column)
                    button.name = str(column) + '_Clip_' + str(row) + '_Button'
                    button_row.append(button)

                matrix.add_row(tuple(button_row))

            self._config_button = ButtonElement(is_momentary,
                                                MIDI_CC_TYPE,
                                                0,
                                                0,
                                                optimized_send_midi=False)
            self._config_button.add_value_listener(self._config_value)
            top_buttons = [
                ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0,
                                          104 + index) for index in range(8)
            ]
            side_buttons = [
                ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0,
                                          SIDE_NOTES[index])
                for index in range(8)
            ]
            top_buttons[0].name = 'Bank_Select_Up_Button'
            top_buttons[1].name = 'Bank_Select_Down_Button'
            top_buttons[2].name = 'Bank_Select_Left_Button'
            top_buttons[3].name = 'Bank_Select_Right_Button'
            top_buttons[4].name = 'Session_Button'
            top_buttons[5].name = 'User1_Button'
            top_buttons[6].name = 'User2_Button'
            top_buttons[7].name = 'Mixer_Button'
            side_buttons[0].name = 'Vol_Button'
            side_buttons[1].name = 'Pan_Button'
            side_buttons[2].name = 'SndA_Button'
            side_buttons[3].name = 'SndB_Button'
            side_buttons[4].name = 'Stop_Button'
            side_buttons[5].name = 'Trk_On_Button'
            side_buttons[6].name = 'Solo_Button'
            side_buttons[7].name = 'Arm_Button'
            self._selector = MainSelectorComponent(matrix, tuple(top_buttons),
                                                   tuple(side_buttons),
                                                   self._config_button)
            self._selector.name = 'Main_Modes'
            for control in self.controls:
                if isinstance(control, ConfigurableButtonElement):
                    control.add_value_listener(self._button_value)

            self.set_highlighting_session_component(
                self._selector.session_component())
            self._suppress_session_highlight = False

    def disconnect(self):
        self._suppress_send_midi = True
        for control in self.controls:
            if isinstance(control, ConfigurableButtonElement):
                control.remove_value_listener(self._button_value)

        self._selector = None
        self._user_byte_write_button.remove_value_listener(
            self._user_byte_value)
        self._config_button.remove_value_listener(self._config_value)
        ControlSurface.disconnect(self)
        self._suppress_send_midi = False
        self._config_button.send_value(32)
        self._config_button.send_value(0)
        self._config_button = None
        self._user_byte_write_button.send_value(0)
        self._user_byte_write_button = None
        return

    def refresh_state(self):
        ControlSurface.refresh_state(self)
        self.schedule_message(5, self._update_hardware)

    def handle_sysex(self, midi_bytes):
        if len(midi_bytes) == 8:
            if midi_bytes[1:5] == (0, 32, 41, 6):
                response = long(midi_bytes[5])
                response += long(midi_bytes[6]) << 8
                if response == Live.Application.encrypt_challenge2(
                        self._challenge):
                    self._on_handshake_successful()

    def _on_handshake_successful(self):
        self._suppress_send_midi = False
        self.set_enabled(True)

    def build_midi_map(self, midi_map_handle):
        ControlSurface.build_midi_map(self, midi_map_handle)
        if self._selector.mode_index == 1:
            new_channel = self._selector.channel_for_current_mode()
            for note in DRUM_NOTES:
                self._translate_message(MIDI_NOTE_TYPE, note, 0, note,
                                        new_channel)

    def _send_midi(self, midi_bytes, optimized=None):
        sent_successfully = False
        if not self._suppress_send_midi:
            sent_successfully = ControlSurface._send_midi(self,
                                                          midi_bytes,
                                                          optimized=optimized)
        return sent_successfully

    def _update_hardware(self):
        self._suppress_send_midi = False
        self._wrote_user_byte = True
        self._user_byte_write_button.send_value(1)
        self._suppress_send_midi = True
        self.set_enabled(False)
        self._suppress_send_midi = False
        self._send_challenge()

    def _send_challenge(self):
        for index in range(4):
            challenge_byte = self._challenge >> 8 * index & 127
            self._send_midi((176, 17 + index, challenge_byte))

    def _user_byte_value(self, value):
        assert value in range(128)
        if not self._wrote_user_byte:
            enabled = value == 1
            self._control_is_with_automap = not enabled
            self._suppress_send_midi = self._control_is_with_automap
            if not self._control_is_with_automap:
                for control in self.controls:
                    if isinstance(control, ConfigurableButtonElement):
                        control.set_force_next_value()

            self._selector.set_mode(0)
            self.set_enabled(enabled)
            self._suppress_send_midi = False
        else:
            self._wrote_user_byte = False

    def _button_value(self, value):
        assert value in range(128)

    def _config_value(self, value):
        assert value in range(128)

    def _set_session_highlight(self, track_offset, scene_offset, width, height,
                               include_return_tracks):
        if not self._suppress_session_highlight:
            ControlSurface._set_session_highlight(self, track_offset,
                                                  scene_offset, width, height,
                                                  include_return_tracks)
示例#42
0
class Launchpad(ControlSurface):

	_active_instances = []
	
	def __init__(self, c_instance):
		ControlSurface.__init__(self, c_instance)
		live = Live.Application.get_application()
		self._live_major_version = live.get_major_version()
		self._live_minor_version = live.get_minor_version()
		self._live_bugfix_version = live.get_bugfix_version()
		self._selector = None #needed because update hardware is called.
		self._mk2_rgb = False
		with self.component_guard():
			self._suppress_send_midi = True
			self._suppress_session_highlight = True
			self._suggested_input_port = ("Launchpad", "Launchpad Mini", "Launchpad S", "Launchpad MK2")
			self._suggested_output_port = ("Launchpad", "Launchpad Mini", "Launchpad S", "Launchpad MK2")				
			self._control_is_with_automap = False
			self._user_byte_write_button = None
			self._config_button = None
			self._wrote_user_byte = False
			self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143
			self._init_done = False
		# caller will send challenge and we will continue as challenge is received.
		
			
	def init(self):
		#skip init if already done.
		if self._init_done:
			return
		self._init_done = True
		
		# second part of the __init__ after model has been identified using its challenge response
		if self._mk2_rgb:
			from SkinMK2 import make_skin
			self._skin = make_skin()
			self._side_notes = (89, 79, 69, 59, 49, 39, 29, 19)
			#self._drum_notes = (20, 30, 31, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126)
			self._drum_notes = (20, 30, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126)
		else:
			from SkinMK1 import make_skin
			self._skin = make_skin()
			self._side_notes = (8, 24, 40, 56, 72, 88, 104, 120)
			self._drum_notes = (41, 42, 43, 44, 45, 46, 47, 57, 58, 59, 60, 61, 62, 63, 73, 74, 75, 76, 77, 78, 79, 89, 90, 91, 92, 93, 94, 95, 105, 106, 107)
		
		with self.component_guard():
			is_momentary = True
			self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0, optimized_send_midi=False)
			self._config_button.add_value_listener(self._config_value)
			self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)
			self._user_byte_write_button.name = 'User_Byte_Button'
			self._user_byte_write_button.send_value(1)
			self._user_byte_write_button.add_value_listener(self._user_byte_value)
			matrix = ButtonMatrixElement()
			matrix.name = 'Button_Matrix'
			for row in range(8):
				button_row = []
				for column in range(8):
					if self._mk2_rgb:
						# for mk2 buttons are assigned "top to bottom"
						midi_note = (81 - (10 * row)) + column
					else:
						midi_note = row * 16 + column
					button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, midi_note, skin = self._skin, control_surface = self)
					button.name = str(column) + '_Clip_' + str(row) + '_Button'
					button_row.append(button)
				matrix.add_row(tuple(button_row))

			top_buttons = [ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0, 104 + index, skin = self._skin) for index in range(8)]
			side_buttons = [ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, self._side_notes[index], skin = self._skin) for index in range(8)]
			top_buttons[0].name = 'Bank_Select_Up_Button'
			top_buttons[1].name = 'Bank_Select_Down_Button'
			top_buttons[2].name = 'Bank_Select_Left_Button'
			top_buttons[3].name = 'Bank_Select_Right_Button'
			top_buttons[4].name = 'Session_Button'
			top_buttons[5].name = 'User1_Button'
			top_buttons[6].name = 'User2_Button'
			top_buttons[7].name = 'Mixer_Button'
			side_buttons[0].name = 'Vol_Button'
			side_buttons[1].name = 'Pan_Button'
			side_buttons[2].name = 'SndA_Button'
			side_buttons[3].name = 'SndB_Button'
			side_buttons[4].name = 'Stop_Button'
			side_buttons[5].name = 'Trk_On_Button'
			side_buttons[6].name = 'Solo_Button'
			side_buttons[7].name = 'Arm_Button'
			self._osd = M4LInterface()
			self._osd.name = "OSD"
			self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button, self._osd, self)
			self._selector.name = 'Main_Modes'
			self._do_combine()
			for control in self.controls:
				if isinstance(control, ConfigurableButtonElement):
					control.add_value_listener(self._button_value)

			self.set_highlighting_session_component(self._selector.session_component())
			self._suppress_session_highlight = False
			# due to our 2 stage init, we need to rebuild midi map 
			self.request_rebuild_midi_map()
			# and request update 
			self._selector.update()
			if self._mk2_rgb:
				self.log_message("LaunchPad95 (mk2) Loaded !")
			else:
				self.log_message("LaunchPad95 Loaded !")
				
	def disconnect(self):
		self._suppress_send_midi = True
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.remove_value_listener(self._button_value)
		self._do_uncombine()
		if self._selector != None:
			self._user_byte_write_button.remove_value_listener(self._user_byte_value)
			self._config_button.remove_value_listener(self._config_value)
		ControlSurface.disconnect(self)
		self._suppress_send_midi = False
		if self._mk2_rgb:
			# launchpad mk2 needs disconnect string sent
			self._send_midi((240, 0, 32, 41, 2, 24, 64, 247))
		if self._config_button != None:
			self._config_button.send_value(32)
			self._config_button.send_value(0)
			self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None

	def _combine_active_instances():
		support_devices = False
		for instance in Launchpad._active_instances:
			support_devices |= (instance._device_component != None)
		offset = 0
		for instance in Launchpad._active_instances:
			instance._activate_combination_mode(offset, support_devices)
			offset += instance._selector._session.width()

	_combine_active_instances = staticmethod(_combine_active_instances)

	def _activate_combination_mode(self, track_offset, support_devices):
		if(Settings.STEPSEQ__LINK_WITH_SESSION):
			self._selector._stepseq.link_with_step_offset(track_offset)
		if(Settings.SESSION__LINK):
			self._selector._session.link_with_track_offset(track_offset)

	def _do_combine(self):
		if (DO_COMBINE and (self not in Launchpad._active_instances)):
			Launchpad._active_instances.append(self)
			Launchpad._combine_active_instances()

	def _do_uncombine(self):
		if self in Launchpad._active_instances:
			Launchpad._active_instances.remove(self)
			if(Settings.SESSION__LINK):
				self._selector._session.unlink()
			if(Settings.STEPSEQ__LINK_WITH_SESSION):
				self._selector._stepseq.unlink()
			Launchpad._combine_active_instances()

	def refresh_state(self):
		ControlSurface.refresh_state(self)
		self.schedule_message(5, self._update_hardware)

	def handle_sysex(self, midi_bytes):
		# MK2 has different challenge and params
		if len(midi_bytes) == 10 and midi_bytes[:7] == (240, 0, 32, 41, 2, 24, 64):
					response = long(midi_bytes[7])
					response += long(midi_bytes[8]) << 8
					if response == Live.Application.encrypt_challenge2(self._challenge):
						self._mk2_rgb = True
						self.log_message("Challenge Response ok (mk2)")
						
						self._suppress_send_midi = False
						self.set_enabled(True)
						self.init()
		#MK1 Challenge
		elif len(midi_bytes) == 8 and midi_bytes[1:5] == (0, 32, 41, 6):
					response = long(midi_bytes[5])
					response += long(midi_bytes[6]) << 8
					if response == Live.Application.encrypt_challenge2(self._challenge):
						self.log_message("Challenge Response ok (mk1)")
						self._mk2_rgb = False
						self.init()
						self._suppress_send_midi = False
						self.set_enabled(True)
		else:
			ControlSurface.handle_sysex(self,midi_bytes)
		

	def build_midi_map(self, midi_map_handle):
		ControlSurface.build_midi_map(self, midi_map_handle)
		if self._selector!=None:
			if self._selector._main_mode_index==2 or self._selector._main_mode_index==1:
				mode = Settings.USER_MODES[ (self._selector._main_mode_index-1) * 3 + self._selector._sub_mode_index[self._selector._main_mode_index] ] 
				#self._selector.mode_index == 1:
				#if self._selector._sub_mode_index[self._selector._mode_index] > 0:  # disable midi map rebuild for instrument mode to prevent light feedback errors
				if mode != "instrument":
					new_channel = self._selector.channel_for_current_mode()
					for note in self._drum_notes:
						self._translate_message(MIDI_NOTE_TYPE, note, 0, note, new_channel)

	def _send_midi(self, midi_bytes, optimized=None):
		sent_successfully = False
		if not self._suppress_send_midi:
			sent_successfully = ControlSurface._send_midi(self, midi_bytes, optimized=optimized)
		return sent_successfully

	def _update_hardware(self):
		self._suppress_send_midi = False
		if self._user_byte_write_button != None:
			self._user_byte_write_button.send_value(1)
			self._wrote_user_byte = True
		self._suppress_send_midi = True
		self.set_enabled(False)
		self._suppress_send_midi = False
		self._send_challenge()

	def _send_challenge(self):
		# send challenge for all models to allow to detect which one is actually plugged
		# mk2
		challenge_bytes = tuple([ self._challenge >> 8 * index & 127 for index in xrange(4) ])
		self._send_midi((240, 0, 32, 41, 2, 24, 64) + challenge_bytes + (247,))
		# mk1's
		for index in range(4):
			challenge_byte = self._challenge >> 8 * index & 127
			self._send_midi((176, 17 + index, challenge_byte))

	def _user_byte_value(self, value):
		assert (value in range(128))
		if not self._wrote_user_byte:
			enabled = (value == 1)
			self._control_is_with_automap = not enabled
			self._suppress_send_midi = self._control_is_with_automap
			if not self._control_is_with_automap:
				for control in self.controls:
					if isinstance(control, ConfigurableButtonElement):
						control.force_next_send()

			self._selector.set_mode(0)
			self.set_enabled(enabled)
			self._suppress_send_midi = False
		else:
			self._wrote_user_byte = False

	def _button_value(self, value):
		assert value in range(128)

	def _config_value(self, value):
		assert value in range(128)

	def _set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks):
		if not self._suppress_session_highlight:
			ControlSurface._set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks)
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())
示例#44
0
class Launchpad(ControlSurface):
	" SCRIPT FOR NOVATION'S LAUNCHPAD CONTROLLER "

	" INITALIZE "
	def __init__(self, c_instance):
		ControlSurface.__init__(self, c_instance)
		with self.component_guard():
			#self.set_suppress_rebuild_requests(True)
			self._suppress_send_midi = True
			self._suppress_session_highlight = True
			is_momentary = True
			self._suggested_input_port = "Launchpad"
			self._suggested_output_port = "Launchpad"
			self._control_is_with_automap = False
			self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16) 
			self._user_byte_write_button.name = "User_Byte_Button"
			self._user_byte_write_button.send_value(1)
			self._user_byte_write_button.add_value_listener(self._user_byte_value)
			self._wrote_user_byte = False
			self._challenge = (Live.Application.get_random_int(0, 400000000) & 2139062143)
			matrix = ButtonMatrixElement()
			matrix.name = "Button_Matrix"
			
			""" TRACKFINDER TEST 
			track_index = 0
			for track in self.song().tracks:
				if track_index < 8:
					button_row = []			
					if track.is_foldable:
						for column in range(8):	
							log("right one: " + str(track_index))		
							button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, ((track_index * 16) + column)) #@UndefinedVariable
							button.name = (((str(column) + "_Clip_") + str(track_index)) + "_Button")
							button_row.append(button)
						track_index = track_index + 1
					else:
						for column in range(8):
							log("wrong one: " + str(track_index))
							button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 99, True) #@UndefinedVariable
							button.name = (str(column) + "_Clip_Button-DUMMY")
							button_row.append(button)
					matrix.add_row(tuple(button_row))
			log("done")"""
			
			""" ORIGINAL CODE """
			for row in range(8):
				button_row = []
				for column in range(8):
					button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, ((row * 16) + column)) 
					button.name = (((str(column) + "_Clip_") + str(row)) + "_Button")
					button_row.append(button)
				matrix.add_row(tuple(button_row))
				
			self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0, optimized_send_midi=False)
			self._config_button.add_value_listener(self._config_value)
			top_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0, (104 + index)) for index in range(8) ] 
			side_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index]) for index in range(8) ] 
			top_buttons[0].name = "Bank_Select_Up_Button"
			top_buttons[1].name = "Bank_Select_Down_Button"
			top_buttons[2].name = "Bank_Select_Left_Button"
			top_buttons[3].name = "Bank_Select_Right_Button"
			top_buttons[4].name = "Session_Button"
			top_buttons[5].name = "User1_Button"
			top_buttons[6].name = "User2_Button"
			top_buttons[7].name = "Mixer_Button"
			side_buttons[0].name = "Vol_Button"
			side_buttons[1].name = "Pan_Button"
			side_buttons[2].name = "SndA_Button"
			side_buttons[3].name = "SndB_Button"
			side_buttons[4].name = "Stop_Button"
			side_buttons[5].name = "Trk_On_Button"
			side_buttons[6].name = "Solo_Button"
			side_buttons[7].name = "Arm_Button"
			self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button)
			self._selector.name = "Main_Modes"
			for control in self.controls:
				if isinstance(control, ConfigurableButtonElement):
					control.add_value_listener(self._button_value)
			self.set_highlighting_session_component(self._selector.session_component())
			self._suppress_session_highlight = False
			#self.set_suppress_rebuild_requests(False)

	" DISCONNECTOR "
	def disconnect(self):
		self._suppress_send_midi = True
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.remove_value_listener(self._button_value)
		self._selector = None
		self._user_byte_write_button.remove_value_listener(self._user_byte_value)
		self._config_button.remove_value_listener(self._config_value)
		ControlSurface.disconnect(self)
		self._suppress_send_midi = False
		self._config_button.send_value(32)
		self._config_button.send_value(0)
		self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None

	" RETURN THE SESSION COMPONENT SHOWING THE RING IN LIVE SESSION "
	def highlighting_session_component(self):		
		return self._selector.session_component()

	" REFRESH "
	def refresh_state(self):
		ControlSurface.refresh_state(self)
		self.schedule_message(5, self._update_hardware)

	" SYSEX HANDLING "
	def handle_sysex(self, midi_bytes):
		if (len(midi_bytes) == 8):
			if (midi_bytes[1:5] == (0, 32, 41, 6)):
				response = long(midi_bytes[5])
				response += (long(midi_bytes[6]) << 8)
				if (response == Live.Application.encrypt_challenge2(self._challenge)):
					self._suppress_send_midi = False
					self.set_enabled(True)

	" MIDI MAP "
	def build_midi_map(self, midi_map_handle):
		ControlSurface.build_midi_map(self, midi_map_handle)
		if (self._selector.mode_index == 1):
			new_channel = self._selector.channel_for_current_mode()
			for note in DRUM_NOTES:
				self._translate_message(MIDI_NOTE_TYPE, note, 0, note, new_channel) 

	" SEND THE MIDI STUFF "
	def _send_midi(self, midi_bytes, optimized = None):
		sent_successfully = False
		if (not self._suppress_send_midi):
			sent_successfully = ControlSurface._send_midi(self, midi_bytes, optimized=optimized)
		return sent_successfully

	" UPDATE THE HARDWARE "
	def _update_hardware(self):
		self._suppress_send_midi = False
		self._wrote_user_byte = True
		self._user_byte_write_button.send_value(1)
		self._suppress_send_midi = True
		self.set_enabled(False)
		self._suppress_send_midi = False
		self._send_challenge()

	" CHALLANGE SEND "
	def _send_challenge(self):
		for index in range(4):
			challenge_byte = ((self._challenge >> (8 * index)) & 127)
			self._send_midi((176, (17 + index),	 challenge_byte))

	" USER BYTE STUFF "
	def _user_byte_value(self, value):
		if not value in range(128):
			raise AssertionError
			enabled = self._wrote_user_byte or value == 1
			self._control_is_with_automap = not enabled
			self._suppress_send_midi = self._control_is_with_automap
			if not self._control_is_with_automap:
				for control in self.controls:
					if isinstance(control, ConfigurableButtonElement):
						control.set_force_next_value()
			self._selector.set_mode(0)
			self.set_enabled(enabled)
			self._suppress_send_midi = False
		else:
			self._wrote_user_byte = False

	" BUTTON VALUE "
	def _button_value(self, value):		
		assert (value in range(128))
		
	" CONFIG VALUE "
	def _config_value(self, value):
		assert (value in range(128))

	" SET THE SESSION HIGHLIGHT "
	def _set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks):
		if (not self._suppress_session_highlight):
			ControlSurface._set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks)
class NanoKontrolShift(ControlSurface):
    __module__ = __name__
    __doc__ = " NanoKontrolShift controller script "

    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        self._suppress_session_highlight = True
        self._suppress_send_midi = True  # Turn off rebuild MIDI map until after we're done setting up
        self.log_message(time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) + "--------------= NanoKontrolShift log opened =--------------") # Writes message into Live's main log file. This is a ControlSurface method.
        with self.component_guard():
            # OBJECTS
            self.session = None #session object
            self.mixer = None #mixer object
            self.view = None #clip/device view object
            self.device = None #device object
            self.transport = None #transport object
            # MODES
            self._shift_button = None
            self._shift_button_pressed = False
            self._alt_button = None
            self._alt_button_pressed = False
            self._ctrl_button = None
            self._ctrl_button_pressed = False
            # INITIALIZE MIXER, SESSIONS
            self._setup_session_control()  # Setup the session object
            self._setup_mixer_control() # Setup the mixer object
            self._setup_view_control() # Setup the clip/view toggler
            self.session.set_mixer(self.mixer) # Bind mixer to session
            self._setup_device_control() # Setup the device object
            self._setup_transport_control() # Setup transport object
            self.set_device_component(self.device) # Bind device to control surface
            # SET INITIAL SESSION/MIXER AND MODIFIERS BUTTONS
            self._set_modifiers_buttons()
            self.__update_matrix()
            # self.set_highlighting_session_component(self.session)

            for component in self.components:
                component.set_enabled(True)

        # self._suppress_session_highlight = True
        self._suppress_send_midi = True # Turn rebuild back on, once we're done setting up

    def _setup_session_control(self):
        self.show_message("#################### SESSION: ON ##############################")
        is_momentary = True
        # CREATE SESSION, SET OFFSETS, BUTTONS NAVIGATION AND BUTTON MATRIX
        self.session = SessionComponent(num_tracks, num_scenes) #(num_tracks, num_scenes)
        self.session.set_offsets(0, 0)
        # self.session.set_scene_bank_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, session_down), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, session_up))
        # self.session.set_track_bank_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, session_right), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, session_left)) # (right_button, left_button) This moves the "red box" selection set left & right. We'll use the mixer track selection instead...

    def _setup_mixer_control(self):
        is_momentary = True
        #CREATE MIXER, SET OFFSET (SPECIALMIXERCOMPONENT USES SPECIALCHANNELSTRIP THAT ALLOWS US TO UNFOLD TRACKS WITH TRACK SELECT BUTTON)
        self.mixer = SpecialMixerComponent(num_tracks, 0, False, False) # 4 tracks, 2 returns, no EQ, no filters
        self.mixer.name = 'Mixer'
        self.mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left)

    def _setup_view_control(self):
        # CREATES OBJECT SO WE CAN TOGGLE DEVICE/CLIP, LOCK DEVICE
        self.view = ViewTogglerComponent(num_tracks, self)

    def _setup_device_control(self):
        # CREATE DEVICE TO ASSIGN PARAMETERS BANK
        self.device = DeviceComponent()
        self.device.name = 'Device_Component'

    def _setup_transport_control(self):
        # CREATE TRANSPORT DEVICE
        self.transport = SpecialTransportComponent(self)


    def _on_selected_scene_changed(self):
        # ALLOWS TO GRAB THE FIRST DEVICE OF A SELECTED TRACK IF THERE'S ANY
        ControlSurface._on_selected_track_changed(self)
        track = self.song().view.selected_track
        if (track.devices is not None):
            self._ignore_track_selection = True
            device_to_select = track.devices[0]
            self.song().view.select_device(device_to_select)
            self._device_component.set_device(device_to_select)
        self._ignore_track_selection = False

    """                                 LED ON, OFF, FLASH WITH SESSION CLIPS                                             """

    # UPDATING BUTTONS FROM CLIP MATRIX IN NK AS SESSION MOVES
    def __update_matrix(self):
        for scene_index in range(num_scenes):
            scene = self.session.scene(scene_index)
            for track_index in range(num_tracks):
                clip_slot = scene.clip_slot(track_index)
                button = clip_slot._launch_button_value.subject
                value_to_send = -1
                if clip_slot._clip_slot != None:
                    if clip_slot.has_clip():
                        value_to_send = 127
                        if clip_slot._clip_slot.clip.is_triggered:
                            if clip_slot._clip_slot.clip.will_record_on_start:
                                value_to_send = clip_slot._triggered_to_record_value
                            else:
                                value_to_send = clip_slot._triggered_to_play_value
                        '''
                        elif clip_slot._clip_slot.clip.is_playing:
                            if clip_slot._clip_slot.clip.is_recording:
                                value_to_send = 127
                                #########      CLIPS PLAYING WILL FLASH
                                for i in range(2000):
                                    if i % 50 == 0:
                                        button.send_value(127)
                                    else:
                                        button.send_value(0)
                            else:
                                for i in range(2000):
                                    if i % 50 == 0:
                                        button.send_value(127)
                                    else:
                                        button.send_value(0)
                        '''
                    elif clip_slot._clip_slot.is_triggered:
                        if clip_slot._clip_slot.will_record_on_start:
                            value_to_send = clip_slot._triggered_to_record_value
                        else:
                            value_to_send = clip_slot._triggered_to_play_value
                    elif clip_slot._clip_slot.is_playing:
                        if clip_slot._clip_slot.is_recording:
                            value_to_send = clip_slot._recording_value
                        else:
                            value_to_send = clip_slot._started_value
                    elif clip_slot._clip_slot.controls_other_clips:
                        value_to_send = 0
                '''
                if value_to_send in range(128):
                    button.send_value(value_to_send)
                else:
                    button.turn_off()
                '''

    """                                 MODIFIERS, MODES, KEYS CONFIG                                             """

    #MODES ARE HERE: INITIALIZATIONS, DISCONNECTS BUTTONS, SLIDERS, ENCODERS
    def _clear_controls(self):
        # TURNING OFF ALL LEDS IN MATRIX
        self._turn_off_matrix()
        # SESSION
        resetsend_controls = []
        self.mixer.send_controls = []
        for scene_index in range(num_scenes):
            scene = self.session.scene(scene_index)
            scene.set_launch_button(None)
            for track_index in range(num_tracks):
                clip_slot = scene.clip_slot(track_index)
                clip_slot.set_launch_button(None)
        self.session.set_stop_track_clip_buttons(None)
        self.session.set_stop_all_clips_button(None)
            # REMOVE LISTENER TO SESSION MOVES
        if self.session.offset_has_listener(self.__update_matrix):
            self.session.remove_offset_listener(self.__update_matrix)
        self.session.set_stop_all_clips_button(None)
        # MIXER
        self.mixer._set_send_nav(None, None)
        for track_index in range(num_tracks):
            strip = self.mixer.channel_strip(track_index)
            strip.set_solo_button(None)
            strip.set_mute_button(None)
            strip.set_arm_button(None)
            resetsend_controls.append(None)
            strip.set_select_button(None)
            for i in range(12):
                self.mixer.send_controls.append(None)
            strip.set_send_controls(tuple(self.mixer.send_controls))
        self.mixer.set_resetsend_buttons(tuple(resetsend_controls))
        # VIEW
        self.view.set_device_nav_buttons(None, None)
        detailclip_view_controls = []
        for track_index in range(num_tracks):
            detailclip_view_controls.append(None)
        self.view.set_buttons(tuple(detailclip_view_controls))
        # DEVICE PARAMETERS
        device_param_controls = []
        self.device.set_parameter_controls(tuple(device_param_controls))
        self.device.set_on_off_button(None)
        self.device.set_lock_button(None)
        # TRANSPORT
        self.transport.set_stop_button(None)
        self.transport.set_play_button(None)
        self.transport.set_record_button(None)
        self.transport._set_quant_toggle_button(None)
        self.transport.set_metronome_button(None)
        self.transport._set_tempo_buttons(None, None)

        self.log_message("Controls Cleared")

    def _set_normal_mode(self):
        is_momentary = True
        self.mixer._set_send_nav(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, send_up), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, send_down))
        for index in range(num_tracks):
            strip = self.mixer.channel_strip(index)
            strip.name = 'Mixer_ChannelStrip_' + str(index)
            self.mixer._update_send_index(self.mixer.sends_index)
            strip.set_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL, mixer_volumefader_cc[index]))
            self.mixer.send_controls[self.mixer.sends_index] = EncoderElement(MIDI_CC_TYPE, CHANNEL, mixer_sendknob_cc[index], Live.MidiMap.MapMode.absolute)
            strip.set_send_controls(tuple(self.mixer.send_controls))
            strip._invert_mute_feedback = True
        ### SET ARM, SOLO, MUTE
        for index in range(num_tracks):
            strip = self.mixer.channel_strip(index)
            strip.set_send_controls(tuple(self.mixer.send_controls))
            strip.set_solo_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, track_solo_cc[index]))
            strip.set_mute_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, track_mute_cc[index]))
            strip.set_arm_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, track_arm_cc[index]))
            # self.transport.set_stop_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, transport_stop_cc))
            for i in range(12):
                self.mixer.send_controls.append(None)
            self.mixer.send_controls[self.mixer.sends_index] = EncoderElement(MIDI_CC_TYPE, CHANNEL, mixer_sendknob_cc[index], Live.MidiMap.MapMode.absolute)
            strip.set_send_controls(tuple(self.mixer.send_controls))
            strip._invert_mute_feedback = True
        self.mixer._update_send_index(self.mixer.sends_index)


    def _set_alt_mode(self):
        is_momentary = True
        self.mixer._set_send_nav(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, send_up), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, send_down))
        stop_track_controls = []
        resetsend_controls = []
        button = None
        buttons = None
        # SET SESSION TRACKSTOP, TRACK SELECT, RESET SEND KNOB
        for index in range(num_tracks):
            strip = self.mixer.channel_strip(index)
            strip.set_select_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, track_select_cc[index]))
            button = ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, stop_track_cc[index])
            stop_track_controls.append(button)
            buttons = ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, track_resetsend_cc[index])
            resetsend_controls.append(buttons)
        self.session.set_stop_track_clip_buttons(tuple(stop_track_controls))
        self.mixer.set_resetsend_buttons(tuple(resetsend_controls))
        self.mixer._update_send_index(self.mixer.sends_index)


    def _set_ctrl_mode(self):
        # CLIP/DEVICE VIEW TOGGLE
        is_momentary = True
        self.view.set_device_nav_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, device_left_cc), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, device_right_cc))
        button = None
        detailclip_view_controls = []
        for index in range(num_tracks):
            button = ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, detailclip_view_cc[index])
            detailclip_view_controls.append(button)
        self.view.set_buttons(tuple(detailclip_view_controls))
        # DEVICE ON/OFF, LOCK AND PARAMETERS
        device_param_controls = []
        onoff_control = ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, onoff_device_cc)
        setlock_control = ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, lock_device_cc)
        for index in range(num_tracks):
            knob = None
            knob = EncoderElement(MIDI_CC_TYPE, CHANNEL, device_param_cc[index], Live.MidiMap.MapMode.absolute)
            device_param_controls.append(knob)
        if None not in device_param_controls:
            self.device.set_parameter_controls(tuple(device_param_controls))
        self.device.set_on_off_button(onoff_control)
        self.device.set_lock_button(setlock_control)
        # TRANSPORT
        # self.transport.set_stop_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, transport_stop_cc))
        # self.transport.set_play_button(ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, transport_play_cc))
        # self.transport.set_record_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, transport_record_cc))
        self.transport._set_quant_toggle_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, transport_quantization_cc))
        self.transport.set_metronome_button(ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, transport_metronome_cc))
        self.transport._set_tempo_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, transport_tempodown_cc), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, transport_tempoup_cc))
        # SESSION STOP ALL CLIPS AND SCENE LAUNCH
        self.session.set_stop_all_clips_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, session_stopall_cc))
        for index in range(num_scenes):
            self.session.scene(index).set_launch_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, session_scenelaunch_cc[index]))

    def _set_modifiers_buttons(self):
        is_momentary = True
        self._shift_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, shift_mod)
        self._alt_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, alt_mod)
        self._ctrl_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, ctrl_mod)

        if (self._shift_button != None):
            self._shift_button.add_value_listener(self._shift_value)

        if (self._alt_button != None):
            self._alt_button.add_value_listener(self._alt_value)

        if (self._ctrl_button != None):
            self._ctrl_button.add_value_listener(self._ctrl_value)
        #INIT NORMAL MODE
        self._manage_modes(0)

    # MODIFIERS LISTENERS FUNCS ARE HERE
    def _shift_value(self, value):
        assert isinstance(value, int)
        assert isinstance(self._shift_button, ButtonElement)
        if value == 127:
            if self._shift_button_pressed is False:
                self._unpress_modes()
                self._shift_button_pressed = True
                self._manage_modes(0)

    def _alt_value(self, value):
        assert isinstance(value, int)
        assert isinstance(self._alt_button, ButtonElement)
        if value == 127:
            if self._alt_button_pressed is False:
                self._unpress_modes()
                self._alt_button_pressed = True
                self._manage_modes(2)

    def _ctrl_value(self, value):
        assert isinstance(value, int)
        assert isinstance(self._ctrl_button, ButtonElement)
        if value == 127:
            if self._ctrl_button_pressed is False:
                self._unpress_modes()
                self._ctrl_button_pressed = True
                self._manage_modes(3)

    def _manage_modes(self, mode_index):
        if mode_index == 0:
            self._clear_controls()
            self._set_normal_mode()
            # self._shift_button.turn_on()
            self._alt_button.turn_on()
            self._ctrl_button.turn_on()
            self.log_message("NORMAL ON")
        elif mode_index == 2:
            self._clear_controls()
            self._set_alt_mode()
            self._alt_button.turn_on()
            self._shift_button.turn_off()
            self._ctrl_button.turn_off()
            self.log_message("ALT ON")
        elif mode_index == 3:
            self._clear_controls()
            self._set_ctrl_mode()
            self._ctrl_button.turn_on()
            self._shift_button.turn_off()
            self._alt_button.turn_off()
            self.log_message("CTRL ON")

    def _unpress_modes(self):
        self._shift_button_pressed = False
        self._alt_button_pressed = False
        self._ctrl_button_pressed = False

    def _turn_off_matrix(self):
        for index in range(24):
            self._send_midi(tuple([176,index+16,0]))

    def disconnect(self):
        """clean things up on disconnect"""
        self.log_message(time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) + "--------------= NanoKontrolShift log closed =--------------") #Create entry in log file
        self._clear_controls()
        self.session = None
        self.mixer = None
        self.view = None
        self.device = None
        self.transport = None
        # MODES
        self._shift_button = None
        self._alt_button = None
        self._ctrl_button = None
        # SENDS
        self.send_button_up = None
        self.send_button_down = None
        self.send_controls = []
        self.send_reset = []

        self.set_device_component(None)
        ControlSurface.disconnect(self)
        return None
示例#46
0
class OP1(ControlSurface):
    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        self.c_instance = c_instance

        self.retries_count = 0
        self.device_connected = False

        self.clip_color_callbacks = {}
        self.slot_callbacks = {}

        self.text_start_sequence = (0xf0, 0x0, 0x20, 0x76, 0x00, 0x03)
        self.text_end_sequence = (0xf7, )
        self.enable_sequence = (0xf0, 0x00, 0x20, 0x76, 0x00, 0x01, 0x02, 0xf7)
        self.disable_sequence = (0xf0, 0x00, 0x20, 0x76, 0x00, 0x01, 0x00,
                                 0xf7)

        self.id_sequence = (0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7)

        self.text_color_start_sequence = (0xf0, 0x0, 0x20, 0x76, 0x00, 0x04)

        self.log('INITIALIZING')

        self.app = Live.Application.get_application()

        #maj = self.app.get_major_version()
        #min = self.app.get_minor_version()
        #bug = self.app.get_bugfix_version()
        #self.show_message(str(1) + "." + str(0) + "." + str(9))

        self.show_message("Version " + VERSION)

        # reseting text
        self.write_text(' ')

        # reset display clips
        self.reset_display_clips()

        # getting browser visible state
        self.session_browser_visible = self.app.view.is_view_visible("Browser")

        # getting browser visible state
        self.arrange_browser_visible = self.app.view.is_view_visible("Browser")

        # getting session view visible state
        self.session_visible = self.app.view.is_view_visible("Session")

        # getting arrange view visible state
        self.arrange_visible = self.app.view.is_view_visible("Arranger")

        # getting detail view visible state
        self.detail_visible = self.app.view.is_view_visible("Detail")

        # getting back to arranger state
        self.back_to_arranger_state = self.song().back_to_arranger

        # initializing channel strip to null
        self._channel_strip = None

        # initializing transport component
        self._transport = TransportComponent()

        # initializing mixer component
        self._mixer = MixerComponent(NUM_TRACKS, 2)

        # initializing session component
        self._session = SessionComponent(NUM_TRACKS, NUM_ROWS)
        self._session.add_offset_listener(self.session_offset_changed)

        # configuring operation mode selector buttons
        self._operation_mode_buttons = ButtonElement(
            True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_1_BUTTON), ButtonElement(
                True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_2_BUTTON), ButtonElement(
                    True, MIDI_CC_TYPE, CHANNEL,
                    OP1_MODE_3_BUTTON), ButtonElement(True, MIDI_CC_TYPE,
                                                      CHANNEL,
                                                      OP1_MODE_4_BUTTON),

        # initializing operation mode selector
        self._operation_mode_selector = OP1ModeSelectorComponent(
            self, self._transport, self._mixer, self._session)

        # setting operation mode selector buttons
        self._operation_mode_selector.set_mode_buttons(
            self._operation_mode_buttons)

        # adding value listener for operation mode index
        self._operation_mode_selector.add_mode_index_listener(
            self.mode_index_changed)

        # setting global transport assignments
        self._transport.set_record_button(
            ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_REC_BUTTON))
        self._transport.set_play_button(
            ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_PLAY_BUTTON))
        self._transport.set_stop_button(
            ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_STOP_BUTTON))
        self._transport.set_metronome_button(
            ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_METRONOME_BUTTON))
        self._transport.set_tap_tempo_button(
            ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_HELP_BUTTON))
        self._transport.set_punch_buttons(
            ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS1_BUTTON),
            ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS2_BUTTON))
        self._transport.set_loop_button(
            ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS3_BUTTON))
        self._transport.set_overdub_button(
            ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS4_BUTTON))

        # setting global session assignments
        self._session.set_scene_bank_buttons(
            ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_COM),
            ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MICRO))

        # setting misc listeners
        self.browser_toggle_button = ButtonElement(False, MIDI_CC_TYPE,
                                                   CHANNEL, 15)
        self.browser_toggle_button.add_value_listener(
            self.browser_toggle_button_callback)

        self.mainview_toggle_button = ButtonElement(False, MIDI_CC_TYPE,
                                                    CHANNEL, 16)
        self.mainview_toggle_button.add_value_listener(
            self.mainview_toggle_button_callback)

        self.detailview_toggle_button = ButtonElement(False, MIDI_CC_TYPE,
                                                      CHANNEL, 17)
        self.detailview_toggle_button.add_value_listener(
            self.detailview_toggle_button_callback)

        self.clear_track_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL,
                                                25)
        self.clear_track_button.add_value_listener(
            self.clear_track_button_callback)

        self.back_to_arranger_button = ButtonElement(True, MIDI_CC_TYPE,
                                                     CHANNEL, 26)
        self.back_to_arranger_button.add_value_listener(
            self.back_to_arranger_button_callback)

        # adding value listener for selected track change
        self.song().view.add_selected_track_listener(
            self.selected_track_changed)

        # adding value listener for selected scene change
        self.song().view.add_selected_scene_listener(
            self.selected_scene_changed)

        # setting assignments for currently selected track
        self.selected_track_changed()

        # setting assignments for currently selected scene
        self.selected_scene_changed()

    def handle_sysex(self, midi_bytes):
        if ((midi_bytes[6] == 32) and (midi_bytes[7] == 118)):
            self.device_connected = True
            self.log("OP-1 CONNECTED. SENDING ABLETON LIVE MODE INIT SEQUENCE")
            self._send_midi(self.enable_sequence)

    def add_clip_slot_listeners(self):
        #self.log('ADDING CLIP SLOT LISTENERS')

        # creating an empty list for all clip slots
        clip_slots = []

        # getting a reference to all tracks
        tracks = self.song().tracks

        # appending all tracks clip slots to clip_slots
        for track in tracks:
            clip_slots.append(track.clip_slots)

        # iterating over all clip slots
        for t in range(len(clip_slots)):
            for c in range(len(clip_slots[t])):
                clip_slot = clip_slots[t][c]

                # adding has clip listener to clip slot
                self.add_slot_listener(clip_slot)

                # if clip slot has clip
                if clip_slot.has_clip:
                    # adding clip listeners
                    self.add_clip_listener(clip_slot.clip)

    def rem_clip_slot_listeners(self):
        #self.log('REMOVING CLIP SLOT LISTENERS')

        # iterate over all clip color change callbacks
        for c in self.clip_color_callbacks:
            # if clip still exists
            if c != None:
                # and it has a has clip listener
                if c.color_has_listener(self.clip_color_callbacks[c]) == 1:
                    # remove it
                    c.remove_color_listener(self.clip_color_callbacks[c])

        # iterate over all clip slot callbacks
        for cs in self.slot_callbacks:
            # if clip slot still exists
            if cs != None:
                # and it has a has clip listener
                if cs.has_clip_has_listener(self.slot_callbacks[cs]) == 1:
                    # remove it
                    cs.remove_has_clip_listener(self.slot_callbacks[cs])

    def add_slot_listener(self, cs):
        # setting has clip listener
        callback = lambda: self.has_clip_listener(cs)

        # if we don't have a clip slot has clip listener for this clip slot yet
        if not (self.slot_callbacks.has_key(cs)):
            # adding has clip callback to clip slot
            cs.add_has_clip_listener(callback)

            # saving callback for future release
            self.slot_callbacks[cs] = callback

    def add_clip_listener(self, clip):
        # setting callback for clip color change
        color_callback = lambda: self.update_display_clips()

        # if we don't have a clip color change callback for this clip yet
        if not (self.clip_color_callbacks.has_key(clip)):
            # adding clip color change callback
            clip.add_color_listener(color_callback)

            # saving callback for future release
            self.clip_color_callbacks[clip] = color_callback

    def has_clip_listener(self, cs):
        # clip slot has clip listener callback
        if cs.has_clip:
            # add clip listener
            self.add_clip_listener(cs.clip)
        else:
            # update display if clip slot was removed
            self.update_display_clips()

    def session_offset_changed(self):
        # if session component offset changes, update display
        self.update_display_clips()

    def selected_scene_changed(self):
        # if on clip mode update display
        if (self._operation_mode_selector.mode_index == OP1_MODE_CLIP):
            self.update_display_clip_mode()

    def mode_index_changed(self):
        # update display to current mode info
        if (self._operation_mode_selector.mode_index == OP1_MODE_PERFORM):
            self.update_display_perform_mode()
        elif (self._operation_mode_selector.mode_index == OP1_MODE_CLIP):
            self.update_display_clip_mode()
        elif (self._operation_mode_selector.mode_index == OP1_MODE_TRANSPORT):
            self.update_display_transport_mode()
        elif (self._operation_mode_selector.mode_index == OP1_MODE_MIXER):
            self.update_display_mixer_mode()

    def clear_track_button_callback(self, value):
        # if clear track button was called, reset track
        if (value == 127):
            for i in range(len(self.song().tracks)):
                self.song().tracks[i].arm = 0
                self.song().tracks[i].solo = 0
                self.song().tracks[i].mute = 0

            for i in range(len(self.song().return_tracks)):
                self.song().tracks[i].solo = 0
                self.song().tracks[i].mute = 0

    def clear_return_track_assignment(self, strip):
        # clear return track assingments
        strip.set_volume_control(None)
        strip.set_pan_control(None)
        strip.set_mute_button(None)
        strip.set_solo_button(None)

    def clear_track_assignment(self, strip):
        # clear track assignments
        strip.set_volume_control(None)
        strip.set_pan_control(None)
        strip.set_mute_button(None)
        strip.set_solo_button(None)
        strip.set_arm_button(None)

    def clear_tracks_assigments(self):
        # for all normal tracks, clear assignments
        for i in range(NUM_TRACKS):
            strip = self._mixer.channel_strip(i)
            if (strip != None):
                self.clear_track_assignment(strip)

        # for all return tracks, clear assignments
        for i in range(2):
            return_strip = self._mixer.return_strip(i)
            if (return_strip != None):
                self.clear_return_track_assignment(return_strip)

    def selected_track_changed(self):
        # if on mixer mode update display
        if (self._operation_mode_selector.mode_index == OP1_MODE_MIXER):
            self.update_display_mixer_mode()

        # clear track assignments
        self.clear_tracks_assigments()

        # getting selected strip
        self._channel_strip = self._mixer.selected_strip()

        # perform track assignments
        self._channel_strip.set_volume_control(
            EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_1,
                           Live.MidiMap.MapMode.relative_two_compliment))
        self._channel_strip.set_pan_control(
            EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_2,
                           Live.MidiMap.MapMode.relative_two_compliment))

        # setting a tuple of encoders to control sends
        send_controls = EncoderElement(
            MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_3,
            Live.MidiMap.MapMode.relative_two_compliment), EncoderElement(
                MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_4,
                Live.MidiMap.MapMode.relative_two_compliment),

        # setting send encoders
        self._channel_strip.set_send_controls(tuple(send_controls))

        # setting solo button
        self._channel_strip.set_solo_button(
            ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS6_BUTTON))

        # if track can be armed, set arm button
        if (self._channel_strip._track.can_be_armed):
            self._channel_strip.set_arm_button(
                ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS7_BUTTON))

        # if track is no master, set mute button
        if (self._channel_strip._track != self.song().master_track):
            self._channel_strip.set_mute_button(
                ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS5_BUTTON))

    def browser_toggle_button_callback(self, value):
        if (value == 127):
            if (self.session_visible):
                if (self.session_browser_visible == True):
                    self.session_browser_visible = False
                    self.app.view.hide_view("Browser")
                else:
                    self.session_browser_visible = True
                    self.app.view.show_view("Browser")

            if (self.arrange_visible):
                if (self.arrange_browser_visible == True):
                    self.arrange_browser_visible = False
                    self.app.view.hide_view("Browser")
                else:
                    self.arrange_browser_visible = True
                    self.app.view.show_view("Browser")

    def back_to_arranger_button_callback(self, value):
        if (value == 127):
            self.song().back_to_arranger = False

    def mainview_toggle_button_callback(self, value):
        if (value == 127):
            if (self.session_visible == True):
                self.session_visible = False
                self.arrange_visible = True
                self.app.view.show_view("Arranger")
                self.arrange_browser_visible = self.app.view.is_view_visible(
                    "Browser")
            else:
                self.session_visible = True
                self.arrange_visible = False
                self.app.view.show_view("Session")
                self.session_browser_visible = self.app.view.is_view_visible(
                    "Browser")

    def detailview_toggle_button_callback(self, value):
        if (value == 127):
            if (self.detail_visible == True):
                self.detail_visible = False
                self.app.view.hide_view("Detail")
            else:
                self.detail_visible = True
                self.app.view.show_view("Detail")

    def write_text(self, msg):
        text_list = []
        sequence = ()

        text_list.append(len(msg.strip()))

        for i in msg.strip():
            text_list.append(ord(i))

        sequence = self.text_start_sequence + tuple(
            text_list) + self.text_end_sequence

        self._send_midi(sequence)

    def suggest_input_port(self):
        return "OP-1 Midi Device"

    def suggest_output_port(self):
        return "OP-1 Midi Device"

    def update_display_perform_mode(self):
        self.write_text("perform\rmode")

    def reset_display_clips(self):
        count = 0
        colors = []
        length = []
        sequence = ()

        for i in range(NUM_TRACKS):
            count += 1

            colors.append(0x00)
            colors.append(0x00)
            colors.append(0x00)

        length.append(count)
        sequence = self.text_color_start_sequence + tuple(length) + tuple(
            colors) + self.text_end_sequence
        self._send_midi(sequence)

    def update_display_clips(self):
        #self.log("UPDATING DISPLAY CLIPS")
        count = 0
        colors = []
        length = []
        sequence = ()

        tracks_len = len(self.song().tracks) - self._session._track_offset

        if (tracks_len > NUM_TRACKS):
            tracks_len = NUM_TRACKS

        for i in range(tracks_len):
            count += 1

            clip_slot = self._session.scene(0).clip_slot(i)

            if (clip_slot != None):
                if (clip_slot.has_clip() != False):
                    clip_color = clip_slot._clip_slot.clip.color
                    colors.append(((clip_color >> 16) & 0x000000ff) >> 1)
                    colors.append(((clip_color >> 8) & 0x000000ff) >> 1)
                    colors.append((clip_color & 0x000000ff) >> 1)
                else:
                    colors.append(0x00)
                    colors.append(0x00)
                    colors.append(0x00)
            else:
                colors.append(0x00)
                colors.append(0x00)
                colors.append(0x00)

        length.append(count)
        sequence = self.text_color_start_sequence + tuple(length) + tuple(
            colors) + self.text_end_sequence
        self._send_midi(sequence)

    def update_display_clip_mode(self):
        self.write_text(
            "sel. scene\r" +
            str(self.song().view.selected_scene.name.lower().strip()))

    def update_display_transport_mode(self):
        song_time = str(self.song().get_current_beats_song_time())
        self.write_text("song pos.\r" + song_time[:len(song_time) - 4])

    def update_display_mixer_mode(self):
        self.write_text("sel. track\r" +
                        str(self.song().view.selected_track.name.lower()))

    def update_display(self):
        if not (self.device_connected):
            if (self.retries_count < 5):
                self.log("TRYING OP-1 CONNECTION")
                self.retries_count += 1
                self._send_midi(self.id_sequence)
                time.sleep(1)

        # if in transport mode, update display with song position
        if (self._operation_mode_selector.mode_index == OP1_MODE_TRANSPORT):
            self.update_display_transport_mode()

        # checking if app current view is session
        if (self.app.view.is_view_visible("Session")):
            # checking if session browser state is diferent from the internal
            if (self.session_browser_visible !=
                    self.app.view.is_view_visible("Browser")):
                self.session_browser_visible = self.app.view.is_view_visible(
                    "Browser")

        # checking if app current view is arrange
        if (self.app.view.is_view_visible("Arranger")):
            # checking if arrange browser state is diferent from the internal
            if (self.arrange_browser_visible !=
                    self.app.view.is_view_visible("Browser")):
                self.arrange_browser_visible = self.app.view.is_view_visible(
                    "Browser")

        # checking if app current view is detail
        if (self.app.view.is_view_visible("Detail")):
            # checking if detail state is diferent from the internal
            if (self.detail_visible !=
                    self.app.view.is_view_visible("Detail")):
                self.detail_visible = self.app.view.is_view_visible("Detail")

    def refresh_state(self):
        self.log("REFRESH STATE")
        self.retries_count = 0
        self.device_connected = False

    def build_midi_map(self, midi_map_handle):
        #self.log("BUILD MIDI MAP")

        assert (self._suppress_requests_counter == 0)
        self._in_build_midi_map = True
        self._midi_map_handle = midi_map_handle
        self._forwarding_registry = {}
        for control in self.controls:
            if isinstance(control, InputControlElement):
                control.install_connections()
        self._midi_map_handle = None
        self._in_build_midi_map = False
        if (self._pad_translations != None):
            self._c_instance.set_pad_translation(self._pad_translations)

        # remove clip listeners
        self.rem_clip_slot_listeners()

        # add clip listeners
        self.add_clip_slot_listeners()

        # update display
        self.update_display_clips()

    def log(self, msg):
        self.c_instance.log_message("[TE OP-1] " + msg)

    def disconnect(self):
        # removing clip slots listeners
        self.rem_clip_slot_listeners()

        # removing value listener for track changed
        self.song().view.remove_selected_track_listener(
            self.selected_track_changed)

        # removing value listener for scene changed
        self.song().view.remove_selected_scene_listener(
            self.selected_scene_changed)

        # removing value listener for operation mode index
        self._operation_mode_selector.remove_mode_index_listener(
            self.mode_index_changed)

        # removing global transport assignments
        self._transport.set_punch_buttons(None, None)
        self._transport.set_loop_button(None)
        self._transport.set_overdub_button(None)
        self._transport.set_record_button(None)
        self._transport.set_play_button(None)
        self._transport.set_stop_button(None)
        self._transport.set_metronome_button(None)
        self._transport.set_tap_tempo_button(None)

        # removing global session assignments
        self._session.set_scene_bank_buttons(None, None)

        # removing misc listeners
        self.browser_toggle_button.remove_value_listener(
            self.browser_toggle_button_callback)
        self.mainview_toggle_button.remove_value_listener(
            self.mainview_toggle_button_callback)
        self.detailview_toggle_button.remove_value_listener(
            self.detailview_toggle_button_callback)
        self.clear_track_button.remove_value_listener(
            self.clear_track_button_callback)
        self.back_to_arranger_button.remove_value_listener(
            self.back_to_arranger_button_callback)

        # sending special ableton mode disable sequence
        self._send_midi(self.disable_sequence)

        # disconnecting control surface
        ControlSurface.disconnect(self)

        self.log("DISCONNECTED")
示例#47
0
class Launchpad(ControlSurface):
	""" Script for Novation's Launchpad Controller """

	def __init__(self, c_instance):
		ControlSurface.__init__(self, c_instance)
		self.set_suppress_rebuild_requests(True)
		self._suppress_send_midi = True
		self._suppress_session_highlight = True
		is_momentary = True
		self._suggested_input_port = 'Launchpad'
		self._suggested_output_port = 'Launchpad'
		self._control_is_with_automap = False
		self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)
		self._user_byte_write_button.name = 'User_Byte_Button'
		self._user_byte_write_button.send_value(1)
		self._user_byte_write_button.add_value_listener(self._user_byte_value)
		self._wrote_user_byte = False
		self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143
		matrix = ButtonMatrixElement()
		matrix.name = 'Button_Matrix'
		for row in range(8):
			button_row = []
			for column in range(8):
				button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, row * 16 + column)
				button.name = str(column) + '_Clip_' + str(row) + '_Button'
				button_row.append(button)

			matrix.add_row(tuple(button_row))

		self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0)
		self._config_button.add_value_listener(self._config_value)
		top_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0, 104 + index) for index in range(8) ]
		side_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index]) for index in range(8) ]
		top_buttons[0].name = 'Bank_Select_Up_Button'
		top_buttons[1].name = 'Bank_Select_Down_Button'
		top_buttons[2].name = 'Bank_Select_Left_Button'
		top_buttons[3].name = 'Bank_Select_Right_Button'
		top_buttons[4].name = 'Session_Button'
		top_buttons[5].name = 'User1_Button'
		top_buttons[6].name = 'User2_Button'
		top_buttons[7].name = 'Mixer_Button'
		side_buttons[0].name = 'Vol_Button'
		side_buttons[1].name = 'Pan_Button'
		side_buttons[2].name = 'SndA_Button'
		side_buttons[3].name = 'SndB_Button'
		side_buttons[4].name = 'Stop_Button'
		side_buttons[5].name = 'Trk_On_Button'
		side_buttons[6].name = 'Solo_Button'
		side_buttons[7].name = 'Arm_Button'
		self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button, self)
		self._selector.name = 'Main_Modes'
		self._do_combine()
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.add_value_listener(self._button_value)

		self._suppress_session_highlight = False
		self.set_suppress_rebuild_requests(False)

		self.log_message("LaunchPad85 Loaded !")

	def disconnect(self):
		self._suppress_send_midi = True
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.remove_value_listener(self._button_value)
		self._do_uncombine()
		self._selector = None
		self._user_byte_write_button.remove_value_listener(self._user_byte_value)
		self._config_button.remove_value_listener(self._config_value)
		ControlSurface.disconnect(self)
		self._suppress_send_midi = False
		self._config_button.send_value(32)
		self._config_button.send_value(0)
		self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None

	_active_instances = []

	def highlighting_session_component(self):
		" Return the session component showing the ring in Live session "
		return self._selector.session_component()

	def _combine_active_instances():
		support_devices = False
		for instance in Launchpad._active_instances:
			support_devices |= (instance._device_component != None)
		offset = 0
		for instance in Launchpad._active_instances:
			instance._activate_combination_mode(offset, support_devices)
			offset += instance._selector._session.width()

	_combine_active_instances = staticmethod(_combine_active_instances)

	def _activate_combination_mode(self, track_offset, support_devices):
		if(LINK_STEPSEQ):
			self._selector._stepseq.link_with_step_offset(track_offset)
		if(LINK_SESSION):
			self._selector._session.link_with_track_offset(track_offset)
		

	def _do_combine(self):
		if (DO_COMBINE and (self not in Launchpad._active_instances)):
			Launchpad._active_instances.append(self)
			Launchpad._combine_active_instances()
	
	def _do_uncombine(self):
		if self in Launchpad._active_instances:
			Launchpad._active_instances.remove(self)
			if(LINK_SESSION):
				self._selector._session.unlink()
			if(LINK_STEPSEQ):
				self._selector._stepseq.unlink()
			Launchpad._combine_active_instances()


	def refresh_state(self):
		ControlSurface.refresh_state(self)
		self.schedule_message(5, self._update_hardware)

	def handle_sysex(self, midi_bytes):
		if len(midi_bytes) == 8:
			if midi_bytes[1:5] == (0, 32, 41, 6):
				response = long(midi_bytes[5])
				response += long(midi_bytes[6]) << 8
				if response == Live.Application.encrypt_challenge2(self._challenge):
					self._suppress_send_midi = False
					self.set_enabled(True)

	def build_midi_map(self, midi_map_handle):
		ControlSurface.build_midi_map(self, midi_map_handle)
		if self._selector.mode_index == 1:
			new_channel = self._selector.channel_for_current_mode()
			for note in DRUM_NOTES:
				self._translate_message(MIDI_NOTE_TYPE, note, 0, note, new_channel)

	def _send_midi(self, midi_bytes):
		sent_successfully = False
		if not self._suppress_send_midi:
			sent_successfully = ControlSurface._send_midi(self, midi_bytes)
		return sent_successfully

	def _update_hardware(self):
		self._suppress_send_midi = False
		self._wrote_user_byte = True
		self._user_byte_write_button.send_value(1)
		self._suppress_send_midi = True
		self.set_enabled(False)
		self._suppress_send_midi = False
		self._send_challenge()

	def _send_challenge(self):
		for index in range(4):
			challenge_byte = self._challenge >> 8 * index & 127
			self._send_midi((176, 17 + index, challenge_byte))

	def _user_byte_value(self, value):
		assert (value in range(128))
		if (not self._wrote_user_byte):
			enabled = (value == 1)
			self._control_is_with_automap = (not enabled)
			self._suppress_send_midi = self._control_is_with_automap
			if not self._control_is_with_automap:
				for control in self.controls:
					if isinstance(control, ConfigurableButtonElement):
						control.set_force_next_value()

			self._selector.set_mode(0)
			self.set_enabled(enabled)
			self._suppress_send_midi = False
		else:
			self._wrote_user_byte = False

	def _button_value(self, value):
		assert (value in range(128))

	def _config_value(self, value):
		assert (value in range(128))

	def _set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks):
		if not self._suppress_session_highlight:
			ControlSurface._set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks)
示例#48
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
示例#49
0
文件: OP1.py 项目: imaginando/op1
class OP1(ControlSurface):
	def __init__(self, c_instance):
		ControlSurface.__init__(self, c_instance)
		self.c_instance = c_instance

		self.retries_count = 0
		self.device_connected = False

		self.clip_color_callbacks = {}
		self.slot_callbacks = {}

		self.text_start_sequence = (0xf0, 0x0, 0x20, 0x76, 0x00, 0x03)
		self.text_end_sequence = (0xf7,)
		self.enable_sequence = (0xf0, 0x00, 0x20, 0x76, 0x00, 0x01, 0x02, 0xf7)
		self.disable_sequence = (0xf0, 0x00, 0x20, 0x76, 0x00, 0x01, 0x00, 0xf7)

		self.id_sequence = (0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7)

		self.text_color_start_sequence = (0xf0, 0x0, 0x20, 0x76, 0x00, 0x04)

		self.log('INITIALIZING')

		self.app = Live.Application.get_application()

		#maj = self.app.get_major_version()
		#min = self.app.get_minor_version()
		#bug = self.app.get_bugfix_version()
		#self.show_message(str(1) + "." + str(0) + "." + str(9))

		self.show_message("Version " + VERSION)

		# reseting text
		self.write_text(' ')

		# reset display clips
		self.reset_display_clips()

		# getting browser visible state
		self.session_browser_visible = self.app.view.is_view_visible("Browser")
		
		# getting browser visible state
		self.arrange_browser_visible = self.app.view.is_view_visible("Browser")

		# getting session view visible state
		self.session_visible = self.app.view.is_view_visible("Session")

		# getting arrange view visible state
		self.arrange_visible = self.app.view.is_view_visible("Arranger")

		# getting detail view visible state
		self.detail_visible = self.app.view.is_view_visible("Detail")

		# getting back to arranger state
		self.back_to_arranger_state = self.song().back_to_arranger

		# initializing channel strip to null
		self._channel_strip = None

		# initializing transport component
		self._transport = TransportComponent()

		# initializing mixer component
		self._mixer = MixerComponent(NUM_TRACKS,2)

		# initializing session component
		self._session = SessionComponent(NUM_TRACKS,NUM_ROWS)
		self._session.add_offset_listener(self.session_offset_changed)

		# configuring operation mode selector buttons
		self._operation_mode_buttons = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_1_BUTTON), ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_2_BUTTON), ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_3_BUTTON), ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_4_BUTTON), 
		
		# initializing operation mode selector
		self._operation_mode_selector = OP1ModeSelectorComponent(self, self._transport, self._mixer, self._session)
		
		# setting operation mode selector buttons
		self._operation_mode_selector.set_mode_buttons(self._operation_mode_buttons)

		# adding value listener for operation mode index
		self._operation_mode_selector.add_mode_index_listener(self.mode_index_changed)

		# setting global transport assignments
		self._transport.set_record_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_REC_BUTTON))
		self._transport.set_play_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_PLAY_BUTTON))
		self._transport.set_stop_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_STOP_BUTTON))  
		self._transport.set_metronome_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_METRONOME_BUTTON))  
		self._transport.set_tap_tempo_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_HELP_BUTTON))
		self._transport.set_punch_buttons(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS1_BUTTON), ButtonElement(True,MIDI_CC_TYPE, CHANNEL, OP1_SS2_BUTTON))
		self._transport.set_loop_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS3_BUTTON))
		self._transport.set_overdub_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS4_BUTTON))

		# setting global session assignments
		self._session.set_scene_bank_buttons(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_COM),ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MICRO))

		# setting misc listeners
		self.browser_toggle_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL, 15)
		self.browser_toggle_button.add_value_listener(self.browser_toggle_button_callback)

		self.mainview_toggle_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL, 16)
		self.mainview_toggle_button.add_value_listener(self.mainview_toggle_button_callback)

		self.detailview_toggle_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL, 17)
		self.detailview_toggle_button.add_value_listener(self.detailview_toggle_button_callback)

		self.clear_track_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, 25)
		self.clear_track_button.add_value_listener(self.clear_track_button_callback)

		self.back_to_arranger_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, 26)
		self.back_to_arranger_button.add_value_listener(self.back_to_arranger_button_callback)

		# adding value listener for selected track change
		self.song().view.add_selected_track_listener(self.selected_track_changed)

		# adding value listener for selected scene change
		self.song().view.add_selected_scene_listener(self.selected_scene_changed)

		# setting assignments for currently selected track
		self.selected_track_changed()

		# setting assignments for currently selected scene
		self.selected_scene_changed()

	def handle_sysex(self, midi_bytes):
		if ((midi_bytes[6]==32) and (midi_bytes[7]==118)):
			self.device_connected = True
			self.log("OP-1 CONNECTED. SENDING ABLETON LIVE MODE INIT SEQUENCE")
			self._send_midi(self.enable_sequence)

	def add_clip_slot_listeners(self):
		#self.log('ADDING CLIP SLOT LISTENERS')
		
		# creating an empty list for all clip slots
		clip_slots = []

		# getting a reference to all tracks
		tracks = self.song().tracks
		
		# appending all tracks clip slots to clip_slots
		for track in tracks:
			clip_slots.append(track.clip_slots)

		# iterating over all clip slots
		for t in range(len(clip_slots)):
			for c in range(len(clip_slots[t])):
				clip_slot = clip_slots[t][c]

				# adding has clip listener to clip slot
				self.add_slot_listener(clip_slot)

				# if clip slot has clip
				if clip_slot.has_clip:
					# adding clip listeners
					self.add_clip_listener(clip_slot.clip)

	def rem_clip_slot_listeners(self):
		#self.log('REMOVING CLIP SLOT LISTENERS')

		# iterate over all clip color change callbacks
		for c in self.clip_color_callbacks:
			# if clip still exists
			if c != None:
				# and it has a has clip listener
				if c.color_has_listener(self.clip_color_callbacks[c]) == 1:
					# remove it
					c.remove_color_listener(self.clip_color_callbacks[c])

		# iterate over all clip slot callbacks
		for cs in self.slot_callbacks:
			# if clip slot still exists
			if cs != None:
				# and it has a has clip listener
				if cs.has_clip_has_listener(self.slot_callbacks[cs]) == 1:
					# remove it
					cs.remove_has_clip_listener(self.slot_callbacks[cs])

	def add_slot_listener(self, cs):
		# setting has clip listener
		callback = lambda :self.has_clip_listener(cs)

		# if we don't have a clip slot has clip listener for this clip slot yet
		if not(self.slot_callbacks.has_key(cs)):
			# adding has clip callback to clip slot
			cs.add_has_clip_listener(callback)

			# saving callback for future release
			self.slot_callbacks[cs] = callback

	def add_clip_listener(self, clip):
		# setting callback for clip color change
		color_callback = lambda :self.update_display_clips()

		# if we don't have a clip color change callback for this clip yet
		if not(self.clip_color_callbacks.has_key(clip)):
			# adding clip color change callback
			clip.add_color_listener(color_callback)

			# saving callback for future release
			self.clip_color_callbacks[clip] = color_callback

	def has_clip_listener(self, cs):
		# clip slot has clip listener callback
		if cs.has_clip:
			# add clip listener
			self.add_clip_listener(cs.clip)
		else:
			# update display if clip slot was removed
			self.update_display_clips()

	def session_offset_changed(self):
		# if session component offset changes, update display
		self.update_display_clips()

	def selected_scene_changed(self):
		# if on clip mode update display
		if (self._operation_mode_selector.mode_index==OP1_MODE_CLIP):
			self.update_display_clip_mode()

	def mode_index_changed(self):
		# update display to current mode info
		if (self._operation_mode_selector.mode_index==OP1_MODE_PERFORM):
			self.update_display_perform_mode()
		elif (self._operation_mode_selector.mode_index==OP1_MODE_CLIP):
			self.update_display_clip_mode()
		elif (self._operation_mode_selector.mode_index==OP1_MODE_TRANSPORT):
			self.update_display_transport_mode()
		elif (self._operation_mode_selector.mode_index==OP1_MODE_MIXER):
			self.update_display_mixer_mode()

	def	clear_track_button_callback(self, value):
		# if clear track button was called, reset track
		if (value==127):
			for i in range(len(self.song().tracks)):
				self.song().tracks[i].arm = 0
				self.song().tracks[i].solo = 0
				self.song().tracks[i].mute = 0

			for i in range(len(self.song().return_tracks)):
				self.song().tracks[i].solo = 0
				self.song().tracks[i].mute = 0

	def clear_return_track_assignment(self, strip):
		# clear return track assingments
		strip.set_volume_control(None)
		strip.set_pan_control(None)
		strip.set_mute_button(None)
		strip.set_solo_button(None)
	
	def clear_track_assignment(self, strip):
		# clear track assignments
		strip.set_volume_control(None)
		strip.set_pan_control(None)
		strip.set_mute_button(None)
		strip.set_solo_button(None)
		strip.set_arm_button(None)

	def clear_tracks_assigments(self):
		# for all normal tracks, clear assignments
		for i in range(NUM_TRACKS):
			strip = self._mixer.channel_strip(i)
			if (strip!=None):
				self.clear_track_assignment(strip)

		# for all return tracks, clear assignments
		for i in range(2):
			return_strip = self._mixer.return_strip(i)
			if (return_strip!=None):
				self.clear_return_track_assignment(return_strip)

	def selected_track_changed(self):
		# if on mixer mode update display
		if (self._operation_mode_selector.mode_index==OP1_MODE_MIXER):
			self.update_display_mixer_mode()

		# clear track assignments
		self.clear_tracks_assigments()

		# getting selected strip
		self._channel_strip = self._mixer.selected_strip()

		# perform track assignments 
		self._channel_strip.set_volume_control(EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_1, Live.MidiMap.MapMode.relative_two_compliment))
		self._channel_strip.set_pan_control(EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_2, Live.MidiMap.MapMode.relative_two_compliment))

		# setting a tuple of encoders to control sends
		send_controls = EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_3, Live.MidiMap.MapMode.relative_two_compliment), EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_4, Live.MidiMap.MapMode.relative_two_compliment),

		# setting send encoders
		self._channel_strip.set_send_controls(tuple(send_controls))

		# setting solo button
		self._channel_strip.set_solo_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS6_BUTTON))

		# if track can be armed, set arm button
		if (self._channel_strip._track.can_be_armed):
			self._channel_strip.set_arm_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS7_BUTTON))

		# if track is no master, set mute button
		if (self._channel_strip._track!=self.song().master_track):
			self._channel_strip.set_mute_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS5_BUTTON))


	def browser_toggle_button_callback(self, value):
		if (value==127):
			if (self.session_visible):
				if (self.session_browser_visible==True):
					self.session_browser_visible=False
					self.app.view.hide_view("Browser")
				else:
					self.session_browser_visible=True
					self.app.view.show_view("Browser")

			if (self.arrange_visible):
				if (self.arrange_browser_visible==True):
					self.arrange_browser_visible=False
					self.app.view.hide_view("Browser")
				else:
					self.arrange_browser_visible=True
					self.app.view.show_view("Browser")

	def back_to_arranger_button_callback(self, value):
		if (value==127):
			self.song().back_to_arranger = False

	def mainview_toggle_button_callback(self, value):
		if (value==127):
			if (self.session_visible==True):
				self.session_visible=False
				self.arrange_visible=True
				self.app.view.show_view("Arranger")
				self.arrange_browser_visible = self.app.view.is_view_visible("Browser");
			else:
				self.session_visible=True
				self.arrange_visible=False
				self.app.view.show_view("Session")
				self.session_browser_visible = self.app.view.is_view_visible("Browser");

	def detailview_toggle_button_callback(self, value):
		if (value==127):
			if (self.detail_visible==True):
				self.detail_visible=False
				self.app.view.hide_view("Detail")
			else:
				self.detail_visible=True
				self.app.view.show_view("Detail")

	def write_text(self, msg):
		text_list = []
		sequence = ()
		
		text_list.append(len(msg.strip()))
		
		for i in msg.strip():
   			text_list.append(ord(i))
   		
   		sequence = self.text_start_sequence + tuple(text_list) + self.text_end_sequence
		
		self._send_midi(sequence)

	def suggest_input_port(self):
		return "OP-1 Midi Device"

	def suggest_output_port(self):
		return "OP-1 Midi Device"

	def update_display_perform_mode(self):
		self.write_text("perform\rmode")

	def reset_display_clips(self):
		count = 0
		colors = []
		length = []
		sequence = ()
		
		for i in range (NUM_TRACKS):
			count+=1

			colors.append(0x00)
			colors.append(0x00)
			colors.append(0x00)

		length.append(count)
		sequence = self.text_color_start_sequence + tuple(length) + tuple(colors) + self.text_end_sequence
		self._send_midi(sequence)

	def update_display_clips(self):
		#self.log("UPDATING DISPLAY CLIPS")
		count = 0
		colors = []
		length = []
		sequence = ()
		
		tracks_len = len(self.song().tracks)-self._session._track_offset

		if (tracks_len>NUM_TRACKS):
			tracks_len = NUM_TRACKS

		for i in range (tracks_len):
			count+=1

			clip_slot = self._session.scene(0).clip_slot(i)
			
			if (clip_slot!=None):
				if (clip_slot.has_clip()!=False):
					clip_color = clip_slot._clip_slot.clip.color
					colors.append(((clip_color>>16)&0x000000ff)>>1)
					colors.append(((clip_color>>8)&0x000000ff)>>1)
					colors.append((clip_color&0x000000ff)>>1)
				else:
					colors.append(0x00)
					colors.append(0x00)
					colors.append(0x00)
			else:
				colors.append(0x00)
				colors.append(0x00)
				colors.append(0x00)

		length.append(count)
		sequence = self.text_color_start_sequence + tuple(length) + tuple(colors) + self.text_end_sequence
		self._send_midi(sequence)

	def update_display_clip_mode(self):
		self.write_text("sel. scene\r" + str(self.song().view.selected_scene.name.lower().strip()))

	def update_display_transport_mode(self):
		song_time = str(self.song().get_current_beats_song_time())
		self.write_text("song pos.\r" + song_time[:len(song_time)-4])

	def update_display_mixer_mode(self):
		self.write_text("sel. track\r" + str(self.song().view.selected_track.name.lower()))

	def update_display(self):
		if not(self.device_connected):
			if (self.retries_count<5):
				self.log("TRYING OP-1 CONNECTION")
				self.retries_count+=1
				self._send_midi(self.id_sequence)
				time.sleep(1)

		# if in transport mode, update display with song position
		if (self._operation_mode_selector.mode_index==OP1_MODE_TRANSPORT):
			self.update_display_transport_mode()

		# checking if app current view is session
		if (self.app.view.is_view_visible("Session")):
			# checking if session browser state is diferent from the internal
			if (self.session_browser_visible != self.app.view.is_view_visible("Browser")):
				self.session_browser_visible = self.app.view.is_view_visible("Browser")

		# checking if app current view is arrange
		if (self.app.view.is_view_visible("Arranger")):
			# checking if arrange browser state is diferent from the internal
			if (self.arrange_browser_visible != self.app.view.is_view_visible("Browser")):
				self.arrange_browser_visible = self.app.view.is_view_visible("Browser")

		# checking if app current view is detail
		if (self.app.view.is_view_visible("Detail")):
			# checking if detail state is diferent from the internal
			if (self.detail_visible != self.app.view.is_view_visible("Detail")):
				self.detail_visible = self.app.view.is_view_visible("Detail")

	def refresh_state(self):
		self.log("REFRESH STATE")
		self.retries_count = 0
		self.device_connected = False

	def build_midi_map(self, midi_map_handle):
		#self.log("BUILD MIDI MAP")

		assert (self._suppress_requests_counter == 0)
		self._in_build_midi_map = True
		self._midi_map_handle = midi_map_handle
		self._forwarding_registry = {}
		for control in self.controls:
			if isinstance(control, InputControlElement):
				control.install_connections()
		self._midi_map_handle = None
		self._in_build_midi_map = False
		if (self._pad_translations != None):
			self._c_instance.set_pad_translation(self._pad_translations)

		# remove clip listeners
		self.rem_clip_slot_listeners()
		
		# add clip listeners
		self.add_clip_slot_listeners()
		
		# update display
		self.update_display_clips()
		
	def log(self, msg):
		self.c_instance.log_message("[TE OP-1] " + msg)

	def disconnect(self):
		# removing clip slots listeners
		self.rem_clip_slot_listeners()

		# removing value listener for track changed
		self.song().view.remove_selected_track_listener(self.selected_track_changed)

		# removing value listener for scene changed
		self.song().view.remove_selected_scene_listener(self.selected_scene_changed)

		# removing value listener for operation mode index
		self._operation_mode_selector.remove_mode_index_listener(self.mode_index_changed)

		# removing global transport assignments
		self._transport.set_punch_buttons(None, None)
		self._transport.set_loop_button(None)
		self._transport.set_overdub_button(None)
		self._transport.set_record_button(None)
		self._transport.set_play_button(None)
		self._transport.set_stop_button(None)  
		self._transport.set_metronome_button(None)  
		self._transport.set_tap_tempo_button(None)

		# removing global session assignments
		self._session.set_scene_bank_buttons(None, None)
		
		# removing misc listeners
		self.browser_toggle_button.remove_value_listener(self.browser_toggle_button_callback)
		self.mainview_toggle_button.remove_value_listener(self.mainview_toggle_button_callback)
		self.detailview_toggle_button.remove_value_listener(self.detailview_toggle_button_callback)
		self.clear_track_button.remove_value_listener(self.clear_track_button_callback)
		self.back_to_arranger_button.remove_value_listener(self.back_to_arranger_button_callback)
		
		# sending special ableton mode disable sequence
		self._send_midi(self.disable_sequence)
		
		# disconnecting control surface
		ControlSurface.disconnect(self)
		
		self.log("DISCONNECTED")
 def add_value_listener(self, callback, identify_sender=False):
     if not self._is_notifying:
         ButtonElement.add_value_listener(self, callback, identify_sender)
     else:
         self._pending_listeners.append((callback, identify_sender))
	def add_value_listener(self, callback, identify_sender = False):
		if (not self._is_notifying):
			ButtonElement.add_value_listener(self, callback, identify_sender)
		else:
			self._pending_listeners.append((callback,
			 identify_sender))
示例#52
0
class Launchpad(ControlSurface):
    " SCRIPT FOR NOVATION'S LAUNCHPAD CONTROLLER "

    " INITALIZE "

    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
            #self.set_suppress_rebuild_requests(True)
            self._suppress_send_midi = True
            self._suppress_session_highlight = True
            is_momentary = True
            self._suggested_input_port = "Launchpad"
            self._suggested_output_port = "Launchpad"
            self._control_is_with_automap = False
            self._user_byte_write_button = ButtonElement(
                is_momentary, MIDI_CC_TYPE, 0, 16)
            self._user_byte_write_button.name = "User_Byte_Button"
            self._user_byte_write_button.send_value(1)
            self._user_byte_write_button.add_value_listener(
                self._user_byte_value)
            self._wrote_user_byte = False
            self._challenge = (Live.Application.get_random_int(0, 400000000)
                               & 2139062143)
            matrix = ButtonMatrixElement()
            matrix.name = "Button_Matrix"
            """ TRACKFINDER TEST 
			track_index = 0
			for track in self.song().tracks:
				if track_index < 8:
					button_row = []			
					if track.is_foldable:
						for column in range(8):	
							log("right one: " + str(track_index))		
							button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, ((track_index * 16) + column)) #@UndefinedVariable
							button.name = (((str(column) + "_Clip_") + str(track_index)) + "_Button")
							button_row.append(button)
						track_index = track_index + 1
					else:
						for column in range(8):
							log("wrong one: " + str(track_index))
							button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 99, True) #@UndefinedVariable
							button.name = (str(column) + "_Clip_Button-DUMMY")
							button_row.append(button)
					matrix.add_row(tuple(button_row))
			log("done")"""
            """ ORIGINAL CODE """
            for row in range(8):
                button_row = []
                for column in range(8):
                    button = ConfigurableButtonElement(is_momentary,
                                                       MIDI_NOTE_TYPE, 0,
                                                       ((row * 16) + column))
                    button.name = (((str(column) + "_Clip_") + str(row)) +
                                   "_Button")
                    button_row.append(button)
                matrix.add_row(tuple(button_row))

            self._config_button = ButtonElement(is_momentary,
                                                MIDI_CC_TYPE,
                                                0,
                                                0,
                                                optimized_send_midi=False)
            self._config_button.add_value_listener(self._config_value)
            top_buttons = [
                ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0,
                                          (104 + index)) for index in range(8)
            ]
            side_buttons = [
                ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0,
                                          SIDE_NOTES[index])
                for index in range(8)
            ]
            top_buttons[0].name = "Bank_Select_Up_Button"
            top_buttons[1].name = "Bank_Select_Down_Button"
            top_buttons[2].name = "Bank_Select_Left_Button"
            top_buttons[3].name = "Bank_Select_Right_Button"
            top_buttons[4].name = "Session_Button"
            top_buttons[5].name = "User1_Button"
            top_buttons[6].name = "User2_Button"
            top_buttons[7].name = "Mixer_Button"
            side_buttons[0].name = "Vol_Button"
            side_buttons[1].name = "Pan_Button"
            side_buttons[2].name = "SndA_Button"
            side_buttons[3].name = "SndB_Button"
            side_buttons[4].name = "Stop_Button"
            side_buttons[5].name = "Trk_On_Button"
            side_buttons[6].name = "Solo_Button"
            side_buttons[7].name = "Arm_Button"
            self._selector = MainSelectorComponent(matrix, tuple(top_buttons),
                                                   tuple(side_buttons),
                                                   self._config_button)
            self._selector.name = "Main_Modes"
            for control in self.controls:
                if isinstance(control, ConfigurableButtonElement):
                    control.add_value_listener(self._button_value)
            self.set_highlighting_session_component(
                self._selector.session_component())
            self._suppress_session_highlight = False
            #self.set_suppress_rebuild_requests(False)

    " DISCONNECTOR "

    def disconnect(self):
        self._suppress_send_midi = True
        for control in self.controls:
            if isinstance(control, ConfigurableButtonElement):
                control.remove_value_listener(self._button_value)
        self._selector = None
        self._user_byte_write_button.remove_value_listener(
            self._user_byte_value)
        self._config_button.remove_value_listener(self._config_value)
        ControlSurface.disconnect(self)
        self._suppress_send_midi = False
        self._config_button.send_value(32)
        self._config_button.send_value(0)
        self._config_button = None
        self._user_byte_write_button.send_value(0)
        self._user_byte_write_button = None

    " RETURN THE SESSION COMPONENT SHOWING THE RING IN LIVE SESSION "

    def highlighting_session_component(self):
        return self._selector.session_component()

    " REFRESH "

    def refresh_state(self):
        ControlSurface.refresh_state(self)
        self.schedule_message(5, self._update_hardware)

    " SYSEX HANDLING "

    def handle_sysex(self, midi_bytes):
        if (len(midi_bytes) == 8):
            if (midi_bytes[1:5] == (0, 32, 41, 6)):
                response = long(midi_bytes[5])
                response += (long(midi_bytes[6]) << 8)
                if (response == Live.Application.encrypt_challenge2(
                        self._challenge)):
                    self._suppress_send_midi = False
                    self.set_enabled(True)

    " MIDI MAP "

    def build_midi_map(self, midi_map_handle):
        ControlSurface.build_midi_map(self, midi_map_handle)
        if (self._selector.mode_index == 1):
            new_channel = self._selector.channel_for_current_mode()
            for note in DRUM_NOTES:
                self._translate_message(MIDI_NOTE_TYPE, note, 0, note,
                                        new_channel)

    " SEND THE MIDI STUFF "

    def _send_midi(self, midi_bytes, optimized=None):
        sent_successfully = False
        if (not self._suppress_send_midi):
            sent_successfully = ControlSurface._send_midi(self,
                                                          midi_bytes,
                                                          optimized=optimized)
        return sent_successfully

    " UPDATE THE HARDWARE "

    def _update_hardware(self):
        self._suppress_send_midi = False
        self._wrote_user_byte = True
        self._user_byte_write_button.send_value(1)
        self._suppress_send_midi = True
        self.set_enabled(False)
        self._suppress_send_midi = False
        self._send_challenge()

    " CHALLANGE SEND "

    def _send_challenge(self):
        for index in range(4):
            challenge_byte = ((self._challenge >> (8 * index)) & 127)
            self._send_midi((176, (17 + index), challenge_byte))

    " USER BYTE STUFF "

    def _user_byte_value(self, value):
        if not value in range(128):
            raise AssertionError
            enabled = self._wrote_user_byte or value == 1
            self._control_is_with_automap = not enabled
            self._suppress_send_midi = self._control_is_with_automap
            if not self._control_is_with_automap:
                for control in self.controls:
                    if isinstance(control, ConfigurableButtonElement):
                        control.set_force_next_value()
            self._selector.set_mode(0)
            self.set_enabled(enabled)
            self._suppress_send_midi = False
        else:
            self._wrote_user_byte = False

    " BUTTON VALUE "

    def _button_value(self, value):
        assert (value in range(128))

    " CONFIG VALUE "

    def _config_value(self, value):
        assert (value in range(128))

    " SET THE SESSION HIGHLIGHT "

    def _set_session_highlight(self, track_offset, scene_offset, width, height,
                               include_return_tracks):
        if (not self._suppress_session_highlight):
            ControlSurface._set_session_highlight(self, track_offset,
                                                  scene_offset, width, height,
                                                  include_return_tracks)
示例#53
0
class NoteRepeatComponent(CompoundComponent):
    """ Noter Repeat Handler"""
    __module__ = __name__
    _knob_handler = None

    def __init__(self, note_repeat=None, *a, **k):
        super(NoteRepeatComponent, self).__init__(*a, **k)
        self._note_repeat = note_repeat
        self._adjust_cfg_value.subject = SliderElement(MIDI_CC_TYPE, 2, 105)
        self._note_repeat_button = ButtonElement(True, MIDI_CC_TYPE, 0, 102)
        self._do_note_repeat.subject = self._note_repeat_button
        self._cfg_adjust_button = ButtonElement(True, MIDI_CC_TYPE, 2, 106)
        self._cfg_adjust_button.add_value_listener(self._do_cfg_button)
        self._cfg_down = False
        self._hold_mode = False
        self.nr_down = False
        self._current_nr_button = None
        self._do_change_nr_1.subject = SliderElement(MIDI_CC_TYPE, 1, 76)
        self._do_change_nr_2.subject = SliderElement(MIDI_CC_TYPE, 1, 77)
        self._do_change_nr_3.subject = SliderElement(MIDI_CC_TYPE, 1, 78)
        self._do_change_nr_4.subject = SliderElement(MIDI_CC_TYPE, 1, 79)

        def createButton(ccindenfier, nr_freq):
            button = ButtonElement(True, MIDI_CC_TYPE, 1, ccindenfier)
            button.add_value_listener(self._select_value, True)
            button.active = False
            button.freq = nr_freq
            button.cfg = False
            button.hold = False
            return button

        def createCfgButton(ccindenfier, nr_freq_idx):
            button = ButtonElement(True, MIDI_CC_TYPE, 2, ccindenfier)
            button.add_value_listener(self._select_value, True)
            button.active = False
            button.fr_idx = nr_freq_idx
            button.freq = CFG_REPEAT_FREQUENCIES[nr_freq_idx]
            button.cfg = True
            button.hold = False
            return button

        self._cfg_buttons = [
            createCfgButton(assign[0], assign[1])
            for assign in CTRL_CFG_TO_FREQ
        ]
        for button in self._cfg_buttons:
            button.send_value(button.active and 1 or 0, True)

        self.nr_frq = CTRL_TO_FREQ[4][1]
        self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0
        self.buttons = [
            createButton(assign[0], assign[1]) for assign in CTRL_TO_FREQ
        ]
        self.buttons[4].active = True
        self._previous_button = self.buttons[4]
        self._last_active_button = self.buttons[4]
        for button in self.buttons:
            button.send_value(button.active and 1 or 0, True)

        return

    def update(self):
        pass

    def store_values(self, dict):
        for button, idx in zip(self._cfg_buttons,
                               range(len(self._cfg_buttons))):
            dict['cofig-nr-val' + str(idx)] = button.fr_idx

    def recall_values(self, dict):
        for button, idx in zip(self._cfg_buttons,
                               range(len(self._cfg_buttons))):
            key = 'cofig-nr-val' + str(idx)
            if key in dict:
                fqidx = dict[key]
                button.fr_idx = fqidx
                button.freq = CFG_REPEAT_FREQUENCIES[fqidx]

    def registerKnobHandler(self, handler):
        self._knob_handler = handler

    def show_note_rates(self):
        rates = ''
        for button, idx in zip(self._cfg_buttons,
                               range(len(self._cfg_buttons))):
            rates += ' ' + CFG_REPEAT_DISPLAY[button.fr_idx].ljust(5)
            if idx < 3:
                rates += '|'

        self.canonical_parent.timed_message(2, rates)

    def mod_button(self, button, inc, which):
        cindex = button.fr_idx
        maxindex = len(CFG_REPEAT_FREQUENCIES) - 1
        minindex = 0
        if self.canonical_parent.isShiftDown():
            inc *= 2
            maxindex = cindex % 2 == 0 and maxindex or maxindex - 1
            minindex = cindex % 2
        new_idx = max(minindex, min(maxindex, cindex + inc))
        if new_idx != cindex:
            self.canonical_parent.show_message('Note Repeat Button ' +
                                               str(which) + ' : ' +
                                               CFG_REPEAT_DISPLAY[new_idx])
            button.fr_idx = new_idx
            button.freq = CFG_REPEAT_FREQUENCIES[new_idx]
            if button.active:
                self.nr_frq = CFG_REPEAT_FREQUENCIES[new_idx]
                self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0

    @subject_slot('value')
    def _do_change_nr_1(self, value):
        self.mod_button(self._cfg_buttons[0], value == REL_KNOB_DOWN and -1
                        or 1, 1)
        self.show_note_rates()

    @subject_slot('value')
    def _do_change_nr_2(self, value):
        self.mod_button(self._cfg_buttons[1], value == REL_KNOB_DOWN and -1
                        or 1, 2)
        self.show_note_rates()

    @subject_slot('value')
    def _do_change_nr_3(self, value):
        self.mod_button(self._cfg_buttons[2], value == REL_KNOB_DOWN and -1
                        or 1, 3)
        self.show_note_rates()

    @subject_slot('value')
    def _do_change_nr_4(self, value):
        self.mod_button(self._cfg_buttons[3], value == REL_KNOB_DOWN and -1
                        or 1, 4)
        self.show_note_rates()

    def _do_cfg_button(self, value):
        if value != 0:
            self._cfg_down = True
            button = self._current_nr_button
            if button and button.cfg and button.fr_idx >= 0:
                self.canonical_parent.show_message(
                    'Note Repeat ' + CFG_REPEAT_DISPLAY[button.fr_idx])
        else:
            self._cfg_down = False
        if self._knob_handler:
            self._knob_handler.do_main_push(value)

    @subject_slot('value')
    def _adjust_cfg_value(self, value):
        button = self._current_nr_button
        if button and button.cfg and (self.nr_down or button.hold
                                      or self._hold_mode and button.active):
            inc = value == 127 and -1 or 1
            cindex = button.fr_idx
            maxindex = len(CFG_REPEAT_FREQUENCIES) - 1
            minindex = 0
            if self._cfg_down:
                inc *= 2
                maxindex = cindex % 2 == 0 and maxindex or maxindex - 1
                minindex = cindex % 2
            new_idx = max(minindex, min(maxindex, cindex + inc))
            self.canonical_parent.show_message('Note Repeat ' +
                                               CFG_REPEAT_DISPLAY[new_idx])
            button.fr_idx = new_idx
            button.freq = CFG_REPEAT_FREQUENCIES[new_idx]
            self.nr_frq = CFG_REPEAT_FREQUENCIES[new_idx]
            self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0
        else:
            if self._knob_handler:
                self._knob_handler.do_main(value)

    def _select_value(self, value, button):
        if value != 0:
            self._current_nr_button = button
            button.hold = True
            self.show_note_rates()
            if self._hold_mode:
                if self._previous_button == button:
                    button.send_value(0, True)
                    button.active = False
                    self._last_active_button = button
                    button.active = False
                    self._note_repeat.repeat_rate = 32.0
                    self._previous_button = None
                elif self._previous_button == None or self._previous_button != button:
                    button.send_value(1, True)
                    button.active = True
                    self.nr_frq = button.freq
                    self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0
                    if not self._note_repeat.enabled:
                        self._note_repeat.enabled = True
                    if self._previous_button != None:
                        self._previous_button.active = False
                        self._previous_button.send_value(0, True)
                    self._previous_button = button
            else:
                button.send_value(1, True)
                button.active = True
                self.nr_frq = button.freq
                self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0
                if self._previous_button != None and self._previous_button != button:
                    self._previous_button.active = False
                    self._previous_button.send_value(0, True)
                self._previous_button = button
        else:
            button.hold = False
        return

    @subject_slot('value')
    def _do_note_repeat(self, value):
        self.nr_down = value > 0
        if self._hold_mode:
            if value > 0:
                self._note_repeat_button.send_value(0)
                self._note_repeat.enabled = False
                self._hold_mode = False
                if self._previous_button == None and self._last_active_button != None:
                    self._previous_button = self._last_active_button
                    self._last_active_button.send_value(1)
                    self._last_active_button.active = True
                    self.nr_frq = self._last_active_button.freq
                    self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0
        else:
            if self.canonical_parent.isShiftDown() and value > 0:
                self._note_repeat_button.send_value(1)
                self._note_repeat.enabled = True
                self._hold_mode = True
                self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0
            else:
                if value == 0:
                    self._note_repeat.enabled = False
                    self._note_repeat_button.send_value(0)
                else:
                    self._note_repeat_button.send_value(1)
                    self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0
                    self._note_repeat.enabled = True
        return

    def disconnect(self):
        super(NoteRepeatComponent, self).disconnect()
示例#54
0
class joyMIDI(ControlSurface):
    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
            self.setup_transport()
            self.setup_mixer()
            self.setup_session()

    def setup_transport(self):
        # elements
        self.play_button = ButtonElement(True, MIDI_NOTE_TYPE, 0, 93)
        self.stop_button = ButtonElement(True, MIDI_NOTE_TYPE, 0, 94)
        self.record_button = ButtonElement(True, MIDI_NOTE_TYPE, 0, 95)
        # transport
        self.transport = TransportComponent()
        self.transport.set_play_button(self.play_button)
        self.transport.set_stop_button(self.stop_button)
        self.transport.set_record_button(self.record_button)

    def setup_mixer(self):
        # elements
        self.mute_button = ButtonElement(True, MIDI_NOTE_TYPE, 0,
                                         92)  # tracks, return_tracks
        self.solo_button = ButtonElement(True, MIDI_NOTE_TYPE, 0,
                                         84)  # tracks, return_tracks
        self.arm_button = ButtonElement(True, MIDI_NOTE_TYPE, 0, 85)  # tracks
        self.senda_up_button = ButtonElement(True, MIDI_NOTE_TYPE, 0,
                                             96)  # tracks, return_tracks
        self.senda_down_button = ButtonElement(True, MIDI_NOTE_TYPE, 0,
                                               88)  # tracks, return_tracks
        self.sendb_up_button = ButtonElement(True, MIDI_NOTE_TYPE, 0,
                                             97)  # tracks, return_tracks
        self.sendb_down_button = ButtonElement(True, MIDI_NOTE_TYPE, 0,
                                               89)  # tracks, return_tracks
        self.pan_up_button = ButtonElement(
            True, MIDI_NOTE_TYPE, 0, 98)  # tracks, return_tracks, master_track
        self.pan_down_button = ButtonElement(
            True, MIDI_NOTE_TYPE, 0, 90)  # tracks, return_tracks, master_track
        self.volume_up_button = ButtonElement(
            True, MIDI_NOTE_TYPE, 0, 99)  # tracks, return_tracks, master_track
        self.volume_down_button = ButtonElement(
            True, MIDI_NOTE_TYPE, 0, 91)  # tracks, return_tracks, master_track
        self.track_nav_encoder = EncoderElement(
            MIDI_CC_TYPE, 0, 14, Live.MidiMap.MapMode.relative_binary_offset)
        # mixer
        self.mixer = MixerComponent(7, 2)
        self.mixer.selected_strip().set_mute_button(self.mute_button)
        self.mixer.selected_strip().set_solo_button(self.solo_button)
        self.mixer.selected_strip().set_arm_button(self.arm_button)
        # send A/B, pan, volume
        self.senda_up_button.add_value_listener(self.on_senda_up_changed)
        self.senda_down_button.add_value_listener(self.on_senda_down_changed)
        self.sendb_up_button.add_value_listener(self.on_sendb_up_changed)
        self.sendb_down_button.add_value_listener(self.on_sendb_down_changed)
        self.pan_up_button.add_value_listener(self.on_pan_up_changed)
        self.pan_down_button.add_value_listener(self.on_pan_down_changed)
        self.volume_up_button.add_value_listener(self.on_volume_up_changed)
        self.volume_down_button.add_value_listener(self.on_volume_down_changed)
        # nav
        self.track_nav_encoder.add_value_listener(self.on_mixer_track_nav)

    def on_senda_up_changed(self, value):
        if value > 0:
            param = self.song().view.selected_track.mixer_device.sends[0]
            param.value = max(
                param.min,
                min(param.max,
                    param.value + ((param.max - param.min) / SEND_STEPS)))

    def on_senda_down_changed(self, value):
        if value > 0:
            param = self.song().view.selected_track.mixer_device.sends[0]
            param.value = max(
                param.min,
                min(param.max,
                    param.value - ((param.max - param.min) / SEND_STEPS)))

    def on_sendb_up_changed(self, value):
        if value > 0:
            param = self.song().view.selected_track.mixer_device.sends[1]
            param.value = max(
                param.min,
                min(param.max,
                    param.value + ((param.max - param.min) / SEND_STEPS)))

    def on_sendb_down_changed(self, value):
        if value > 0:
            param = self.song().view.selected_track.mixer_device.sends[1]
            param.value = max(
                param.min,
                min(param.max,
                    param.value - ((param.max - param.min) / SEND_STEPS)))

    def on_pan_up_changed(self, value):
        if value > 0:
            param = self.song().view.selected_track.mixer_device.panning
            param.value = max(
                param.min,
                min(param.max,
                    param.value + ((param.max - param.min) / PAN_STEPS)))

    def on_pan_down_changed(self, value):
        if value > 0:
            param = self.song().view.selected_track.mixer_device.panning
            param.value = max(
                param.min,
                min(param.max,
                    param.value - ((param.max - param.min) / PAN_STEPS)))

    def on_volume_up_changed(self, value):
        if value > 0:
            param = self.song().view.selected_track.mixer_device.volume
            param.value = max(
                param.min,
                min(param.max,
                    param.value + ((param.max - param.min) / VOLUME_STEPS)))

    def on_volume_down_changed(self, value):
        if value > 0:
            param = self.song().view.selected_track.mixer_device.volume
            param.value = max(
                param.min,
                min(param.max,
                    param.value - ((param.max - param.min) / VOLUME_STEPS)))

    def on_mixer_track_nav(self, value):
        move = -1 if value > 64 else +1
        # get tracks-info
        tracks = self.song().tracks
        return_tracks = self.song().return_tracks
        master_track = self.song().master_track
        all_tracks = list(chain(tracks, return_tracks))
        all_tracks.append(master_track)
        num_tracks = len(tracks)
        num_return_tracks = len(return_tracks)
        num_master_track = 1
        num_all_tracks = num_tracks + num_return_tracks + num_master_track
        # update selected-track
        index = index_if(lambda t: t == self.song().view.selected_track,
                         all_tracks)
        index += move
        index = min(max(index, 0), num_all_tracks - 1)
        self.song().view.selected_track = all_tracks[index]

    def setup_session(self):
        num_tracks = 7
        num_scenes = 1
        track_offset = 0
        scene_offset = 0
        # elements
        self.clip_launch_buttons = ButtonMatrixElement(rows=[[
            ButtonElement(True, MIDI_NOTE_TYPE, 0, 76 + i)
            for i in range(num_tracks)
        ]])
        self.clip_stop_buttons = [
            ButtonElement(True, MIDI_NOTE_TYPE, 0, 68 + i)
            for i in range(num_tracks)
        ]
        self.scene_launch_buttons = ButtonMatrixElement(rows=[[
            ButtonElement(True, MIDI_NOTE_TYPE, 0, 83 + i)
            for i in range(num_scenes)
        ]])
        self.scene_stop_button = ButtonElement(True, MIDI_NOTE_TYPE, 0, 75)
        self.session_scene_nav_encoder = EncoderElement(
            MIDI_CC_TYPE, 0, 15, Live.MidiMap.MapMode.relative_binary_offset)
        # session
        self.session = SessionComponent(num_tracks, num_scenes)
        self.session.set_offsets(track_offset, scene_offset)
        self.session.add_offset_listener(self.on_session_offset_changed)
        self.set_highlighting_session_component(self.session)
        # clips
        self.session.set_clip_launch_buttons(self.clip_launch_buttons)
        self.session.set_stop_track_clip_buttons(self.clip_stop_buttons)
        self.session.set_scene_launch_buttons(self.scene_launch_buttons)
        self.session.set_stop_all_clips_button(self.scene_stop_button)
        # nav
        self.session_scene_nav_encoder.add_value_listener(
            self.on_session_scene_nav)

    def on_session_offset_changed(self):
        pass

    def on_session_scene_nav(self, value):
        value -= 64
        value = -value
        track_offset = self.session.track_offset()
        scene_offset = max(0, self.session.scene_offset() + value)
        self.session.set_offsets(track_offset, scene_offset)

    def disconnect(self):
        u"""Live -> Script
        Called right before we get disconnected from Live.
        """
        self.log_message('disconnect')
        self.show_message('disconnect')
示例#55
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()
示例#56
0
class Launchpad(ControlSurface):
	" Script for Novation's Launchpad Controller "

	def __init__(self, c_instance):
		ControlSurface.__init__(self, c_instance)
		self.set_suppress_rebuild_requests(True)
		self._suppress_send_midi = True
		self._suppress_session_highlight = True
		is_momentary = True
		self._suggested_input_port = "Launchpad"
		self._suggested_output_port = "Launchpad"
		self._control_is_with_automap = False
		self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)
		self._user_byte_write_button.name = "User_Byte_Button"
		self._user_byte_write_button.send_value(1)
		self._user_byte_write_button.add_value_listener(self._user_byte_value)
		self._wrote_user_byte = False
		self._challenge = (Live.Application.get_random_int(0, 400000000) & 2139062143)
		matrix = ButtonMatrixElement()
		matrix.name = "Button_Matrix"
		for row in range(8):
			button_row = []
			for column in range(8):
				button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, ((row * 16) + column))
				button.name = (((str(column) + "_Clip_") + str(row)) + "_Button")
				button_row.append(button)

			matrix.add_row(tuple(button_row))

		self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0)
		self._config_button.add_value_listener(self._config_value)
		top_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0, (104 + index)) for index in range(8) ]
		side_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index]) for index in range(8) ]
		top_buttons[0].name = "Bank_Select_Up_Button"
		top_buttons[1].name = "Bank_Select_Down_Button"
		top_buttons[2].name = "Bank_Select_Left_Button"
		top_buttons[3].name = "Bank_Select_Right_Button"
		top_buttons[4].name = "Session_Button"
		top_buttons[5].name = "User1_Button"
		top_buttons[6].name = "User2_Button"
		top_buttons[7].name = "Mixer_Button"
		side_buttons[0].name = "Vol_Button"
		side_buttons[1].name = "Pan_Button"
		side_buttons[2].name = "SndA_Button"
		side_buttons[3].name = "SndB_Button"
		side_buttons[4].name = "Stop_Button"
		side_buttons[5].name = "Trk_On_Button"
		side_buttons[6].name = "Solo_Button"
		side_buttons[7].name = "Arm_Button"
		self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button, self)
		self._selector.name = "Main_Modes"
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.add_value_listener(self._button_value)

		self._suppress_session_highlight = False
		self.set_suppress_rebuild_requests(False)

		self.log_message("LaunchPad85 Loaded !")

	def disconnect(self):
		self._suppress_send_midi = True
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.remove_value_listener(self._button_value)

		self._selector = None
		self._user_byte_write_button.remove_value_listener(self._user_byte_value)
		self._config_button.remove_value_listener(self._config_value)
		ControlSurface.disconnect(self)
		self._suppress_send_midi = False
		self._config_button.send_value(32)
		self._config_button.send_value(0)
		self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None



	def highlighting_session_component(self):
		" Return the session component showing the ring in Live session "
		return self._selector.session_component()



	def refresh_state(self):
		ControlSurface.refresh_state(self)
		self.schedule_message(5, self._update_hardware)



	def handle_sysex(self, midi_bytes):
		if (len(midi_bytes) == 8):
			if (midi_bytes[1:5] == (0, 32, 41, 6)):
				response = long(midi_bytes[5])
				response += (long(midi_bytes[6]) << 8)
				if (response == Live.Application.encrypt_challenge2(self._challenge)):
					self._suppress_send_midi = False
					self.set_enabled(True)



	def build_midi_map(self, midi_map_handle):
		ControlSurface.build_midi_map(self, midi_map_handle)
		if (self._selector.mode_index == 1):
			new_channel = self._selector.channel_for_current_mode()
			for note in DRUM_NOTES:
				self._translate_message(MIDI_NOTE_TYPE, note, 0, note, new_channel)




	def _send_midi(self, midi_bytes):
		sent_successfully = False
		if (not self._suppress_send_midi):
			sent_successfully = ControlSurface._send_midi(self, midi_bytes)
		return sent_successfully



	def _update_hardware(self):
		self._suppress_send_midi = False
		self._wrote_user_byte = True
		self._user_byte_write_button.send_value(1)
		self._suppress_send_midi = True
		self.set_enabled(False)
		self._suppress_send_midi = False
		self._send_challenge()



	def _send_challenge(self):
		for index in range(4):
			challenge_byte = ((self._challenge >> (8 * index)) & 127)
			self._send_midi((176,
			 (17 + index),
			 challenge_byte))




	def _user_byte_value(self, value):
		assert (value in range(128))
		if (not self._wrote_user_byte):
			enabled = (value == 1)
			self._control_is_with_automap = (not enabled)
			self._suppress_send_midi = self._control_is_with_automap
			if (not self._control_is_with_automap):
				for control in self.controls:
					if isinstance(control, ConfigurableButtonElement):
						control.set_force_next_value()

			self._selector.set_mode(0)
			self.set_enabled(enabled)
			self._suppress_send_midi = False
		else:
			self._wrote_user_byte = False



	def _button_value(self, value):
		assert (value in range(128))



	def _config_value(self, value):
		assert (value in range(128))



	def _set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks):
		if (not self._suppress_session_highlight):
			ControlSurface._set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks)