class SLMkIII(IdentifiableControlSurface): _sysex_message_cache = MidiMessageCache() def __init__(self, *a, **k): super(SLMkIII, self).__init__( product_id_bytes=(sysex.NOVATION_MANUFACTURER_ID + sysex.DEVICE_FAMILY_CODE + sysex.DEVICE_FAMILY_MEMBER_CODE), *a, **k) self._main_modes = NullModes() self._element_injector = inject( element_container=const(None)).everywhere() self._message_injector = inject(message=const(None)).everywhere() with self.component_guard(): with inject(skin=const(skin), message_cache=const( self._sysex_message_cache)).everywhere(): self._elements = Elements() self._element_injector = inject( element_container=const(self._elements)).everywhere() with self.component_guard(): self._create_message() self._message_injector = inject( message=const(self._message)).everywhere() self._switch_display_layout(sysex.KNOB_SCREEN_LAYOUT_BYTE) self._device_bank_registry = DeviceBankRegistry() with self.component_guard(): self._create_session() self._create_mixer() self._create_transport() self._create_session_recording() self._create_auto_arm() self._create_track_navigation() self._create_drums() self._create_device() self._create_device_navigation() self._create_actions() self._create_clip_actions() self._create_background() self._create_modes() self._drum_group_finder = self.register_disconnectable( PercussionInstrumentFinder( device_parent=self.song.view.selected_track)) self.__on_drum_group_found.subject = self._drum_group_finder self.__on_drum_group_found() self.__on_selected_track_changed.subject = self.song.view self.__on_selected_track_changed() self.__on_session_record_changed.subject = self.song self.__on_record_mode_changed.subject = self.song self.set_feedback_channels([DRUM_FEEDBACK_CHANNEL]) self._set_feedback_velocity() def on_identified(self, midi_bytes): self._switch_display_layout(sysex.KNOB_SCREEN_LAYOUT_BYTE, force=True) self._main_modes.selected_mode = u'device_control' self._auto_arm.set_enabled(True) self._session_ring.set_enabled(True) self.set_feedback_channels([DRUM_FEEDBACK_CHANNEL]) super(SLMkIII, self).on_identified(midi_bytes) def disconnect(self): self._auto_arm.set_enabled(False) super(SLMkIII, self).disconnect() def port_settings_changed(self): self._auto_arm.set_enabled(False) self._session_ring.set_enabled(False) super(SLMkIII, self).port_settings_changed() @contextmanager def _component_guard(self): with super(SLMkIII, self)._component_guard(): with self._element_injector: with self._message_injector: yield self._format_and_send_sysex() def _format_and_send_sysex(self): messages_to_send = sysex.make_sysex_from_segments( self._sysex_message_cache.messages) for msg in messages_to_send: self._send_midi(msg) self._sysex_message_cache.clear() def _install_mapping(self, midi_map_handle, control, parameter, feedback_delay, feedback_map): success = False if control.message_type() == MIDI_CC_TYPE: feedback_rule = Live.MidiMap.CCFeedbackRule() feedback_rule.cc_no = control.message_identifier() feedback_rule.cc_value_map = feedback_map feedback_rule.channel = getattr(control, u'feedback_channel', control.message_channel()) feedback_rule.delay_in_ms = feedback_delay success = Live.MidiMap.map_midi_cc_with_feedback_map( midi_map_handle, parameter, control.message_channel(), control.message_identifier(), control.message_map_mode(), feedback_rule, not control.needs_takeover(), control.mapping_sensitivity) if success: Live.MidiMap.send_feedback_for_parameter( midi_map_handle, parameter) return success def _create_message(self): self._message = MessageComponent( name=u'Message', is_enabled=False, layer=Layer(display=u'message_display')) self._message.set_enabled(True) def _switch_display_layout(self, layout_byte, force=False): display_layout_switch = self._elements.display_layout_switch if force: display_layout_switch.clear_send_cache() display_layout_switch.send_value(layout_byte) self._clear_display_send_cache() def _clear_display_send_cache(self): for display in self._elements.text_display_lines: display.clear_send_cache() def _create_session(self): self._session_ring = SessionRingComponent( is_enabled=False, num_tracks=SESSION_WIDTH, num_scenes=SESSION_HEIGHT, tracks_to_use=lambda: tuple(self.song.visible_tracks) + tuple( self.song.return_tracks) + (self.song.master_track, ), name=u'Session_Ring') self._session = SessionComponent( is_enabled=False, session_ring=self._session_ring, name=u'Session', layer=Layer( clip_launch_buttons=u'pads', scene_launch_buttons=u'scene_launch_buttons', stop_track_clip_buttons=u'shifted_pad_row_1', stop_all_clips_button=u'shifted_scene_launch_button_1')) self._session.set_rgb_mode(CLIP_COLOR_TABLE, RGB_COLOR_TABLE) self._session.set_enabled(True) self._session_navigation = SessionNavigationComponent( session_ring=self._session_ring, name=u'Session_Navigation') def _create_mixer(self): self._mixer = MixerComponent( name=u'Mixer', is_enabled=False, auto_name=True, tracks_provider=self._session_ring, track_assigner=RightAlignTracksTrackAssigner( song=self.song, include_master_track=True), invert_mute_feedback=True, layer=Layer(volume_controls=u'sliders', volume_leds=u'slider_leds')) self._mixer.set_enabled(True) self._mixer_button_modes = DisplayingNavigatableModesComponent( name=u'Mixer_Button_Modes') self._mixer_button_modes.add_mode( u'mute_solo', AddLayerMode( self._mixer, Layer(mute_buttons=u'mixer_soft_button_row_0', solo_buttons=u'mixer_soft_button_row_1'))) self._mixer_button_modes.add_mode( u'monitor_arm', AddLayerMode( self._mixer, Layer(monitoring_state_buttons=u'mixer_soft_button_row_0', arm_buttons=u'mixer_soft_button_row_1'))) self._mixer_button_modes.layer = Layer( prev_mode_button=u'mixer_up_button', next_mode_button=u'mixer_down_button', display_1=u'mixer_display_1', display_2=u'mixer_display_2', color_field_1=u'mixer_color_field_1', color_field_2=u'mixer_color_field_2') self._mixer_button_modes.selected_mode = u'mute_solo' def _create_transport(self): self._transport = TransportComponent( name=u'Transport', is_enabled=False, layer=Layer(play_button=u'play_button', stop_button=u'stop_button', seek_backward_button=u'rw_button', seek_forward_button=u'ff_button', loop_button=u'loop_button', record_button=u'record_button', continue_playing_button=u'play_button_with_shift')) self._transport.set_enabled(True) def _create_session_recording(self): self._session_recording = SessionRecordingComponent( name=u'Session_Recording', is_enabled=False, layer=Layer(record_button=u'record_button_with_shift')) self._session_recording.set_enabled(True) def _create_auto_arm(self): self._auto_arm = AutoArmComponent(is_enabled=False, name=u'Auto_Arm') def _create_track_navigation(self): self._view_control = NotifyingViewControlComponent( name=u'view_control', is_enabled=False, track_provider=self._session_ring, layer=Layer( prev_track_button=u'track_left_button', next_track_button=u'track_right_button', prev_track_page_button=u'track_left_button_with_shift', next_track_page_button=u'track_right_button_with_shift', prev_scene_button=u'up_button_with_shift', next_scene_button=u'down_button_with_shift')) self._view_control.set_enabled(True) self._session_ring_selection_linking = self.register_disconnectable( SessionRingSelectionLinking( session_ring=self._session_ring, selection_changed_notifier=self._view_control)) def _create_drums(self): self._drum_group = DrumGroupComponent( name=u'Drum_Group', translation_channel=DRUM_FEEDBACK_CHANNEL) def _create_device(self): self._banking_info = BankingInfo(BANK_DEFINITIONS) self._device = DeviceComponent( device_decorator_factory=DeviceDecoratorFactory(), device_bank_registry=self._device_bank_registry, banking_info=self._banking_info, name=u'Device') self._device_parameters = DeviceParameterComponent( parameter_provider=self._device, name=u'Device_Parameters') def _create_device_navigation(self): self._device_navigation = DisplayingDeviceNavigationComponent( banking_info=self._banking_info, device_bank_registry=self._device_bank_registry, device_component=self._device, num_visible_items=NUM_VISIBLE_ITEMS, name=u'Device_Navigation') def _create_actions(self): self._actions = ActionsComponent( name=u'Actions', is_enabled=False, layer=Layer( actions_color_fields=u'color_field_line_2_with_shift', undo_button=u'select_buttons_with_shift_raw[0]', redo_button=u'select_buttons_with_shift_raw[1]', metronome_button=u'select_buttons_with_shift_raw[2]', capture_midi_button=u'select_buttons_with_shift_raw[7]')) self._actions.set_enabled(True) def _create_clip_actions(self): self._clip_actions = ClipActionsComponent( name=u'Clip_Actions', is_enabled=False, layer=Layer(delete_button=u'clear_button', duplicate_button=u'duplicate_button', double_loop_button=u'duplicate_button_with_shift')) self._clip_actions.set_enabled(True) def _create_background(self): self._background = BackgroundComponent( name=u'Background', is_enabled=False, add_nop_listeners=True, layer=Layer( select_button_7_with_shift=u'select_buttons_with_shift_raw[3]', select_button_4_with_shift=u'select_buttons_with_shift_raw[4]', select_button_5_with_shift=u'select_buttons_with_shift_raw[5]', select_button_6_with_shift=u'select_buttons_with_shift_raw[6]') ) self._background.set_enabled(True) def _create_modes(self): self._encoder_modes = DisplayingSkinableModesComponent( name=u'Encoder_Modes') self._encoder_modes.add_mode(u'devices', [ partial(self._switch_display_layout, sysex.BOX_SCREEN_LAYOUT_BYTE), AddLayerMode( self._encoder_modes, Layer(mode_display=self._elements.text_display_line_5, mode_color_fields=self._elements.color_field_line_2, mode_selection_fields=self._elements. selection_field_line_2)), LayerMode( self._device_navigation, Layer(select_buttons=u'pads_flattened', device_color_fields=u'color_field_lines_0_1_flattened', device_name_display_1=u'text_display_line_0', device_name_display_2=u'text_display_line_2', device_bank_name_display_1=u'text_display_line_1', device_bank_name_display_2=u'text_display_line_3', device_selection_fields= u'selection_field_lines_0_1_flattened', selected_device_name_display=u'center_display_1')), SetAttributeMode(self._device_navigation, u'scroll_left_layer', Layer(button=u'up_button')), SetAttributeMode(self._device_navigation, u'scroll_right_layer', Layer(button=u'down_button')), LayerMode( self._device, Layer(prev_bank_button=u'display_up_button', next_bank_button=u'display_down_button')), AddLayerMode( self._mixer, Layer(selected_track_color_field=u'center_color_field', selected_track_name_display=u'center_display_1')), AddLayerMode( self._background, Layer(center_display_2=u'center_display_2', scene_launch_buttons=u'scene_launch_buttons', encoders=u'encoders')), AddLayerMode( self._actions, Layer(actions_display=u'text_display_line_5_with_shift', actions_selection_fields= u'selection_field_line_2_with_shift')) ]) self._encoder_modes.add_mode(u'pan', [ partial(self._switch_display_layout, sysex.KNOB_SCREEN_LAYOUT_BYTE), AddLayerMode( self._encoder_modes, Layer(mode_display=self._elements.text_display_line_3, mode_color_fields=self._elements.color_field_line_2, mode_selection_fields=self._elements. selection_field_line_1, selected_mode_color_field=u'center_color_field')), AddLayerMode( self._mixer, Layer(pan_controls=u'encoders', track_names_display=u'text_display_line_0', pan_value_display=u'text_display_line_1', pan_encoder_color_fields=u'encoder_color_fields', track_color_fields=u'color_field_line_0', mixer_display=u'center_display_1', pan_display=u'center_display_2')), AddLayerMode( self._background, Layer(display_up_button=u'display_up_button', display_down_button=u'display_down_button')), AddLayerMode( self._actions, Layer(actions_display=u'text_display_line_3_with_shift', actions_selection_fields= u'selection_field_line_1_with_shift')) ]) self._encoder_modes.add_mode(u'sends', [ partial(self._switch_display_layout, sysex.KNOB_SCREEN_LAYOUT_BYTE), AddLayerMode( self._encoder_modes, Layer(mode_display=self._elements.text_display_line_3, mode_color_fields=self._elements.color_field_line_2, mode_selection_fields=self._elements. selection_field_line_1, selected_mode_color_field=u'center_color_field')), AddLayerMode( self._mixer, Layer(send_controls=u'encoders', send_up_button=u'display_up_button', send_down_button=u'display_down_button', track_names_display=u'text_display_line_0', track_color_fields=u'color_field_line_0', mixer_display=u'center_display_1', send_index_display=u'center_display_2', send_value_display=u'text_display_line_1', send_encoder_color_fields=u'encoder_color_fields')), AddLayerMode( self._actions, Layer(actions_display=u'text_display_line_3_with_shift', actions_selection_fields= u'selection_field_line_1_with_shift')) ]) self._pad_modes = ModesComponent(name=u'Pad_Modes') self._pad_modes.add_mode( u'drum', LayerMode( self._drum_group, Layer(matrix=u'pads_quadratic', scroll_up_button=u'up_button', scroll_down_button=u'down_button'))) self._pad_modes.add_mode( u'disabled', AddLayerMode( self._background, Layer(matrix=u'pads_quadratic', scroll_up_button=u'up_button', scroll_down_button=u'down_button'))) self._main_modes = ModesComponent(name=u'Encoder_Modes') set_main_mode = partial(setattr, self._main_modes, u'selected_mode') self._main_modes.add_mode(u'device_control', [ partial(self._switch_display_layout, sysex.KNOB_SCREEN_LAYOUT_BYTE), AddLayerMode( self._mixer, Layer(track_select_buttons=u'select_buttons', track_names_display=u'text_display_line_3', track_color_fields=u'color_field_line_2', track_selection_fields=u'selection_field_line_1', selected_track_color_field=u'center_color_field')), LayerMode( self._device_parameters, Layer(parameter_controls=u'encoders', name_display_line=u'text_display_line_0', value_display_line=u'text_display_line_1', parameter_color_fields=u'color_field_line_0', encoder_color_fields=u'encoder_color_fields')), LayerMode( self._session_navigation, Layer(up_button=u'up_button', down_button=u'down_button')), LayerMode( self._device, Layer(prev_bank_button=u'display_up_button', next_bank_button=u'display_down_button')), LayerMode( self._device_navigation, Layer(selected_device_name_display=u'center_display_1', selected_device_bank_name_display=u'center_display_2')), AddLayerMode( self._actions, Layer(actions_display=u'text_display_line_3_with_shift', actions_selection_fields= u'selection_field_line_1_with_shift')) ]) self._main_modes.add_mode( u'options', [ self._encoder_modes, LayerMode( self._encoder_modes, Layer(devices_button=u'select_buttons_raw[0]', pan_button=u'select_buttons_raw[1]', sends_button=u'select_buttons_raw[2]')), SetAttributeMode(self._encoder_modes, u'selected_mode', u'devices'), AddLayerMode( self._background, Layer(select_button_3=u'select_buttons_raw[3]', select_button_4=u'select_buttons_raw[4]', select_button_5=u'select_buttons_raw[5]', select_button_6=u'select_buttons_raw[6]', select_button_7=u'select_buttons_raw[7]')) ], behaviour=ReenterBehaviour( on_reenter=partial(set_main_mode, u'device_control'))) self._main_modes.add_mode(u'grid', [ partial(self._switch_display_layout, sysex.KNOB_SCREEN_LAYOUT_BYTE), self._pad_modes, AddLayerMode( self._mixer, Layer(track_select_buttons=u'select_buttons', track_names_display=u'text_display_line_3', track_color_fields=u'color_field_line_2', track_selection_fields=u'selection_field_line_1', selected_track_color_field=u'center_color_field')), self._select_grid_mode, LayerMode( self._device_parameters, Layer(parameter_controls=u'encoders', name_display_line=u'text_display_line_0', value_display_line=u'text_display_line_1', parameter_color_fields=u'color_field_line_0', encoder_color_fields=u'encoder_color_fields')), LayerMode( self._device, Layer(prev_bank_button=u'display_up_button', next_bank_button=u'display_down_button')), LayerMode( self._device_navigation, Layer(selected_device_name_display=u'center_display_1', selected_device_bank_name_display=u'center_display_2')), AddLayerMode(self._background, Layer(scene_launch_buttons=u'scene_launch_buttons')), AddLayerMode( self._actions, Layer(actions_display=u'text_display_line_3_with_shift', actions_selection_fields= u'selection_field_line_1_with_shift')) ], behaviour=ReenterBehaviour( on_reenter=partial( set_main_mode, u'device_control'))) self._main_modes.layer = Layer(options_button=u'options_button', grid_button=u'grid_button') self._main_modes.selected_mode = u'device_control' @listens(u'instrument') def __on_drum_group_found(self): self._drum_group.set_drum_group_device( self._drum_group_finder.drum_group) self._select_grid_mode() @listens(u'selected_track') def __on_selected_track_changed(self): track = self.song.view.selected_track self.__on_selected_track_implicit_arm_changed.subject = track self._drum_group_finder.device_parent = track self._select_grid_mode() @listens(u'session_record') def __on_session_record_changed(self): self._set_feedback_velocity() @listens(u'implicit_arm') def __on_selected_track_implicit_arm_changed(self): self._set_feedback_velocity() @listens(u'record_mode') def __on_record_mode_changed(self): self._set_feedback_velocity() def _select_grid_mode(self): if self._main_modes.selected_mode == u'grid': drum_device = self._drum_group_finder.drum_group self._pad_modes.selected_mode = u'drum' if drum_device else u'disabled' if drum_device: self.set_controlled_track(self.song.view.selected_track) self._set_feedback_velocity() else: self.release_controlled_track() def _set_feedback_velocity(self): if is_song_recording( self.song) and self.song.view.selected_track.implicit_arm: feedback_velocity = Rgb.RED.midi_value else: feedback_velocity = Rgb.GREEN.midi_value self._c_instance.set_feedback_velocity(int(feedback_velocity))
class Launchkey_Mini_MK3(InstrumentControlMixin, NovationBase): model_family_code = ids.LK_MINI_MK3_FAMILY_CODE element_class = Elements session_height = SESSION_HEIGHT skin = skin suppress_layout_switch = False def __init__(self, *a, **k): self._last_pad_layout_byte = midi.PAD_SESSION_LAYOUT self._last_pot_layout_byte = midi.POT_VOLUME_LAYOUT (super(Launchkey_Mini_MK3, self).__init__)(*a, **k) def disconnect(self): self._elements.pad_layout_switch.send_value(midi.PAD_DRUM_LAYOUT) self._auto_arm.set_enabled(False) super(Launchkey_Mini_MK3, self).disconnect() def on_identified(self, midi_bytes): self._elements.incontrol_mode_switch.send_value( midi.INCONTROL_ONLINE_VALUE) self._elements.pad_layout_switch.send_value(self._last_pad_layout_byte) self._elements.pot_layout_switch.send_value(self._last_pot_layout_byte) self._target_track_changed() self._drum_group_changed() self._auto_arm.set_enabled(True) self.set_feedback_channels([DRUM_FEEDBACK_CHANNEL]) super(Launchkey_Mini_MK3, self).on_identified(midi_bytes) def port_settings_changed(self): self._auto_arm.set_enabled(False) super(Launchkey_Mini_MK3, self).port_settings_changed() def _create_components(self): super(Launchkey_Mini_MK3, self)._create_components() self.register_slot(self._elements.incontrol_mode_switch, nop, 'value') self._background = BackgroundComponent(name='Background', add_nop_listeners=True) self._create_auto_arm() self._create_view_control() self._create_transport() self._create_device() self._create_drum_group() self._create_pot_modes() self._create_stop_solo_mute_modes() self._create_pad_modes() self._create_recording_modes() def _create_session_layer(self): return super(Launchkey_Mini_MK3, self)._create_session_layer() + Layer( scene_launch_buttons='scene_launch_buttons') def _create_session_navigation_layer(self): return Layer(up_button='scene_launch_button_with_shift', down_button='stop_solo_mute_button_with_shift') def _create_auto_arm(self): self._auto_arm = AutoArmComponent(name='Auto_Arm', is_enabled=False) def _create_view_control(self): self._view_control = NotifyingViewControlComponent( name='Track_Scroller', is_enabled=False, track_provider=(self._session_ring), layer=Layer(prev_track_button='left_button', next_track_button='right_button')) self._view_control.set_enabled(True) self._session_ring_selection_linking = self.register_disconnectable( SessionRingSelectionLinking( session_ring=(self._session_ring), selection_changed_notifier=(self._view_control))) def _create_transport(self): self._transport = TransportComponent( name='Transport', is_enabled=False, layer=Layer(play_button='play_button', continue_playing_button='play_button_with_shift', capture_midi_button='record_button_with_shift')) self._transport.set_enabled(True) def _create_recording_modes(self): super(Launchkey_Mini_MK3, self)._create_recording_modes() self._recording_modes.add_mode( 'arrange', AddLayerMode(self._transport, Layer(record_button='record_button'))) self._Launchkey_Mini_MK3__on_main_view_changed.subject = self.application.view self._select_recording_mode() def _create_device(self): self._device = SimpleDeviceParameterComponent( name='Device', is_enabled=False, layer=Layer(parameter_controls='pots')) def _create_drum_group(self): self._drum_group = DrumGroupComponent( name='Drum_Group', is_enabled=False, translation_channel=DRUM_FEEDBACK_CHANNEL, layer=Layer( matrix='drum_pads', scroll_page_up_button='scene_launch_button_with_shift', scroll_page_down_button='stop_solo_mute_button_with_shift')) def _create_pot_modes(self): self._pot_modes = ModesComponent( name='Pot_Modes', is_enabled=False, layer=Layer(mode_selection_control='pot_layout_switch')) self._pot_modes.add_mode('custom', None) self._pot_modes.add_mode( 'volume', AddLayerMode(self._mixer, Layer(volume_controls='pots'))) self._pot_modes.add_mode('device', self._device) self._pot_modes.add_mode( 'pan', AddLayerMode(self._mixer, Layer(pan_controls='pots'))) self._pot_modes.add_mode( 'send_a', AddLayerMode(self._mixer, Layer(send_a_controls='pots'))) self._pot_modes.add_mode( 'send_b', AddLayerMode(self._mixer, Layer(send_b_controls='pots'))) self._pot_modes.selected_mode = 'volume' self._pot_modes.set_enabled(True) self._Launchkey_Mini_MK3__on_pot_mode_byte_changed.subject = self._pot_modes def _create_stop_solo_mute_modes(self): self._stop_solo_mute_modes = ModesComponent( name='Stop_Solo_Mute_Modes', is_enabled=False, support_momentary_mode_cycling=False) bottom_row = self._elements.clip_launch_matrix.submatrix[:, 1:] self._stop_solo_mute_modes.add_mode( 'launch', None, cycle_mode_button_color='Mode.Launch.On') self._stop_solo_mute_modes.add_mode( 'stop', (AddLayerMode(self._session, Layer(stop_track_clip_buttons=bottom_row))), cycle_mode_button_color='Session.StopClip') self._stop_solo_mute_modes.add_mode( 'solo', (AddLayerMode(self._mixer, Layer(solo_buttons=bottom_row))), cycle_mode_button_color='Mixer.SoloOn') self._stop_solo_mute_modes.add_mode( 'mute', (AddLayerMode(self._mixer, Layer(mute_buttons=bottom_row))), cycle_mode_button_color='Mixer.MuteOff') self._stop_solo_mute_modes.selected_mode = 'launch' self._stop_solo_mute_modes.set_enabled(True) def _create_pad_modes(self): self._pad_modes = ModesComponent( name='Pad_Modes', is_enabled=False, layer=Layer(mode_selection_control='pad_layout_switch')) bg_mode = AddLayerMode( (self._background), layer=Layer(scene_launch_buttons='scene_launch_buttons')) self._pad_modes.add_mode('custom', bg_mode) self._pad_modes.add_mode('drum', (bg_mode, self._drum_group)) self._pad_modes.add_mode( 'session', LayerMode((self._stop_solo_mute_modes), layer=Layer(cycle_mode_button=( self._elements.scene_launch_buttons_raw[1])))) self._pad_modes.selected_mode = 'session' self._pad_modes.set_enabled(True) self._Launchkey_Mini_MK3__on_pad_mode_changed.subject = self._pad_modes self._Launchkey_Mini_MK3__on_pad_mode_byte_changed.subject = self._pad_modes def _select_recording_mode(self): if self.application.view.is_view_visible('Session'): self._recording_modes.selected_mode = 'track' if self._pad_modes.selected_mode == 'drum' else 'session' else: self._recording_modes.selected_mode = 'arrange' @listens('is_view_visible', 'Session') def __on_main_view_changed(self): self._select_recording_mode() @listens('selected_mode') def __on_pad_mode_changed(self, mode): self._select_recording_mode() self._update_controlled_track() @listens('mode_byte') def __on_pad_mode_byte_changed(self, mode_byte): self._last_pad_layout_byte = mode_byte @listens('mode_byte') def __on_pot_mode_byte_changed(self, mode_byte): self._last_pot_layout_byte = mode_byte def _drum_group_changed(self): self._drum_group.set_drum_group_device( self._drum_group_finder.drum_group) def _is_instrument_mode(self): return self._pad_modes.selected_mode == 'drum'
class ATOMSQ(ControlSurface): def __init__(self, *a, **k): super(ATOMSQ, self).__init__(*a, **k) with self.component_guard(): self._elements = Elements() with inject(element_container=const(self._elements)).everywhere(): self._create_background() self._create_transport() self._create_undo() self._create_view_toggle() self._create_device_parameters() self._create_translating_background() self._create_device_navigation() self._create_launch_and_stop() self._create_session() self._create_mixer() self._create_view_control() self._create_button_labels() self._create_record_modes() self._create_lower_pad_modes() self._create_main_modes() self.__on_main_view_changed.subject = self.application.view def disconnect(self): super(ATOMSQ, self).disconnect() self._send_midi(midi.NATIVE_MODE_OFF_MESSAGE) def port_settings_changed(self): self._send_midi(midi.NATIVE_MODE_ON_MESSAGE) if self._main_modes.selected_mode == b'instrument': self.schedule_message( 1, self._elements.upper_firmware_toggle_switch.send_value, 1) if self._main_modes.selected_mode != b'song': self.schedule_message( 1, self._elements.lower_firmware_toggle_switch.send_value, 1) super(ATOMSQ, self).port_settings_changed() def _create_background(self): self._background = BackgroundComponent( name=b'Background', is_enabled=False, add_nop_listeners=True, layer=Layer(**{name: name for name in BANK_BUTTON_NAMES})) self._background.set_enabled(True) def _create_transport(self): self._transport = TransportComponent( name=b'Transport', is_enabled=False, layer=Layer(scroll_encoder=b'display_encoder', play_button=b'play_button', loop_button=b'play_button_with_shift', stop_button=b'stop_button', metronome_button=b'click_button', capture_midi_button=b'record_button_with_shift', prev_cue_button=b'display_left_button', next_cue_button=b'display_right_button', shift_button=b'shift_button')) self._transport.set_enabled(True) def _create_undo(self): self._undo = UndoRedoComponent( name=b'Undo', is_enabled=False, layer=Layer(undo_button=b'stop_button_with_shift')) self._undo.set_enabled(True) def _create_view_toggle(self): self._view_toggle = ViewToggleComponent( name=b'View_Toggle', is_enabled=False, layer=Layer(main_view_toggle_button=b'bank_a_button', browser_view_toggle_button=b'bank_b_button', detail_view_toggle_button=b'bank_d_button', clip_view_toggle_button=b'bank_h_button')) def _create_device_parameters(self): self._device_parameters = SimpleDeviceParameterComponent( name=b'Device_Parameters', device_bank_registry=self._device_bank_registry, toggle_lock=self.toggle_lock, layer=Layer(device_name_display=b'device_name_display'), is_enabled=False) self._device_parameters.set_enabled(True) def _create_translating_background(self): self._translating_background = TranslatingBackgroundComponent( name=b'Translating_Background', is_enabled=False, add_nop_listeners=True, layer=Layer(encoders=b'encoders', channel_selection_buttons=b'display_buttons')) def _create_device_navigation(self): self._device_navigation = SimpleDeviceNavigationComponent( name=b'Device_Navigation', is_enabled=False, layer=Layer(prev_button=b'display_buttons_raw[1]', next_button=b'display_buttons_raw[2]')) def _create_launch_and_stop(self): self._launch_and_stop = LaunchAndStopComponent( name=b'Launch_And_Stop', is_enabled=False, layer=Layer(clip_launch_button=b'display_buttons_raw[3]', scene_launch_button=b'display_buttons_raw[4]', track_stop_button=b'display_buttons_raw[5]')) def _create_session(self): self._session_ring = SessionRingComponent(name=b'Session_Ring', num_tracks=SESSION_WIDTH, num_scenes=SESSION_HEIGHT) self._session = SessionComponent( name=b'Session', is_enabled=False, session_ring=self._session_ring, layer=Layer(clip_launch_buttons=b'upper_pads')) self._session_navigation = SessionNavigationComponent( name=b'Session_Navigation', is_enabled=False, session_ring=self._session_ring, layer=Layer(up_button=b'up_button_with_shift', down_button=b'down_button_with_shift')) self._session_navigation.set_enabled(True) def _create_mixer(self): self._mixer = MixerComponent( name=b'Mixer', auto_name=True, tracks_provider=self._session_ring, track_assigner=SimpleTrackAssigner(), channel_strip_component_type=ChannelStripComponent) self._mixer.selected_strip().layer = Layer( track_name_display=b'track_name_display') self._mixer.set_enabled(True) def _create_view_control(self): self._view_control = NotifyingViewControlComponent( name=b'View_Control', is_enabled=False, track_provider=self._session_ring, enable_skinning=False, layer=Layer(next_track_button=b'right_button', prev_track_button=b'left_button', next_scene_button=b'down_button', prev_scene_button=b'up_button')) self._view_control.set_enabled(True) self._session_ring_selection_linking = self.register_disconnectable( SessionRingSelectionLinking( session_ring=self._session_ring, selection_changed_notifier=self._view_control)) def _create_button_labels(self): self._button_labels = ButtonLabelsComponent( is_enabled=False, layer=Layer(display_lines=b'button_label_display_matrix')) self._button_labels.set_enabled(True) def _create_record_modes(self): self._session_record = SessionRecordingComponent( name=b'Session_Record', is_enabled=False, layer=Layer(record_button=b'record_button')) self._record_modes = ModesComponent(name=b'Record_Modes') self._record_modes.add_mode(b'session', EnablingMode(self._session_record)) self._record_modes.add_mode( b'arrange', AddLayerMode(self._transport, layer=Layer(record_button=b'record_button'))) self.__on_main_view_changed() def _create_lower_pad_modes(self): self._lower_pad_modes = ModesComponent( name=b'Lower_Pad_Modes', is_enabled=False, layer=Layer(cycle_mode_button=b'minus_button')) self._lower_pad_modes.add_mode( b'select', AddLayerMode(self._mixer, Layer(track_select_buttons=b'lower_pads')), cycle_mode_button_color=b'Session.StopClipDisabled') self._lower_pad_modes.add_mode( b'stop', AddLayerMode(self._session, Layer(stop_track_clip_buttons=b'lower_pads')), cycle_mode_button_color=b'Session.StopClip') self._lower_pad_modes.selected_mode = b'select' def _create_main_modes(self): self._main_modes = ModesComponent( name=b'Main_Modes', is_enabled=False, layer=Layer(song_button=b'song_mode_button', instrument_button=b'instrument_mode_button', editor_button=b'editor_mode_button', user_button=b'user_mode_button')) device_params_mode = AddLayerMode( self._device_parameters, Layer(parameter_controls=b'encoders')) enable_lower_fw_functions = partial( self._elements.lower_firmware_toggle_switch.send_value, 1) disable_upper_fw_functions = partial( self._elements.upper_firmware_toggle_switch.send_value, 0) self._main_modes.add_mode( b'song', (partial(self._elements.lower_firmware_toggle_switch.send_value, 0), disable_upper_fw_functions, self._elements.display_buttons.reset, self._view_toggle, self._launch_and_stop, self._session, self._lower_pad_modes, AddLayerMode(self._session.scene(0), Layer(launch_button=b'plus_button')), AddLayerMode( self._mixer.selected_strip(), Layer(volume_control=b'encoders_raw[0]', pan_control=b'encoders_raw[1]', send_controls=self._elements.encoders.submatrix[2:, :], solo_button=b'display_buttons_raw[0]', mute_button=b'display_buttons_raw[1]', arm_button=b'display_buttons_raw[2]')), AddLayerMode(self._mixer, Layer(crossfader_control=b'touch_strip')))) self._main_modes.add_mode( b'instrument', (enable_lower_fw_functions, partial(self._elements.upper_firmware_toggle_switch.send_value, 1), device_params_mode)) self._main_modes.add_mode( b'editor', (enable_lower_fw_functions, disable_upper_fw_functions, device_params_mode, self._device_navigation, AddLayerMode( self._device_parameters, Layer(device_lock_button=b'display_buttons_raw[0]', device_on_off_button=b'display_buttons_raw[3]', prev_bank_button=b'display_buttons_raw[4]', next_bank_button=b'display_buttons_raw[5]')))) self._main_modes.add_mode( b'user', (enable_lower_fw_functions, disable_upper_fw_functions, self._translating_background)) self._main_modes.selected_mode = b'instrument' self._main_modes.set_enabled(True) self.__on_main_modes_changed.subject = self._main_modes @listens(b'selected_mode') def __on_main_modes_changed(self, mode): self._button_labels.show_button_labels_for_mode(mode) self._elements.track_name_display.clear_send_cache() self._elements.device_name_display.clear_send_cache() @listens(b'is_view_visible', b'Session') def __on_main_view_changed(self): if self.application.view.is_view_visible(b'Session'): self._record_modes.selected_mode = b'session' else: self._record_modes.selected_mode = b'arrange'
class Launchkey_MK3(InstrumentControlMixin, NovationBase): element_class = Elements session_height = SESSION_HEIGHT mixer_class = MixerComponent channel_strip_class = ChannelStripComponent skin = skin suppress_layout_switch = False def __init__(self, *a, **k): self._is_small_model = False self._last_pad_layout_byte = midi.PAD_SESSION_LAYOUT self._last_pot_layout_byte = None self._last_fader_layout_byte = midi.VOLUME_LAYOUT super(Launchkey_MK3, self).__init__(*a, **k) def disconnect(self): self._elements.pad_layout_switch.send_value(midi.PAD_DRUM_LAYOUT) self._auto_arm.set_enabled(False) super(Launchkey_MK3, self).disconnect() def on_identified(self, midi_bytes): if self._last_pot_layout_byte is None: self._last_pot_layout_byte = midi.VOLUME_LAYOUT if self._is_small_model else midi.PAN_LAYOUT self._pot_modes.selected_mode = u'volume' if self._is_small_model else u'pan' self._elements.incontrol_mode_switch.send_value(midi.INCONTROL_ONLINE_VALUE) self._elements.pad_layout_switch.send_value(self._last_pad_layout_byte) self._elements.pot_layout_switch.send_value(self._last_pot_layout_byte) if not self._is_small_model: self._elements.fader_layout_switch.send_value(self._last_fader_layout_byte) self._target_track_changed() self._drum_group_changed() self._auto_arm.set_enabled(True) self.set_feedback_channels([DRUM_FEEDBACK_CHANNEL]) super(Launchkey_MK3, self).on_identified(midi_bytes) def port_settings_changed(self): self._auto_arm.set_enabled(False) super(Launchkey_MK3, self).port_settings_changed() def _create_components(self): super(Launchkey_MK3, self)._create_components() self.register_slot(self._elements.incontrol_mode_switch, nop, u'value') self._create_auto_arm() self._create_background() self._create_notification() self._create_view_control() self._create_transport() self._create_recording_modes() self._create_undo() self._create_quantization() self._create_device() self._create_drum_group() self._pot_modes = self._create_pot_or_fader_modes(u'pot') self._create_stop_solo_mute_modes() self._create_pad_modes() if not self._is_small_model: self._fader_modes = self._create_pot_or_fader_modes(u'fader') self._setup_master_fader() self._create_fader_button_modes() def _setup_master_fader(self): strip = self._mixer.master_strip() strip.set_volume_control(self._elements.master_fader) strip.volume_display.set_control_element(self._elements.master_fader_parameter_value_display) self._elements.master_fader_parameter_name_display.display_message(u'Master Volume') def _create_session_navigation_layer(self): return Layer(up_button=u'up_button', down_button=u'down_button') def _create_session_layer(self): return super(Launchkey_MK3, self)._create_session_layer() + Layer(scene_launch_buttons=u'scene_launch_buttons') def _create_auto_arm(self): self._auto_arm = AutoArmComponent(name=u'Auto_Arm', is_enabled=False) def _create_background(self): self._background = BackgroundComponent(name=u'Background', is_enabled=False, add_nop_listeners=True, layer=Layer(secondary_up_button=u'secondary_up_button', secondary_down_button=u'secondary_down_button', device_select_button=u'device_select_button', unused_matrix=self._elements.device_select_matrix.submatrix[:, 1:], pot_parameter_name_displays=u'pot_parameter_name_displays', pot_parameter_value_displays=u'pot_parameter_value_displays', fader_parameter_name_displays=u'fader_parameter_name_displays', fader_parameter_value_displays=u'fader_parameter_value_displays')) self._background.set_enabled(True) def _create_notification(self): self._notification_component = NotificationComponent(name=u'Notifications', is_enabled=False, layer=Layer(display_lines=u'notification_display')) self._notification_component.set_enabled(True) def _create_view_control(self): self._view_control = NotifyingViewControlComponent(name=u'Track_Scroller', is_enabled=False, track_provider=self._session_ring, layer=Layer(prev_track_button=u'left_button', next_track_button=u'right_button')) self._view_control.set_enabled(True) self._session_ring_selection_linking = self.register_disconnectable(SessionRingSelectionLinking(session_ring=self._session_ring, selection_changed_notifier=self._view_control)) def _create_transport(self): self._transport = TransportComponent(name=u'Transport', is_enabled=False, layer=Layer(play_button=u'play_button', alt_stop_button=u'stop_button', loop_button=u'loop_button', metronome_button=u'click_button', capture_midi_button=u'capture_midi_button')) self._transport.set_enabled(True) def _create_undo(self): self._undo = UndoRedoComponent(name=u'Undo', is_enabled=False, layer=Layer(undo_button=u'undo_button')) self._undo.set_enabled(True) def _create_quantization(self): self._quantization = QuantizationComponent(name=u'Quantization') self._clip_actions = ClipActionsComponent(name=u'Clip_Actions', is_enabled=False, layer=Layer(quantize_button=u'quantize_button')) self._clip_actions.set_enabled(True) ClipActionsComponent.quantization_component = self._quantization def _create_device(self): self._device = DeviceComponent(name=u'Device', is_enabled=False, show_notification=self._notification_component.show_notification, device_bank_registry=self._device_bank_registry, toggle_lock=self.toggle_lock, use_parameter_banks=True, layer=Layer(device_lock_button=u'device_lock_button')) self._device.set_enabled(True) def _create_drum_group(self): self._drum_group = DrumGroupComponent(name=u'Drum_Group', is_enabled=False, translation_channel=DRUM_FEEDBACK_CHANNEL, layer=Layer(matrix=u'drum_pads', scroll_page_up_button=u'up_button', scroll_page_down_button=u'down_button')) def _create_pot_or_fader_modes(self, modes_type_name): modes = ModesComponent(name=u'{}_Modes'.format(modes_type_name.title()), is_enabled=False, layer=Layer(mode_selection_control=u'{}_layout_switch'.format(modes_type_name))) elements_name = u'{}s'.format(modes_type_name) name_displays_element_name = u'{}_parameter_name_displays'.format(modes_type_name) value_displays_element_name = u'{}_parameter_value_displays'.format(modes_type_name) def add_pot_or_fader_mixer_mode(parameter_name): modes.add_mode(parameter_name, (partial(getattr(self._mixer, u'set_{}_parameter_name'.format(modes_type_name)), parameter_name.replace(u'_', u' ').title()), AddLayerMode(self._mixer, Layer(**{u'{}_controls'.format(parameter_name): elements_name, u'{}_parameter_name_displays'.format(modes_type_name): name_displays_element_name, u'{}_displays'.format(parameter_name): value_displays_element_name})))) modes.add_mode(u'dummy', None) add_pot_or_fader_mixer_mode(u'volume') modes.add_mode(u'device', AddLayerMode(self._device, Layer(parameter_controls=elements_name, parameter_name_displays=name_displays_element_name, parameter_value_displays=value_displays_element_name))) if modes_type_name == u'pot': add_pot_or_fader_mixer_mode(u'pan') else: modes.add_mode(u'pan', None) add_pot_or_fader_mixer_mode(u'send_a') add_pot_or_fader_mixer_mode(u'send_b') for i in range(4): modes.add_mode(u'custom{}'.format(i), None) modes.selected_mode = u'pan' if modes_type_name == u'pot' else u'volume' modes.set_enabled(True) self.register_slot(modes, getattr(self, u'_on_{}_mode_byte_changed'.format(modes_type_name)), u'mode_byte') return modes def _create_fader_button_modes(self): self._fader_button_modes = ModesComponent(name=u'Fader_Modes', is_enabled=False, support_momentary_mode_cycling=False, layer=Layer(cycle_mode_button=u'fader_button_modes_button')) self._fader_button_modes.add_mode(u'arm', AddLayerMode(self._mixer, Layer(arm_buttons=u'fader_buttons')), cycle_mode_button_color=u'DefaultButton.Off') self._fader_button_modes.add_mode(u'track_select', AddLayerMode(self._mixer, Layer(track_select_buttons=u'fader_buttons')), cycle_mode_button_color=u'DefaultButton.On') self._fader_button_modes.selected_mode = u'arm' self._fader_button_modes.set_enabled(True) def _create_stop_solo_mute_modes(self): self._stop_solo_mute_modes = ModesComponent(name=u'Stop_Solo_Mute_Modes', is_enabled=False, support_momentary_mode_cycling=False) lower_matrix_row = self._elements.clip_launch_matrix.submatrix[:, 1:] self._stop_solo_mute_modes.add_mode(u'launch', None, cycle_mode_button_color=u'Mode.Launch.On') self._stop_solo_mute_modes.add_mode(u'stop', AddLayerMode(self._session, Layer(stop_track_clip_buttons=lower_matrix_row)), cycle_mode_button_color=u'Session.StopClip') self._stop_solo_mute_modes.add_mode(u'solo', AddLayerMode(self._mixer, Layer(solo_buttons=lower_matrix_row)), cycle_mode_button_color=u'Mixer.SoloOn') self._stop_solo_mute_modes.add_mode(u'mute', AddLayerMode(self._mixer, Layer(mute_buttons=lower_matrix_row)), cycle_mode_button_color=u'Mixer.MuteOff') self._stop_solo_mute_modes.selected_mode = u'launch' self._stop_solo_mute_modes.set_enabled(True) self.__on_stop_solo_mute_mode_changed.subject = self._stop_solo_mute_modes def _create_pad_modes(self): self._pad_modes = ModesComponent(name=u'Pad_Modes', is_enabled=False, layer=Layer(mode_selection_control=u'pad_layout_switch')) suppress_scene_launch_buttons = AddLayerMode(self._background, layer=Layer(scene_launch_buttons=u'scene_launch_buttons')) suppress_all_buttons_around_pads = AddLayerMode(self._background, layer=Layer(scene_launch_buttons=u'scene_launch_buttons', up_button=u'up_button', down_button=u'down_button')) self._pad_modes.add_mode(u'dummy', suppress_all_buttons_around_pads) self._pad_modes.add_mode(u'drum', (suppress_scene_launch_buttons, self._drum_group)) self._pad_modes.add_mode(u'session', LayerMode(self._stop_solo_mute_modes, layer=Layer(cycle_mode_button=self._elements.scene_launch_buttons_raw[1]))) for i in range(6): self._pad_modes.add_mode(u'custom{}'.format(i), suppress_all_buttons_around_pads) upper_matrix_row = self._elements.device_select_matrix.submatrix[:, :1] self._pad_modes.add_mode(u'device_select', (suppress_scene_launch_buttons, self._device.show_device_name_and_bank, AddLayerMode(self._device, layer=Layer(bank_select_buttons=upper_matrix_row, prev_button=u'up_button', next_button=u'down_button')))) self._pad_modes.selected_mode = u'session' self._pad_modes.set_enabled(True) self.__on_pad_mode_changed.subject = self._pad_modes self.__on_pad_mode_byte_changed.subject = self._pad_modes @listens(u'selected_mode') def __on_pad_mode_changed(self, mode): self._recording_modes.selected_mode = u'track' if mode == u'drum' else u'session' self._update_controlled_track() @listens(u'selected_mode') def __on_stop_solo_mute_mode_changed(self, mode): if mode: self._notification_component.show_notification(u'Lower Pad Mode', mode.title()) @listens(u'mode_byte') def __on_pad_mode_byte_changed(self, mode_byte): self._last_pad_layout_byte = mode_byte def _on_pot_mode_byte_changed(self, mode_byte): self._last_pot_layout_byte = mode_byte def _on_fader_mode_byte_changed(self, mode_byte): self._last_fader_layout_byte = mode_byte def _drum_group_changed(self): self._drum_group.set_drum_group_device(self._drum_group_finder.drum_group) def _target_track_changed(self): super(Launchkey_MK3, self)._target_track_changed() self._notification_component.show_notification(u'Track', self._target_track.target_track.name) def _is_instrument_mode(self): return self._pad_modes.selected_mode == u'drum' def _extract_product_id_bytes(self, midi_bytes): u""" Extends standard to deal with each model having a different ID byte, determine whether the model is one of the small models and compose the target product ID bytes based on the bytes that were received. """ id_bytes = super(Launchkey_MK3, self)._extract_product_id_bytes(midi_bytes) model_id_byte = id_bytes[3] if id_bytes[:3] == sysex.NOVATION_MANUFACTURER_ID and model_id_byte in midi.MODEL_ID_BYTES and id_bytes[4:] == midi.MODEL_ID_BYTE_SUFFIX: self._is_small_model = model_id_byte in midi.SMALL_MODEL_ID_BYTES self._product_id_bytes = sysex.NOVATION_MANUFACTURER_ID + id_bytes[3:] return id_bytes