예제 #1
0
class MiniLab(ArturiaControlSurface):
    session_component_type = SessionComponent
    encoder_msg_channel = 0
    encoder_msg_ids = (7, 74, 71, 76, 77, 93, 73, 75, 114, 18, 19, 16, 17, 91, 79, 72)
    pad_channel = 9

    def __init__(self, *a, **k):
        super(MiniLab, self).__init__(*a, **k)
        with self.component_guard():
            self._create_controls()
            self._create_device()
            self._create_session()
            self._create_mixer()

    def _create_controls(self):
        self._device_controls = ButtonMatrixElement(rows=[ [ EncoderElement(MIDI_CC_TYPE, self.encoder_msg_channel, identifier, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Encoder_%d_%d' % (column_index, row_index)) for column_index, identifier in enumerate(row) ] for row_index, row in enumerate((self.encoder_msg_ids[:4], self.encoder_msg_ids[8:12])) ])
        self._horizontal_scroll_encoder = EncoderElement(MIDI_CC_TYPE, self.encoder_msg_channel, self.encoder_msg_ids[7], Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Horizontal_Scroll_Encoder')
        self._vertical_scroll_encoder = EncoderElement(MIDI_CC_TYPE, self.encoder_msg_channel, self.encoder_msg_ids[15], Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Vertical_Scroll_Encoder')
        self._volume_encoder = EncoderElement(MIDI_CC_TYPE, self.encoder_msg_channel, self.encoder_msg_ids[13], Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Volume_Encoder')
        self._pan_encoder = EncoderElement(MIDI_CC_TYPE, self.encoder_msg_channel, self.encoder_msg_ids[12], Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Pan_Encoder')
        self._send_a_encoder = EncoderElement(MIDI_CC_TYPE, self.encoder_msg_channel, self.encoder_msg_ids[4], Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Send_A_Encoder')
        self._send_b_encoder = EncoderElement(MIDI_CC_TYPE, self.encoder_msg_channel, self.encoder_msg_ids[5], Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Send_B_Encoder')
        self._send_encoders = ButtonMatrixElement(rows=[[self._send_a_encoder, self._send_b_encoder]])
        self._return_a_encoder = EncoderElement(MIDI_CC_TYPE, self.encoder_msg_channel, self.encoder_msg_ids[6], Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Return_A_Encoder')
        self._return_b_encoder = EncoderElement(MIDI_CC_TYPE, self.encoder_msg_channel, self.encoder_msg_ids[14], Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Return_B_Encoder')
        self._return_encoders = ButtonMatrixElement(rows=[[self._return_a_encoder, self._return_b_encoder]])
        self._pads = ButtonMatrixElement(rows=[ [ ButtonElement(True, MIDI_NOTE_TYPE, self.pad_channel, col + 36 + 8 * row, name='Pad_%d_%d' % (col, row)) for col in xrange(8) ] for row in xrange(2) ])

    def _create_device(self):
        self._device = DeviceComponent(name='Device', is_enabled=False, layer=Layer(parameter_controls=self._device_controls), device_selection_follows_track_selection=True)
        self._device.set_enabled(True)
        self.set_device_component(self._device)

    def _create_session(self):
        self._session = self.session_component_type(num_tracks=self._pads.width(), num_scenes=self._pads.height(), name='Session', is_enabled=False, layer=Layer(clip_launch_buttons=self._pads, scene_select_control=self._vertical_scroll_encoder))
        self._session.set_enabled(True)

    def _create_mixer(self):
        self._mixer = MixerComponent(name='Mixer', is_enabled=False, num_returns=2, layer=Layer(track_select_encoder=self._horizontal_scroll_encoder, selected_track_volume_control=self._volume_encoder, selected_track_pan_control=self._pan_encoder, selected_track_send_controls=self._send_encoders, return_volume_controls=self._return_encoders))
        self._mixer.set_enabled(True)

    def _collect_setup_messages(self):
        for cc_id, encoder_id in izip(self.encoder_msg_ids, HARDWARE_ENCODER_IDS):
            self._setup_hardware_encoder(encoder_id, cc_id, channel=self.encoder_msg_channel)

        for index, pad_id in enumerate(HARDWARE_BUTTON_IDS):
            self._setup_hardware_button(pad_id, index + PAD_IDENTIFIER_OFFSET, self.pad_channel)
class MiniLab(ArturiaControlSurface):

    def __init__(self, *a, **k):
        super(MiniLab, self).__init__(*a, **k)
        with self.component_guard():
            self._create_controls()
            self._create_device()
            self._create_session()
            self._create_mixer()

    def _create_controls(self):
        self._device_controls = ButtonMatrixElement(rows=[ [ EncoderElement(MIDI_CC_TYPE, 0, identifier, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Encoder_%d_%d' % (column_index, row_index)) for column_index, identifier in enumerate(row) ] for row_index, row in enumerate((ENCODER_MSG_IDS[:4], ENCODER_MSG_IDS[8:12])) ])
        self._horizontal_scroll_encoder = EncoderElement(MIDI_CC_TYPE, 0, 75, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Horizontal_Scroll_Encoder')
        self._vertical_scroll_encoder = EncoderElement(MIDI_CC_TYPE, 0, 72, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Vertical_Scroll_Encoder')
        self._volume_encoder = EncoderElement(MIDI_CC_TYPE, 0, 91, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Volume_Encoder')
        self._pan_encoder = EncoderElement(MIDI_CC_TYPE, 0, 17, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Pan_Encoder')
        self._send_a_encoder = EncoderElement(MIDI_CC_TYPE, 0, 77, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Send_A_Encoder')
        self._send_b_encoder = EncoderElement(MIDI_CC_TYPE, 0, 93, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Send_B_Encoder')
        self._send_encoders = ButtonMatrixElement(rows=[[self._send_a_encoder, self._send_b_encoder]])
        self._return_a_encoder = EncoderElement(MIDI_CC_TYPE, 0, 73, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Return_A_Encoder')
        self._return_b_encoder = EncoderElement(MIDI_CC_TYPE, 0, 79, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Return_B_Encoder')
        self._return_encoders = ButtonMatrixElement(rows=[[self._return_a_encoder, self._return_b_encoder]])
        self._pads = ButtonMatrixElement(rows=[ [ ButtonElement(True, MIDI_NOTE_TYPE, PAD_CHANNEL, col + 36 + 8 * row, name='Pad_%d_%d' % (col, row)) for col in xrange(8) ] for row in xrange(2) ])

    def _create_device(self):
        self._device = DeviceComponent(name='Device', is_enabled=False, layer=Layer(parameter_controls=self._device_controls))
        self._device.set_enabled(True)
        self.set_device_component(self._device)
        self._device_selection_follows_track_selection = True

    def _create_session(self):
        self._session = SessionComponent(num_tracks=self._pads.width(), num_scenes=self._pads.height(), name='Session', is_enabled=False, layer=Layer(clip_launch_buttons=self._pads, scene_select_control=self._vertical_scroll_encoder))
        self._session.set_enabled(True)

    def _create_mixer(self):
        self._mixer = MixerComponent(name='Mixer', is_enabled=False, num_returns=2, layer=Layer(track_select_encoder=self._horizontal_scroll_encoder, selected_track_volume_control=self._volume_encoder, selected_track_pan_control=self._pan_encoder, selected_track_send_controls=self._send_encoders, return_volume_controls=self._return_encoders))
        self._mixer.set_enabled(True)

    def _collect_setup_messages(self):
        for cc_id, encoder_id in izip(ENCODER_MSG_IDS, HARDWARE_ENCODER_IDS):
            self._setup_hardware_encoder(encoder_id, cc_id)

        for index, pad_id in enumerate(HARDWARE_BUTTON_IDS):
            identifier = index + PAD_IDENTIFIER_OFFSET
            channel = PAD_CHANNEL
            self._setup_hardware_button(pad_id, identifier, channel)
예제 #3
0
class Launchpad_MK2(IdentifiableControlSurface, OptimizedControlSurface):
    identity_request = consts.IDENTITY_REQUEST

    def __init__(self, c_instance, *a, **k):
        super(Launchpad_MK2,
              self).__init__(product_id_bytes=consts.PRODUCT_ID_BYTES,
                             c_instance=c_instance,
                             *a,
                             **k)
        self._challenge = Live.Application.get_random_int(
            0, 400000000) & 2139062143
        with self.component_guard():
            self._skin = make_default_skin()
            with inject(skin=const(self._skin)).everywhere():
                self._create_controls()
            self._create_session()
            self._create_mixer()
            self._last_sent_layout_byte = None
            with inject(switch_layout=const(self._switch_layout)).everywhere():
                self._create_modes()
        return

    def _create_controls(self):
        multi_button_channels = consts.USER_MODE_CHANNELS
        self._session_button_single = make_button(108,
                                                  0,
                                                  'Session_Mode_Button',
                                                  msg_type=MIDI_CC_TYPE,
                                                  is_modifier=True)
        self._session_button = FilteringMultiElement(
            [self._session_button_single] + [
                make_button(108,
                            channel,
                            msg_type=MIDI_CC_TYPE,
                            name='Session_Mode_Button_ch_%d' % (channel, ))
                for channel in multi_button_channels
            ],
            feedback_channels=[0])
        self._user_1_button = FilteringMultiElement(
            [
                make_button(109,
                            channel,
                            msg_type=MIDI_CC_TYPE,
                            name='User_1_Mode_Button_ch_%d' % (channel, ))
                for channel in (0, ) + multi_button_channels
            ],
            feedback_channels=[0, 5, 6, 7])
        self._user_2_button = FilteringMultiElement(
            [
                make_button(110,
                            channel,
                            msg_type=MIDI_CC_TYPE,
                            name='User_2_Mode_Button_ch_%d' % (channel, ))
                for channel in (0, ) + multi_button_channels
            ],
            feedback_channels=[0, 13, 14, 15])
        self._mixer_button = FilteringMultiElement([
            make_button(111,
                        channel,
                        msg_type=MIDI_CC_TYPE,
                        name='Mixer_Mode_Button_ch_%d' % (channel, ))
            for channel in (0, ) + multi_button_channels
        ],
                                                   feedback_channels=[0])
        self._up_button = make_button(104,
                                      0,
                                      msg_type=MIDI_CC_TYPE,
                                      name='Up_Button')
        self._down_button = make_button(105,
                                        0,
                                        msg_type=MIDI_CC_TYPE,
                                        name='Down_Button')
        self._left_button = make_button(106,
                                        0,
                                        msg_type=MIDI_CC_TYPE,
                                        name='Left_Button')
        self._right_button = make_button(107,
                                         0,
                                         msg_type=MIDI_CC_TYPE,
                                         name='Right_Button')
        self._session_matrix_raw = [[
            make_button(col + offset,
                        0,
                        name='Session_Matrix_Button_%d_%d' % (col, row))
            for col in xrange(consts.SESSION_WIDTH)
        ] for row, offset in enumerate(xrange(81, 10, -10))]
        self._session_matrix = ButtonMatrixElement(
            rows=self._session_matrix_raw, name='Session_Matrix')
        self._scene_launch_matrix_raw = [
            make_button(identifier,
                        0,
                        name='Scene_Launch_Button_%d' % (index, ))
            for index, identifier in enumerate(xrange(89, 18, -10))
        ]
        self._scene_launch_matrix = ButtonMatrixElement(
            rows=[self._scene_launch_matrix_raw], name='Scene_Launch_Buttons')
        self._session_zoom_matrix = ButtonMatrixElement(rows=recursive_map(
            partial(with_modifier, self._session_button_single),
            self._session_matrix_raw))
        self._volume_reset_buttons = self._session_matrix.submatrix[:, :1]
        self._pan_reset_buttons = self._session_matrix.submatrix[:, 1:2]
        self._send_a_reset_buttons = self._session_matrix.submatrix[:, 2:3]
        self._send_b_reset_buttons = self._session_matrix.submatrix[:, 3:4]
        self._stop_clip_buttons = self._session_matrix.submatrix[:, 4:5]
        self._mute_buttons = self._session_matrix.submatrix[:, 5:6]
        self._solo_buttons = self._session_matrix.submatrix[:, 6:7]
        self._arm_buttons = self._session_matrix.submatrix[:, 7:]
        self._volume_button = self._scene_launch_matrix_raw[0]
        self._pan_button = self._scene_launch_matrix_raw[1]
        self._send_a_button = self._scene_launch_matrix_raw[2]
        self._send_b_button = self._scene_launch_matrix_raw[3]
        self._stop_button = self._scene_launch_matrix_raw[4]
        self._mute_button = self._scene_launch_matrix_raw[5]
        self._solo_button = self._scene_launch_matrix_raw[6]
        self._record_arm_button = self._scene_launch_matrix_raw[7]
        self._sliders = ButtonMatrixElement(rows=[[
            SliderElement(MIDI_CC_TYPE, 0, identifier)
            for identifier in xrange(21, 29)
        ]])
        self._create_user_controls()

    def _create_user_controls(self):
        u"""
        These control elements are not used anywhere in the script;
        instead, they are created so users can access them via
        Max for Live.
        """
        self._user_1_matrix = ButtonMatrixElement(rows=[[
            make_button(identifier,
                        USER_1_CHANNEL,
                        name='User_1_Button_%d_%d' % (row_index, col_index))
            for col_index, identifier in enumerate(row)
        ] for row_index, row in enumerate(USER_1_MATRIX_IDENTIFIERS)],
                                                  name='User_1_Matrix')
        self._user_1_arrow_buttons = ButtonMatrixElement(
            rows=[[
                make_button(identifier,
                            USER_1_CHANNEL,
                            msg_type=MIDI_CC_TYPE,
                            name='User_1_Arrow_Button_%d' % (index, ))
                for index, identifier in enumerate(xrange(104, 108))
            ]],
            name='User_1_Arrow_Buttons')
        self._user_1_side_buttons = ButtonMatrixElement(
            rows=[[
                make_button(identifier,
                            USER_1_CHANNEL,
                            name='User_1_Side_Button_%d' % (index, ))
            ] for index, identifier in enumerate(xrange(100, 108))],
            name='User_1_Side_Buttons')
        self._user_2_matrix = ButtonMatrixElement(rows=[[
            make_button(offset + col_index,
                        USER_2_CHANNEL,
                        name='User_2_Button_%d_%d' % (col_index, row_index))
            for col_index in xrange(8)
        ] for row_index, offset in enumerate(xrange(81, 10, -10))],
                                                  name='User_2_Matrix')
        self._user_2_arrow_buttons = ButtonMatrixElement(
            rows=[[
                make_button(identifier,
                            USER_2_CHANNEL,
                            msg_type=MIDI_CC_TYPE,
                            name='User_2_Arrow_Button_%d' % (index, ))
                for index, identifier in enumerate(xrange(104, 108))
            ]],
            name='User_2_Arrow_Buttons')
        self._user_2_side_buttons = ButtonMatrixElement(
            rows=[[
                make_button(identifier,
                            USER_2_CHANNEL,
                            name='User_2_Side_Button_%d' % (index, ))
            ] for index, identifier in enumerate(xrange(89, 18, -10))],
            name='User_2_Side_Buttons')

    def _create_session(self):
        self._session = SessionComponent(
            is_enabled=False,
            num_tracks=self._session_matrix.width(),
            num_scenes=self._session_matrix.height(),
            enable_skinning=True,
            name='Session',
            is_root=True,
            layer=Layer(track_bank_left_button=self._left_button,
                        track_bank_right_button=self._right_button,
                        scene_bank_up_button=self._up_button,
                        scene_bank_down_button=self._down_button))
        self._session.set_rgb_mode(LIVE_COLORS_TO_MIDI_VALUES, RGB_COLOR_TABLE)
        self._session_layer_mode = AddLayerMode(
            self._session,
            Layer(clip_launch_buttons=self._session_matrix,
                  scene_launch_buttons=self._scene_launch_matrix))
        self._session_zoom = SessionZoomingComponent(
            self._session,
            is_enabled=False,
            enable_skinning=True,
            layer=Layer(
                nav_up_button=with_modifier(self._session_button_single,
                                            self._up_button),
                nav_down_button=with_modifier(self._session_button_single,
                                              self._down_button),
                nav_left_button=with_modifier(self._session_button_single,
                                              self._left_button),
                nav_right_button=with_modifier(self._session_button_single,
                                               self._right_button),
                button_matrix=self._session_zoom_matrix))
        self._stop_clip_layer_mode = AddLayerMode(
            self._session,
            Layer(stop_track_clip_buttons=self._stop_clip_buttons,
                  stop_all_clips_button=self._stop_button))

    def _create_mixer(self):
        self._mixer = MixerComponent(is_enabled=False,
                                     num_tracks=consts.SESSION_WIDTH,
                                     invert_mute_feedback=True,
                                     enable_skinning=True,
                                     name='Mixer',
                                     is_root=True)
        self._session.set_mixer(self._mixer)
        self._mixer_home_page_layer = LayerMode(
            self._mixer,
            Layer(volume_reset_buttons=self._volume_reset_buttons,
                  pan_reset_buttons=self._pan_reset_buttons,
                  send_a_reset_buttons=self._send_a_reset_buttons,
                  send_b_reset_buttons=self._send_b_reset_buttons,
                  mute_buttons=self._mute_buttons,
                  solo_buttons=self._solo_buttons,
                  arm_buttons=self._arm_buttons,
                  unmute_all_button=self._mute_button,
                  unsolo_all_button=self._solo_button,
                  unarm_all_button=self._record_arm_button))
        self._mixer_volume_layer = LayerMode(
            self._mixer, Layer(volume_controls=self._sliders))
        self._mixer_pan_layer = LayerMode(self._mixer,
                                          Layer(pan_controls=self._sliders))
        self._mixer_sends_layer = LayerMode(self._mixer,
                                            Layer(send_controls=self._sliders))

    def _create_translating_mixer_background(self, translation_channel):
        return TranslatingBackgroundComponent(
            translation_channel=translation_channel,
            is_enabled=False,
            name='Background',
            layer=Layer(stop_button=self._stop_button,
                        mute_buttons=self._mute_button,
                        solo_button=self._solo_button,
                        record_arm_button=self._record_arm_button))

    def _create_modes(self):
        self._modes = NotifyingModesComponent(is_root=True)
        self._modes.default_behaviour = mixin(SkinableBehaviourMixin,
                                              ImmediateBehaviour)()
        self._modes.add_mode(
            'session_mode', [self._session, self._session_layer_mode],
            layout_byte=0,
            behaviour=EnablingReenterBehaviour(self._session_zoom))
        self._modes.add_mode('user_1_mode', [], layout_byte=1)
        self._modes.add_mode('user_2_mode', [], layout_byte=2)
        self._modes.add_mode('volume_mode', [
            self._session,
            self._create_translating_mixer_background(
                consts.VOLUME_MODE_CHANNEL), self._mixer_volume_layer
        ],
                             layout_byte=4,
                             groups=set('mixer'))
        self._modes.add_mode('pan_mode', [
            self._session,
            self._create_translating_mixer_background(consts.PAN_MODE_CHANNEL),
            self._mixer_pan_layer
        ],
                             layout_byte=5,
                             groups=set('mixer'))
        self._modes.add_mode('send_a_mode', [
            self._session,
            self._create_translating_mixer_background(
                consts.SEND_A_MODE_CHANNEL),
            partial(self._set_send_index, 0), self._mixer_sends_layer
        ],
                             layout_byte=6,
                             groups=set('mixer'))
        self._modes.add_mode('send_b_mode', [
            self._session,
            self._create_translating_mixer_background(
                consts.SEND_B_MODE_CHANNEL),
            partial(self._set_send_index, 1), self._mixer_sends_layer
        ],
                             layout_byte=7,
                             groups=set('mixer'))
        self._modes.add_mode('mixer_mode', [
            self._session, self._stop_clip_layer_mode,
            self._mixer_home_page_layer
        ],
                             layout_byte=3,
                             groups=set('mixer'))
        self._modes.layer = Layer(session_mode_button=self._session_button,
                                  user_1_mode_button=self._user_1_button,
                                  user_2_mode_button=self._user_2_button,
                                  mixer_mode_button=self._mixer_button,
                                  volume_mode_button=self._volume_button,
                                  pan_mode_button=self._pan_button,
                                  send_a_mode_button=self._send_a_button,
                                  send_b_mode_button=self._send_b_button)
        self._modes.selected_mode = 'session_mode'

    def _set_send_index(self, index):
        self._mixer.send_index = index

    def _switch_layout(self, layout_byte):
        if layout_byte != self._last_sent_layout_byte:
            prefix = consts.STANDARD_SYSEX_PREFIX + consts.LAYOUT_CHANGE_BYTE
            self._send_midi(prefix + (layout_byte, 247))
            self._clear_send_cache()
            self._last_sent_layout_byte = layout_byte

    def _clear_send_cache(self):
        with self.component_guard():
            for control in self.controls:
                control.clear_send_cache()

    def on_identified(self):
        self._send_challenge()

    def _send_challenge(self):
        challenge_bytes = tuple(
            [self._challenge >> 8 * index & 127 for index in xrange(4)])
        self._send_midi(consts.STANDARD_SYSEX_PREFIX +
                        consts.CHALLENGE_RESPONSE_BYTE + challenge_bytes +
                        (247, ))

    def handle_sysex(self, midi_bytes):
        if self._is_challenge_response(midi_bytes) and self._is_response_valid(
                midi_bytes):
            self._on_handshake_successful()
        else:
            super(Launchpad_MK2, self).handle_sysex(midi_bytes)

    def _is_challenge_response(self, midi_bytes):
        return len(
            midi_bytes
        ) == 10 and midi_bytes[:7] == consts.STANDARD_SYSEX_PREFIX + consts.CHALLENGE_RESPONSE_BYTE

    def _is_response_valid(self, midi_bytes):
        response = long(midi_bytes[7])
        response += long(midi_bytes[8] << 8)
        return response == Live.Application.encrypt_challenge2(self._challenge)

    def _on_handshake_successful(self):
        self._modes.set_enabled(True)
        self._mixer.set_enabled(True)
        self._last_sent_layout_byte = None
        self._modes.send_switch_layout_message()
        self.set_highlighting_session_component(self._session)
        self.update()
        return

    def disconnect(self):
        self._send_midi(consts.QUIT_MESSAGE)
        super(Launchpad_MK2, self).disconnect()
예제 #4
0
class KeyLab(ArturiaControlSurface):
    def __init__(self, *a, **k):
        super(KeyLab, self).__init__(*a, **k)
        with self.component_guard():
            self._create_controls()
            self._create_display()
            self._create_device()
            self._create_drums()
            self._create_transport()
            self._create_session()
            self._create_session_recording()
            self._create_mixer()

    def _create_controls(self):
        self._device_encoders = ButtonMatrixElement(rows=[[
            EncoderElement(MIDI_CC_TYPE,
                           ENCODER_CHANNEL,
                           identifier,
                           Live.MidiMap.MapMode.relative_smooth_binary_offset,
                           name=b'Device_Encoder_%d_%d' %
                           (col_index, row_index))
            for col_index, identifier in enumerate(row)
        ] for row_index, row in enumerate((ENCODER_MSG_IDS[:4],
                                           ENCODER_MSG_IDS[4:8]))])
        self._horizontal_scroll_encoder = EncoderElement(
            MIDI_CC_TYPE,
            ENCODER_CHANNEL,
            ENCODER_MSG_IDS[(-2)],
            Live.MidiMap.MapMode.relative_smooth_binary_offset,
            name=b'Horizontal_Scroll_Encoder')
        self._vertical_scroll_encoder = EncoderElement(
            MIDI_CC_TYPE,
            ENCODER_CHANNEL,
            ENCODER_MSG_IDS[(-1)],
            Live.MidiMap.MapMode.relative_smooth_binary_offset,
            name=b'Vertical_Scroll_Encoder')
        self._volume_sliders = ButtonMatrixElement(rows=[[
            SliderElement(MIDI_CC_TYPE, ENCODER_CHANNEL, identifier)
            for identifier in SLIDER_MSG_IDS[:-1]
        ]])
        self._master_slider = SliderElement(MIDI_CC_TYPE, ENCODER_CHANNEL,
                                            SLIDER_MSG_IDS[(-1)])

        def make_keylab_button(name):
            button = ButtonElement(True,
                                   MIDI_CC_TYPE,
                                   0,
                                   get_button_identifier_by_name(name),
                                   name=name.title())
            return button

        for button_name in BUTTON_HARDWARE_AND_MESSAGE_IDS.keys():
            setattr(self, b'_' + button_name, make_keylab_button(button_name))

        self._pads = ButtonMatrixElement(rows=[[
            ButtonElement(True,
                          MIDI_CC_TYPE,
                          PAD_CHANNEL,
                          col_index + row_offset,
                          name=b'Pad_%d_%d' % (col_index, row_index))
            for col_index in xrange(4)
        ] for row_index, row_offset in enumerate(xrange(48, 35, -4))])

    def _create_display(self):
        self._display_line1, self._display_line2 = DisplayElement(
            16, 1), DisplayElement(16, 1)
        for index, display_line in enumerate(
            (self._display_line1, self._display_line2)):
            display_line.set_message_parts(SETUP_MSG_PREFIX + (4, 0, 96),
                                           SETUP_MSG_SUFFIX)
            display_line.segment(0).set_position_identifier((index + 1, ))

        def adjust_null_terminated_string(string, width):
            return string.ljust(width, b' ') + b'\x00'

        self._display_line1_data_source, self._display_line2_data_source = DisplayDataSource(
            adjust_string_fn=adjust_null_terminated_string), DisplayDataSource(
                adjust_string_fn=adjust_null_terminated_string)
        self._display_line1.segment(0).set_data_source(
            self._display_line1_data_source)
        self._display_line2.segment(0).set_data_source(
            self._display_line2_data_source)
        self._display_line1_data_source.set_display_string(b'KeyLab')
        self._display_line2_data_source.set_display_string(b'Ableton Live')

    def _create_device(self):
        self._device = DeviceComponent(
            name=b'Device',
            is_enabled=False,
            layer=Layer(parameter_controls=self._device_encoders),
            device_selection_follows_track_selection=True)
        self._device.set_enabled(True)
        self.set_device_component(self._device)
        self._device_navigation = DeviceNavigationComponent(
            name=b'Device_Navigation',
            is_enabled=False,
            layer=Layer(device_nav_left_button=self._device_left_button,
                        device_nav_right_button=self._device_right_button))
        self._device_navigation.set_enabled(True)

    def _create_drums(self):
        self._drums = DrumRackComponent(name=b'Drums',
                                        is_enabled=False,
                                        layer=Layer(pads=self._pads))
        self._drums.set_enabled(True)

    def _create_transport(self):
        self._transport = TransportComponent(
            name=b'Transport',
            is_enabled=False,
            layer=Layer(play_button=self._play_button,
                        stop_button=self._stop_button,
                        record_button=self._record_button,
                        loop_button=self._loop_button))
        self._transport.set_enabled(True)

    def _create_session(self):
        self._session = SessionComponent(
            num_tracks=8,
            num_scenes=1,
            name=b'Session',
            is_enabled=False,
            layer=Layer(select_next_button=self._scene_down_button,
                        select_prev_button=self._scene_up_button,
                        selected_scene_launch_button=self._scene_launch_button,
                        stop_all_clips_button=self._stop_all_clips_button,
                        scene_select_encoder=self._vertical_scroll_encoder))
        self._session.set_enabled(True)

    def _create_session_recording(self):
        self._session_recording = SessionRecordingComponent(
            ClipCreator(),
            ViewControlComponent(),
            name=b'Session_Recording',
            is_enabled=False,
            layer=Layer(record_button=self._session_record_button))
        self._session_recording.set_enabled(True)

    def _create_mixer(self):
        self._mixer = MixerComponent(
            num_tracks=self._volume_sliders.width(),
            name=b'Mixer',
            is_enabled=False,
            layer=Layer(volume_controls=self._volume_sliders,
                        track_select_encoder=self._horizontal_scroll_encoder))
        self._mixer.master_strip().layer = Layer(
            volume_control=self._master_slider)
        self._mixer.set_enabled(True)

    def _collect_setup_messages(self):
        for hardware_id, identifier in izip(ENCODER_HARDWARE_IDS,
                                            ENCODER_MSG_IDS):
            self._setup_hardware_encoder(hardware_id, identifier,
                                         ENCODER_CHANNEL)

        for hardware_id, identifier in izip(SLIDER_HARDWARE_IDS,
                                            SLIDER_MSG_IDS):
            self._setup_hardware_slider(hardware_id, identifier,
                                        ENCODER_CHANNEL)

        for hardware_id, identifier in BUTTON_HARDWARE_AND_MESSAGE_IDS.itervalues(
        ):
            self._setup_hardware_button(hardware_id, identifier)

        for hardware_id, identifier in izip(PAD_HARDWARE_IDS, PAD_MSG_IDS):
            self._setup_hardware_pad(hardware_id, identifier)

    def _setup_hardware_encoder(self, hardware_id, identifier, channel=0):
        self._set_encoder_cc_msg_type(hardware_id, is_relative=True)
        self._set_identifier(hardware_id, identifier)
        self._set_channel(hardware_id, channel)

    def _setup_hardware_button(self, hardware_id, identifier, channel=0, **k):
        self._set_encoder_cc_msg_type(hardware_id)
        self._set_identifier(hardware_id, identifier)
        self._set_channel(hardware_id, channel)
        self._set_value_minimum(hardware_id)
        self._set_value_maximum(hardware_id)

    def _setup_hardware_pad(self,
                            hardware_id,
                            identifier,
                            channel=PAD_CHANNEL):
        self._set_pad_note_msg_type(hardware_id)
        self._set_identifier(hardware_id, identifier)
        self._set_channel(hardware_id, channel)

    def _set_pad_note_msg_type(self, hardware_id):
        self._collect_setup_message(MODE_PROPERTY, hardware_id, PAD_NOTE_MODE)
예제 #5
0
class BeatStep(ArturiaControlSurface):
    def __init__(self, *a, **k):
        super(BeatStep, self).__init__(*a, **k)
        self._skin = Skin(Colors)
        with self.component_guard():
            self._create_controls()
            self._create_device()
            self._create_session()
            self._create_mixer()
            self._create_transport()

    def _create_controls(self):
        self._device_encoders = ButtonMatrixElement(rows=[[
            EncoderElement(MIDI_CC_TYPE,
                           0,
                           identifier,
                           Live.MidiMap.MapMode.relative_smooth_two_compliment,
                           name='Encoder_%d_%d' % (column_index, row_index))
            for column_index, identifier in enumerate(row)
        ] for row_index, row in enumerate((ENCODER_MSG_IDS[:4],
                                           ENCODER_MSG_IDS[8:12]))])
        self._horizontal_scroll_encoder = EncoderElement(
            MIDI_CC_TYPE,
            0,
            75,
            Live.MidiMap.MapMode.relative_smooth_two_compliment,
            name='Horizontal_Scroll_Encoder')
        self._vertical_scroll_encoder = EncoderElement(
            MIDI_CC_TYPE,
            0,
            72,
            Live.MidiMap.MapMode.relative_smooth_two_compliment,
            name='Vertical_Scroll_Encoder')
        self._volume_encoder = EncoderElement(
            MIDI_CC_TYPE,
            0,
            91,
            Live.MidiMap.MapMode.relative_smooth_two_compliment,
            name='Volume_Encoder')
        self._pan_encoder = EncoderElement(
            MIDI_CC_TYPE,
            0,
            17,
            Live.MidiMap.MapMode.relative_smooth_two_compliment,
            name='Pan_Encoder')
        self._send_a_encoder = EncoderElement(
            MIDI_CC_TYPE,
            0,
            77,
            Live.MidiMap.MapMode.relative_smooth_two_compliment,
            name='Send_A_Encoder')
        self._send_b_encoder = EncoderElement(
            MIDI_CC_TYPE,
            0,
            93,
            Live.MidiMap.MapMode.relative_smooth_two_compliment,
            name='Send_B_Encoder')
        self._send_encoders = ButtonMatrixElement(
            rows=[[self._send_a_encoder, self._send_b_encoder]])
        self._return_a_encoder = EncoderElement(
            MIDI_CC_TYPE,
            0,
            73,
            Live.MidiMap.MapMode.relative_smooth_two_compliment,
            name='Return_A_Encoder')
        self._return_b_encoder = EncoderElement(
            MIDI_CC_TYPE,
            0,
            79,
            Live.MidiMap.MapMode.relative_smooth_two_compliment,
            name='Return_B_Encoder')
        self._return_encoders = ButtonMatrixElement(
            rows=[[self._return_a_encoder, self._return_b_encoder]])
        self._pads = ButtonMatrixElement(rows=[[
            ButtonElement(True,
                          MIDI_NOTE_TYPE,
                          PAD_CHANNEL,
                          identifier,
                          name='Pad_%d_%d' % (col_index, row_index),
                          skin=self._skin)
            for col_index, identifier in enumerate(row)
        ] for row_index, row in enumerate(PAD_MSG_IDS)])
        self._stop_button = ButtonElement(True,
                                          MIDI_CC_TYPE,
                                          0,
                                          1,
                                          name='Stop_Button')
        self._play_button = ButtonElement(True,
                                          MIDI_CC_TYPE,
                                          0,
                                          2,
                                          name='Play_Button')

    def _create_device(self):
        self._device = DeviceComponent(
            name='Device',
            is_enabled=False,
            layer=Layer(parameter_controls=self._device_encoders))
        self._device.set_enabled(True)
        self.set_device_component(self._device)
        self._device_selection_follows_track_selection = True

    def _create_session(self):
        self._session = SessionComponent(
            name='Session',
            is_enabled=False,
            num_tracks=self._pads.width(),
            num_scenes=self._pads.height(),
            enable_skinning=True,
            layer=Layer(clip_launch_buttons=self._pads,
                        scene_select_control=self._vertical_scroll_encoder))
        self._session.set_enabled(True)

    def _create_mixer(self):
        self._mixer = MixerComponent(
            name='Mixer',
            is_enabled=False,
            num_returns=2,
            layer=Layer(track_select_encoder=self._horizontal_scroll_encoder,
                        selected_track_volume_control=self._volume_encoder,
                        selected_track_pan_control=self._pan_encoder,
                        selected_track_send_controls=self._send_encoders,
                        return_volume_controls=self._return_encoders))
        self._mixer.set_enabled(True)

    def _create_transport(self):
        self._transport = TransportComponent(
            name='Transport',
            is_enabled=False,
            layer=Layer(stop_button=self._stop_button,
                        play_button=self._play_button))
        self._transport.set_enabled(True)

    def _collect_setup_messages(self):
        for identifier, hardware_id in izip(ENCODER_MSG_IDS,
                                            HARDWARE_ENCODER_IDS):
            self._setup_hardware_encoder(hardware_id, identifier)

        self._setup_hardware_button(HARDWARE_STOP_BUTTON_ID, 1, msg_type='cc')
        self._setup_hardware_button(HARDWARE_PLAY_BUTTON_ID, 2, msg_type='cc')
        for hardware_id, identifier in izip(HARDWARE_PAD_IDS,
                                            chain(*PAD_MSG_IDS)):
            self._setup_hardware_button(hardware_id,
                                        identifier,
                                        PAD_CHANNEL,
                                        msg_type='note')
예제 #6
0
class Launchkey_MK2(OptimizedControlSurface):
    identity_request_delay = 0.5

    def __init__(self, c_instance, *a, **k):
        super(Launchkey_MK2, self).__init__(c_instance=c_instance, *a, **k)
        self._is_25_key_model = False
        self._is_in_control_on = True
        self._identity_response_pending = False
        with self.component_guard():
            self._skin = make_skin()
            with inject(skin=const(self._skin)).everywhere():
                self._create_controls()
        self._request_task = self._tasks.add(Task.sequence(Task.wait(self.identity_request_delay), Task.run(self._send_identity_request)))
        self._request_task.kill()

    def _create_controls(self):
        self._encoders = ButtonMatrixElement(rows=[[ make_encoder(identifier, name=u'Encoder_%d' % (index,)) for index, identifier in enumerate(xrange(21, 29)) ]])
        self._top_pad_row = ButtonMatrixElement(rows=[[ make_button(identifier, name=u'Pad_0_%d' % (index,)) for index, identifier in enumerate(xrange(96, 104)) ]])
        self._bottom_pad_row_raw = [ make_button(identifier, name=u'Pad_1_%d' % (index,)) for index, identifier in enumerate(xrange(112, 120)) ]
        self._bottom_pad_row = ButtonMatrixElement(rows=[self._bottom_pad_row_raw])
        self._top_launch_button = make_button(104, name=u'Scene_Launch_Button')
        self._bottom_launch_button = make_button(120, name=u'Stop_All_Clips_Button')
        self._scene_up_button = make_button(112, MIDI_CC_TYPE, name=u'Scene_Up_Button')
        self._scene_down_button = make_button(113, MIDI_CC_TYPE, name=u'Scene_Down_Button')
        self._stop_button = make_button(114, MIDI_CC_TYPE, name=u'Stop_Button')
        self._play_button = make_button(115, MIDI_CC_TYPE, name=u'Play_Button')
        self._loop_button = make_button(116, MIDI_CC_TYPE, name=u'Loop_Button')
        self._record_button = make_button(117, MIDI_CC_TYPE, name=u'Record_Button')
        self._sliders = ButtonMatrixElement(rows=[[ make_slider(identifier, name=u'Slider_%d' % (index,)) for index, identifier in enumerate(xrange(41, 49)) ]])
        self._master_slider = make_slider(7, name=u'Master_Slider')
        self._25_key_slider = make_slider(7, name=u'Slider', channel=0)
        self._mute_buttons_raw = [ make_button(identifier, MIDI_CC_TYPE, name=u'Mute_Button_%d' % (index,)) for index, identifier in enumerate(xrange(51, 59)) ]
        self._mute_buttons = ButtonMatrixElement(rows=[self._mute_buttons_raw])
        self._master_button = make_button(59, MIDI_CC_TYPE, name=u'Master_Button')
        self._track_left_button = make_button(102, MIDI_CC_TYPE, name=u'Track_Left_Button')
        self._track_right_button = make_button(103, MIDI_CC_TYPE, name=u'Track_Right_Button')
        self._device_mode_button = self._bottom_pad_row_raw[0]
        self._pan_mode_button = self._bottom_pad_row_raw[1]
        self._send_mode_buttons = dict()
        for index in xrange(consts.MAX_SENDS):
            setattr(self, u'_send_%d_button' % (index,), self._bottom_pad_row_raw[index + 2])
            self._send_mode_buttons[u'send_%d_mode_button' % (index,)] = getattr(self, u'_send_%d_button' % (index,))

        self._extended_mode_button = make_button(12, name=u'Dummy_Extended_Mode_Button')
        self._extended_mode_button.add_value_listener(nop)
        self._encoder_incontrol_button = make_button(13, is_momentary=False, name=u'Encoder_InControl_Button')
        self._encoder_incontrol_button.add_value_listener(nop)
        self._slider_incontrol_button = make_button(14, is_momentary=False, name=u'Fader_InControl_Button')
        self._slider_incontrol_button.add_value_listener(nop)
        self._pad_incontrol_button = make_button(15, is_momentary=False, name=u'Pad_InControl_Button')
        self._pad_incontrol_button.add_value_listener(self._update_pads)
        self._encoder_incontrol_button2 = make_button(16, name=u'Encoder_InControl_Button')
        self._pad_in_control_status_button = make_button(11, name=u'Dummy_InControl_Button')

    def _create_session(self):
        self._session = SessionComponent(name=u'Session', is_enabled=False, num_tracks=self._top_pad_row.width(), num_scenes=self._top_pad_row.height(), enable_skinning=True, layer=Layer(clip_launch_buttons=self._top_pad_row, scene_launch_buttons=ButtonMatrixElement(rows=[[self._top_launch_button]]), stop_track_clip_buttons=self._bottom_pad_row, stop_all_clips_button=self._bottom_launch_button))
        self._session.set_rgb_mode(LIVE_COLORS_TO_MIDI_VALUES, RGB_COLOR_TABLE)
        self._session.set_mixer(self._mixer)
        self._session.set_enabled(True)

    def _setup_navigation(self):
        self._session_navigation = SessionNavigationComponent(is_enabled=False, name=u'Session_Navigation', layer=Layer(next_track_button=self._track_right_button, prev_track_button=self._track_left_button, next_scene_button=self._scene_down_button, prev_scene_button=self._scene_up_button))
        self._session_navigation.set_enabled(True)

    def _create_transport(self):
        self._transport = TransportComponent(is_enabled=False, name=u'Transport', layer=Layer(play_button=self._play_button, stop_button=self._stop_button, loop_button=self._loop_button, record_button=self._record_button))
        self._transport.set_enabled(True)

    def _create_mixer(self):
        mixer_volume_layer = None
        if self._is_25_key_model:
            mixer_volume_layer = Layer(volume_control=self._25_key_slider)
        else:
            mixer_volume_layer = Layer(volume_controls=self._sliders)
        self._mixer = MixerComponent(is_enabled=False, name=u'Mixer', num_tracks=self._sliders.width(), layer=mixer_volume_layer)
        if not self._is_25_key_model:
            self._mixer.master_strip().layer = Layer(volume_control=self._master_slider)
        self._mixer.set_enabled(True)
        self._mute_button_modes = ModesComponent()
        mute_mode = AddLayerMode(self._mixer, Layer(mute_buttons=self._mute_buttons))
        solo_mode = AddLayerMode(self._mixer, Layer(solo_buttons=self._mute_buttons))
        self._mute_button_modes.add_mode(u'mute_mode', mute_mode)
        self._mute_button_modes.add_mode(u'solo_mode', solo_mode, behaviour=CancellableBehaviour())
        self._mute_button_modes.layer = Layer(solo_mode_button=self._master_button)
        self._mute_button_modes.selected_mode = u'mute_mode'
        self._mute_button_modes.set_enabled(True)

    def _create_device(self):
        self._device = DeviceComponent(name=u'Device', is_enabled=False, device_selection_follows_track_selection=True)
        self.set_device_component(self._device)
        self._device.set_enabled(True)

    def _create_background(self):
        self._background = BackgroundComponent(name=u'BackgroundComponent')

    def _create_encoder_modes(self):
        self._encoder_modes = DisablingModesComponent()
        self._encoder_modes.default_behaviour = mixin(SkinableBehaviourMixin, ImmediateBehaviour)()
        device_mode = LayerMode(self._device, Layer(parameter_controls=self._encoders, bank_buttons=self._top_pad_row))
        pan_mode = AddLayerMode(self._mixer, Layer(pan_controls=self._encoders))
        sends_mode = AddLayerMode(self._mixer, Layer(send_controls=self._encoders))
        background_mode = LayerMode(self._background, Layer(bank_buttons=self._top_pad_row))
        self._encoder_modes.add_mode(u'device_mode', device_mode, is_enabled=True)
        self._encoder_modes.add_mode(u'pan_mode', [pan_mode, background_mode], is_enabled=True)
        for index in xrange(6):
            self._encoder_modes.add_mode(u'send_%d_mode' % (index,), [sends_mode, partial(self._set_send_index, index), background_mode], is_enabled=False)

        self._encoder_modes.selected_mode = u'device_mode'
        self._encoder_modes.set_enabled(True)

    def _create_mode_selector(self):
        self._mode_selector = ModesComponent()
        mode_selection = LayerMode(self._encoder_modes, Layer(device_mode_button=self._device_mode_button, pan_mode_button=self._pan_mode_button, **self._send_mode_buttons))
        device_navigation = AddLayerMode(self._device, Layer(device_nav_left_button=self._track_left_button, device_nav_right_button=self._track_right_button))
        self._mode_selector.add_mode(u'mode_selection', [partial(self._toggle_in_control, True), mode_selection, device_navigation], behaviour=MomentaryBehaviour())
        session_control = AddLayerMode(self._session, Layer(clip_launch_buttons=self._top_pad_row))
        self._mode_selector.add_mode(u'session_mode', [partial(self._toggle_in_control, False), session_control])
        self._mode_selector.layer = Layer(mode_selection_button=self._encoder_incontrol_button2)

    def _create_in_control_status_listener(self):
        self._in_control_status = InControlStatusComponent(set_is_in_control_on=self._set_is_in_control_on, is_enabled=False, layer=Layer(in_control_status_button=self._pad_in_control_status_button))
        self._in_control_status.set_enabled(True)

    @subject_slot(u'value')
    def _update_pads(self, value):
        if value:
            self.update()

    @subject_slot(u'return_tracks')
    def _on_return_tracks_changed(self):
        num_sends = self._mixer.num_sends
        for index in xrange(6):
            self._encoder_modes.set_mode_enabled(u'send_%d_mode' % (index,), True if index < num_sends else False)

    def _set_send_index(self, index):
        self._mixer.send_index = index

    def _set_is_in_control_on(self, value):
        self._is_in_control_on = value

    def _toggle_in_control(self, value):
        if not self._is_in_control_on:
            self._send_midi(consts.DRUM_IN_CONTROL_ON_MESSAGE if value else consts.DRUM_IN_CONTROL_OFF_MESSAGE)

    def port_settings_changed(self):
        self._disconnect_and_unregister_all_components()
        self._request_task.restart()

    def handle_sysex(self, midi_bytes):
        if self._is_identity_response(midi_bytes):
            product_id_bytes = self._extract_product_id_bytes(midi_bytes)
            if self._is_identity_response_valid(product_id_bytes):
                self._set_model_type(product_id_bytes)
                self._request_task.kill()
                if self._identity_response_pending:
                    self.on_identified()
                    self._identity_response_pending = False
            else:
                self.log_message(u'MIDI device responded with wrong product id (%s).' % (str(product_id_bytes),))
        else:
            super(Launchkey_MK2, self).handle_sysex(midi_bytes)

    def _extract_product_id_bytes(self, midi_bytes):
        return midi_bytes[5:]

    def _is_identity_response(self, midi_bytes):
        return midi_bytes[3:5] == (6, 2)

    def _is_identity_response_valid(self, product_id_bytes):
        return product_id_bytes[:3] == consts.PRODUCT_ID_BYTE_PREFIX and product_id_bytes[3] in consts.PRODUCT_ID_BYTES

    def _set_model_type(self, product_id_bytes):
        self._is_25_key_model = product_id_bytes[3] == consts.LAUNCHKEY_25_ID_BYTE

    def _send_identity_request(self):
        self._identity_response_pending = True
        self._send_midi(consts.IDENTITY_REQUEST)

    def on_identified(self):
        self._extended_mode_button.turn_on()
        with self.component_guard():
            self._create_mixer()
            self._create_session()
            self._setup_navigation()
            self._create_transport()
            self._create_device()
            self._create_background()
            self._create_encoder_modes()
            self._create_mode_selector()
            self._create_in_control_status_listener()
            self._on_return_tracks_changed.subject = self.song()
            self._on_return_tracks_changed()
        self._mode_selector.selected_mode = u'session_mode'
        self.update()

    def disconnect(self):
        self._extended_mode_button.turn_off()
        super(Launchkey_MK2, self).disconnect()
class KeyLab(ArturiaControlSurface):

    def __init__(self, *a, **k):
        super(KeyLab, self).__init__(*a, **k)
        with self.component_guard():
            self._create_controls()
            self._create_display()
            self._create_device()
            self._create_drums()
            self._create_transport()
            self._create_session()
            self._create_session_recording()
            self._create_mixer()

    def _create_controls(self):
        self._device_encoders = ButtonMatrixElement(rows=[ [ EncoderElement(MIDI_CC_TYPE, ENCODER_CHANNEL, identifier, Live.MidiMap.MapMode.relative_smooth_binary_offset, name='Device_Encoder_%d_%d' % (col_index, row_index)) for col_index, identifier in enumerate(row) ] for row_index, row in enumerate((ENCODER_MSG_IDS[:4], ENCODER_MSG_IDS[4:8])) ])
        self._horizontal_scroll_encoder = EncoderElement(MIDI_CC_TYPE, ENCODER_CHANNEL, ENCODER_MSG_IDS[-2], Live.MidiMap.MapMode.relative_smooth_binary_offset, name='Horizontal_Scroll_Encoder')
        self._vertical_scroll_encoder = EncoderElement(MIDI_CC_TYPE, ENCODER_CHANNEL, ENCODER_MSG_IDS[-1], Live.MidiMap.MapMode.relative_smooth_binary_offset, name='Vertical_Scroll_Encoder')
        self._volume_sliders = ButtonMatrixElement(rows=[[ SliderElement(MIDI_CC_TYPE, ENCODER_CHANNEL, identifier) for identifier in SLIDER_MSG_IDS[:-1] ]])
        self._master_slider = SliderElement(MIDI_CC_TYPE, ENCODER_CHANNEL, SLIDER_MSG_IDS[-1])

        def make_keylab_button(name):
            button = ButtonElement(True, MIDI_CC_TYPE, 0, get_button_identifier_by_name(name), name=name.title())
            return button

        for button_name in BUTTON_HARDWARE_AND_MESSAGE_IDS.keys():
            setattr(self, '_' + button_name, make_keylab_button(button_name))

        self._pads = ButtonMatrixElement(rows=[ [ ButtonElement(True, MIDI_CC_TYPE, PAD_CHANNEL, col_index + row_offset, name='Pad_%d_%d' % (col_index, row_index)) for col_index in xrange(4) ] for row_index, row_offset in enumerate(xrange(48, 35, -4)) ])

    def _create_display(self):
        self._display_line1, self._display_line2 = DisplayElement(16, 1), DisplayElement(16, 1)
        for index, display_line in enumerate((self._display_line1, self._display_line2)):
            display_line.set_message_parts(SETUP_MSG_PREFIX + (4, 0, 96), SETUP_MSG_SUFFIX)
            display_line.segment(0).set_position_identifier((index + 1,))

        def adjust_null_terminated_string(string, width):
            return string.ljust(width, ' ') + '\x00'

        self._display_line1_data_source, self._display_line2_data_source = DisplayDataSource(adjust_string_fn=adjust_null_terminated_string), DisplayDataSource(adjust_string_fn=adjust_null_terminated_string)
        self._display_line1.segment(0).set_data_source(self._display_line1_data_source)
        self._display_line2.segment(0).set_data_source(self._display_line2_data_source)
        self._display_line1_data_source.set_display_string('KeyLab')
        self._display_line2_data_source.set_display_string('Ableton Live')

    def _create_device(self):
        self._device = DeviceComponent(name='Device', is_enabled=False, layer=Layer(parameter_controls=self._device_encoders))
        self._device.set_enabled(True)
        self.set_device_component(self._device)
        self._device_selection_follows_track_selection = True
        self._device_navigation = DeviceNavigationComponent(name='Device_Navigation', is_enabled=False, layer=Layer(device_nav_left_button=self._device_left_button, device_nav_right_button=self._device_right_button))
        self._device_navigation.set_enabled(True)

    def _create_drums(self):
        self._drums = DrumRackComponent(name='Drums', is_enabled=False, layer=Layer(pads=self._pads))
        self._drums.set_enabled(True)

    def _create_transport(self):
        self._transport = TransportComponent(name='Transport', is_enabled=False, layer=Layer(play_button=self._play_button, stop_button=self._stop_button, record_button=self._record_button, loop_button=self._loop_button))
        self._transport.set_enabled(True)

    def _create_session(self):
        self._session = SessionComponent(num_tracks=8, num_scenes=1, name='Session', is_enabled=False, layer=Layer(select_next_button=self._scene_down_button, select_prev_button=self._scene_up_button, selected_scene_launch_button=self._scene_launch_button, stop_all_clips_button=self._stop_all_clips_button, scene_select_encoder=self._vertical_scroll_encoder))
        self._session.set_enabled(True)

    def _create_session_recording(self):
        self._session_recording = SessionRecordingComponent(ClipCreator(), ViewControlComponent(), name='Session_Recording', is_enabled=False, layer=Layer(record_button=self._session_record_button))
        self._session_recording.set_enabled(True)

    def _create_mixer(self):
        self._mixer = MixerComponent(num_tracks=self._volume_sliders.width(), name='Mixer', is_enabled=False, layer=Layer(volume_controls=self._volume_sliders, track_select_encoder=self._horizontal_scroll_encoder))
        self._mixer.master_strip().layer = Layer(volume_control=self._master_slider)
        self._mixer.set_enabled(True)

    def _collect_setup_messages(self):
        for hardware_id, identifier in izip(ENCODER_HARDWARE_IDS, ENCODER_MSG_IDS):
            self._setup_hardware_encoder(hardware_id, identifier, ENCODER_CHANNEL)

        for hardware_id, identifier in izip(SLIDER_HARDWARE_IDS, SLIDER_MSG_IDS):
            self._setup_hardware_slider(hardware_id, identifier, ENCODER_CHANNEL)

        for hardware_id, identifier in BUTTON_HARDWARE_AND_MESSAGE_IDS.itervalues():
            self._setup_hardware_button(hardware_id, identifier)

        for hardware_id, identifier in izip(PAD_HARDWARE_IDS, PAD_MSG_IDS):
            self._setup_hardware_pad(hardware_id, identifier)

    def _setup_hardware_encoder(self, hardware_id, identifier, channel = 0):
        self._set_encoder_cc_msg_type(hardware_id, is_relative=True)
        self._set_identifier(hardware_id, identifier)
        self._set_channel(hardware_id, channel)

    def _setup_hardware_button(self, hardware_id, identifier, channel = 0, **k):
        self._set_encoder_cc_msg_type(hardware_id)
        self._set_identifier(hardware_id, identifier)
        self._set_channel(hardware_id, channel)
        self._set_value_minimum(hardware_id)
        self._set_value_maximum(hardware_id)

    def _setup_hardware_pad(self, hardware_id, identifier, channel = PAD_CHANNEL):
        self._set_pad_note_msg_type(hardware_id)
        self._set_identifier(hardware_id, identifier)
        self._set_channel(hardware_id, channel)

    def _set_pad_note_msg_type(self, hardware_id):
        self._collect_setup_message(MODE_PROPERTY, hardware_id, PAD_NOTE_MODE)
예제 #8
0
class Launchkey_MK2(OptimizedControlSurface):
    identity_request_delay = 0.5

    def __init__(self, c_instance, *a, **k):
        super(Launchkey_MK2, self).__init__(c_instance=c_instance, *a, **k)
        self._is_25_key_model = False
        self._is_in_control_on = True
        with self.component_guard():
            self._skin = make_skin()
            with inject(skin=const(self._skin)).everywhere():
                self._create_controls()
        self._request_task = self._tasks.add(Task.sequence(Task.wait(self.identity_request_delay), Task.run(self._send_identity_request)))
        self._request_task.kill()

    def _create_controls(self):
        self._encoders = ButtonMatrixElement(rows=[[ make_encoder(identifier, name='Encoder_%d' % (index,)) for index, identifier in enumerate(xrange(21, 29)) ]])
        self._top_pad_row = ButtonMatrixElement(rows=[[ make_button(identifier, name='Pad_0_%d' % (index,)) for index, identifier in enumerate(xrange(96, 104)) ]])
        self._bottom_pad_row_raw = [ make_button(identifier, name='Pad_1_%d' % (index,)) for index, identifier in enumerate(xrange(112, 120)) ]
        self._bottom_pad_row = ButtonMatrixElement(rows=[self._bottom_pad_row_raw])
        self._top_launch_button = make_button(104, name='Scene_Launch_Button')
        self._bottom_launch_button = make_button(120, name='Stop_All_Clips_Button')
        self._scene_up_button = make_button(112, MIDI_CC_TYPE, name='Scene_Up_Button')
        self._scene_down_button = make_button(113, MIDI_CC_TYPE, name='Scene_Down_Button')
        self._stop_button = make_button(114, MIDI_CC_TYPE, name='Stop_Button')
        self._play_button = make_button(115, MIDI_CC_TYPE, name='Play_Button')
        self._loop_button = make_button(116, MIDI_CC_TYPE, name='Loop_Button')
        self._record_button = make_button(117, MIDI_CC_TYPE, name='Record_Button')
        self._sliders = ButtonMatrixElement(rows=[[ make_slider(identifier, name='Slider_%d' % (index,)) for index, identifier in enumerate(xrange(41, 49)) ]])
        self._master_slider = make_slider(7, name='Master_Slider')
        self._25_key_slider = make_slider(7, name='Slider', channel=0)
        self._mute_buttons_raw = [ make_button(identifier, MIDI_CC_TYPE, name='Mute_Button_%d' % (index,)) for index, identifier in enumerate(xrange(51, 59)) ]
        self._mute_buttons = ButtonMatrixElement(rows=[self._mute_buttons_raw])
        self._master_button = make_button(59, MIDI_CC_TYPE, name='Master_Button')
        self._track_left_button = make_button(102, MIDI_CC_TYPE, name='Track_Left_Button')
        self._track_right_button = make_button(103, MIDI_CC_TYPE, name='Track_Right_Button')
        self._device_mode_button = self._bottom_pad_row_raw[0]
        self._pan_mode_button = self._bottom_pad_row_raw[1]
        self._send_mode_buttons = dict()
        for index in xrange(consts.MAX_SENDS):
            setattr(self, '_send_%d_button' % (index,), self._bottom_pad_row_raw[index + 2])
            self._send_mode_buttons['send_%d_mode_button' % (index,)] = getattr(self, '_send_%d_button' % (index,))

        self._extended_mode_button = make_button(12, name='Dummy_Extended_Mode_Button')
        self._extended_mode_button.add_value_listener(nop)
        self._encoder_incontrol_button = make_button(13, is_momentary=False, name='Encoder_InControl_Button')
        self._encoder_incontrol_button.add_value_listener(nop)
        self._slider_incontrol_button = make_button(14, is_momentary=False, name='Fader_InControl_Button')
        self._slider_incontrol_button.add_value_listener(nop)
        self._pad_incontrol_button = make_button(15, is_momentary=False, name='Pad_InControl_Button')
        self._pad_incontrol_button.add_value_listener(self._update_pads)
        self._encoder_incontrol_button2 = make_button(16, name='Encoder_InControl_Button')
        self._pad_in_control_status_button = make_button(11, name='Dummy_InControl_Button')

    def _create_session(self):
        self._session = SessionComponent(name='Session', is_enabled=False, num_tracks=self._top_pad_row.width(), num_scenes=self._top_pad_row.height(), enable_skinning=True, layer=Layer(clip_launch_buttons=self._top_pad_row, scene_launch_buttons=ButtonMatrixElement(rows=[[self._top_launch_button]]), stop_track_clip_buttons=self._bottom_pad_row, stop_all_clips_button=self._bottom_launch_button))
        self._session.set_rgb_mode(CLIP_COLOR_TABLE, RGB_COLOR_TABLE)
        self._session.set_mixer(self._mixer)
        self._session.set_enabled(True)

    def _setup_navigation(self):
        self._session_navigation = SessionNavigationComponent(is_enabled=False, name='Session_Navigation', layer=Layer(next_track_button=self._track_right_button, prev_track_button=self._track_left_button, next_scene_button=self._scene_down_button, prev_scene_button=self._scene_up_button))
        self._session_navigation.set_enabled(True)

    def _create_transport(self):
        self._transport = TransportComponent(is_enabled=False, name='Transport', layer=Layer(play_button=self._play_button, stop_button=self._stop_button, loop_button=self._loop_button, record_button=self._record_button))
        self._transport.set_enabled(True)

    def _create_mixer(self):
        mixer_volume_layer = None
        if self._is_25_key_model:
            mixer_volume_layer = Layer(volume_control=self._25_key_slider)
        else:
            mixer_volume_layer = Layer(volume_controls=self._sliders)
        self._mixer = MixerComponent(is_enabled=False, name='Mixer', num_tracks=self._sliders.width(), layer=mixer_volume_layer)
        if not self._is_25_key_model:
            self._mixer.master_strip().layer = Layer(volume_control=self._master_slider)
        self._mixer.set_enabled(True)
        self._mute_button_modes = ModesComponent()
        mute_mode = AddLayerMode(self._mixer, Layer(mute_buttons=self._mute_buttons))
        solo_mode = AddLayerMode(self._mixer, Layer(solo_buttons=self._mute_buttons))
        self._mute_button_modes.add_mode('mute_mode', mute_mode)
        self._mute_button_modes.add_mode('solo_mode', solo_mode, behaviour=CancellableBehaviour())
        self._mute_button_modes.layer = Layer(solo_mode_button=self._master_button)
        self._mute_button_modes.selected_mode = 'mute_mode'
        self._mute_button_modes.set_enabled(True)

    def _create_device(self):
        self._device = DeviceComponent(name='Device', is_enabled=False, device_selection_follows_track_selection=True)
        self.set_device_component(self._device)
        self._device.set_enabled(True)

    def _create_background(self):
        self._background = BackgroundComponent(name='BackgroundComponent')

    def _create_encoder_modes(self):
        self._encoder_modes = DisablingModesComponent()
        self._encoder_modes.default_behaviour = mixin(SkinableBehaviourMixin, ImmediateBehaviour)()
        device_mode = LayerMode(self._device, Layer(parameter_controls=self._encoders, bank_buttons=self._top_pad_row))
        pan_mode = AddLayerMode(self._mixer, Layer(pan_controls=self._encoders))
        sends_mode = AddLayerMode(self._mixer, Layer(send_controls=self._encoders))
        background_mode = LayerMode(self._background, Layer(bank_buttons=self._top_pad_row))
        self._encoder_modes.add_mode('device_mode', device_mode, is_enabled=True)
        self._encoder_modes.add_mode('pan_mode', [pan_mode, background_mode], is_enabled=True)
        for index in xrange(6):
            self._encoder_modes.add_mode('send_%d_mode' % (index,), [sends_mode, partial(self._set_send_index, index), background_mode], is_enabled=False)

        self._encoder_modes.selected_mode = 'device_mode'
        self._encoder_modes.set_enabled(True)

    def _create_mode_selector(self):
        self._mode_selector = ModesComponent()
        mode_selection = LayerMode(self._encoder_modes, Layer(device_mode_button=self._device_mode_button, pan_mode_button=self._pan_mode_button, **self._send_mode_buttons))
        device_navigation = AddLayerMode(self._device, Layer(device_nav_left_button=self._track_left_button, device_nav_right_button=self._track_right_button))
        self._mode_selector.add_mode('mode_selection', [partial(self._toggle_in_control, True), mode_selection, device_navigation], behaviour=MomentaryBehaviour())
        session_control = AddLayerMode(self._session, Layer(clip_launch_buttons=self._top_pad_row))
        self._mode_selector.add_mode('session_mode', [partial(self._toggle_in_control, False), session_control])
        self._mode_selector.layer = Layer(mode_selection_button=self._encoder_incontrol_button2)

    def _create_in_control_status_listener(self):
        self._in_control_status = InControlStatusComponent(set_is_in_control_on=self._set_is_in_control_on, is_enabled=False, layer=Layer(in_control_status_button=self._pad_in_control_status_button))
        self._in_control_status.set_enabled(True)

    @subject_slot('value')
    def _update_pads(self, value):
        if value:
            self.update()

    @subject_slot('return_tracks')
    def _on_return_tracks_changed(self):
        num_sends = self._mixer.num_sends
        for index in xrange(6):
            self._encoder_modes.set_mode_enabled('send_%d_mode' % (index,), True if index < num_sends else False)

    def _set_send_index(self, index):
        self._mixer.send_index = index

    def _set_is_in_control_on(self, value):
        self._is_in_control_on = value

    def _toggle_in_control(self, value):
        if not self._is_in_control_on:
            self._send_midi(consts.DRUM_IN_CONTROL_ON_MESSAGE if value else consts.DRUM_IN_CONTROL_OFF_MESSAGE)

    def port_settings_changed(self):
        self._disconnect_and_unregister_all_components()
        self._request_task.restart()

    def handle_sysex(self, midi_bytes):
        if self._is_identity_response(midi_bytes):
            product_id_bytes = self._extract_product_id_bytes(midi_bytes)
            if self._is_identity_response_valid(product_id_bytes):
                self._set_model_type(product_id_bytes)
                self._request_task.kill()
                self.on_identified()
            else:
                self.log_message('MIDI device responded with wrong product id (%s).' % (str(product_id_bytes),))
        else:
            super(Launchkey_MK2, self).handle_sysex(midi_bytes)

    def _extract_product_id_bytes(self, midi_bytes):
        return midi_bytes[5:]

    def _is_identity_response(self, midi_bytes):
        return midi_bytes[3:5] == (6, 2)

    def _is_identity_response_valid(self, product_id_bytes):
        return product_id_bytes[:3] == consts.PRODUCT_ID_BYTE_PREFIX and product_id_bytes[3] in consts.PRODUCT_ID_BYTES

    def _set_model_type(self, product_id_bytes):
        self._is_25_key_model = product_id_bytes[3] == consts.LAUNCHKEY_25_ID_BYTE

    def _send_identity_request(self):
        self._send_midi(consts.IDENTITY_REQUEST)

    def on_identified(self):
        self._extended_mode_button.turn_on()
        with self.component_guard():
            self._create_mixer()
            self._create_session()
            self._setup_navigation()
            self._create_transport()
            self._create_device()
            self._create_background()
            self._create_encoder_modes()
            self._create_mode_selector()
            self._create_in_control_status_listener()
            self._on_return_tracks_changed.subject = self.song()
            self._on_return_tracks_changed()
        self._mode_selector.selected_mode = 'session_mode'
        self.update()

    def disconnect(self):
        self._extended_mode_button.turn_off()
        super(Launchkey_MK2, self).disconnect()
예제 #9
0
class Roland_A_PRO(ControlSurface):
    def __init__(self, *a, **k):
        super(Roland_A_PRO, self).__init__(*a, **k)
        with self.component_guard():
            self._create_controls()
            self._create_transport()
            self._create_mixer()
            self._create_device()
            self._create_drums()
            self._create_modes()

    def _create_controls(self):
        self._encoders = ButtonMatrixElement(rows=[[
            EncoderElement(MIDI_CC_TYPE,
                           0,
                           identifier,
                           Live.MidiMap.MapMode.absolute,
                           name='Encoder_%d' % index)
            for index, identifier in enumerate(ENCODER_IDS)
        ]])
        self._master_encoder = EncoderElement(MIDI_CC_TYPE,
                                              0,
                                              10,
                                              Live.MidiMap.MapMode.absolute,
                                              name='Master_Encoder')
        self._sliders = ButtonMatrixElement(rows=[[
            SliderElement(
                MIDI_CC_TYPE, 0, identifier, name='Slider_%d' % index)
            for index, identifier in enumerate(SLIDER_IDS)
        ]])
        self._master_slider = SliderElement(MIDI_CC_TYPE,
                                            0,
                                            7,
                                            name='Master_Slider')
        self._play_button = ButtonElement(True, MIDI_CC_TYPE, 0, 26)
        self._stop_button = ButtonElement(True, MIDI_CC_TYPE, 0, 25)
        self._record_button = ButtonElement(True, MIDI_CC_TYPE, 0, 28)
        self._forward_button = ButtonElement(True, MIDI_CC_TYPE, 0, 24)
        self._backward_button = ButtonElement(True, MIDI_CC_TYPE, 0, 21)
        self._ff_button = ButtonElement(True, MIDI_CC_TYPE, 0, 23)
        self._rw_button = ButtonElement(True, MIDI_CC_TYPE, 0, 22)
        self._device_mode_button = ButtonElement(True, MIDI_CC_TYPE, 0, 80)
        self._pan_mode_button = ButtonElement(True, MIDI_CC_TYPE, 0, 81)
        self._send_a_mode_button = ButtonElement(True, MIDI_CC_TYPE, 0, 82)
        self._send_b_mode_button = ButtonElement(True, MIDI_CC_TYPE, 0, 83)
        self._pads = ButtonMatrixElement(rows=[[
            ButtonElement(True, MIDI_NOTE_TYPE, 0, identifier)
            for identifier in row
        ] for row in PAD_ROWS])

    def _create_transport(self):
        self._transport = TransportComponent(
            name='Transport',
            is_enabled=False,
            layer=Layer(play_button=self._play_button,
                        stop_button=self._stop_button,
                        record_button=self._record_button))
        self._transport.set_enabled(True)

    def _create_mixer(self):
        mixer_size = self._sliders.width()
        self._mixer = MixerComponent(
            mixer_size,
            name='Mixer',
            is_enabled=False,
            layer=Layer(volume_controls=self._sliders,
                        prehear_volume_control=self._master_encoder))
        self._mixer.master_strip().layer = Layer(
            volume_control=self._master_slider)
        self._mixer.set_enabled(True)

    def _create_device(self):
        self._device = DeviceComponent(
            device_selection_follows_track_selection=True)
        self._device_navigation = DeviceNavigationComponent()
        self._device.set_enabled(True)
        self._device_navigation.set_enabled(True)
        self.set_device_component(self._device)

    def _create_drums(self):
        self._drums = DrumRackComponent(name='Drum_Rack',
                                        is_enabled=False,
                                        layer=Layer(pads=self._pads))
        self._drums.set_enabled(True)

    def _create_modes(self):
        self._encoder_modes = ModesComponent()
        device_layer_mode = LayerMode(self._device,
                                      Layer(parameter_controls=self._encoders))
        device_navigation_layer_mode = LayerMode(
            self._device_navigation,
            Layer(device_nav_right_button=self._forward_button,
                  device_nav_left_button=self._backward_button))
        self._encoder_modes.add_mode(
            'device_mode', [device_layer_mode, device_navigation_layer_mode])
        self._encoder_modes.add_mode(
            'pan_mode',
            AddLayerMode(
                self._mixer,
                Layer(pan_controls=self._encoders,
                      bank_up_button=self._forward_button,
                      bank_down_button=self._backward_button,
                      track_up_button=self._ff_button,
                      track_down_button=self._rw_button)))
        send_layer_mode = AddLayerMode(
            self._mixer,
            Layer(send_controls=self._encoders,
                  bank_up_button=self._forward_button,
                  bank_down_button=self._backward_button,
                  track_up_button=self._ff_button,
                  track_down_button=self._rw_button))
        self._encoder_modes.add_mode(
            'send_a_mode', [send_layer_mode,
                            partial(self._set_send_index, 0)])
        self._encoder_modes.add_mode(
            'send_b_mode', [send_layer_mode,
                            partial(self._set_send_index, 1)])
        self._encoder_modes.layer = Layer(
            device_mode_button=self._device_mode_button,
            pan_mode_button=self._pan_mode_button,
            send_a_mode_button=self._send_a_mode_button,
            send_b_mode_button=self._send_b_mode_button)
        self._encoder_modes.selected_mode = 'device_mode'
        self._encoder_modes.set_enabled(True)

    def _set_send_index(self, index):
        self._mixer.send_index = index
class BeatStep(ArturiaControlSurface):

    def __init__(self, *a, **k):
        super(BeatStep, self).__init__(*a, **k)
        self._skin = Skin(Colors)
        with self.component_guard():
            self._create_controls()
            self._create_device()
            self._create_session()
            self._create_mixer()
            self._create_transport()

    def _create_controls(self):
        self._device_encoders = ButtonMatrixElement(rows=[ [ EncoderElement(MIDI_CC_TYPE, 0, identifier, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Encoder_%d_%d' % (column_index, row_index)) for column_index, identifier in enumerate(row) ] for row_index, row in enumerate((ENCODER_MSG_IDS[:4], ENCODER_MSG_IDS[8:12])) ])
        self._horizontal_scroll_encoder = EncoderElement(MIDI_CC_TYPE, 0, 75, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Horizontal_Scroll_Encoder')
        self._vertical_scroll_encoder = EncoderElement(MIDI_CC_TYPE, 0, 72, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Vertical_Scroll_Encoder')
        self._volume_encoder = EncoderElement(MIDI_CC_TYPE, 0, 91, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Volume_Encoder')
        self._pan_encoder = EncoderElement(MIDI_CC_TYPE, 0, 17, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Pan_Encoder')
        self._send_a_encoder = EncoderElement(MIDI_CC_TYPE, 0, 77, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Send_A_Encoder')
        self._send_b_encoder = EncoderElement(MIDI_CC_TYPE, 0, 93, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Send_B_Encoder')
        self._send_encoders = ButtonMatrixElement(rows=[[self._send_a_encoder, self._send_b_encoder]])
        self._return_a_encoder = EncoderElement(MIDI_CC_TYPE, 0, 73, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Return_A_Encoder')
        self._return_b_encoder = EncoderElement(MIDI_CC_TYPE, 0, 79, Live.MidiMap.MapMode.relative_smooth_two_compliment, name='Return_B_Encoder')
        self._return_encoders = ButtonMatrixElement(rows=[[self._return_a_encoder, self._return_b_encoder]])
        self._pads = ButtonMatrixElement(rows=[ [ ButtonElement(True, MIDI_NOTE_TYPE, PAD_CHANNEL, identifier, name='Pad_%d_%d' % (col_index, row_index), skin=self._skin) for col_index, identifier in enumerate(row) ] for row_index, row in enumerate(PAD_MSG_IDS) ])
        self._stop_button = ButtonElement(True, MIDI_CC_TYPE, 0, 1, name='Stop_Button')
        self._play_button = ButtonElement(True, MIDI_CC_TYPE, 0, 2, name='Play_Button')

    def _create_device(self):
        self._device = DeviceComponent(name='Device', is_enabled=False, layer=Layer(parameter_controls=self._device_encoders))
        self._device.set_enabled(True)
        self.set_device_component(self._device)
        self._device_selection_follows_track_selection = True

    def _create_session(self):
        self._session = SessionComponent(name='Session', is_enabled=False, num_tracks=self._pads.width(), num_scenes=self._pads.height(), enable_skinning=True, layer=Layer(clip_launch_buttons=self._pads, scene_select_control=self._vertical_scroll_encoder))
        self._session.set_enabled(True)

    def _create_mixer(self):
        self._mixer = MixerComponent(name='Mixer', is_enabled=False, num_returns=2, layer=Layer(track_select_encoder=self._horizontal_scroll_encoder, selected_track_volume_control=self._volume_encoder, selected_track_pan_control=self._pan_encoder, selected_track_send_controls=self._send_encoders, return_volume_controls=self._return_encoders))
        self._mixer.set_enabled(True)

    def _create_transport(self):
        self._transport = TransportComponent(name='Transport', is_enabled=False, layer=Layer(stop_button=self._stop_button, play_button=self._play_button))
        self._transport.set_enabled(True)

    def _collect_setup_messages(self):
        for identifier, hardware_id in izip(ENCODER_MSG_IDS, HARDWARE_ENCODER_IDS):
            self._setup_hardware_encoder(hardware_id, identifier)

        self._setup_hardware_button(HARDWARE_STOP_BUTTON_ID, 1, msg_type='cc')
        self._setup_hardware_button(HARDWARE_PLAY_BUTTON_ID, 2, msg_type='cc')
        for hardware_id, identifier in izip(HARDWARE_PAD_IDS, chain(*PAD_MSG_IDS)):
            self._setup_hardware_button(hardware_id, identifier, PAD_CHANNEL, msg_type='note')
예제 #11
0
class KontrolF1(ControlSurface):
    __module__ = __name__
    __doc__ = " Script for Native Instruments Traktor Kontrol F1 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

        self._suggested_input_port = 'Traktor Kontrol F1'
        self._suggested_output_port = 'Traktor Kontrol F1'

        self._blink_state = False

        self._matrix = ButtonMatrixElement()
        for row in range(HEIGHT):
            button_row = [ ConfigurableButtonElement(c_instance, True, MIDI_CC_TYPE, 2, ((row * HEIGHT) + column)) for column in range(WIDTH) ]
            self._matrix.add_row(tuple(button_row))

        self._nav_buttons  = [ ConfigurableButtonElement(c_instance, True, MIDI_CC_TYPE, 0, NAV_ENCODER),
                               ConfigurableButtonElement(c_instance, True, MIDI_CC_TYPE, 0, TOGGLE_LEFT_DOWN) ]
        self._scene_buttons = [ ConfigurableButtonElement(c_instance, True, MIDI_CC_TYPE, 0, SCENE_LAUNCH[index]) for index in range(HEIGHT) ]
        
        self._stop_buttons = []
        for index in range(WIDTH):
            self._stop_buttons.append(ConfigurableButtonElement(c_instance, True, MIDI_CC_TYPE, 0, STOP_LAUNCH[index]))
        
        self._session = SpecialSessionComponent(self._matrix.width(), self._matrix.height())

        self._all_buttons = []
        for button in (self._scene_buttons + self._nav_buttons + self._stop_buttons):
            self._all_buttons.append(button)

        for scene_index in range(self._matrix.height()):
            for track_index in range(self._matrix.width()):
                self._all_buttons.append(self._matrix.get_button(track_index, scene_index))
        self._all_buttons = tuple(self._all_buttons)



        self._suppress_session_highlight = False
        self.set_suppress_rebuild_requests(False)
        self._suppress_send_midi = False
        self.set_enabled(True)
        self.update()
        self._set_session_highlight(0,0,WIDTH,HEIGHT,True)

    def disconnect(self):
        self._suppress_send_midi = True

        self._session = None
        for button in self._all_buttons:
            button.set_on_off_values(127, 0)

        self._matrix = None
        self._stop_buttons = None
        self._scene_buttons = None
        self._nav_buttons = None

        ControlSurface.disconnect(self)
        self._suppress_send_midi = False

    def update_display(self):
        tracks = self.song().visible_tracks
        number_tracks = len(tracks)

        if self._blink_state:
            self._blink_state = False
        else:
            self._blink_state = True

        for track in range(WIDTH):
            to = track + self._session._track_offset
            if (to < number_tracks):
                for y in range(HEIGHT):
                    ys = self._session._scene_offset+y
                    yx = (y*4)+track
                    slot = tracks[to].clip_slots[ys]
                    if (slot.controls_other_clips) or (slot.has_clip):
                        if slot.is_triggered:
                            if self._blink_state:
                                self._send_midi(tuple([178,yx,40]))
                            else:
                                self._send_midi(tuple([178,yx,127]))
               


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

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

    def _update_hardware(self):
        pass

    def _send_challenge(self):
        pass

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

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

    def _install_forwarding(self, control):
        result = ControlSurface._install_forwarding(self, control)
        return result

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


    def on_enabled_changed(self):
        self.update()

    def update(self):
        for scene_index in range(HEIGHT):
            self._scene_buttons[scene_index].set_enabled(True)
            self._stop_buttons[scene_index].set_enabled(True)
            for track_index in range(WIDTH):
                self._matrix.get_button(track_index, scene_index).set_enabled(True)


        for button in self._nav_buttons:
            button.set_enabled(True)

        self._session.set_allow_update(False)


        for scene_index in range(HEIGHT):
            scene = self._session.scene(scene_index)
            scene.set_launch_button(self._scene_buttons[scene_index])
            for track_index in range(WIDTH):
                scene.clip_slot(track_index).set_launch_button(self._matrix.get_button(track_index, scene_index))

        #self.log_message(str(tuple(self._stop_buttons)))
        self._session.set_stop_track_clip_buttons(tuple(self._stop_buttons))
        self._session.set_track_bank_buttons(self._nav_buttons[1], self._nav_buttons[1])
        self._session.set_scene_bank_buttons(self._nav_buttons[0], self._nav_buttons[0])
        self._session.set_allow_update(True)
예제 #12
0
class Roland_A_PRO(ControlSurface):

    def __init__(self, *a, **k):
        super(Roland_A_PRO, self).__init__(*a, **k)
        with self.component_guard():
            self._create_controls()
            self._create_transport()
            self._create_mixer()
            self._create_device()
            self._create_drums()
            self._create_modes()

    def _create_controls(self):
        self._encoders = ButtonMatrixElement(rows=[[ EncoderElement(MIDI_CC_TYPE, 0, identifier, Live.MidiMap.MapMode.absolute, name='Encoder_%d' % index) for index, identifier in enumerate(ENCODER_IDS) ]])
        self._master_encoder = EncoderElement(MIDI_CC_TYPE, 0, 10, Live.MidiMap.MapMode.absolute, name='Master_Encoder')
        self._sliders = ButtonMatrixElement(rows=[[ SliderElement(MIDI_CC_TYPE, 0, identifier, name='Slider_%d' % index) for index, identifier in enumerate(SLIDER_IDS) ]])
        self._master_slider = SliderElement(MIDI_CC_TYPE, 0, 7, name='Master_Slider')
        self._play_button = ButtonElement(True, MIDI_CC_TYPE, 0, 26)
        self._stop_button = ButtonElement(True, MIDI_CC_TYPE, 0, 25)
        self._record_button = ButtonElement(True, MIDI_CC_TYPE, 0, 28)
        self._forward_button = ButtonElement(True, MIDI_CC_TYPE, 0, 24)
        self._backward_button = ButtonElement(True, MIDI_CC_TYPE, 0, 21)
        self._ff_button = ButtonElement(True, MIDI_CC_TYPE, 0, 23)
        self._rw_button = ButtonElement(True, MIDI_CC_TYPE, 0, 22)
        self._device_mode_button = ButtonElement(True, MIDI_CC_TYPE, 0, 80)
        self._pan_mode_button = ButtonElement(True, MIDI_CC_TYPE, 0, 81)
        self._send_a_mode_button = ButtonElement(True, MIDI_CC_TYPE, 0, 82)
        self._send_b_mode_button = ButtonElement(True, MIDI_CC_TYPE, 0, 83)
        self._pads = ButtonMatrixElement(rows=[ [ ButtonElement(True, MIDI_NOTE_TYPE, 0, identifier) for identifier in row ] for row in PAD_ROWS ])

    def _create_transport(self):
        self._transport = TransportComponent(name='Transport', is_enabled=False, layer=Layer(play_button=self._play_button, stop_button=self._stop_button, record_button=self._record_button))
        self._transport.set_enabled(True)

    def _create_mixer(self):
        mixer_size = self._sliders.width()
        self._mixer = MixerComponent(mixer_size, name='Mixer', is_enabled=False, layer=Layer(volume_controls=self._sliders, prehear_volume_control=self._master_encoder))
        self._mixer.master_strip().layer = Layer(volume_control=self._master_slider)
        self._mixer.set_enabled(True)

    def _create_device(self):
        self._device = DeviceComponent(device_selection_follows_track_selection=True)
        self._device_navigation = DeviceNavigationComponent()
        self._device.set_enabled(True)
        self._device_navigation.set_enabled(True)
        self.set_device_component(self._device)

    def _create_drums(self):
        self._drums = DrumRackComponent(name='Drum_Rack', is_enabled=False, layer=Layer(pads=self._pads))
        self._drums.set_enabled(True)

    def _create_modes(self):
        self._encoder_modes = ModesComponent()
        device_layer_mode = LayerMode(self._device, Layer(parameter_controls=self._encoders))
        device_navigation_layer_mode = LayerMode(self._device_navigation, Layer(device_nav_right_button=self._forward_button, device_nav_left_button=self._backward_button))
        self._encoder_modes.add_mode('device_mode', [device_layer_mode, device_navigation_layer_mode])
        self._encoder_modes.add_mode('pan_mode', AddLayerMode(self._mixer, Layer(pan_controls=self._encoders, bank_up_button=self._forward_button, bank_down_button=self._backward_button, track_up_button=self._ff_button, track_down_button=self._rw_button)))
        send_layer_mode = AddLayerMode(self._mixer, Layer(send_controls=self._encoders, bank_up_button=self._forward_button, bank_down_button=self._backward_button, track_up_button=self._ff_button, track_down_button=self._rw_button))
        self._encoder_modes.add_mode('send_a_mode', [send_layer_mode, partial(self._set_send_index, 0)])
        self._encoder_modes.add_mode('send_b_mode', [send_layer_mode, partial(self._set_send_index, 1)])
        self._encoder_modes.layer = Layer(device_mode_button=self._device_mode_button, pan_mode_button=self._pan_mode_button, send_a_mode_button=self._send_a_mode_button, send_b_mode_button=self._send_b_mode_button)
        self._encoder_modes.selected_mode = 'device_mode'
        self._encoder_modes.set_enabled(True)

    def _set_send_index(self, index):
        self._mixer.send_index = index
class Launchpad_MK2(IdentifiableControlSurface, OptimizedControlSurface):

    def __init__(self, c_instance, *a, **k):
        super(Launchpad_MK2, self).__init__(product_id_bytes=consts.PRODUCT_ID_BYTES, c_instance=c_instance, *a, **k)
        self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143
        with self.component_guard():
            self._skin = make_default_skin()
            with inject(skin=const(self._skin)).everywhere():
                self._create_controls()
            self._create_session()
            self._create_mixer()
            self._last_sent_layout_byte = None
            with inject(switch_layout=const(self._switch_layout)).everywhere():
                self._create_modes()

    def _create_controls(self):
        multi_button_channels = consts.USER_MODE_CHANNELS
        self._session_button_single = make_button(108, 0, 'Session_Mode_Button', msg_type=MIDI_CC_TYPE, is_modifier=True)
        self._session_button = FilteringMultiElement([self._session_button_single] + [ make_button(108, channel, msg_type=MIDI_CC_TYPE, name='Session_Mode_Button_ch_%d' % (channel,)) for channel in multi_button_channels ], feedback_channels=[0])
        self._user_1_button = FilteringMultiElement([ make_button(109, channel, msg_type=MIDI_CC_TYPE, name='User_1_Mode_Button_ch_%d' % (channel,)) for channel in (0,) + multi_button_channels ], feedback_channels=[0,
         5,
         6,
         7])
        self._user_2_button = FilteringMultiElement([ make_button(110, channel, msg_type=MIDI_CC_TYPE, name='User_2_Mode_Button_ch_%d' % (channel,)) for channel in (0,) + multi_button_channels ], feedback_channels=[0,
         13,
         14,
         15])
        self._mixer_button = FilteringMultiElement([ make_button(111, channel, msg_type=MIDI_CC_TYPE, name='Mixer_Mode_Button_ch_%d' % (channel,)) for channel in (0,) + multi_button_channels ], feedback_channels=[0])
        self._up_button = make_button(104, 0, msg_type=MIDI_CC_TYPE, name='Up_Button')
        self._down_button = make_button(105, 0, msg_type=MIDI_CC_TYPE, name='Down_Button')
        self._left_button = make_button(106, 0, msg_type=MIDI_CC_TYPE, name='Left_Button')
        self._right_button = make_button(107, 0, msg_type=MIDI_CC_TYPE, name='Right_Button')
        self._session_matrix_raw = [ [ make_button(col + offset, 0, name='Session_Matrix_Button_%d_%d' % (col, row)) for col in xrange(consts.SESSION_WIDTH) ] for row, offset in enumerate(xrange(81, 10, -10)) ]
        self._session_matrix = ButtonMatrixElement(rows=self._session_matrix_raw, name='Session_Matrix')
        self._scene_launch_matrix_raw = [ make_button(identifier, 0, name='Scene_Launch_Button_%d' % (index,)) for index, identifier in enumerate(xrange(89, 18, -10)) ]
        self._scene_launch_matrix = ButtonMatrixElement(rows=[self._scene_launch_matrix_raw], name='Scene_Launch_Buttons')
        self._session_zoom_matrix = ButtonMatrixElement(rows=recursive_map(partial(with_modifier, self._session_button_single), self._session_matrix_raw))
        self._volume_reset_buttons = self._session_matrix.submatrix[:, :1]
        self._pan_reset_buttons = self._session_matrix.submatrix[:, 1:2]
        self._send_a_reset_buttons = self._session_matrix.submatrix[:, 2:3]
        self._send_b_reset_buttons = self._session_matrix.submatrix[:, 3:4]
        self._stop_clip_buttons = self._session_matrix.submatrix[:, 4:5]
        self._mute_buttons = self._session_matrix.submatrix[:, 5:6]
        self._solo_buttons = self._session_matrix.submatrix[:, 6:7]
        self._arm_buttons = self._session_matrix.submatrix[:, 7:]
        self._volume_button = self._scene_launch_matrix_raw[0]
        self._pan_button = self._scene_launch_matrix_raw[1]
        self._send_a_button = self._scene_launch_matrix_raw[2]
        self._send_b_button = self._scene_launch_matrix_raw[3]
        self._stop_button = self._scene_launch_matrix_raw[4]
        self._mute_button = self._scene_launch_matrix_raw[5]
        self._solo_button = self._scene_launch_matrix_raw[6]
        self._record_arm_button = self._scene_launch_matrix_raw[7]
        self._sliders = ButtonMatrixElement(rows=[[ SliderElement(MIDI_CC_TYPE, 0, identifier) for identifier in xrange(21, 29) ]])

    def _create_session(self):
        self._session = SessionComponent(is_enabled=False, num_tracks=self._session_matrix.width(), num_scenes=self._session_matrix.height(), enable_skinning=True, name='Session', is_root=True, layer=Layer(track_bank_left_button=self._left_button, track_bank_right_button=self._right_button, scene_bank_up_button=self._up_button, scene_bank_down_button=self._down_button))
        self._session.set_rgb_mode(CLIP_COLOR_TABLE, RGB_COLOR_TABLE)
        self._session_layer_mode = AddLayerMode(self._session, Layer(clip_launch_buttons=self._session_matrix, scene_launch_buttons=self._scene_launch_matrix))
        self._session_zoom = SessionZoomingComponent(self._session, is_enabled=False, enable_skinning=True, layer=Layer(nav_up_button=with_modifier(self._session_button_single, self._up_button), nav_down_button=with_modifier(self._session_button_single, self._down_button), nav_left_button=with_modifier(self._session_button_single, self._left_button), nav_right_button=with_modifier(self._session_button_single, self._right_button), button_matrix=self._session_zoom_matrix))
        self._stop_clip_layer_mode = AddLayerMode(self._session, Layer(stop_track_clip_buttons=self._stop_clip_buttons, stop_all_clips_button=self._stop_button))

    def _create_mixer(self):
        self._mixer = MixerComponent(is_enabled=False, num_tracks=consts.SESSION_WIDTH, invert_mute_feedback=True, enable_skinning=True, name='Mixer', is_root=True)
        self._session.set_mixer(self._mixer)
        self._mixer_home_page_layer = LayerMode(self._mixer, Layer(volume_reset_buttons=self._volume_reset_buttons, pan_reset_buttons=self._pan_reset_buttons, send_a_reset_buttons=self._send_a_reset_buttons, send_b_reset_buttons=self._send_b_reset_buttons, mute_buttons=self._mute_buttons, solo_buttons=self._solo_buttons, arm_buttons=self._arm_buttons, unmute_all_button=self._mute_button, unsolo_all_button=self._solo_button, unarm_all_button=self._record_arm_button))
        self._mixer_volume_layer = LayerMode(self._mixer, Layer(volume_controls=self._sliders))
        self._mixer_pan_layer = LayerMode(self._mixer, Layer(pan_controls=self._sliders))
        self._mixer_sends_layer = LayerMode(self._mixer, Layer(send_controls=self._sliders))

    def _create_translating_mixer_background(self, translation_channel):
        return TranslatingBackgroundComponent(translation_channel=translation_channel, is_enabled=False, name='Background', layer=Layer(stop_button=self._stop_button, mute_buttons=self._mute_button, solo_button=self._solo_button, record_arm_button=self._record_arm_button))

    def _create_modes(self):
        self._modes = NotifyingModesComponent(is_root=True)
        self._modes.default_behaviour = mixin(SkinableBehaviourMixin, ImmediateBehaviour)()
        self._modes.add_mode('session_mode', [self._session, self._session_layer_mode], layout_byte=0, behaviour=EnablingReenterBehaviour(self._session_zoom))
        self._modes.add_mode('user_1_mode', [], layout_byte=1)
        self._modes.add_mode('user_2_mode', [], layout_byte=2)
        self._modes.add_mode('volume_mode', [self._session, self._create_translating_mixer_background(consts.VOLUME_MODE_CHANNEL), self._mixer_volume_layer], layout_byte=4, groups=set('mixer'))
        self._modes.add_mode('pan_mode', [self._session, self._create_translating_mixer_background(consts.PAN_MODE_CHANNEL), self._mixer_pan_layer], layout_byte=5, groups=set('mixer'))
        self._modes.add_mode('send_a_mode', [self._session,
         self._create_translating_mixer_background(consts.SEND_A_MODE_CHANNEL),
         partial(self._set_send_index, 0),
         self._mixer_sends_layer], layout_byte=6, groups=set('mixer'))
        self._modes.add_mode('send_b_mode', [self._session,
         self._create_translating_mixer_background(consts.SEND_B_MODE_CHANNEL),
         partial(self._set_send_index, 1),
         self._mixer_sends_layer], layout_byte=7, groups=set('mixer'))
        self._modes.add_mode('mixer_mode', [self._session, self._stop_clip_layer_mode, self._mixer_home_page_layer], layout_byte=3, groups=set('mixer'))
        self._modes.layer = Layer(session_mode_button=self._session_button, user_1_mode_button=self._user_1_button, user_2_mode_button=self._user_2_button, mixer_mode_button=self._mixer_button, volume_mode_button=self._volume_button, pan_mode_button=self._pan_button, send_a_mode_button=self._send_a_button, send_b_mode_button=self._send_b_button)
        self._modes.selected_mode = 'session_mode'

    def _set_send_index(self, index):
        self._mixer.send_index = index

    def _switch_layout(self, layout_byte):
        if layout_byte != self._last_sent_layout_byte:
            prefix = consts.STANDARD_SYSEX_PREFIX + consts.LAYOUT_CHANGE_BYTE
            self._send_midi(prefix + (layout_byte, 247))
            self._clear_send_cache()
            self._last_sent_layout_byte = layout_byte

    def _clear_send_cache(self):
        with self.component_guard():
            for control in self.controls:
                control.clear_send_cache()

    def _send_identity_request(self):
        self._send_midi(consts.IDENTITY_REQUEST)

    def on_identified(self):
        self._send_challenge()

    def _send_challenge(self):
        challenge_bytes = tuple([ self._challenge >> 8 * index & 127 for index in xrange(4) ])
        self._send_midi(consts.STANDARD_SYSEX_PREFIX + consts.CHALLENGE_RESPONSE_BYTE + challenge_bytes + (247,))

    def handle_sysex(self, midi_bytes):
        if self._is_challenge_response(midi_bytes) and self._is_response_valid(midi_bytes):
            self._on_handshake_successful()
        else:
            super(Launchpad_MK2, self).handle_sysex(midi_bytes)

    def _is_challenge_response(self, midi_bytes):
        return len(midi_bytes) == 10 and midi_bytes[:7] == consts.STANDARD_SYSEX_PREFIX + consts.CHALLENGE_RESPONSE_BYTE

    def _is_response_valid(self, midi_bytes):
        response = long(midi_bytes[7])
        response += long(midi_bytes[8] << 8)
        return response == Live.Application.encrypt_challenge2(self._challenge)

    def _on_handshake_successful(self):
        self._modes.set_enabled(True)
        self._mixer.set_enabled(True)
        self._last_sent_layout_byte = None
        self._modes.send_switch_layout_message()
        self.set_highlighting_session_component(self._session)
        self.update()

    def disconnect(self):
        self._send_midi(consts.QUIT_MESSAGE)
        super(Launchpad_MK2, self).disconnect()
class MiniLab(ArturiaControlSurface):
    session_component_type = SessionComponent
    encoder_msg_channel = 0
    encoder_msg_ids = (7, 74, 71, 76, 77, 93, 73, 75, 114, 18, 19, 16, 17, 91,
                       79, 72)
    pad_channel = 9

    def __init__(self, *a, **k):
        super(MiniLab, self).__init__(*a, **k)
        with self.component_guard():
            self._create_controls()
            self._create_device()
            self._create_session()
            self._create_mixer()

    def _create_controls(self):
        self._device_controls = ButtonMatrixElement(rows=[[
            EncoderElement(MIDI_CC_TYPE,
                           self.encoder_msg_channel,
                           identifier,
                           Live.MidiMap.MapMode.relative_smooth_binary_offset,
                           name=u'Encoder_%d_%d' % (column_index, row_index))
            for column_index, identifier in enumerate(row)
        ] for row_index, row in enumerate((self.encoder_msg_ids[:4],
                                           self.encoder_msg_ids[8:12]))])
        self._horizontal_scroll_encoder = EncoderElement(
            MIDI_CC_TYPE,
            self.encoder_msg_channel,
            self.encoder_msg_ids[7],
            Live.MidiMap.MapMode.relative_smooth_binary_offset,
            name=u'Horizontal_Scroll_Encoder')
        self._vertical_scroll_encoder = EncoderElement(
            MIDI_CC_TYPE,
            self.encoder_msg_channel,
            self.encoder_msg_ids[15],
            Live.MidiMap.MapMode.relative_smooth_binary_offset,
            name=u'Vertical_Scroll_Encoder')
        self._volume_encoder = EncoderElement(
            MIDI_CC_TYPE,
            self.encoder_msg_channel,
            self.encoder_msg_ids[13],
            Live.MidiMap.MapMode.relative_smooth_binary_offset,
            name=u'Volume_Encoder')
        self._pan_encoder = EncoderElement(
            MIDI_CC_TYPE,
            self.encoder_msg_channel,
            self.encoder_msg_ids[12],
            Live.MidiMap.MapMode.relative_smooth_binary_offset,
            name=u'Pan_Encoder')
        self._send_a_encoder = EncoderElement(
            MIDI_CC_TYPE,
            self.encoder_msg_channel,
            self.encoder_msg_ids[4],
            Live.MidiMap.MapMode.relative_smooth_binary_offset,
            name=u'Send_A_Encoder')
        self._send_b_encoder = EncoderElement(
            MIDI_CC_TYPE,
            self.encoder_msg_channel,
            self.encoder_msg_ids[5],
            Live.MidiMap.MapMode.relative_smooth_binary_offset,
            name=u'Send_B_Encoder')
        self._send_encoders = ButtonMatrixElement(
            rows=[[self._send_a_encoder, self._send_b_encoder]])
        self._return_a_encoder = EncoderElement(
            MIDI_CC_TYPE,
            self.encoder_msg_channel,
            self.encoder_msg_ids[6],
            Live.MidiMap.MapMode.relative_smooth_binary_offset,
            name=u'Return_A_Encoder')
        self._return_b_encoder = EncoderElement(
            MIDI_CC_TYPE,
            self.encoder_msg_channel,
            self.encoder_msg_ids[14],
            Live.MidiMap.MapMode.relative_smooth_binary_offset,
            name=u'Return_B_Encoder')
        self._return_encoders = ButtonMatrixElement(
            rows=[[self._return_a_encoder, self._return_b_encoder]])
        self._pads = ButtonMatrixElement(rows=[[
            ButtonElement(True,
                          MIDI_NOTE_TYPE,
                          self.pad_channel,
                          col + 36 + 8 * row,
                          name=u'Pad_%d_%d' % (col, row)) for col in xrange(8)
        ] for row in xrange(2)])

    def _create_device(self):
        self._device = DeviceComponent(
            name=u'Device',
            is_enabled=False,
            layer=Layer(parameter_controls=self._device_controls),
            device_selection_follows_track_selection=True)
        self._device.set_enabled(True)
        self.set_device_component(self._device)

    def _create_session(self):
        self._session = self.session_component_type(
            num_tracks=self._pads.width(),
            num_scenes=self._pads.height(),
            name=u'Session',
            is_enabled=False,
            layer=Layer(clip_launch_buttons=self._pads,
                        scene_select_control=self._vertical_scroll_encoder))
        self._session.set_enabled(True)

    def _create_mixer(self):
        self._mixer = MixerComponent(
            name=u'Mixer',
            is_enabled=False,
            num_returns=2,
            layer=Layer(track_select_encoder=self._horizontal_scroll_encoder,
                        selected_track_volume_control=self._volume_encoder,
                        selected_track_pan_control=self._pan_encoder,
                        selected_track_send_controls=self._send_encoders,
                        return_volume_controls=self._return_encoders))
        self._mixer.set_enabled(True)

    def _collect_setup_messages(self):
        #        for cc_id, encoder_id in izip(self.encoder_msg_ids, HARDWARE_ENCODER_IDS):
        #            self._setup_hardware_encoder(encoder_id, cc_id, channel=self.encoder_msg_channel)

        for index, pad_id in enumerate(HARDWARE_BUTTON_IDS):
            self._setup_hardware_button(pad_id, index + PAD_IDENTIFIER_OFFSET,
                                        self.pad_channel)