def _set_global_buttons(self): is_momentary = True self._undo_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 85) self._do_undo.subject = self._undo_button self._redo_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 87) self._do_redo.subject = self._redo_button self._stop_all_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 111) self._do_stop_all.subject = self._stop_all_button self._toggle_detail_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1, 121) self._action_toogle_detail_view.subject = self._toggle_detail_button self._fire_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 9) self._do_fire_button.subject = self._fire_button self._g_clear_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1, 106) self._hold_clear_action.subject = self._g_clear_button self._g_duplicate_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1, 107) self._hold_duplicate_action.subject = self._g_duplicate_button self.track_left_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 120) self.track_right_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 121) self.set_sel_arm_button = StateButton(is_momentary, MIDI_CC_TYPE, 2, 56) self._reenable_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1, 120) self._do_auto_reenable.subject = self._reenable_button self._on_change_reenabled.subject = self.song() self._on_change_reenabled() self._a_trk_left.subject = self.track_left_button self._a_trk_right.subject = self.track_right_button self._a_sel_arm.subject = self.set_sel_arm_button
def _set_up_device_control(self): is_momentary = True device = MaschineDeviceComponent() param_controls = [] for index in range(8): param_controls.append( SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_CC_OFF + index)) device.set_parameter_controls(tuple(param_controls)) self.device_control = param_controls device.set_on_off_button( StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF)) device.set_bank_nav_buttons( StateButton(is_momentary, MIDI_CC_TYPE, 3, 104), ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 105)) self._device_nav_button_left = StateButton(is_momentary, MIDI_CC_TYPE, 3, 106) self._device_nav_button_right = StateButton(is_momentary, MIDI_CC_TYPE, 3, 107) self._navigate_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 127) self._nav_value_left.subject = self._device_nav_button_left self._nav_value_right.subject = self._device_nav_button_right self._do_focus_navigate.subject = self._navigate_button self.set_device_component(device) return device
def _set_up_mixer(self): is_momentary = True self._mixer = MaschineMixerComponent(8) self.send_sliders = [] for track in range(8): self.send_sliders.append( SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, SEND_CC_OFF + track)) for track in range(8): strip = self._mixer.channel_strip(track) strip.set_arm_button( StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, ARM_CC_OFF + track)) strip.set_solo_button( StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, SOLO_CC_OFF + track)) strip.set_mute_button( StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, MUTE_CC_OFF + track)) strip.set_volume_control( SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, LEVEL_CC_OFF + track)) strip.set_pan_control( SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, PAN_CC_OFF + track)) strip.set_select_button( StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, SELECT_CC_OFF + track)) st = tuple([self.send_sliders[track]]) strip.set_send_controls(st) self.send_slider_toggle_button = StateButton(False, MIDI_CC_TYPE, 0, 90) self._do_toggle_send.subject = self.send_slider_toggle_button self._session.set_mixer(self._mixer)
def create_button(ccval, channel=0, cname=None): button = StateButton(True, MIDI_CC_TYPE, channel, ccval, name=cname) button.last_value = 0 return button
def create_button(self, index): button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, 22 + index, name='Page_Button_' + str(index + 1) + '_Control') button.cindex = index return ButtonHandler(index, button, self)
def _init_maschine(self): self.__jog_wheel_section = JogWheelSection() self.__metro_tap_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_TAP_METRO_BUTTON, name='Tap_metro_button') self._do_tap_metro.subject = self.__metro_tap_button self.update_arrange_button()
def _set_modecontrol(self): is_momentary = True self.scene_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 112) self.clip_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 113) self.pad_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 114) self.control_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 115) self.xfade_assign_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 116) self.scene_mode_button.add_value_listener(self._a_mode_scene) self.clip_mode_button.add_value_listener(self._a_mode_clip) self.pad_mode_button.add_value_listener(self._a_mode_pad) self.control_mode_button.add_value_listener(self._a_mode_control)
def _set_mode_buttons(self): self.xfade_assign_button = StateButton(True, MIDI_CC_TYPE, 0, 116) self._pad_select_button = StateButton(False, MIDI_CC_TYPE, 0, 117) self._pad_solo_button = StateButton(False, MIDI_CC_TYPE, 0, 118) self._mute_button = StateButton(False, MIDI_CC_TYPE, 0, 119) self._pad_scale_up = GatedColorButton(True, MIDI_CC_TYPE, 83, 0) self._pad_scale_down = GatedColorButton(True, MIDI_CC_TYPE, 94, 16) self._pad_select_button.add_value_listener(self._do_pad_select_multi) self._mute_button.add_value_listener(self._do_mute_button) self._pad_solo_button.add_value_listener(self._do_pad_solo_multi) self.xfade_assign_button.add_value_listener(self._do_xfade_assign) self._pad_scale_up.add_value_listener(self._do_pad_note_up) self._pad_scale_down.add_value_listener(self._do_pad_note_down)
def _setup_transport(self): is_momentary = True transport = TransportComponent() studiotransport = MaschineTransport() playButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 108) stopButton = StateButton(not is_momentary, MIDI_CC_TYPE, 0, 110) recordButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 109) overdubButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 107) metrononmeButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 104) eventRecButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 98) playButton.name = 'Play' stopButton.name = 'Stop' recordButton.name = 'Record' overdubButton.name = 'Overdub' metrononmeButton.name = 'Metronome' transport.set_play_button(playButton) transport.set_stop_button(stopButton) transport.set_record_button(recordButton) transport.set_overdub_button(overdubButton) transport.set_metronome_button(metrononmeButton) studiotransport.set_session_auto_button(eventRecButton) studiotransport.set_arrangement_overdub_button(StateButton(is_momentary, MIDI_CC_TYPE, 0, 106)) studiotransport.set_back_arrange_button(StateButton(is_momentary, MIDI_CC_TYPE, 0, 105)) transport.set_nudge_buttons(StateButton(is_momentary, MIDI_CC_TYPE, 1, 51), StateButton(is_momentary, MIDI_CC_TYPE, 1, 50)) punchinbutton = ToggleButton(MIDI_CC_TYPE, 1, 52) punchoutbutton = ToggleButton(MIDI_CC_TYPE, 1, 53) punchinbutton.name = 'Punch In' punchoutbutton.name = 'Punch Out' transport.set_punch_buttons(punchinbutton, punchoutbutton) transport.set_loop_button(StateButton(is_momentary, MIDI_CC_TYPE, 1, 54)) self.song_follow_button = ButtonElement(True, MIDI_CC_TYPE, 2, 98) self._do_song_follow.subject = self.song_follow_button self._song_follow_changed.subject = self.song().view self._song_follow_changed() self.prehear_knob = SliderElement(MIDI_CC_TYPE, 0, 41) self.prehear_knob.connect_to(self.song().master_track.mixer_device.cue_volume) self.transp_ff_button = ButtonElement(True, MIDI_CC_TYPE, 1, 59) self.transp_rw_button = ButtonElement(True, MIDI_CC_TYPE, 1, 58) transport.set_seek_buttons(self.transp_ff_button, self.transp_rw_button) self.xfadeKnob = SliderElement(MIDI_CC_TYPE, 1, 105) self.xfadeKnob.connect_to(self.song().master_track.mixer_device.crossfader) self.master_knob = SliderElement(MIDI_CC_TYPE, 0, 99) self.master_knob.connect_to(self.song().master_track.mixer_device.volume) self.tap_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 88) self._do_tap_tempo.subject = self.tap_button self.cue_add_delete_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 55) self.cue_prev_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 56) self.cue_next_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 57) self._do_toggle_cue.subject = self.cue_add_delete_button self._do_toggle_prev_cue.subject = self.cue_prev_button self._do_toggle_next_cue.subject = self.cue_next_button
def set_up_function_buttons(self): is_momentary = True self.keycolor_mod_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 73) self._do_key_color.subject = self.keycolor_mod_button self._update_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 86) self._do_update_display.subject = self._update_button
def _set_up_session(self, mode_selector): is_momentary = True self._session = MaschineSessionComponent() self._session.set_color_manager(mode_selector.get_color_manager()) self.nav_buttons = ( self.create_gated_button(92, COLOR_HUE_NAV), self.create_gated_button(81, COLOR_HUE_NAV), self.create_gated_button(93, COLOR_HUE_NAV), self.create_gated_button(91, COLOR_HUE_NAV)) self._session.set_scene_bank_buttons(self.nav_buttons[0], self.nav_buttons[1]) self._session.set_track_bank_buttons(self.nav_buttons[2], self.nav_buttons[3]) track_stop_buttons = [ StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, index + STOP_CC_OFF) for index in range(4) ] self._session.set_stop_track_clip_buttons(tuple(track_stop_buttons)) self._matrix = [] self._bmatrix = ButtonMatrixElement() for scene_index in range(4): button_row = [] for track_index in range(4): button = self.create_pad_button(scene_index, track_index, mode_selector) button_row.append(button) self._matrix.append(tuple(button_row)) self._bmatrix.add_row(tuple(button_row)) self._session.set_matrix(self._matrix) for button, (track_index, scene_index) in self._bmatrix.iterbuttons(): if button: scene = self._session.scene(scene_index) clip_slot = scene.clip_slot(track_index) clip_slot.set_launch_button(button) clip_slot.set_triggered_to_play_value(1) clip_slot.set_triggered_to_record_value(1) clip_slot.set_started_value(1) clip_slot.set_recording_value(1) clip_slot.set_stopped_value(1) self._session._link()
def _set_up_device_control(self): is_momentary = True device = MaschineDeviceComponent(self) device.set_device_changed_listener(self._handle_device_changed) device.set_device_parm_listener(self._hande_device_parm_changed) param_controls = [] for index in range(8): param_controls.append(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_CC_OFF + index)) device.set_parameter_controls(tuple(param_controls)) device.set_on_off_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF)) device.set_bank_nav_buttons(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF + 4), ButtonElement(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF + 5)) self._device_nav_button_left = StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF + 6) self._device_nav_button_right = StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF + 7) self._device_nav_button_left.add_value_listener(self._nav_value_left) self._device_nav_button_right.add_value_listener(self._nav_value_right) device.name = 'Device_Component' self.set_device_component(device) return device
def __init__(self, monochrome=False, *a, **k): super(ModeSelector, self).__init__(*a, **k) is_momentary = True self._monochrome = monochrome self._scene_mode = SceneMode(0) self._clip_mode = StudioClipMode(1) self._pad_mode = PadMode(2, monochrome) self._drum_mode = DrumMode(2, monochrome) self._control_mode = ControlMode(2, monochrome) self._pad_mode.set_alternate_mode(self._drum_mode) self._drum_mode.set_alternate_mode(self._pad_mode) self._tracks_assign = TrackAssign() self._arm_mode = TrackArmMode(self._tracks_assign) self._solo_mode = TrackSoloMode(self._tracks_assign) self._stop_mode = TrackStopMode(self._tracks_assign) self._mute_mode = TrackMuteMode(self._tracks_assign) self._select_mode = TrackSelectMode(self._tracks_assign) self._xfade_mode = TrackXFadeMode(self._tracks_assign) self._color_select_mode = MaschineColorSelectMode(5) self._mode = self._clip_mode self._return_mode = None def create_button(ccval, channel=0): return StateButton(is_momentary, MIDI_CC_TYPE, channel, ccval) self._scene_mode_button = create_button(112) self._clip_mode_button = create_button(113) self._pad_mode_button = create_button(114) self._select_button = create_button(117) self._solo_button = create_button(118) self._mute_button = create_button(119) self._xfade_button = self.canonical_parent.create_gated_button(84, 5) self._stop_button = self.canonical_parent.create_gated_button(94, 16) self._arm_button = self.canonical_parent.create_gated_button(83, 0) self._solo_button = StateButton(False, MIDI_CC_TYPE, 0, 118) self._clip_mode_button.send_value(127, True) self._select_clip_mode.subject = self._clip_mode_button self._select_scene_mode.subject = self._scene_mode_button self._select_pad_mode.subject = self._pad_mode_button self._select_arm.subject = self._arm_button self._select_solo.subject = self._solo_button self._select_stop.subject = self._stop_button self._select_xfade.subject = self._xfade_button self._select_mute.subject = self._mute_button self._select_select.subject = self._select_button self._arm_exclusive_button = create_button(51, 2) self._action_arm_exclusive.subject = self._arm_exclusive_button self._solo_exclusive_button = create_button(52, 2) self._action_solo_exclusive.subject = self._solo_exclusive_button self._scene_mode_button.send_value(0, True) self._clip_mode_button.send_value(1, True) self._pad_mode_button.send_value(0, True) self._mode._active = True return
def __init__(self, c_instance): ControlSurface.__init__(self, c_instance, False) with self.component_guard(): self._suppress_send_midi = True self.togglecolor = (10, 30, 50, 70, 90) self.toggleindex = 0 self._c_ref = c_instance self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143 self._c_inst = c_instance is_momentary = True self._active = True self._modifier_down = False self._return_mode = 0 self._returntopad = False self._mode = CLIP_MODE self.init_slot = 0 self.init_done = False self._midi_pause_count = 0 self.nav_index = 0 self._base_note = 0 self._octave = 0.55 self._scale_select_mode = MODE_PRESS_NONE self.send_slider_index = 0 self._pad_mode = PM_OFF self._note_display_mode = ND_KEYBOARD1 self._set_suppress_rebuild_requests(True) self._scenematrix = SceneMatrix(self) self._master_knob = Mk2KnobControl(self) self._device = self._set_up_device_control() self.show_message(str('')) self.request_rebuild_midi_map() self._set_global_buttons() self._set_mode_buttons() self._setup_transport() self._set_modecontrol() self._set_up_session() self._set_up_mixer() self._set_up_timer() self._set_up_machine_knobs() self.current_scale_index = 0 self.assign_transpose(SCALES[self.current_scale_index]) self.set_highlighting_session_component(self._session) self._navigate_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 127) self._navigate_button.add_value_listener(self._do_focus_navigate) self.display_update_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 86) self.display_update_button.add_value_listener(self._a_display_update) self._set_suppress_rebuild_requests(False) self.song().view.add_detail_clip_listener(self.clip_handle) self.song().add_visible_tracks_listener(self.clip_handle) self.song().add_scenes_listener(self.clip_handle) self.application().view.add_view_focus_changed_listener(self.focus_changed) self.log_message('########## LIVE 9 MASCHINE MK2 V 1.02 #############') self._suppress_send_midi = False
def _set_global_buttons(self): is_momentary = True self._undo_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 85) self._undo_button.add_value_listener(self._do_undo) self._redo_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 87) self._redo_button.add_value_listener(self._do_redo) self._armsolomode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 89) self._armsolomode_button.add_value_listener(self._do_armsolo_mode) self._fire_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 9) self._fire_button.add_value_listener(self._do_fire_button) self.track_left_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 120) self.track_right_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 121) self.track_left_button.add_value_listener(self._a_trk_left) self.track_right_button.add_value_listener(self._a_trk_right) self.test_button = StateButton(True, MIDI_CC_TYPE, 5, 60) self.note_repeat_button = StateButton(True, MIDI_CC_TYPE, 5, 61) self.test_button.add_value_listener(self.do_test) self.note_repeat_button.add_value_listener(self.do_note_repeat) self.reset_test_button = StateButton(True, MIDI_CC_TYPE, 5, 62) self.reset_test_button.add_value_listener(self.do_reset)
def set_up_function_buttons(self): is_momentary = True self._do_octave_button.subject = StateButton(is_momentary, MIDI_CC_TYPE, 1, 70) self._do_scale_button.subject = StateButton(is_momentary, MIDI_CC_TYPE, 1, 71) self._do_note_button.subject = StateButton(is_momentary, MIDI_CC_TYPE, 1, 72) self._do_loop_mod.subject = StateButton(is_momentary, MIDI_CC_TYPE, 1, 69) self._color_edit_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 114) self._do_color_button.subject = self._color_edit_button self.scrub_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 2, 53) self._action_scrub_mode.subject = self.scrub_mode_button self._action_loop_button.subject = StateButton(is_momentary, MIDI_CC_TYPE, 2, 54) self._action_quant_button.subject = StateButton( is_momentary, MIDI_CC_TYPE, 2, 55)
def _setup_transport(self): is_momentary = True self.shiftButton = SysExButton(120, name='Shift_Button') self.__play_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 108, name='Play_Button') self._hand_play_pressed.subject = self.__play_button self._listen_playing.subject = self.song() self._channel_led_left = SliderElement(MIDI_CC_TYPE, 0, 38) self._channel_led_right = SliderElement(MIDI_CC_TYPE, 0, 39) self._channel_led_left.last_raw = 0.0 self._channel_led_left.last_send = 0 self._channel_led_right.last_raw = 0.0 self._channel_led_right.last_send = 0 self._listen_master_left.subject = self.song().master_track self._listen_master_right.subject = self.song().master_track self._auto_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 98, name='Auto_Button') self._listen_automation_record.subject = self.song() self._handle_automation_record.subject = self._auto_button self._do_direction_up.subject = StateButton(is_momentary, MIDI_CC_TYPE, 0, 40, name='Up_Arrow') self._do_direction_down.subject = StateButton(is_momentary, MIDI_CC_TYPE, 0, 41, name='Down_Arrow') self._do_direction_left.subject = StateButton(is_momentary, MIDI_CC_TYPE, 0, 42, name='Left_Arrow') self._do_direction_right.subject = StateButton(is_momentary, MIDI_CC_TYPE, 0, 43, name='Right_Arrow')
def _set_up_mixer(self): is_momentary = True self._mixer = MixerComponent(8) self.send_sliders = [] for track in range(8): self.send_sliders.append(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, SEND_CC_OFF + track)) for track in range(8): strip = self._mixer.channel_strip(track) strip.set_arm_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, ARM_CC_OFF + track)) strip.set_solo_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, SOLO_CC_OFF + track)) strip.set_mute_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, MUTE_CC_OFF + track)) strip.set_volume_control(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, LEVEL_CC_OFF + track)) strip.set_pan_control(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, PAN_CC_OFF + track)) strip.set_select_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, SELECT_CC_OFF + track)) st = tuple([self.send_sliders[track]]) strip.set_send_controls(st) self.send_slider_toggle_button = StateButton(False, MIDI_CC_TYPE, 0, 90) self.send_slider_toggle_button.add_value_listener(self._do_toggle_send) self._session.set_mixer(self._mixer)
def __init__(self, *a, **k): super(EditSection, self).__init__(*a, **k) is_momentary = True self.mikro_shift_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 2, 80) self._do_shift_mikro.subject = self.mikro_shift_button self.shift_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1, 80) self._do_shift.subject = self.shift_button self.alt_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1, 82) self._do_alt.subject = self.alt_button self.mikro_shift = False self.shiftdown = False self.altdown = False self.edit_state = ES_NONE self._down_button = None self._action_set_quant.subject = SliderElement(MIDI_CC_TYPE, 2, 110) self._action_init_loop.subject = SliderElement(MIDI_CC_TYPE, 2, 111) self._nav_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 115) self._action_navigate.subject = self._nav_button self._copy_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 95) self._action_duplicate.subject = self._copy_button self._quantize_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 97) self._action_quantize.subject = self._quantize_button self._paste_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 96) self._action_new.subject = self._paste_button self._note_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 101) self._action_note.subject = self._note_button self._clear_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 103) self._action_clear.subject = self._clear_button self._nudge_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 100) self._action_nudge_button.subject = self._nudge_button self.action_time = False self.pad_action = False self.pad_wheel_action = False self.quantize = 5 self.quantize_amount = 1.0 self.initial_clip_len = 4.0 self._focused_clip = None self._focused_c_index = None self._color_edit = False self.nav_index = 0 return
def __init__(self, *a, **k): super(EncoderView, self).__init__(*a, **k) self.__session = self.canonical_parent.get_session() self.__encoders = [self.create_encoders(index) for index in range(8)] self.__buttons = [self.create_button(index) for index in range(8)] self._return_tracks_change.subject = self.song() self._tracks_change.subject = self.song() self._handle_track_changed.subject = self.song().view self._handle_visble_tracks_changed.subject = self.song() self._left_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_LEFT_PAGE_BUTTON) self._right_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_RIGHT_PAGE_BUTTON) self._mixer_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_MIXER_BUTTON) self._plugin_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_PLUGIN_BUTTON) self._handle_left.subject = self._left_button self._handle_right.subject = self._right_button self._handle_mixer_button.subject = self._mixer_button self._handle_plugin_button.subject = self._plugin_button
def _setup_transport(self): is_momentary = True transport = TransportComponent() self.__play_button = StateButton(is_momentary, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_PLAY_BUTTON, name='Play_Button') self.__restart_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_RESTART_BUTTON) stop_button = StateButton(not is_momentary, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_STOP_BUTTON, name='Stop_Button') self._rec_button = StateButton(is_momentary, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_RECORD_BUTTON, name='Record_Button') metrononme_button = StateButton(is_momentary, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_METRONOME_BUTTON, name='Metronome_Button') self._song_follow_button = StateButton(is_momentary, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_FOLLOW_BUTTON, name='Follow_Button') self._do_rec_button.subject = self._rec_button if self._has_stop_button: transport.set_play_button(self.__play_button) transport.set_stop_button(stop_button) else: self._hand_play_pressed.subject = self.__play_button self._listen_playing.subject = self.song() self._stopall_button = StateButton(True, MIDI_CC_TYPE, 0, CC_ALL_BUTTON) self._do_stop_all.subject = self._stopall_button self._auto_button = StateButton(True, MIDI_CC_TYPE, 0, CC_AUTO_BUTTON, name='Auto_Button') self._handle_automation_record.subject = self._auto_button self._listen_automation_record.subject = self.song() self._handle_restart_button.subject = self.__restart_button self._handle_follows_button.subject = self._song_follow_button self._follow_song_changed.subject = self.song().view transport.set_metronome_button(metrononme_button) self._listen_overdub.subject = self.song()
def __init__(self, session, *a, **k): super(ModifierComponent, self).__init__(*a, **k) self.__session = session self.__delete_button = StateButton(True, MIDI_CC_TYPE, 0, 95, name='Clear_Button') self.__do_delete.subject = self.__delete_button self.__duplicate_button = StateButton(True, MIDI_CC_TYPE, 0, 96, name='Duplicate_Button') self.__do_duplicate.subject = self.__duplicate_button self._select_button = StateButton(True, MIDI_CC_TYPE, 0, 80, name='Select_Button') self.__do_select_button.subject = self._select_button self.__lock_button = StateButton(True, MIDI_CC_TYPE, 0, 47, name='Lock_Button') self.__do_lock.subject = self.__lock_button self.__macro_button = StateButton(True, MIDI_CC_TYPE, 0, 90, name='Macro_Button') self.__do_macro.subject = self.__macro_button self._left_button = StateButton(True, MIDI_CC_TYPE, 0, 107, name='Metro_Button') self._right_button = StateButton(True, MIDI_CC_TYPE, 0, 104, name='Loop_Button') self._rec_button = StateButton(True, MIDI_CC_TYPE, 0, 109, name='Record_Button') self._do_left_button.subject = self._left_button self._do_right_button.subject = self._right_button self._do_rec_button.subject = self._rec_button self._listen_overdub.subject = self.song() self._listen_loop.subject = self.song() self._listen_metronome.subject = self.song() self.__action_listener = None self.__shift_listener = None return
def __init__(self, parent): self._parent = parent self.master_track = parent.song().master_track self.volume_button = None self._set_volume_button(StateButton(True, MIDI_CC_TYPE, 3, 110)) self.the_slider = SliderElement(MIDI_CC_TYPE, 1, 86) self.the_slider.add_value_listener(self._do_main_slider, True) self.xfade_button = None self._set_xfade_button(StateButton(True, MIDI_CC_TYPE, 3, 116)) self.swing_button = None self._set_swing_button(StateButton(True, MIDI_CC_TYPE, 3, 111)) self.mode = KN2_MODE_VOLUME self.previous_mode = -1 self.tempo_button = None self._set_tempo_button(StateButton(True, MIDI_CC_TYPE, 3, 112)) self.push_button = None self._set_push_button(StateButton(True, MIDI_CC_TYPE, 1, 87)) self.clipn_v_button = None self.clipn_h_button = None self._set_clipn_h_button(StateButton(True, MIDI_CC_TYPE, 3, 114)) self._set_clipn_v_button(StateButton(True, MIDI_CC_TYPE, 3, 115)) self.toggle_buttons = [ self.volume_button, self.xfade_button, self.swing_button, self.tempo_button, self.clipn_h_button, self.clipn_v_button ] self.shift_button = None self._set_shift_button(StateButton(True, MIDI_CC_TYPE, 3, 113)) self.shift_on = False self.scroll_mod_left_button = None self.scroll_mod_right_button = None self._set_scroll_mod_left_button( StateButton(True, MIDI_CC_TYPE, 0, 105)) self._set_scroll_mod_right_button( StateButton(True, MIDI_CC_TYPE, 0, 106)) self._prev_mode = KN2_MODE_VOLUME self.lrmode = LR_CONTROL_CLIP self._challenge = Live.Application.get_random_int( 0, 400000000) & 2139062143 self.loop_div_index = 0 self.loop_incdex = 4.0 self.arrow_mode_button = ColorButton(True, MIDI_CC_TYPE, 30) self.arrow_mode_button.add_value_listener(self.toggle_arrow_mode) self.arrow_mode_button.send_color(LR_MODE_HUES[self.lrmode]) self.arrow_mode_button.send_value(127, True) self.navflags = 0 self.octave_mod_button = StateButton(True, MIDI_CC_TYPE, 1, 70) self.octave_mod_button.add_value_listener(self._action_octave) self.scale_mod_button = StateButton(True, MIDI_CC_TYPE, 1, 71) self.scale_mod_button.add_value_listener(self._action_scale) self.basenote_mod_button = StateButton(True, MIDI_CC_TYPE, 1, 72) self.basenote_mod_button.add_value_listener(self._action_base_note) self.keycolor_mod_button = StateButton(True, MIDI_CC_TYPE, 1, 73) self.keycolor_mod_button.add_value_listener(self._action_key_color) self.pad_to_mainknob_mode = 0 self._measure_left_click = 0 self._measure_right_click = 0 self.mode_assign_map = { KN2_MODE_VOLUME: (self.chg_volume, 0, 'Master Knob controls MASTER Volume', KN2_MODE_CUE), KN2_MODE_CUE: (self.chg_cue, 0, 'Master Knob controls Cue Level', KN2_MODE_VOLUME), KN2_MODE_TEMPO_COARSE: (self.chg_tempo, 3, 'Master Knob controls TEMPO Coarse', KN2_MODE_TEMPO_FINE), KN2_MODE_TEMPO_FINE: (self.chg_tempo_fine, 3, 'Master Knob controls TEMPO Fine', KN2_MODE_TEMPO_COARSE), KN2_MODE_XFADE: (self.chg_xfade, 1, 'Master Knob controls Crossfader', -1), KN2_MODE_QUANT: (self.chg_quant, 2, 'Master Knob controls Recording Quantize', KN2_MODE_CLIP_QUANT), KN2_MODE_CLIP_QUANT: (self.chg_clip_q, 2, 'Master Knob controls Clip Start Quantize', KN2_MODE_QUANT), KN2_MODE_CLIPN_HOR: (self.nav_c_hor, 4, 'Master Knob Clip View horizontally', -1), KN2_MODE_CLIPN_VER: (self.nav_c_ver, 5, 'Master Knob Clip View vertically', -1), KN2_MODE_GENERAL: (self.chg_general, -1, None, -1), KN2_P_SCALES: (self.modify_pad_scaling, -1, None, -1) }
class MaschineMk2(ControlSurface): __module__ = __name__ __doc__ = 'Control Script for Maschine Mk2 and Maschine Mikro Mk2' def __init__(self, c_instance): ControlSurface.__init__(self, c_instance, False) with self.component_guard(): self._suppress_send_midi = True self.togglecolor = (10, 30, 50, 70, 90) self.toggleindex = 0 self._c_ref = c_instance self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143 self._c_inst = c_instance is_momentary = True self._active = True self._modifier_down = False self._return_mode = 0 self._returntopad = False self._mode = CLIP_MODE self.init_slot = 0 self.init_done = False self._midi_pause_count = 0 self.nav_index = 0 self._base_note = 0 self._octave = 0.55 self._scale_select_mode = MODE_PRESS_NONE self.send_slider_index = 0 self._pad_mode = PM_OFF self._note_display_mode = ND_KEYBOARD1 self._set_suppress_rebuild_requests(True) self._scenematrix = SceneMatrix(self) self._master_knob = Mk2KnobControl(self) self._device = self._set_up_device_control() self.show_message(str('')) self.request_rebuild_midi_map() self._set_global_buttons() self._set_mode_buttons() self._setup_transport() self._set_modecontrol() self._set_up_session() self._set_up_mixer() self._set_up_timer() self._set_up_machine_knobs() self.current_scale_index = 0 self.assign_transpose(SCALES[self.current_scale_index]) self.set_highlighting_session_component(self._session) self._navigate_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 127) self._navigate_button.add_value_listener(self._do_focus_navigate) self.display_update_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 86) self.display_update_button.add_value_listener(self._a_display_update) self._set_suppress_rebuild_requests(False) self.song().view.add_detail_clip_listener(self.clip_handle) self.song().add_visible_tracks_listener(self.clip_handle) self.song().add_scenes_listener(self.clip_handle) self.application().view.add_view_focus_changed_listener(self.focus_changed) self.log_message('########## LIVE 9 MASCHINE MK2 V 1.02 #############') self._suppress_send_midi = False def _set_up_mixer(self): is_momentary = True self._mixer = MixerComponent(8) self.send_sliders = [] for track in range(8): self.send_sliders.append(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, SEND_CC_OFF + track)) for track in range(8): strip = self._mixer.channel_strip(track) strip.set_arm_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, ARM_CC_OFF + track)) strip.set_solo_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, SOLO_CC_OFF + track)) strip.set_mute_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, MUTE_CC_OFF + track)) strip.set_volume_control(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, LEVEL_CC_OFF + track)) strip.set_pan_control(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, PAN_CC_OFF + track)) strip.set_select_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, SELECT_CC_OFF + track)) st = tuple([self.send_sliders[track]]) strip.set_send_controls(st) self.send_slider_toggle_button = StateButton(False, MIDI_CC_TYPE, 0, 90) self.send_slider_toggle_button.add_value_listener(self._do_toggle_send) self._session.set_mixer(self._mixer) def _set_global_buttons(self): is_momentary = True self._undo_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 85) self._undo_button.add_value_listener(self._do_undo) self._redo_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 87) self._redo_button.add_value_listener(self._do_redo) self._armsolomode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 89) self._armsolomode_button.add_value_listener(self._do_armsolo_mode) self._fire_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 9) self._fire_button.add_value_listener(self._do_fire_button) self.track_left_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 120) self.track_right_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 121) self.track_left_button.add_value_listener(self._a_trk_left) self.track_right_button.add_value_listener(self._a_trk_right) self.test_button = StateButton(True, MIDI_CC_TYPE, 5, 60) self.note_repeat_button = StateButton(True, MIDI_CC_TYPE, 5, 61) self.test_button.add_value_listener(self.do_test) self.note_repeat_button.add_value_listener(self.do_note_repeat) self.reset_test_button = StateButton(True, MIDI_CC_TYPE, 5, 62) self.reset_test_button.add_value_listener(self.do_reset) def _set_mode_buttons(self): self.xfade_assign_button = StateButton(True, MIDI_CC_TYPE, 0, 116) self._pad_select_button = StateButton(False, MIDI_CC_TYPE, 0, 117) self._pad_solo_button = StateButton(False, MIDI_CC_TYPE, 0, 118) self._mute_button = StateButton(False, MIDI_CC_TYPE, 0, 119) self._pad_scale_up = GatedColorButton(True, MIDI_CC_TYPE, 83, 0) self._pad_scale_down = GatedColorButton(True, MIDI_CC_TYPE, 94, 16) self._pad_select_button.add_value_listener(self._do_pad_select_multi) self._mute_button.add_value_listener(self._do_mute_button) self._pad_solo_button.add_value_listener(self._do_pad_solo_multi) self.xfade_assign_button.add_value_listener(self._do_xfade_assign) self._pad_scale_up.add_value_listener(self._do_pad_note_up) self._pad_scale_down.add_value_listener(self._do_pad_note_down) def set_appointed_device(self, device): with self.component_guard(): self._device_component.set_device(device) def _set_up_device_control(self): is_momentary = True device = MaschineDeviceComponent(self) device.set_device_changed_listener(self._handle_device_changed) device.set_device_parm_listener(self._hande_device_parm_changed) param_controls = [] for index in range(8): param_controls.append(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_CC_OFF + index)) device.set_parameter_controls(tuple(param_controls)) device.set_on_off_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF)) device.set_bank_nav_buttons(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF + 4), ButtonElement(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF + 5)) self._device_nav_button_left = StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF + 6) self._device_nav_button_right = StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF + 7) self._device_nav_button_left.add_value_listener(self._nav_value_left) self._device_nav_button_right.add_value_listener(self._nav_value_right) device.name = 'Device_Component' self.set_device_component(device) return device def _setup_transport(self): is_momentary = True transport = TransportComponent() playButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 108) stopButton = StateButton(not is_momentary, MIDI_CC_TYPE, 0, 110) recordButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 109) overdubButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 107) metrononmeButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 104) playButton.name = 'Play' stopButton.name = 'Stop' recordButton.name = 'Record' overdubButton.name = 'Overdub' metrononmeButton.name = 'Metronome' transport.set_play_button(playButton) transport.set_stop_button(stopButton) transport.set_record_button(recordButton) transport.set_overdub_button(overdubButton) transport.set_metronome_button(metrononmeButton) transport.set_nudge_buttons(StateButton(is_momentary, MIDI_CC_TYPE, 1, 51), StateButton(is_momentary, MIDI_CC_TYPE, 1, 50)) punchinbutton = ToggleButton(MIDI_CC_TYPE, 1, 52) punchoutbutton = ToggleButton(MIDI_CC_TYPE, 1, 53) punchinbutton.name = 'Punch In' punchoutbutton.name = 'Punch Out' transport.set_punch_buttons(punchinbutton, punchoutbutton) transport.set_loop_button(StateButton(is_momentary, MIDI_CC_TYPE, 1, 54)) self.transp_ff_button = ButtonElement(True, MIDI_CC_TYPE, 1, 59) self.transp_rw_button = ButtonElement(True, MIDI_CC_TYPE, 1, 58) transport.set_seek_buttons(self.transp_ff_button, self.transp_rw_button) self.xfadeKnob = SliderElement(MIDI_CC_TYPE, 1, 100) self.xfadeKnob.connect_to(self.song().master_track.mixer_device.crossfader) self.tap_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 88) self.tap_button.add_value_listener(self._do_tap_tempo) self.cue_add_delete_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 55) self.cue_prev_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 56) self.cue_next_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 57) self.cue_add_delete_button.add_value_listener(self._do_toggle_cue) self.cue_prev_button.add_value_listener(self._do_toggle_prev_cue) self.cue_next_button.add_value_listener(self._do_toggle_next_cue) def _set_up_machine_knobs(self): master_track = self.song().master_track self.master_volume = SliderElement(MIDI_CC_TYPE, 0, 40) self.prehear = SliderElement(MIDI_CC_TYPE, 0, 41) self.master_volume.connect_to(master_track.mixer_device.volume) self.prehear.connect_to(master_track.mixer_device.cue_volume) def _set_up_session(self): is_momentary = True self._session = MaschineSessionComponent() self._session.add_offset_listener(self.notify_track_scroll) nhue = COLOR_HUE_NAV self.nav_buttons = (GatedColorButton(True, MIDI_CC_TYPE, 92, nhue), GatedColorButton(True, MIDI_CC_TYPE, 81, nhue), GatedColorButton(True, MIDI_CC_TYPE, 93, nhue), GatedColorButton(True, MIDI_CC_TYPE, 91, nhue)) self._session.set_scene_bank_buttons(self.nav_buttons[0], self.nav_buttons[1]) self._session.set_track_bank_buttons(self.nav_buttons[2], self.nav_buttons[3]) self._session.set_stop_all_clips_button(StateButton(is_momentary, MIDI_CC_TYPE, 0, 111)) track_stop_buttons = [ StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, index + STOP_CC_OFF) for index in range(4) ] self._session.set_stop_track_clip_buttons(tuple(track_stop_buttons)) self._init_matrix() self._set_up_buttons() self._session._link() self._session.set_advance(STEP4) def _set_up_buttons(self): self._bmatrix = ButtonMatrixElement() for scene_index in range(4): button_row = [] scene = self._session.scene(scene_index) for track_index in range(4): button = self._matrix[scene_index][track_index] clip_slot = scene.clip_slot(track_index) clip_slot.set_launch_button(button) clip_slot.set_triggered_to_play_value(1) clip_slot.set_triggered_to_record_value(1) clip_slot.set_started_value(1) clip_slot.set_recording_value(1) clip_slot.set_stopped_value(1) self._bmatrix.add_row(tuple(button_row)) def _init_matrix(self): is_momentary = True self._button_sequence = [] self._matrix = [] for scene_index in range(4): button_row = [] for track_index in range(4): button = VarButtonElement(is_momentary, 0, scene_index, track_index, self) partner = TwinButton(is_momentary, 1, button) partner.add_value_listener(self.ox, True) button_row.append(button) self._matrix.append(tuple(button_row)) for scene_index in [3, 2, 1, 0]: for track_index in range(4): self._button_sequence.append(self._matrix[scene_index][track_index]) self._session.set_matrix(self._matrix) def set_pad_translations(self, pad_translations): ControlSurface.set_pad_translations(pad_translations) def refresh_state(self): ControlSurface.refresh_state(self) self._update_hardware() def ox(self, value, button): if not isinstance(button, TwinButton): raise AssertionError self._mode == PAD_MODE and button.fire(value) def _update_hardware(self): self._session.update() self._set_suppress_rebuild_requests(True) self._set_mode() self._master_knob.update() if self._scenematrix.soloexclusive: self._armsolomode_button.send_value(1, True) else: self._armsolomode_button.send_value(0, True) self._master_knob.start_up() self._pad_scale_up.activate() self._pad_scale_down.activate() self.current_scale_to_display() self.send_to_display(KEY_COLOR_MODES_STRINGS[self._note_display_mode], 1) for scene_index in range(4): scene = self._session.scene(scene_index) for track_index in range(4): button = self._matrix[scene_index][track_index] button.refresh() self._set_suppress_rebuild_requests(False) def get_color(self, value, track_index, scene_index): if not self._active: return if self._mode == SCENE_MODE or self._mode == CONTROL_MODE or self._pad_mode == PM_ON: element = self._scenematrix.get_element(scene_index, track_index) return element.get_color(value) elif self._mode == CLIP_MODE: scene = self._session.scene(scene_index) clip_slot = scene.clip_slot(track_index)._clip_slot cindex = 0 if value == 0: cindex = 1 if clip_slot != None: if clip_slot.has_clip: if clip_slot.clip.is_recording or clip_slot.clip.will_record_on_start: return PColor.CLIP_RECORD[cindex] if clip_slot.clip.is_playing: return PColor.CLIP_PLAY[cindex] elif clip_slot.clip.is_triggered: return PColor.CLIP_PLAY[cindex] else: return PColor.CLIP_STOPPED[cindex] elif clip_slot.will_record_on_start: return PColor.CLIP_RECORD[cindex] elif clip_slot.is_playing: return PColor.CLIP_GROUP_PLAY[cindex] elif clip_slot.controls_other_clips: return PColor.CLIP_GROUP_CONTROL[cindex] elif clip_slot.is_triggered: return PColor.CLIP_GROUP_TRIGGER[cindex] elif self._mode == PAD_MODE: button = self._matrix[scene_index][track_index] return self.get_color_by_note_mode(button.get_identifier(), value > 0) def step_key_color_mode(self): self._note_display_mode = (self._note_display_mode + 1) % len(KEY_COLOR_MODES_STRINGS) self.show_message('Pad Mode Key Color = ' + KEY_COLOR_MODES_STRINGS[self._note_display_mode]) self.send_to_display('Colors: ' + KEY_COLOR_MODES_STRINGS[self._note_display_mode], 1) if self._mode == PAD_MODE: for note_index in range(16): button = self._button_sequence[note_index] button.send_color_direct(self.get_color_by_note_mode(button.get_identifier(), False)) def get_color_by_note_mode(self, midi_note, on): if self._note_display_mode == ND_BASE_OTHER: interval = (midi_note + 12 - self._base_note) % 12 if on: return INTERVAL_COLOR_MAP[interval][0] else: return INTERVAL_COLOR_MAP[interval][1] elif on: return KEY_COLOR_MAP[midi_note % 12][0] else: return KEY_COLOR_MAP[midi_note % 12][1] def _send_midi(self, midi_bytes, **keys): self._c_ref.send_midi(midi_bytes) if self._midi_pause_count == 2: time.sleep(0.002) self._midi_pause_count = 0 else: self._midi_pause_count = self._midi_pause_count + 1 return True def clip_handle(self): if self._mode == SCENE_MODE or self._mode == CONTROL_MODE or self._modifier_down: self._scenematrix.update() def _a_display_update(self, value): if not self.display_update_button != None: raise AssertionError raise value in range(128) or AssertionError (value != 0 or not self.display_update_button.is_momentary()) and self._update_hardware() self.show_message('Maschine Display Updated') def _set_up_timer(self): self.blink_state = 1 def update_display(self): with self.component_guard(): with self._is_sending_scheduled_messages(): self._task_group.update(0.1) if self._mode == CLIP_MODE and not self._modifier_down: if self.blink_state == 0: self._session.notify(1, 0) elif self.blink_state == 1: self._session.notify(1, 1) elif self.blink_state == 3: self._session.notify(2, 0) elif self.blink_state == 4: self._session.notify(2, 1) elif self._mode == PAD_MODE: pass elif self.blink_state == 0: self._scenematrix.notify_scene_mode(1) elif self.blink_state == 2: self._scenematrix.notify_scene_mode(0) self.blink_state = (self.blink_state + 1) % 4 self.init_slot += 1 def _invoke_track_edit(self, mode): self._deassign_matrix() self._scenematrix.assign() self._scenematrix.set_mode(mode) self._pad_mode = PM_ON self.request_rebuild_midi_map() self._scenematrix.update() def _set_modecontrol(self): is_momentary = True self.scene_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 112) self.clip_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 113) self.pad_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 114) self.control_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 115) self.xfade_assign_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 116) self.scene_mode_button.add_value_listener(self._a_mode_scene) self.clip_mode_button.add_value_listener(self._a_mode_clip) self.pad_mode_button.add_value_listener(self._a_mode_pad) self.control_mode_button.add_value_listener(self._a_mode_control) def _set_mode(self, mode = None): if mode == None: mode = self._mode if mode == SCENE_MODE: self.clip_mode_button.send_value(OFF_VALUE, True) self.pad_mode_button.send_value(OFF_VALUE, True) self.control_mode_button.send_value(OFF_VALUE, True) self.scene_mode_button.send_value(ON_VALUE, True) elif mode == CLIP_MODE: self.scene_mode_button.send_value(OFF_VALUE, True) self.pad_mode_button.send_value(OFF_VALUE, True) self.control_mode_button.send_value(OFF_VALUE, True) self.clip_mode_button.send_value(ON_VALUE, True) elif mode == PAD_MODE: self.scene_mode_button.send_value(OFF_VALUE, True) self.clip_mode_button.send_value(OFF_VALUE, True) self.control_mode_button.send_value(OFF_VALUE, True) self.pad_mode_button.send_value(ON_VALUE, True) elif mode == CONTROL_MODE: self.scene_mode_button.send_value(OFF_VALUE, True) self.clip_mode_button.send_value(OFF_VALUE, True) self.pad_mode_button.send_value(OFF_VALUE, True) self.control_mode_button.send_value(ON_VALUE, True) def _reset_matrix(self): for scene_index in range(4): scene = self._session.scene(scene_index) for track_index in range(4): button = self._matrix[scene_index][track_index] clip_slot = scene.clip_slot(track_index) clip_slot.set_launch_button(button) def update_button_matrix(self): self._session.update() for scene_index in range(4): scene = self._session.scene(scene_index) for track_index in range(4): button = self._matrix[scene_index][track_index] clip_slot = scene.clip_slot(track_index) if clip_slot._clip_slot != None and clip_slot._clip_slot.clip != None: button.send_value(1, True) else: button.send_value(0, True) def _deassign_matrix(self): for scene_index in range(4): scene = self._session.scene(scene_index) for track_index in range(4): clip_slot = scene.clip_slot(track_index) clip_slot.set_launch_button(None) def _from_pad_mode(self, matrix_mode): self._mode = SCENE_MODE self._register_buttons() self._scenematrix.assign() self._scenematrix.set_mode(matrix_mode) self._set_suppress_rebuild_requests(True) self.request_rebuild_midi_map() self._scenematrix.update() self._set_suppress_rebuild_requests(False) def _enter_pad_mode(self): self._set_mode(PAD_MODE) if self._mode == CLIP_MODE: self._deassign_matrix() elif self._mode == SCENE_MODE: self._scenematrix.deassign() elif self._mode == CONTROL_MODE: self._scenematrix.deassign() self._master_knob.exit_matrix_mode() self._mode = PAD_MODE self._set_suppress_rebuild_requests(True) for row in range(4): for column in range(4): button = self._matrix[row][column] button.send_value(0, True) button.set_to_notemode(True) self._forwarding_registry[MIDI_NOTE_ON_STATUS, button.get_identifier()] = button self._forwarding_registry[MIDI_NOTE_OFF_STATUS, button.get_identifier()] = button self._set_suppress_rebuild_requests(False) def _register_buttons(self, update = False): self._set_suppress_rebuild_requests(True) for row in range(4): for column in range(4): button = self._matrix[row][column] button.set_to_notemode(False) if update: button.send_value(127, True) fwkey = [MIDI_NOTE_ON_STATUS] fwkey.append(button.get_identifier()) self._forwarding_registry[tuple(fwkey)] = button self._forwarding_registry[MIDI_NOTE_OFF_STATUS, button.get_identifier()] = button self._set_suppress_rebuild_requests(False) def _back_to_clip_mode(self): self._pad_mode = PM_OFF self._scenematrix.set_mode(SCENE_MODE_NORMAL) self._scenematrix.deassign() self._set_up_clip_matrix() def _set_up_clip_matrix(self): for row in range(4): for column in range(4): button = self._matrix[row][column] button.set_to_notemode(False) self._set_suppress_rebuild_requests(True) self.request_rebuild_midi_map() self._reset_matrix() self.update_button_matrix() self._set_suppress_rebuild_requests(False) def _enter_scene_mode(self): self._set_mode(SCENE_MODE) if self._mode == CLIP_MODE: self._deassign_matrix() elif self._mode == CONTROL_MODE: self._master_knob.exit_matrix_mode() elif self._mode == PAD_MODE: self._register_buttons() self._mode = SCENE_MODE self._scenematrix.assign() self._scenematrix.set_mode(SCENE_MODE_NORMAL) self._return_mode = SCENE_MODE_NORMAL self.request_rebuild_midi_map() def _enter_clip_mode(self): self._set_suppress_rebuild_requests(True) self._set_mode(CLIP_MODE) if self._mode == SCENE_MODE: self._scenematrix.deassign() elif self._mode == CONTROL_MODE: self._master_knob.exit_matrix_mode() self._mode = CLIP_MODE self._set_up_clip_matrix() self.request_rebuild_midi_map() self._set_suppress_rebuild_requests(False) def _enter_control_mode(self): self._set_mode(CONTROL_MODE) if self._mode == CLIP_MODE: self._deassign_matrix() elif self._mode == PAD_MODE: self._mode = CONTROL_MODE self._register_buttons() self._mode = CONTROL_MODE self._set_suppress_rebuild_requests(True) self._scenematrix.set_mode(SCENE_MODE_CONTROL) self._return_mode = SCENE_MODE_CONTROL self._scenematrix.assign() self._master_knob.switch_to_matrix_mode() self._set_suppress_rebuild_requests(False) self.request_rebuild_midi_map() self._scenematrix.update() def _a_mode_scene(self, value): if not self.scene_mode_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.show_message('SCENE MODE') self._enter_scene_mode() def _a_mode_clip(self, value): if not self.clip_mode_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.show_message('CLIP MODE') self._enter_clip_mode() def _a_mode_pad(self, value): if not self.pad_mode_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.show_message('PAD MODE') self._enter_pad_mode() def _a_mode_control(self, value): if not self.control_mode_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.show_message('CONTROL MODE') self._enter_control_mode() def _do_pad_select_multi(self, value): if not value in range(128): raise AssertionError self._modifier_down = value != 0 if self._mode == PAD_MODE or self._returntopad: value != 0 and self._from_pad_mode(SCENE_MODE_SELECT) self._returntopad = True else: self._returntopad = False self._enter_pad_mode() elif self._mode == CLIP_MODE: if value != 0: self._invoke_track_edit(SCENE_MODE_SELECT) else: self._back_to_clip_mode() elif self._mode != PAD_MODE: if value == 0: self._scenematrix.set_mode(self._return_mode) else: if self._scenematrix.in_main_mode(): self._return_mode = self._scenematrix.mode self._scenematrix.set_mode(SCENE_MODE_SELECT) def _do_mute_button(self, value): if not self._mute_button != None: raise AssertionError if not value in range(128): raise AssertionError self._modifier_down = value != 0 (self._mode == PAD_MODE or self._returntopad) and value != 0 and self._from_pad_mode(SCENE_MODE_MUTE) self._returntopad = True else: self._returntopad = False self._enter_pad_mode() elif self._mode == SCENE_MODE or self._mode == CONTROL_MODE: if value == 0: self._scenematrix.set_mode(self._return_mode) self._pad_mode = PM_OFF else: if self._scenematrix.in_main_mode(): self._return_mode = self._scenematrix.mode self._scenematrix.set_mode(SCENE_MODE_MUTE) self._pad_mode = PM_ON elif self._mode == CLIP_MODE: if value > 0: self._invoke_track_edit(SCENE_MODE_MUTE) else: self._back_to_clip_mode() self._pad_mode = PM_OFF def _do_pad_solo_multi(self, value): if not value in range(128): raise AssertionError self._modifier_down = value != 0 if self._mode == PAD_MODE or self._returntopad: value != 0 and self._from_pad_mode(SCENE_MODE_SOLO) self._returntopad = True else: self._returntopad = False self._enter_pad_mode() elif self._mode == CLIP_MODE: if value != 0: self._invoke_track_edit(SCENE_MODE_SOLO) else: self._back_to_clip_mode() elif self._mode != PAD_MODE: if value == 0: self._scenematrix.set_mode(self._return_mode) else: if self._scenematrix.in_main_mode(): self._return_mode = self._scenematrix.mode self._scenematrix.set_mode(SCENE_MODE_SOLO) def _do_xfade_assign(self, value): if not self.xfade_assign_button != None: raise AssertionError if not value in range(128): raise AssertionError (self._mode == PAD_MODE or self._returntopad) and value != 0 and self._from_pad_mode(SCENE_MODE_XFADE) self._returntopad = True else: self._returntopad = False self._enter_pad_mode() elif self._mode == CLIP_MODE: if value != 0: self._invoke_track_edit(SCENE_MODE_XFADE) else: self._back_to_clip_mode() elif self._mode == SCENE_MODE or self._mode == CONTROL_MODE: if value == 0: self._scenematrix.set_mode(self._return_mode) else: if self._scenematrix.in_main_mode(): self._return_mode = self._scenematrix.mode self._scenematrix.set_mode(SCENE_MODE_XFADE) def _do_pad_note_up(self, value): if not self._pad_scale_up != None: raise AssertionError if not value in range(128): raise AssertionError self._pad_scale_up.send_value(value, True) self._modifier_down = value != 0 (self._mode == PAD_MODE or self._returntopad) and value != 0 and self._from_pad_mode(SCENE_MODE_ARM) self._returntopad = True else: self._returntopad = False self._enter_pad_mode() elif self._mode == CLIP_MODE: self.show_message('Arm tracks with pads') if value != 0: self._invoke_track_edit(SCENE_MODE_ARM) else: self._back_to_clip_mode() elif self._mode == SCENE_MODE or self._mode == CONTROL_MODE: self.show_message('Arm tracks with pads') if value == 0: self._scenematrix.set_mode(self._return_mode) else: if self._scenematrix.in_main_mode(): self._return_mode = self._scenematrix.mode self._scenematrix.set_mode(SCENE_MODE_ARM) def _do_pad_note_down(self, value): if not self._pad_scale_down != None: raise AssertionError if not value in range(128): raise AssertionError self._pad_scale_down.send_value(value, True) self._modifier_down = value != 0 (self._mode == PAD_MODE or self._returntopad) and value != 0 and self._from_pad_mode(SCENE_MODE_STOP) self._returntopad = True else: self._returntopad = False self._enter_pad_mode() elif self._mode == CLIP_MODE: self.show_message('Stop tracks with pads') if value != 0: self._invoke_track_edit(SCENE_MODE_STOP) else: self._back_to_clip_mode() elif self._mode == SCENE_MODE or self._mode == CONTROL_MODE: self.show_message('Stop tracks with pads') if value == 0: self._scenematrix.set_mode(self._return_mode) else: if self._scenematrix.in_main_mode(): self._return_mode = self._scenematrix.mode self._scenematrix.set_mode(SCENE_MODE_STOP) def modify_track_offset(self, delta): self._scenematrix.mod_track_offset(delta) def modify_scene_offset(self, delta): self._scenematrix.mod_scene_offset(delta) def move_view_horizontal(self, delta): if delta == 1: self._session.bank_right() else: self._session.bank_left() if self._mode == CONTROL_MODE: self._scenematrix.update() def inc_octave(self, inc): scale = SCALES[self.current_scale_index] octave = scale.to_octave(self._octave) newoctave = octave + inc if newoctave < 0: newoctave = 0 elif newoctave > scale.octave_range: newoctave = scale.octave_range self._octave = scale.to_relative(newoctave, self._octave) scale = SCALES[self.current_scale_index] self.show_message(' OCTAVE ' + BASE_NOTE[self._base_note] + str(newoctave - 2) + ' to ' + scale.name) self.current_scale_to_display() def inc_base_note(self, inc): newbase = self._base_note + inc if newbase < 0: self._base_note = 0 elif newbase > 11: self._base_note = 11 else: self._base_note = newbase scale = SCALES[self.current_scale_index] self.show_message(' Base Note ' + BASE_NOTE[self._base_note] + ' to ' + scale.name) self.current_scale_to_display() def current_scale_to_display(self): scale = SCALES[self.current_scale_index] text = scale.name + ' ' + BASE_NOTE[self._base_note] + str(scale.to_octave(self._octave)) self.send_to_display(text) def inc_scale(self, inc): nr_of_scales = len(SCALES) newindex = self.current_scale_index + inc if newindex < 0: newindex = 0 elif newindex >= nr_of_scales: newindex = nr_of_scales - 1 else: self.current_scale_index += inc newscale = SCALES[self.current_scale_index] self.show_message(' PAD Scale ' + newscale.name + ' ' + BASE_NOTE[self._base_note] + str(newscale.to_octave(self._octave) - 2)) self.current_scale_to_display() def update_transpose(self): self.assign_transpose(SCALES[self.current_scale_index]) self._set_suppress_rebuild_requests(True) self.request_rebuild_midi_map() self._set_suppress_rebuild_requests(False) def set_scale(self, scale): raise isinstance(scale, PadScale) or AssertionError scale_len = len(scale.notevalues) octave = scale.to_octave(self._octave) def assign_transpose(self, scale): raise isinstance(scale, PadScale) or AssertionError scale_len = len(scale.notevalues) octave = scale.to_octave(self._octave) last_note_val = None for note_index in range(16): button = self._button_sequence[note_index] scale_index = note_index % scale_len octave_offset = note_index / scale_len note_value = scale.notevalues[scale_index] + self._base_note + octave * 12 + octave_offset * 12 if note_value < 128: last_note_val = note_value elif last_note_val != None: note_value = last_note_val button.set_send_note(note_value) if self._mode == PAD_MODE: button.send_color_direct(self.get_color_by_note_mode(note_value, False)) def do_reset(self, value): if value == 0: return for row in range(4): for column in range(4): button = self._matrix[row][column] data_byte1 = button._original_identifier button.send_midi((MIDI_CC_STATUS + 2, data_byte1, 0)) def do_test(self, value): color = self.togglecolor[self.toggleindex] self.toggleindex = (self.toggleindex + 1) % len(self.togglecolor) if value == 0: return for row in range(4): for column in range(4): button = self._matrix[row][column] self.schedule_message(1, self.dosend, (color, 127, 127, row, column)) def dosend(self, parm = None): button = self._matrix[parm[3]][parm[4]] data_byte1 = button._original_identifier button.send_midi((MIDI_CC_STATUS + 0, data_byte1, parm[0])) button.send_midi((MIDI_CC_STATUS + 1, data_byte1, parm[1])) button.send_midi((MIDI_CC_STATUS + 2, data_byte1, parm[2])) def do_note_repeat(self, value): nrvalue = 0 if value != 0: nrvalue = 1 self._c_ref.set_note_repeat_state(nrvalue) def _do_toggle_send(self, value): nr_of_tracks = len(self.song().return_tracks) if value == 0 or nr_of_tracks < 1: return prev = self.send_slider_index self.send_slider_index += 1 if self.send_slider_index >= nr_of_tracks: self.send_slider_index = 0 self.show_message(' Set Send ' + str(SENDS[self.send_slider_index])) if prev != self.send_slider_index: for track in range(8): strip = self._mixer.channel_strip(track) slider_list = [] for index in range(self.send_slider_index + 1): if index < self.send_slider_index - 1: slider_list.append(None) else: slider_list.append(self.send_sliders[track]) strip.set_send_controls(tuple(slider_list)) def _do_armsolo_mode(self, value): if not self._armsolomode_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self._scenematrix.set_armsolo_exclusive(self._armsolomode_button) def _do_fire_button(self, value): if not self._fire_button != None: raise AssertionError if not value in range(128): raise AssertionError clip_slot = (value != 0 or not self._mute_button.is_momentary()) and self.song().view.highlighted_clip_slot clip_slot and clip_slot.fire() def _do_undo(self, value): if not self._undo_button != None: raise AssertionError if not value in range(128): raise AssertionError (value != 0 or not self._undo_button.is_momentary()) and self.song().can_undo == 1 and self.song().undo() self.show_message(str('UNDO')) def _do_redo(self, value): if not self._redo_button != None: raise AssertionError if not value in range(128): raise AssertionError (value != 0 or not self._redo_button.is_momentary()) and self.song().can_redo == 1 and self.song().redo() self.show_message(str('REDO')) def _a_trk_left(self, value): if not value in range(128): raise AssertionError if value != 0: direction = self.application().view.is_view_visible('Session') and Live.Application.Application.View.NavDirection.left self.application().view.scroll_view(direction, 'Session', True) def _a_trk_right(self, value): if not value in range(128): raise AssertionError if value != 0: direction = self.application().view.is_view_visible('Session') and Live.Application.Application.View.NavDirection.right self.application().view.scroll_view(direction, 'Session', True) def _nav_value_left(self, value): if not self._device_nav_button_left != None: raise AssertionError if not value in range(128): raise AssertionError modifier_pressed = True value > 0 and (not self.application().view.is_view_visible('Detail') or not self.application().view.is_view_visible('Detail/DeviceChain')) and self.application().view.show_view('Detail') self.application().view.show_view('Detail/DeviceChain') else: direction = Live.Application.Application.View.NavDirection.left self.application().view.scroll_view(direction, 'Detail/DeviceChain', not modifier_pressed) def _nav_value_right(self, value): if not self._device_nav_button_right != None: raise AssertionError if not value in range(128): raise AssertionError modifier_pressed = value > 0 and True (not self.application().view.is_view_visible('Detail') or not self.application().view.is_view_visible('Detail/DeviceChain')) and self.application().view.show_view('Detail') self.application().view.show_view('Detail/DeviceChain') else: direction = Live.Application.Application.View.NavDirection.right self.application().view.scroll_view(direction, 'Detail/DeviceChain', not modifier_pressed) def _do_tap_tempo(self, value): if not value in range(128): raise AssertionError value > 0 and self.song().tap_tempo() def _do_toggle_cue(self, value): if not value in range(128): raise AssertionError value > 0 and self.song().set_or_delete_cue() def _do_toggle_prev_cue(self, value): if not value in range(128): raise AssertionError value > 0 and self.song().jump_to_prev_cue() def _do_toggle_next_cue(self, value): if not value in range(128): raise AssertionError value > 0 and self.song().jump_to_next_cue() def focus_changed(self): pass def _handle_device_changed(self, device): pass def _hande_device_parm_changed(self): pass def _do_focus_navigate(self, value): if not self._navigate_button != None: raise AssertionError raise value in range(128) or AssertionError self.nav_index = value != 0 and (self.nav_index + 1) % len(VIEWS_ALL) self.application().view.focus_view(VIEWS_ALL[self.nav_index]) self.show_message('Focus on : ' + str(VIEWS_ALL[self.nav_index])) def scroll_focus(self, delta): if delta == 1: self.nav_index = (self.nav_index + 1) % len(VIEWS_ALL) elif self.nav_index == 0: self.nav_index = len(VIEWS_ALL) - 1 else: self.nav_index -= 1 self.show_message('Focus on : ' + str(VIEWS_ALL[self.nav_index])) self.application().view.focus_view(VIEWS_ALL[self.nav_index]) def scroll_device(self, delta): if not (delta == 1 or delta == -1): raise AssertionError direction = delta == 1 and Live.Application.Application.View.NavDirection.right else: direction = Live.Application.Application.View.NavDirection.left self.application().view.scroll_view(direction, 'Detail/DeviceChain', True) def scroll_scene(self, delta): if not self.track_left_button != None: raise AssertionError raise delta == 1 or delta == -1 or AssertionError direction = delta == 1 and Live.Application.Application.View.NavDirection.down else: direction = Live.Application.Application.View.NavDirection.up self.application().view.scroll_view(direction, 'Session', True) def index_in_strip(self, track): for ind in range(len(self._mixer._channel_strips)): strack = self._mixer._channel_strips[ind]._track if strack == track: return ind return -1 def notify_track_scroll(self): self._scenematrix.update_control_selection() if self._mode == CONTROL_MODE: self._scenematrix.eval_matrix() self._scenematrix.fire_values() def send_to_display(self, text, grid = 0): if USE_DISPLAY == False: return if len(text) > 28: text = text[:27] msgsysex = [240, 0, 0, 102, 23, 18, min(grid, 3) * 28] filled = text.ljust(28) for c in filled: msgsysex.append(ord(c)) msgsysex.append(247) self._send_midi(tuple(msgsysex)) def send_color(self, button, hue, sat, bright): raise isinstance(button, ButtonElement) or AssertionError raise hue in range(128) or AssertionError raise sat in range(128) or AssertionError raise bright in range(128) or AssertionError data_byte1 = button._original_identifier button.send_midi((MIDI_CC_STATUS + 2, data_byte1, bright)) button.send_midi((MIDI_CC_STATUS + 1, data_byte1, sat)) button.send_midi((MIDI_CC_STATUS + 0, data_byte1, hue)) def turn_off_matrix(self): for row in range(4): for column in range(4): button = self._matrix[row][column] self.send_color(button, 2, 0, 0) button.set_to_notemode(False) def remove_listener(self, control, callback): if control != None and control.value_has_listener(callback): control.remove_value_listener(callback) control.disconnect() def disconnect(self): self.turn_off_matrix() self.scene_mode_button.send_value(0, True) self.clip_mode_button.send_value(0, True) self.pad_mode_button.send_value(0, True) self.control_mode_button.send_value(0, True) time.sleep(0.2) self._active = False self._suppress_send_midi = True self.remove_listener(self.scene_mode_button, self._a_mode_scene) self.remove_listener(self.clip_mode_button, self._a_mode_clip) self.remove_listener(self.pad_mode_button, self._a_mode_pad) self.remove_listener(self.control_mode_button, self._a_mode_control) self.remove_listener(self._undo_button, self._do_undo) self.remove_listener(self._redo_button, self._do_redo) self.remove_listener(self._armsolomode_button, self._do_armsolo_mode) self.remove_listener(self.xfade_assign_button, self._do_xfade_assign) self.remove_listener(self._fire_button, self._do_fire_button) self._session.remove_offset_listener(self.notify_track_scroll) self._mixer.disconnect() ControlSurface.disconnect(self)
def _setup_transport(self): is_momentary = True transport = TransportComponent() playButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 108) stopButton = StateButton(not is_momentary, MIDI_CC_TYPE, 0, 110) recordButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 109) overdubButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 107) metrononmeButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 104) playButton.name = 'Play' stopButton.name = 'Stop' recordButton.name = 'Record' overdubButton.name = 'Overdub' metrononmeButton.name = 'Metronome' transport.set_play_button(playButton) transport.set_stop_button(stopButton) transport.set_record_button(recordButton) transport.set_overdub_button(overdubButton) transport.set_metronome_button(metrononmeButton) transport.set_nudge_buttons(StateButton(is_momentary, MIDI_CC_TYPE, 1, 51), StateButton(is_momentary, MIDI_CC_TYPE, 1, 50)) punchinbutton = ToggleButton(MIDI_CC_TYPE, 1, 52) punchoutbutton = ToggleButton(MIDI_CC_TYPE, 1, 53) punchinbutton.name = 'Punch In' punchoutbutton.name = 'Punch Out' transport.set_punch_buttons(punchinbutton, punchoutbutton) transport.set_loop_button(StateButton(is_momentary, MIDI_CC_TYPE, 1, 54)) self.transp_ff_button = ButtonElement(True, MIDI_CC_TYPE, 1, 59) self.transp_rw_button = ButtonElement(True, MIDI_CC_TYPE, 1, 58) transport.set_seek_buttons(self.transp_ff_button, self.transp_rw_button) self.xfadeKnob = SliderElement(MIDI_CC_TYPE, 1, 100) self.xfadeKnob.connect_to(self.song().master_track.mixer_device.crossfader) self.tap_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 88) self.tap_button.add_value_listener(self._do_tap_tempo) self.cue_add_delete_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 55) self.cue_prev_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 56) self.cue_next_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 57) self.cue_add_delete_button.add_value_listener(self._do_toggle_cue) self.cue_prev_button.add_value_listener(self._do_toggle_prev_cue) self.cue_next_button.add_value_listener(self._do_toggle_next_cue)
class EncoderView(CompoundComponent): __module__ = __name__ __mode = ENC_MODE_VOL __prev_mode = None __session = None __encoders = None __buttons = None __send_offset = 0 __last_non_step_mode = ENC_MODE_VOL __track = None __device = None __selection_map = {} __nr_of_banks = 0 __bank_index = 0 __param_list = None __plugin_down = False def __init__(self, *a, **k): super(EncoderView, self).__init__(*a, **k) self.__session = self.canonical_parent.get_session() self.__encoders = [self.create_encoders(index) for index in range(8)] self.__buttons = [self.create_button(index) for index in range(8)] self._return_tracks_change.subject = self.song() self._tracks_change.subject = self.song() self._handle_track_changed.subject = self.song().view self._handle_visble_tracks_changed.subject = self.song() self._left_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_LEFT_PAGE_BUTTON) self._right_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_RIGHT_PAGE_BUTTON) self._mixer_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_MIXER_BUTTON) self._plugin_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_PLUGIN_BUTTON) self._handle_left.subject = self._left_button self._handle_right.subject = self._right_button self._handle_mixer_button.subject = self._mixer_button self._handle_plugin_button.subject = self._plugin_button def connect(self): self.__assign_encoders() self.setup_select_track() self.light_mode() def light_mode(self): self._mixer_button.send_value( (self.__mode == ENC_MODE_VOL or self.__mode == ENC_MODE_SENDS) and 127 or 0) self._plugin_button.send_value(self.__mode == ENC_MODE_DEVICE and 127 or 0) def create_encoders(self, index): touch = TouchButton(MIDI_CC_TYPE, 0, 10 + index, name='Touch_Tap' + str(index + 1) + '_Control') touch.cindex = index slider = Encoder(MIDI_CC_TYPE, 0, 70 + index, index, self, name='Encoder' + str(index + 1) + '_Control') slider.cindex = index return EncoderHandler(index, slider, touch, self) def create_button(self, index): button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, 22 + index, name='Page_Button_' + str(index + 1) + '_Control') button.cindex = index return ButtonHandler(index, button, self) def gettrack(self, index, off): tracks = self.song().visible_tracks if index + off < len(tracks): return tracks[index + off] return def notify_shift(self, value): pass def notify_touch(self, parameter): pass def is_shift_down(self): return self.canonical_parent.is_shift_down() def is_modifier_down(self): return self.canonical_parent.is_shift_down() def set_led_value(self, index, value): pass def reset_led(self): pass def navigate(self, nav_dir, modifier, alt_modifier=False, nav_src=NAV_SRC_ENCODER): pass def handle_offset_changed(self): if self.__mode == ENC_MODE_VOL or self.__mode == ENC_MODE_SENDS: self.__assign_encoders(False) def setup_select_track(self): if self.__track: self._handle_device_changed.subject = None self._handle_devices_changed.subject = None self.__track = self.song().view.selected_track if self.__track: self.__device = self.__track.view.selected_device self._handle_device_changed.subject = self.__track.view self._handle_devices_changed.subject = self.__track self._handle_device_changed(True) if self.__device: self._handle_parameters_changed.subject = self.__device else: self._handle_parameters_changed.subject = None return def refresh_state(self): for encoder in self.__encoders: encoder.refresh() for button in self.__buttons: button.refresh() self.update_display(None, True) return @subject_slot('value') def _handle_mixer_button(self, value): if value == 0: return if self.__mode == ENC_MODE_VOL: self.__mode = ENC_MODE_SENDS self.__assign_encoders() self.light_mode() else: if self.__mode == ENC_MODE_SENDS or self.__mode == ENC_MODE_DEVICE: self.__mode = ENC_MODE_VOL self.__assign_encoders() self.light_mode() @subject_slot('value') def _handle_plugin_button(self, value): self.__plugin_down = value > 0 if value == 0: return if self.__mode == ENC_MODE_VOL or self.__mode == ENC_MODE_SENDS: self.__mode = ENC_MODE_DEVICE self.__assign_encoders() self.light_mode() self.application().view.show_view('Detail/DeviceChain') @subject_slot('value') def _handle_left(self, value): self._left_button.send_value(value) if value: if self.canonical_parent.is_shift_down(): if self.__mode == ENC_MODE_SENDS: new_val = self.__send_offset - 1 if new_val >= 0: self.__send_offset = new_val self.__assign_encoders() elif self.__mode == ENC_MODE_DEVICE: self.navigate_device(-1) elif self.__plugin_down and self.__mode == ENC_MODE_DEVICE: self.nav_device_param_banks(-1) else: self.canonical_parent.get_session().bank_left(1) self.__assign_encoders() @subject_slot('value') def _handle_right(self, value): self._left_button.send_value(value) if value: if self.canonical_parent.is_shift_down(): if self.__mode == ENC_MODE_SENDS: nr_of_ret_tracks = len(self.song().return_tracks) new_val = self.__send_offset + 1 if new_val < nr_of_ret_tracks: self.__send_offset = new_val self.__assign_encoders() elif self.__mode == ENC_MODE_DEVICE: self.navigate_device(1) elif self.__plugin_down and self.__mode == ENC_MODE_DEVICE: self.nav_device_param_banks(1) else: self.canonical_parent.get_session().bank_right(1) self.__assign_encoders() @subject_slot('return_tracks') def _return_tracks_change(self): if self.__send_offset >= len(self.song().return_tracks): if self.__mode == ENC_MODE_SENDS: self.__assign_encoders() @subject_slot('tracks') def _tracks_change(self): self.__assign_encoders(False) self._cleanup_mapping() @subject_slot('selected_track') def _handle_track_changed(self): self.setup_select_track() @subject_slot('devices') def _handle_devices_changed(self): if self.__device != self.__track.view.selected_device: self._handle_device_changed() @subject_slot('selected_device') def _handle_device_changed(self, force_change=False): self.__device = self.__track.view.selected_device if self.__device: self._handle_parameters_changed.subject = self.__device self._hande_device_name_changed.subject = self.__device else: self._handle_parameters_changed.subject = None self._hande_device_name_changed.subject = None if self.__mode == ENC_MODE_DEVICE: if not self.__device: self.__device = self._choose_device() if self.__device: self.song().view.select_device(self.__device) self.__bank_index = self._get_stored_bank_index() self.__assign_encoders() self.update_display() return @subject_slot('name') def _hande_device_name_changed(self): if self.__mode == ENC_MODE_DEVICE: self.update_display() def _choose_device(self): device_list = self.__track.devices if not device_list or len(device_list) == 0: return if len(device_list) > 0: return device_list[0] return @subject_slot('parameters') def _handle_parameters_changed(self): if self.__mode == ENC_MODE_DEVICE: self.__assign_encoders(False) @subject_slot('visible_tracks') def _handle_visble_tracks_changed(self): self.__assign_encoders(False) self._cleanup_mapping() if self.__mode == ENC_MODE_VOL: self.refresh_state() def _cleanup_mapping(self): tracks = self.song().visible_tracks cmaps = {} keys = self.__selection_map.keys() for track in tracks: cmaps[track] = True for track in keys: if track not in cmaps and track in self.__selection_map: del self.__selection_map[track] def get_param_list_left(self): result = '' if self.__param_list: for i in xrange(0, 4): namestr = i < len(self.__param_list) and self.__param_list[ i] != EMPTY_PARAM and self.__param_list[i][0].name or '' if i < len(self.__param_list) - 1 and i < 3: result += to_display_name(namestr) + '|' else: result += to_display_name(namestr) return result def get_param_list_right(self): result = '' if self.__param_list: for i in xrange(4, 8): namestr = i < len(self.__param_list) and self.__param_list[ i] != EMPTY_PARAM and self.__param_list[i][0].name or '' if i < len(self.__param_list) - 1 and i < 7: result += to_display_name(namestr) + '|' else: result += to_display_name(namestr) return result def get_track_names(self): trackoff = self.__session.track_offset() track_names = '' for i in range(4): track = self.gettrack(i, trackoff) if self.__mode in (ENC_MODE_VOL, ENC_MODE_PAN, ENC_MODE_SENDS): if track is None: track_names += ' -- ' else: track_names += to_display_name(track.name) if i < 3: track_names += '|' return track_names def update_track_names(self): if self.__mode in (ENC_MODE_VOL, ENC_MODE_SENDS, ENC_MODE_PAN): track_names = self.get_track_names() self.canonical_parent.send_to_display(track_names, 2) self.canonical_parent.send_to_display(track_names, 3) def update_display(self, track_names=None, force=False): if self.__mode == ENC_MODE_VOL: self.canonical_parent.send_to_display('Level & Mute ', 0, force) self.canonical_parent.send_to_display('Pan', 1, force) names = track_names is not None and track_names or self.get_track_names( ) self.canonical_parent.send_to_display(names, 2, force) self.canonical_parent.send_to_display(names, 3, force) else: if self.__mode == ENC_MODE_SENDS: nr_of_ret_tracks = len(self.song().return_tracks) if self.__send_offset < nr_of_ret_tracks: self.canonical_parent.send_to_display( 'Sends ' + SENDS[self.__send_offset] + ' & Mute ', 0, force) else: self.canonical_parent.send_to_display( 'Sends - & Mute ', 0, force) if self.__send_offset + 1 < nr_of_ret_tracks: self.canonical_parent.send_to_display( 'Sends ' + SENDS[self.__send_offset + 1] + '', 1, force) else: self.canonical_parent.send_to_display('', 1, force) names = track_names is not None and track_names or self.get_track_names( ) self.canonical_parent.send_to_display(names, 2, force) self.canonical_parent.send_to_display(names, 3, force) else: if self.__mode == ENC_MODE_DEVICE: if self.__device: self.canonical_parent.send_to_display( self.__device.class_name + ':' + filter_umls(self.__device.name), 0, force) self.canonical_parent.send_to_display('', 1, force) self.canonical_parent.send_to_display( self.get_param_list_left(), 2, force) self.canonical_parent.send_to_display( self.get_param_list_right(), 3, force) else: self.canonical_parent.send_to_display( '<No Device>', 0, force) self.canonical_parent.send_to_display('', 1, force) self.canonical_parent.send_to_display('', 2, force) self.canonical_parent.send_to_display('', 3, force) return def __assign_encoders(self, show_message=True): trackoff = self.__session.track_offset() if self.__mode in (ENC_MODE_VOL, ENC_MODE_PAN, ENC_MODE_SENDS): for i in range(4): left_enc = self.__encoders[i] right_enc = self.__encoders[i + 4] left_button = self.__buttons[i] track = self.gettrack(i, trackoff) if track is None: left_enc.assign_parameter(None) right_enc.assign_parameter(None) left_button.deassign_track() else: left_button.assign_mute_track(track) if self.__mode == ENC_MODE_VOL: left_enc.assign_parameter(track.mixer_device.volume, track, True) right_enc.assign_parameter(track.mixer_device.panning, track, True) if self.__mode == ENC_MODE_SENDS: nr_of_ret_tracks = len(self.song().return_tracks) if self.__send_offset < nr_of_ret_tracks: left_enc.assign_parameter( track.mixer_device.sends[self.__send_offset], track, True) else: left_enc.assign_parameter(None) if self.__send_offset + 1 < nr_of_ret_tracks: right_enc.assign_parameter( track.mixer_device.sends[self.__send_offset + 1], track, True) else: right_enc.assign_parameter(None) else: if self.__mode == ENC_MODE_DEVICE: paramlist = self.get_device_parameter() self.__param_list = paramlist if paramlist: for i in range(8): enc = self.__encoders[i] parm = i < len(paramlist) and paramlist[i] or None if not parm or parm == EMPTY_PARAM: enc.assign_parameter(None) else: enc.assign_parameter(parm[0], False) else: for i in range(8): enc = self.__encoders[i] enc.assign_parameter(None) self.update_display() return def get_device_parameter(self): mapping = None if self.__device: parmlist = [] params = self.__device.parameters if self.__device.class_name in DEVICE_MAP: mappingObj = DEVICE_MAP[self.__device.class_name] if isinstance(mappingObj, tuple): mapping = mappingObj elif 'params' in mappingObj: mapping = mappingObj['params'] if mapping != None: self.__nr_of_banks = len(mapping) bank_mapping = mapping[self.__bank_index] for idx in xrange(0, 8): if bank_mapping != None and idx < len( bank_mapping) and bank_mapping[idx] != None: mp = bank_mapping[idx] if isinstance(mp, tuple): mp_len = len(mp) if mp_len == 4: parmlist.append( (self.__device.parameters[mp[0]], mp[1], mp[2], mp[3])) elif mp_len == 3: parmlist.append( (self.__device.parameters[mp[0]], mp[1], mp[2])) elif mp_len == 2: parmlist.append( (self.__device.parameters[mp[0]], mp[1], None, None)) else: parmlist.append(EMPTY_PARAM) return parmlist self.__nr_of_banks = max(0, len(params) - 2) / 8 + 1 for i in xrange(0, 8): idx = self.__bank_index * 8 + i + 1 if idx < len(self.__device.parameters): parmlist.append( (self.__device.parameters[idx], DEF_NAME, None)) return parmlist else: return return def _get_selmap(self): if self.__track not in self.__selection_map: self.__selection_map[self.__track] = TrackDeviceSelection( self.__track) return self.__selection_map[self.__track] def _get_stored_bank_index(self): if not self.__device: return 0 selmap = self._get_selmap() if selmap: return selmap.get_bank_index(self.__device) return 0 def nav_device_param_banks(self, nav_dir): prev = self.__bank_index newpos = min(max(0, prev + nav_dir), self.__nr_of_banks - 1) if newpos != prev: self.__bank_index = newpos selmap = self._get_selmap() if selmap: selmap.register_selected_bank(self.__device, self.__bank_index) self.__assign_encoders(True) def navigate_device(self, nav_dir): device_list = self.__track.devices if self.__device and isinstance(self.__device.canonical_parent, Live.Chain.Chain): device_list = self.__device.canonical_parent.devices self.__do_device_nav(vindexof(device_list, self.__device), device_list, nav_dir) def __do_device_nav(self, index, device_list, nav_dir): if index != None and len(device_list) > 1: newvalue = min(max(0, index + nav_dir), len(device_list) - 1) if newvalue != index: self.song().view.select_device(device_list[newvalue]) return
class Mk2KnobControl: __module__ = __name__ __doc__ = "Mk2 Module for Controlling Parameters with Master Knob" def __init__(self, parent): self._parent = parent self.master_track = parent.song().master_track self.volume_button = None self._set_volume_button(StateButton(True, MIDI_CC_TYPE, 3, 110)) self.the_slider = SliderElement(MIDI_CC_TYPE, 1, 86) self.the_slider.add_value_listener(self._do_main_slider, True) self.xfade_button = None self._set_xfade_button(StateButton(True, MIDI_CC_TYPE, 3, 116)) self.swing_button = None self._set_swing_button(StateButton(True, MIDI_CC_TYPE, 3, 111)) self.mode = KN2_MODE_VOLUME self.previous_mode = -1 self.tempo_button = None self._set_tempo_button(StateButton(True, MIDI_CC_TYPE, 3, 112)) self.push_button = None self._set_push_button(StateButton(True, MIDI_CC_TYPE, 1, 87)) self.clipn_v_button = None self.clipn_h_button = None self._set_clipn_h_button(StateButton(True, MIDI_CC_TYPE, 3, 114)) self._set_clipn_v_button(StateButton(True, MIDI_CC_TYPE, 3, 115)) self.toggle_buttons = [ self.volume_button, self.xfade_button, self.swing_button, self.tempo_button, self.clipn_h_button, self.clipn_v_button, ] self.shift_button = None self._set_shift_button(StateButton(True, MIDI_CC_TYPE, 3, 113)) self.shift_on = False self.scroll_mod_left_button = None self.scroll_mod_right_button = None self._set_scroll_mod_left_button(StateButton(True, MIDI_CC_TYPE, 0, 105)) self._set_scroll_mod_right_button(StateButton(True, MIDI_CC_TYPE, 0, 106)) self._prev_mode = KN2_MODE_VOLUME self.lrmode = LR_CONTROL_CLIP self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143 self.loop_div_index = 0 self.loop_incdex = 4.0 self.arrow_mode_button = ColorButton(True, MIDI_CC_TYPE, 30) self.arrow_mode_button.add_value_listener(self.toggle_arrow_mode) self.arrow_mode_button.send_color(LR_MODE_HUES[self.lrmode]) self.arrow_mode_button.send_value(127, True) self.navflags = 0 self.octave_mod_button = StateButton(True, MIDI_CC_TYPE, 1, 70) self.octave_mod_button.add_value_listener(self._action_octave) self.scale_mod_button = StateButton(True, MIDI_CC_TYPE, 1, 71) self.scale_mod_button.add_value_listener(self._action_scale) self.basenote_mod_button = StateButton(True, MIDI_CC_TYPE, 1, 72) self.basenote_mod_button.add_value_listener(self._action_base_note) self.keycolor_mod_button = StateButton(True, MIDI_CC_TYPE, 1, 73) self.keycolor_mod_button.add_value_listener(self._action_key_color) self.pad_to_mainknob_mode = 0 self._measure_left_click = 0 self._measure_right_click = 0 self.mode_assign_map = { KN2_MODE_VOLUME: (self.chg_volume, 0, "Master Knob controls MASTER Volume", KN2_MODE_CUE), KN2_MODE_CUE: (self.chg_cue, 0, "Master Knob controls Cue Level", KN2_MODE_VOLUME), KN2_MODE_TEMPO_COARSE: (self.chg_tempo, 3, "Master Knob controls TEMPO Coarse", KN2_MODE_TEMPO_FINE), KN2_MODE_TEMPO_FINE: (self.chg_tempo_fine, 3, "Master Knob controls TEMPO Fine", KN2_MODE_TEMPO_COARSE), KN2_MODE_XFADE: (self.chg_xfade, 1, "Master Knob controls Crossfader", -1), KN2_MODE_QUANT: (self.chg_quant, 2, "Master Knob controls Recording Quantize", KN2_MODE_CLIP_QUANT), KN2_MODE_CLIP_QUANT: (self.chg_clip_q, 2, "Master Knob controls Clip Start Quantize", KN2_MODE_QUANT), KN2_MODE_CLIPN_HOR: (self.nav_c_hor, 4, "Master Knob Clip View horizontally", -1), KN2_MODE_CLIPN_VER: (self.nav_c_ver, 5, "Master Knob Clip View vertically", -1), KN2_MODE_GENERAL: (self.chg_general, -1, None, -1), KN2_P_SCALES: (self.modify_pad_scaling, -1, None, -1), } def start_up(self): self._set_mode(KN2_MODE_VOLUME) self.arrow_mode_button.send_value(127, True) def toggle_arrow_mode(self, value): if value > 0: self.lrmode = (self.lrmode + 1) % 4 self.arrow_mode_button.send_hue(LR_MODE_HUES[self.lrmode]) self._parent.show_message( "Left/Right Buttons Control: " + L_MODE_FUNCTION[self.lrmode] + " / " + R_MODE_FUNCTION[self.lrmode] ) def switch_to_matrix_mode(self): if self.mode != KN2_MODE_GENERAL: self.previous_mode = self.mode self._set_mode(KN2_MODE_GENERAL) def exit_matrix_mode(self): if self.mode == KN2_MODE_GENERAL: self._set_mode(self.previous_mode) self.previous_mode = -1 def update_shift(self): if self.shift_on: self.shift_button.send_value(127, True) else: self.shift_button.send_value(0, True) def _set_mode(self, mode): if not mode in range(11): raise AssertionError self.update_shift() if mode == self.mode: return self._prev_mode = mode self.mode = mode self.switch_radio_buttons(self.mode_assign_map[self.mode][1]) message = self.mode_assign_map[self.mode][2] message != None and self._parent.show_message(message) def switch_radio_buttons(self, which): for index in range(len(self.toggle_buttons)): if index == which: self.toggle_buttons[index].send_value(127, True) else: self.toggle_buttons[index].send_value(0, True) def update(self): self.switch_radio_buttons(self.mode_assign_map[self.mode][1]) self.arrow_mode_button.send_color(LR_MODE_HUES[self.lrmode]) self.arrow_mode_button.send_value(127, True) def _do_main_slider(self, value, encoder): if not value in range(128): raise AssertionError if not isinstance(encoder, EncoderElement): raise AssertionError if value == 1: delta = 1 else: delta = -1 if self.pad_to_mainknob_mode != 0: self.mode_assign_map[KN2_P_SCALES][0](delta) elif self.navflags == 0: self.mode_assign_map[self.mode][0](delta) if self.lrmode == LR_CONTROL_CLIP: self.navflags & LEFT_DOWN != 0 and self.nav_c_hor(delta) self.navflags & RIGHT_DOWN != 0 and self.nav_c_ver(delta) elif self.lrmode == LR_CONTROL_SEL: if self.navflags & LEFT_DOWN != 0: self.nav_track(delta) if self.navflags & RIGHT_DOWN != 0: self._parent.scroll_scene(delta) elif self.lrmode == LR_CONTROL_DEV: if self.navflags & LEFT_DOWN != 0: self.nav_track(delta) if self.navflags & RIGHT_DOWN != 0: self._parent.scroll_device(delta) elif self.lrmode == LR_CONTROL_LOOP: if self.navflags & LEFT_DOWN != 0: self.adjust_loop_start(delta) if self.navflags & RIGHT_DOWN != 0: self.adjust_loop_length(delta) def modify_pad_scaling(self, delta): if self.pad_to_mainknob_mode & PAD_KNOB_OCTAVE != 0: self._parent.inc_octave(delta) if self.pad_to_mainknob_mode & PAD_KNOB_SCALE != 0: self._parent.inc_scale(delta) if self.pad_to_mainknob_mode & PAD_KNOB_BASEN != 0: self._parent.inc_base_note(delta) self._parent.update_transpose() def adjust_loop_start(self, delta): loopval = self._parent.song().loop_start loopval += self.loop_incdex * delta if loopval < 0: loopval = 0 elif loopval > 999: loopval = 999 self._parent.song().loop_start = loopval def adjust_loop_length(self, delta): loopval = self._parent.song().loop_length loopval += self.loop_incdex * delta if loopval < self.loop_incdex: loopval = self.loop_incdex elif loopval > 999: loopval = 999 self._parent.song().loop_length = loopval def chg_general(self, delta): self._parent._scenematrix.control_handler.mod_value(delta, self.shift_on) def nav_track(self, direction): if direction == 1: self._parent._a_trk_right(1) else: self._parent._a_trk_left(1) def nav_c_hor(self, direction): self._parent.move_view_horizontal(direction) def nav_c_ver(self, direction): if direction == 1: self._parent._session.bank_up() else: self._parent._session.bank_down() def chg_volume(self, diff): if self.shift_on: self.repeat(self.master_track.mixer_device.volume, diff) else: self.master_track.mixer_device.volume.value = self.calc_new_parm( self.master_track.mixer_device.volume, diff ) def chg_xfade(self, diff): if self.shift_on: self.repeat(self.master_track.mixer_device.crossfader, diff) else: self.master_track.mixer_device.crossfader.value = self.calc_new_parm( self.master_track.mixer_device.crossfader, diff ) def chg_cue(self, diff): if self.shift_on: self.repeat(self.master_track.mixer_device.cue_volume, diff) else: self.master_track.mixer_device.cue_volume.value = self.calc_new_parm( self.master_track.mixer_device.cue_volume, diff ) def repeat(self, parm, delta): count = 0 while count < SHIFT_INC: parm.value = self.calc_new_parm(parm, delta) count += 1 def calc_new_parm(self, parm, delta): parm_range = parm.max - parm.min int_val = int((parm.value - parm.min) / parm_range * PARM_RANGE + 0.1) inc_val = min(PARM_RANGE, max(0, int_val + delta)) return float(inc_val) / float(PARM_RANGE) * parm_range + parm.min def chg_quant(self, diff): rec_quant = self._parent.song().midi_recording_quantization index = self.get_quant_index(rec_quant) new_index = index + diff if new_index >= 0 and new_index < len(QUANT_CONST): self._parent.song().midi_recording_quantization = QUANT_CONST[new_index] self._parent.show_message(QUANT_DESCR[new_index]) def chg_clip_q(self, diff): quant = self._parent.song().clip_trigger_quantization self._parent.song().clip_trigger_quantization = max(0, min(13, quant + diff)) self._parent.show_message("Clip Quantize " + CLIQ_DESCR[self._parent.song().clip_trigger_quantization]) def chg_tempo_fine(self, diff): if diff < 0: amount = -0.01 else: amount = 0.01 self.chg_tempo(amount) def chg_tempo(self, diff): self._parent.song().tempo = max(20, min(999, self._parent.song().tempo + diff)) def get_quant_index(self, const): for index in range(len(QUANT_CONST)): if const == QUANT_CONST[index]: return index return -1 def _action_octave(self, value): if value != 0: self.pad_to_mainknob_mode |= PAD_KNOB_OCTAVE else: self.pad_to_mainknob_mode &= ~PAD_KNOB_OCTAVE def _action_scale(self, value): if value != 0: self.pad_to_mainknob_mode |= PAD_KNOB_SCALE else: self.pad_to_mainknob_mode &= ~PAD_KNOB_SCALE def _action_base_note(self, value): if value != 0: self.pad_to_mainknob_mode |= PAD_KNOB_BASEN else: self.pad_to_mainknob_mode &= ~PAD_KNOB_BASEN def _action_key_color(self, value): if value != 0: self._parent.step_key_color_mode() def _set_volume_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.volume_button != None: self.volume_button.remove_value_listener(self._action_volume) self.volume_button = button self.volume_button != None and self.volume_button.add_value_listener(self._action_volume) def _action_volume(self, value): if not self.volume_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_VOLUME and self._set_mode(KN2_MODE_VOLUME) def _set_xfade_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.xfade_button != None: self.xfade_button.remove_value_listener(self._action_xfade) self.xfade_button = button self.xfade_button != None and self.xfade_button.add_value_listener(self._action_xfade) def _action_xfade(self, value): if not self.xfade_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_XFADE and self._set_mode(KN2_MODE_XFADE) def _set_swing_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.swing_button != None: self.swing_button.remove_value_listener(self._action_swing) self.swing_button = button self.swing_button != None and self.swing_button.add_value_listener(self._action_swing) def _action_swing(self, value): if not self.swing_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_QUANT and self._set_mode(KN2_MODE_QUANT) def _set_tempo_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.tempo_button != None: self.tempo_button.remove_value_listener(self._action_tempo) self.tempo_button = button self.tempo_button != None and self.tempo_button.add_value_listener(self._action_tempo) def _action_tempo(self, value): if not self.tempo_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_TEMPO_COARSE and self._set_mode(KN2_MODE_TEMPO_COARSE) def _set_clipn_h_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.clipn_h_button != None: self.clipn_h_button.remove_value_listener(self._action_clipnh) self.clipn_h_button = button self.clipn_h_button != None and self.clipn_h_button.add_value_listener(self._action_clipnh) def _action_clipnh(self, value): if not self.clipn_h_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_CLIPN_HOR and self._set_mode(KN2_MODE_CLIPN_HOR) def _set_clipn_v_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.clipn_v_button != None: self.clipn_v_button.remove_value_listener(self._action_clipnv) self.clipn_v_button = button self.clipn_v_button != None and self.clipn_v_button.add_value_listener(self._action_clipnv) def _action_clipnv(self, value): if not self.clipn_v_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_CLIPN_VER and self._set_mode(KN2_MODE_CLIPN_VER) def _set_shift_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.shift_button != None: self.shift_button.remove_value_listener(self._action_shift) self.shift_button = button self.shift_button != None and self.shift_button.add_value_listener(self._action_shift) def _action_shift(self, value): if not self.shift_button != None: raise AssertionError raise value in range(128) or AssertionError self.shift_on = value != 0 and not self.shift_on self.update_shift() def _set_scroll_mod_left_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.scroll_mod_left_button != None: self.scroll_mod_left_button.remove_value_listener(self._action_scroll_left) self.scroll_mod_left_button = button self.scroll_mod_left_button != None and self.scroll_mod_left_button.add_value_listener( self._action_scroll_left ) def _set_scroll_mod_right_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.scroll_mod_right_button != None: self.scroll_mod_right_button.remove_value_listener(self._action_scroll_right) self.scroll_mod_right_button = button self.scroll_mod_right_button != None and self.scroll_mod_right_button.add_value_listener( self._action_scroll_right ) def _action_scroll_left(self, value): if not self.scroll_mod_left_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.scroll_mod_left_button.send_value(127, True) self.navflags |= LEFT_DOWN self._measure_left_click = int(round(time.time() * 1000)) else: self.scroll_mod_left_button.send_value(0, True) self.navflags &= ~LEFT_DOWN clicktime = int(round(time.time() * 1000)) - self._measure_left_click if clicktime < CLICK_TIME: if self._parent._modifier_down: self._parent.modify_track_offset(-1) elif self._parent._mode == PAD_MODE: self._do_lr_as_scale_mode(-1) elif self._parent._mode == SCENE_MODE: self._parent.modify_scene_offset(-1) elif self._parent._mode == CLIP_MODE: self._parent.move_view_horizontal(-1) elif self._parent._mode == CONTROL_MODE: self._parent.move_view_horizontal(-1) def _action_scroll_right(self, value): if not self.scroll_mod_right_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.scroll_mod_right_button.send_value(127, True) self.navflags |= RIGHT_DOWN self._measure_right_click = int(round(time.time() * 1000)) else: self.scroll_mod_right_button.send_value(0, True) self.navflags &= ~RIGHT_DOWN clicktime = int(round(time.time() * 1000)) - self._measure_right_click if clicktime < CLICK_TIME: if self._parent._modifier_down: self._parent.modify_track_offset(1) elif self._parent._mode == PAD_MODE: self._do_lr_as_scale_mode(1) elif self._parent._mode == SCENE_MODE: self._parent.modify_scene_offset(1) elif self._parent._mode == CLIP_MODE: self._parent.move_view_horizontal(1) elif self._parent._mode == CONTROL_MODE: self._parent.move_view_horizontal(1) def _do_lr_as_scale_mode(self, delta): if self.pad_to_mainknob_mode == PAD_KNOB_SCALE: self._parent.inc_scale(delta) elif self.pad_to_mainknob_mode == PAD_KNOB_BASEN: self._parent.inc_base_note(delta) else: self._parent.inc_octave(delta) self._parent.update_transpose() def _set_push_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.push_button != None: self.push_button.remove_value_listener(self._action_push) self.push_button = button self.push_button != None and self.push_button.add_value_listener(self._action_push) def _action_push(self, value): if not self.push_button != None: raise AssertionError if not value in range(128): raise AssertionError next_mode = self.mode_assign_map[self.mode][3] next_mode != -1 and self._set_mode(next_mode) self.loop_div_index = ( self.lrmode == LR_CONTROL_LOOP and self.navflags != 0 and (self.loop_div_index + 1) % len(LOOP_KNOB_DIVISION) ) self._parent.show_message( "Loop Selection Granularity : " + str(LOOP_KNOB_DIVISION[self.loop_div_index]) + " beats " ) self.loop_incdex = LOOP_KNOB_DIVISION[self.loop_div_index] def remove_listener(self, control, callback): if control != None and control.value_has_listener(callback): control.remove_value_listener(callback) control.disconnect() def disconnect(self): self.remove_listener(self.the_slider, self._do_main_slider) self.remove_listener(self.arrow_mode_button, self.toggle_arrow_mode) self.remove_listener(self.volume_button, self._action_volume) self.remove_listener(self.xfade_button, self._action_xfade) self.remove_listener(self.swing_button, self._action_swing) self.remove_listener(self.clipn_h_button, self._action_clipnh) self.remove_listener(self.clipn_v_button, self._action_clipnv) self.remove_listener(self.shift_button, self._action_shift) self.remove_listener(self.scroll_mod_left_button, self._action_scroll_left) self.remove_listener(self.scroll_mod_right_button, self._action_scroll_right) self.remove_listener(self.push_button, self._action_push) self.remove_listener(self.octave_mod_button, self._action_octave) self.remove_listener(self.scale_mod_button, self._action_scale) self.remove_listener(self.basenote_mod_button, self._action_base_note) self.remove_listener(self.keycolor_mod_button, self._action_key_color) self._parent = None self.master_track = None self.the_slider = None self.mode_assign_map = None
class Maschine(ControlSurface): __module__ = __name__ __doc__ = 'Basic Control Script for All Maschine Modell Mikro, Mikro Mk2, Mk1, Mk2, Studio' def __init__(self, c_instance): super(Maschine, self).__init__(c_instance) with self.component_guard(): register_sender(self) self._diplay_cache = ['', '', '', ''] self._suppress_send_midi = True is_momentary = True self._c_ref = c_instance self.display_task = DisplayTask() self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143 self._active = False self._midi_pause_count = 0 self.blink_state = 0 self.send_slider_index = 0 self.nav_index = 0 self.arm_selected_track = False self.undo_state = 0 self.redo_state = 0 self._set_suppress_rebuild_requests(True) self._modeselect = ModeSelector(self.is_monochrome()) self._device = self._set_up_device_control() self._set_up_session(self._modeselect) self._set_up_mixer() self._setup_transport() self._set_global_buttons() self._editsection = EditSection() self._editsection.connect_session(self._session) self._editsection.set_mode_selector(self._modeselect) self._session.set_mode(self._modeselect._clip_mode) self._audio_clip_editor = AudioClipEditComponent() self._note_repeater = NoteRepeatComponent(c_instance.note_repeat) self._midi_edit = MidiEditSection() self._init_settings() self._init_maschine() self.set_highlighting_session_component(self._session) self.set_pad_translations(PAD_TRANSLATIONS) self._on_selected_track_changed() self.set_up_function_buttons() self.show_message(str('')) self.request_rebuild_midi_map() self._set_suppress_rebuild_requests(False) self._active = True self._display_device_param = False self.set_feedback_channels(FEEDBACK_CHANNELS) self._final_init() self._suppress_send_midi = False self.apply_preferences() self.init_text_display() self._on_appointed_device_changed.subject = self.song() def _init_maschine(self): pass def _final_init(self): pass def create_pad_button(self, scene_index, track_index, color_source): pass def create_gated_button(self, identifier, hue): pass def apply_preferences(self): pref_dict = self._pref_dict if 'step_advance' in pref_dict: self._session.set_step_advance(pref_dict['step_advance']) if 'solo_exclusive' in pref_dict: self._modeselect.set_solo_exclusive(pref_dict['solo_exclusive']) else: self._modeselect.set_solo_exclusive(True) if 'arm_exclusive' in pref_dict: self._modeselect.set_arm_exclusive(pref_dict['arm_exclusive']) else: self._modeselect.set_arm_exclusive(True) if 'quantize_val' in pref_dict: self._editsection.quantize = pref_dict['quantize_val'] else: self._editsection.quantize = 5 if 'initial_cliplen' in pref_dict: self._editsection.initial_clip_len = pref_dict['initial_cliplen'] else: self._editsection.initial_clip_len = 4.0 if 'auto_arm_sel_track' in pref_dict: self.arm_selected_track = pref_dict['auto_arm_sel_track'] else: self.arm_selected_track = False if 'note_color_mode' in pref_dict: self._modeselect._pad_mode._note_display_mode = pref_dict['note_color_mode'] else: self._modeselect._pad_mode._note_display_mode = ND_KEYBOARD1 self._pref_dict['note_color_mode'] = self._modeselect._pad_mode._note_display_mode self.set_sel_arm_button.send_value(self.arm_selected_track and 127 or 0, True) self._note_repeater.recall_values(self._pref_dict) def store_preferences(self): self._pref_dict['step_advance'] = self._session.get_step_advance() self._pref_dict['solo_exclusive'] = self._modeselect.is_solo_exclusive() self._pref_dict['arm_exclusive'] = self._modeselect.is_arm_exclusive() self._pref_dict['quantize_val'] = self._editsection.quantize self._pref_dict['initial_cliplen'] = self._editsection.initial_clip_len self._pref_dict['auto_arm_sel_track'] = self.arm_selected_track self._pref_dict['note_color_mode'] = self._modeselect._pad_mode._note_display_mode self._note_repeater.store_values(self._pref_dict) def _init_settings(self): from pickle import loads, dumps from encodings import ascii nop(ascii) preferences = self._c_instance.preferences(self.preferences_name()) self._pref_dict = {} try: self._pref_dict = loads(str(preferences)) except Exception: pass pref_dict = self._pref_dict preferences.set_serializer(lambda : dumps(pref_dict)) def preferences_name(self): return 'Maschine' def _pre_serialize(self): from pickle import dumps from encodings import ascii nop(ascii) preferences = self._c_instance.preferences('Maschine') self.store_preferences() dump = dumps(self._pref_dict) preferences.set_serializer(lambda : dump) def toggle_nav_mode(self): self._session.switch_step_advance() self.show_message(' View Navigation in steps of ' + str(self._session.get_step_advance())) def _set_up_session(self, mode_selector): is_momentary = True self._session = MaschineSessionComponent() self._session.set_color_manager(mode_selector.get_color_manager()) self.nav_buttons = (self.create_gated_button(92, COLOR_HUE_NAV), self.create_gated_button(81, COLOR_HUE_NAV), self.create_gated_button(93, COLOR_HUE_NAV), self.create_gated_button(91, COLOR_HUE_NAV)) self._session.set_scene_bank_buttons(self.nav_buttons[0], self.nav_buttons[1]) self._session.set_track_bank_buttons(self.nav_buttons[2], self.nav_buttons[3]) track_stop_buttons = [ StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, index + STOP_CC_OFF) for index in range(4) ] self._session.set_stop_track_clip_buttons(tuple(track_stop_buttons)) self._matrix = [] self._bmatrix = ButtonMatrixElement() for scene_index in range(4): button_row = [] for track_index in range(4): button = self.create_pad_button(scene_index, track_index, mode_selector) button_row.append(button) self._matrix.append(tuple(button_row)) self._bmatrix.add_row(tuple(button_row)) self._session.set_matrix(self._matrix) for button, (track_index, scene_index) in self._bmatrix.iterbuttons(): if button: scene = self._session.scene(scene_index) clip_slot = scene.clip_slot(track_index) clip_slot.set_launch_button(button) clip_slot.set_triggered_to_play_value(1) clip_slot.set_triggered_to_record_value(1) clip_slot.set_started_value(1) clip_slot.set_recording_value(1) clip_slot.set_stopped_value(1) self._session._link() def _set_up_mixer(self): is_momentary = True self._mixer = MaschineMixerComponent(8) self.send_sliders = [] for track in range(8): self.send_sliders.append(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, SEND_CC_OFF + track)) for track in range(8): strip = self._mixer.channel_strip(track) strip.set_arm_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, ARM_CC_OFF + track)) strip.set_solo_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, SOLO_CC_OFF + track)) strip.set_mute_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, MUTE_CC_OFF + track)) strip.set_volume_control(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, LEVEL_CC_OFF + track)) strip.set_pan_control(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, PAN_CC_OFF + track)) strip.set_select_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, SELECT_CC_OFF + track)) st = tuple([self.send_sliders[track]]) strip.set_send_controls(st) self.send_slider_toggle_button = StateButton(False, MIDI_CC_TYPE, 0, 90) self._do_toggle_send.subject = self.send_slider_toggle_button self._session.set_mixer(self._mixer) def _set_global_buttons(self): is_momentary = True self._undo_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 85) self._do_undo.subject = self._undo_button self._redo_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 87) self._do_redo.subject = self._redo_button self._stop_all_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 111) self._do_stop_all.subject = self._stop_all_button self._toggle_detail_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1, 121) self._action_toogle_detail_view.subject = self._toggle_detail_button self._fire_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 9) self._do_fire_button.subject = self._fire_button self._g_clear_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1, 106) self._hold_clear_action.subject = self._g_clear_button self._g_duplicate_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1, 107) self._hold_duplicate_action.subject = self._g_duplicate_button self.track_left_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 120) self.track_right_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 121) self.set_sel_arm_button = StateButton(is_momentary, MIDI_CC_TYPE, 2, 56) self._reenable_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1, 120) self._do_auto_reenable.subject = self._reenable_button self._on_change_reenabled.subject = self.song() self._on_change_reenabled() self._a_trk_left.subject = self.track_left_button self._a_trk_right.subject = self.track_right_button self._a_sel_arm.subject = self.set_sel_arm_button def _set_up_device_control(self): is_momentary = True device = MaschineDeviceComponent() param_controls = [] for index in range(8): param_controls.append(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_CC_OFF + index)) device.set_parameter_controls(tuple(param_controls)) self.device_control = param_controls device.set_on_off_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF)) device.set_bank_nav_buttons(StateButton(is_momentary, MIDI_CC_TYPE, 3, 104), ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 105)) self._device_nav_button_left = StateButton(is_momentary, MIDI_CC_TYPE, 3, 106) self._device_nav_button_right = StateButton(is_momentary, MIDI_CC_TYPE, 3, 107) self._navigate_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 127) self._nav_value_left.subject = self._device_nav_button_left self._nav_value_right.subject = self._device_nav_button_right self._do_focus_navigate.subject = self._navigate_button self.set_device_component(device) return device def _setup_transport(self): is_momentary = True transport = TransportComponent() studiotransport = MaschineTransport() playButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 108) stopButton = StateButton(not is_momentary, MIDI_CC_TYPE, 0, 110) recordButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 109) overdubButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 107) metrononmeButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 104) eventRecButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 98) playButton.name = 'Play' stopButton.name = 'Stop' recordButton.name = 'Record' overdubButton.name = 'Overdub' metrononmeButton.name = 'Metronome' transport.set_play_button(playButton) transport.set_stop_button(stopButton) transport.set_record_button(recordButton) transport.set_overdub_button(overdubButton) transport.set_metronome_button(metrononmeButton) studiotransport.set_session_auto_button(eventRecButton) studiotransport.set_arrangement_overdub_button(StateButton(is_momentary, MIDI_CC_TYPE, 0, 106)) studiotransport.set_back_arrange_button(StateButton(is_momentary, MIDI_CC_TYPE, 0, 105)) transport.set_nudge_buttons(StateButton(is_momentary, MIDI_CC_TYPE, 1, 51), StateButton(is_momentary, MIDI_CC_TYPE, 1, 50)) punchinbutton = ToggleButton(MIDI_CC_TYPE, 1, 52) punchoutbutton = ToggleButton(MIDI_CC_TYPE, 1, 53) punchinbutton.name = 'Punch In' punchoutbutton.name = 'Punch Out' transport.set_punch_buttons(punchinbutton, punchoutbutton) transport.set_loop_button(StateButton(is_momentary, MIDI_CC_TYPE, 1, 54)) self.song_follow_button = ButtonElement(True, MIDI_CC_TYPE, 2, 98) self._do_song_follow.subject = self.song_follow_button self._song_follow_changed.subject = self.song().view self._song_follow_changed() self.prehear_knob = SliderElement(MIDI_CC_TYPE, 0, 41) self.prehear_knob.connect_to(self.song().master_track.mixer_device.cue_volume) self.transp_ff_button = ButtonElement(True, MIDI_CC_TYPE, 1, 59) self.transp_rw_button = ButtonElement(True, MIDI_CC_TYPE, 1, 58) transport.set_seek_buttons(self.transp_ff_button, self.transp_rw_button) self.xfadeKnob = SliderElement(MIDI_CC_TYPE, 1, 105) self.xfadeKnob.connect_to(self.song().master_track.mixer_device.crossfader) self.master_knob = SliderElement(MIDI_CC_TYPE, 0, 99) self.master_knob.connect_to(self.song().master_track.mixer_device.volume) self.tap_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 88) self._do_tap_tempo.subject = self.tap_button self.cue_add_delete_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 55) self.cue_prev_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 56) self.cue_next_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 57) self._do_toggle_cue.subject = self.cue_add_delete_button self._do_toggle_prev_cue.subject = self.cue_prev_button self._do_toggle_next_cue.subject = self.cue_next_button def set_up_function_buttons(self): is_momentary = True self.keycolor_mod_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 73) self._do_key_color.subject = self.keycolor_mod_button self._update_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 86) self._do_update_display.subject = self._update_button @subject_slot('appointed_device') def _on_appointed_device_changed(self): self._modeselect._device_changed() def _update_hardware(self): self._session.update() self._modeselect.refresh() self.update_undo_redo(True) def refresh_state(self): ControlSurface.refresh_state(self) self._update_hardware() def _send_midi(self, midi_bytes, **keys): self._c_ref.send_midi(midi_bytes) return True def init_text_display(self): if USE_DISPLAY: self._modeselect._pad_mode.update_text_display() def _on_selected_track_changed(self): super(Maschine, self)._on_selected_track_changed() self.set_controlled_track(self.song().view.selected_track) self._on_devices_changed.subject = self.song().view.selected_track @subject_slot('devices') def _on_devices_changed(self): pass def update(self): self.set_feedback_channels(FEEDBACK_CHANNELS) super(Maschine, self).update() def is_monochrome(self): return False def _deassign_matrix(self): for scene_index in range(4): scene = self._session.scene(scene_index) for track_index in range(4): clip_slot = scene.clip_slot(track_index) clip_slot.set_launch_button(None) def update_display(self): with self.component_guard(): with self._is_sending_scheduled_messages(): self._task_group.update(0.1) self._modeselect.notify(self.blink_state) self.blink_state = (self.blink_state + 1) % 4 self.display_task.tick() self.update_undo_redo(False) def update_undo_redo(self, force = False): if force: self.undo_state = self.song().can_undo self.redo_state = self.song().can_redo if self.song().can_undo != self.undo_state: self.undo_state = self.song().can_undo self._undo_button.send_value(self.undo_state == 1 and 127 or 0) if self.song().can_redo != self.redo_state: self.redo_state = self.song().can_redo self._redo_button.send_value(self.redo_state == 1 and 127 or 0) def adjust_loop_start(self, delta): loopval = self.song().loop_start self.song().loop_start = min(self.song().song_length, max(0, loopval + delta)) def adjust_loop_length(self, delta): loopval = self.song().loop_length self.song().loop_length = min(self.song().song_length, max(abs(delta), loopval + delta)) def _do_armsolo_mode(self, value): pass @subject_slot('value') def _do_fire_button(self, value): raise self._fire_button != None or AssertionError raise value in range(128) or AssertionError if value != 0: if self.isShiftDown(): self.song().tap_tempo() else: clip_slot = self.song().view.highlighted_clip_slot if clip_slot: clip_slot.fire() @subject_slot('value') def _do_undo(self, value): if value != 0: if self.use_layered_buttons() and self.isShiftDown(): if self.song().can_redo == 1: self.song().redo() self.show_message(str('REDO')) elif self.song().can_undo == 1: self.song().undo() self.show_message(str('UNDO')) @subject_slot('value') def _do_redo(self, value): if value != 0: if self.song().can_redo == 1: self.song().redo() self.show_message(str('REDO')) @subject_slot('value') def _do_stop_all(self, value): if value != 0: if self.use_layered_buttons() and self.isShiftDown(): self.song().stop_all_clips(0) else: self.song().stop_all_clips(1) def isShiftDown(self): return self._editsection.isShiftdown() def modifiers(self): return self._editsection.modifiers() def use_layered_buttons(self): return False def _handle_base_note(self, diff): self._modeselect._pad_mode.inc_base_note(diff) def _handle_octave(self, diff): self._modeselect._pad_mode.inc_octave(diff) octave_val = self._modeselect._pad_mode def _handle_scale(self, diff): self._modeselect._pad_mode.inc_scale(diff) @subject_slot('value') def _do_update_display(self, value): if value != 0: self.refresh_state() @subject_slot('value') def _do_key_color(self, value): if not value in range(128): raise AssertionError value != 0 and self._modeselect._pad_mode.step_key_color_mode() @subject_slot('value') def _do_tap_tempo(self, value): if not value in range(128): raise AssertionError value != 0 and self.song().tap_tempo() @subject_slot('value') def _do_toggle_cue(self, value): if not value in range(128): raise AssertionError value != 0 and self.song().set_or_delete_cue() @subject_slot('value') def _do_toggle_prev_cue(self, value): if not value in range(128): raise AssertionError value != 0 and self.song().jump_to_prev_cue() @subject_slot('value') def _do_toggle_next_cue(self, value): if not value in range(128): raise AssertionError value != 0 and self.song().jump_to_next_cue() @subject_slot('value') def _do_toggle_send(self, value): if not value in range(128): raise AssertionError if self.isShiftDown(): value != 0 and self.refresh_state() self.show_message('Refresh Display') else: nr_of_tracks = len(self.song().return_tracks) if value == 0 or nr_of_tracks < 1: return prev = self.send_slider_index self.send_slider_index += 1 if self.send_slider_index >= nr_of_tracks: self.send_slider_index = 0 self.show_message(' Set Send ' + str(SENDS[self.send_slider_index])) self.timed_message(2, ' Set Send ' + str(SENDS[self.send_slider_index])) if prev != self.send_slider_index: for track in range(8): strip = self._mixer.channel_strip(track) slider_list = [] for index in range(self.send_slider_index + 1): if index < self.send_slider_index - 1: slider_list.append(None) else: slider_list.append(self.send_sliders[track]) strip.set_send_controls(tuple(slider_list)) @subject_slot('value') def _a_trk_left(self, value): if not value in range(128): raise AssertionError if value != 0: if self.application().view.is_view_visible('Session'): direction = Live.Application.Application.View.NavDirection.left self.application().view.scroll_view(direction, 'Session', True) track = self.song().view.selected_track self.timed_message(2, 'T:' + track.name, False) self.arm_selected_track and track.can_be_armed and arm_exclusive(self.song(), track) @subject_slot('value') def _a_trk_right(self, value): if not value in range(128): raise AssertionError if value != 0: if self.application().view.is_view_visible('Session'): direction = Live.Application.Application.View.NavDirection.right self.application().view.scroll_view(direction, 'Session', True) track = self.song().view.selected_track self.timed_message(2, 'T:' + track.name, False) self.arm_selected_track and track.can_be_armed and arm_exclusive(self.song(), track) @subject_slot('value') def _a_sel_arm(self, value): if value != 0: if self.arm_selected_track: self.arm_selected_track = False self.set_sel_arm_button.send_value(0, True) else: self.arm_selected_track = True self.set_sel_arm_button.send_value(127, True) @subject_slot('value') def _nav_value_left(self, value): if not self._device_nav_button_left != None: raise AssertionError if not value in range(128): raise AssertionError modifier_pressed = True value != 0 and (not self.application().view.is_view_visible('Detail') or not self.application().view.is_view_visible('Detail/DeviceChain')) and self.application().view.show_view('Detail') self.application().view.show_view('Detail/DeviceChain') else: direction = Live.Application.Application.View.NavDirection.left self.application().view.scroll_view(direction, 'Detail/DeviceChain', not modifier_pressed) @subject_slot('value') def _nav_value_right(self, value): if not self._device_nav_button_right != None: raise AssertionError if not value in range(128): raise AssertionError modifier_pressed = value != 0 and True (not self.application().view.is_view_visible('Detail') or not self.application().view.is_view_visible('Detail/DeviceChain')) and self.application().view.show_view('Detail') self.application().view.show_view('Detail/DeviceChain') else: direction = Live.Application.Application.View.NavDirection.right self.application().view.scroll_view(direction, 'Detail/DeviceChain', not modifier_pressed) @subject_slot('value') def _do_focus_navigate(self, value): if not self._navigate_button != None: raise AssertionError raise value in range(128) or AssertionError self.nav_index = value != 0 and (self.nav_index + 1) % len(VIEWS_ALL) self.application().view.focus_view(VIEWS_ALL[self.nav_index]) self.show_message('Focus on : ' + str(VIEWS_ALL[self.nav_index])) def focus_clip_detail(self): self.application().view.focus_view('Detail/Clip') @subject_slot('follow_song') def _song_follow_changed(self): view = self.song().view if view.follow_song: self.song_follow_button.send_value(1, True) else: self.song_follow_button.send_value(0, True) @subject_slot('value') def _do_song_follow(self, value): if value != 0: view = self.song().view if view.follow_song: view.follow_song = False self.song_follow_button.send_value(0, True) else: view.follow_song = True self.song_follow_button.send_value(1, True) @subject_slot('value') def _hold_duplicate_action(self, value): if value != 0: pass @subject_slot('value') def _hold_clear_action(self, value): if value != 0: self._mixer.enter_clear_mode() self._device_component.enter_clear_mode() else: self._mixer.exit_clear_mode() self._device_component.exit_clear_mode() @subject_slot('value') def _action_toogle_main_view(self, value): if value != 0: appv = self.application().view if appv.is_view_visible('Arranger'): appv.show_view('Session') else: appv.show_view('Arranger') @subject_slot('value') def _action_toogle_detail_view(self, value): if value != 0: appv = self.application().view if self.isShiftDown(): if appv.is_view_visible('Arranger'): appv.show_view('Session') else: appv.show_view('Arranger') elif appv.is_view_visible('Detail/Clip'): appv.show_view('Detail/DeviceChain') else: appv.show_view('Detail/Clip') @subject_slot('re_enable_automation_enabled') def _on_change_reenabled(self): if self.song().re_enable_automation_enabled: self._reenable_button.turn_on() else: self._reenable_button.turn_off() @subject_slot('value') def _do_auto_reenable(self, value): if value != 0: self.song().re_enable_automation() def to_color_edit_mode(self, active): pass def clear_display_all(self): self.send_to_display('', 0) self.send_to_display('', 1) self.send_to_display('', 2) self.send_to_display('', 3) def clear_display(self, grid): self.send_to_display('', grid) def timed_message(self, grid, text, hold = False): if USE_DISPLAY == False: self.show_message(text) else: self.display_task.set_func(self.clear_display, grid) self.send_to_display(text, grid) if hold: self.display_task.hold() self.display_task.start() def timed_message_release(self): self.display_task.release() def update_bank_display(self): if USE_DISPLAY: name, bank = self._device._current_bank_details() if self._display_device_param: prms = len(bank) d1 = '' for i in range(4): parm = bank[i] if parm: name = parm.name d1 += name[:6] + (i < 3 and '|' or '') else: d1 += ' ' + (i < 3 and '|' or '') self.send_to_display(d1, 2) d1 = '' for i in range(4): parm = bank[i + 4] if parm: name = parm.name d1 += name[:6] + (i < 3 and '|' or '') else: d1 += ' ' + (i < 3 and '|' or '') self.send_to_display(d1, 4) else: self.timed_message(2, 'Bank: ' + name) def display_parameters(self, paramlist): if USE_DISPLAY == False: return def send_to_display(self, text, grid = 0): if USE_DISPLAY == False: return if self._diplay_cache[grid] == text: return self._diplay_cache[grid] = text if len(text) > 28: text = text[:27] msgsysex = [240, 0, 0, 102, 23, 18, min(grid, 3) * 28] filled = text.ljust(28) for c in filled: msgsysex.append(ord(c)) msgsysex.append(247) self._send_midi(tuple(msgsysex)) def cleanup(self): pass def disconnect(self): self._pre_serialize() self.clear_display_all() for button, (track_index, scene_index) in self._bmatrix.iterbuttons(): if button: button.send_color_direct(PColor.OFF[0]) time.sleep(0.2) self._active = False self._suppress_send_midi = True super(Maschine, self).disconnect()
def _set_global_buttons(self): self._undo_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_UNDO_BUTTON) self._do_undo.subject = self._undo_button self._redo_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_REDO_BUTTON) self._do_redo.subject = self._redo_button self._shift_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_SHIFT_BUTTON) self._do_shift.subject = self._shift_button self._erase_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_ERASE_BUTTON) self._do_erase.subject = self._erase_button self._duplicate_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_DUPLICATE_BUTTON) self._do_duplicate.subject = self._duplicate_button self._selectback_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_BACKSEL_BUTTON) self._do_selectback.subject = self._selectback_button self._event_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_EVENTS_BUTTON) self._do_event_button.subject = self._event_button self.__arrange_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_ARRANGE_BUTTON, name='Arrange_button') self.__arrange_button.view_mode = VM_SESSION self._do_arrange.subject = self.__arrange_button
def create_button(ccval, channel=0): return StateButton(is_momentary, MIDI_CC_TYPE, channel, ccval)
class ModifierComponent(CompoundComponent): __shift_down = False __select_down = False __delete_down = False __duplicate_down = False __browse_down = False __macro_down = False __quantize_setting = 5 def __init__(self, session, *a, **k): super(ModifierComponent, self).__init__(*a, **k) self.__session = session self.__delete_button = StateButton(True, MIDI_CC_TYPE, 0, 95, name='Clear_Button') self.__do_delete.subject = self.__delete_button self.__duplicate_button = StateButton(True, MIDI_CC_TYPE, 0, 96, name='Duplicate_Button') self.__do_duplicate.subject = self.__duplicate_button self._select_button = StateButton(True, MIDI_CC_TYPE, 0, 80, name='Select_Button') self.__do_select_button.subject = self._select_button self.__lock_button = StateButton(True, MIDI_CC_TYPE, 0, 47, name='Lock_Button') self.__do_lock.subject = self.__lock_button self.__macro_button = StateButton(True, MIDI_CC_TYPE, 0, 90, name='Macro_Button') self.__do_macro.subject = self.__macro_button self._left_button = StateButton(True, MIDI_CC_TYPE, 0, 107, name='Metro_Button') self._right_button = StateButton(True, MIDI_CC_TYPE, 0, 104, name='Loop_Button') self._rec_button = StateButton(True, MIDI_CC_TYPE, 0, 109, name='Record_Button') self._do_left_button.subject = self._left_button self._do_right_button.subject = self._right_button self._do_rec_button.subject = self._rec_button self._listen_overdub.subject = self.song() self._listen_loop.subject = self.song() self._listen_metronome.subject = self.song() self.__action_listener = None self.__shift_listener = None return @subject_slot('overdub') def _listen_overdub(self): if self.__shift_down: self._rec_button.set_display_value( self.song().overdub and 127 or 0, True) @subject_slot('loop') def _listen_loop(self): if self.__shift_down: self._right_button.set_display_value(self.song().loop and 127 or 0, True) @subject_slot('metronome') def _listen_metronome(self): if self.__shift_down: self._left_button.set_display_value( self.song().metronome and 127 or 0, True) def _update_shift_status(self): if self.__shift_down: self._rec_button.set_display_value( self.song().overdub and 127 or 0, True) self._right_button.set_display_value(self.song().loop and 127 or 0, True) self._left_button.set_display_value( self.song().metronome and 127 or 0, True) else: self._rec_button.set_display_value(0, True) self._left_button.set_display_value(0, True) self._right_button.set_display_value(0, True) def set_browse_down(self, value): self.__browse_down = value @subject_slot('value', identify_sender=True) def __do_lock(self, value, sender): if sender.grabbed: return if self.__action_listener and value > 0: newstate = self.__action_listener.notify_edit_toggle( LOCK_BUTTON, self.__shift_down) self.__lock_button.set_value(newstate) @subject_slot('value', identify_sender=True) def __do_macro(self, value, sender): if sender.grabbed: return self.__macro_down = value > 0 self.__macro_button.set_display_value(value, True) def set_edit_state(self, **args): if 'lock' in args: self.__lock_button.set_value(args['lock'] and 127 or 0) else: self.__lock_button.set_value(0) def set_shiftstatus(self, value): self.__shift_down = value > 0 self._update_shift_status() if self.__shift_listener: self.__shift_listener.notify_shift(self.__shift_down) @subject_slot('value', identify_sender=True) def __do_select_button(self, value, sender): if sender.grabbed: return self._select_button.send_value(value) self.__select_down = value > 0 def register_shift_listener(self, listener): self.__shift_listener = listener @subject_slot('value', identify_sender=True) def __do_delete(self, value, sender): if sender.grabbed: return self.__delete_button.send_value(value) if not self.__shift_down: self.__delete_down = value > 0 else: if value != 0: clip = self.song().view.detail_clip if clip != None: clip.clear_all_envelopes() self.canonical_parent.show_message('Clear Envelopes ' + clip.name) return @subject_slot('value', identify_sender=True) def __do_duplicate(self, value, sender): if sender.grabbed: return self.__duplicate_button.send_value(value) if not self.__shift_down: self.__duplicate_down = value > 0 else: if value != 0: clip = self.song().view.detail_clip if clip != None and clip.is_midi_clip: if clip.length <= 128.0: clip.duplicate_loop() self.canonical_parent.show_message( 'Double Loop : ' + str(int(clip.length / 4)) + ' Bars') self.application().view.focus_view('Detail/Clip') else: self.canonical_parent.show_message( 'Clip is to long to Duplicate') return def set_action_listener(self, listener): self.__action_listener = listener def handle_edit(self, clipslotcomp, value): if value == 0: return if clipslotcomp._clip_slot is not None: if self.__delete_down: self.__handle_delete(clipslotcomp) elif self.__duplicate_down: self.__handle_duplicate(clipslotcomp) elif self.__browse_down: self.__handle_mode_scene_clip(clipslotcomp) elif self.__macro_down: self.__handle_new_action(clipslotcomp) elif self.__select_down: self.__handle_select_action(clipslotcomp) elif self.__shift_down: self.__handle_shift_action(clipslotcomp) else: if self.__browse_down: self.__handle_mode_scene_clip(clipslotcomp) else: if self.__shift_down: self.__handle_shift_action(clipslotcomp) return def __handle_shift_action(self, clipslotcomp): columm, row = clipslotcomp.get_index() if row == 0: self.handle_edit_action(columm) def __handle_select_action(self, clipslotcomp): self.song().view.highlighted_clip_slot = clipslotcomp._clip_slot @subject_slot('value', identify_sender=True) def _do_left_button(self, value, sender): if sender.grabbed: return if self.__shift_down: if value == 0: return self.song().metronome = not self.song().metronome else: self._left_button.set_display_value(value > 0 and 127 or 0, True) if value == 0: return self.canonical_parent.invoke_nav_left() @subject_slot('value', identify_sender=True) def _do_right_button(self, value, sender): if sender.grabbed: return if self.__shift_down: if value == 0: return self.song().loop = not self.song().loop else: self._right_button.set_display_value(value > 0 and 127 or 0, True) if value == 0: return self.canonical_parent.invoke_nav_right() @subject_slot('value', identify_sender=True) def _do_rec_button(self, value, sender): if sender.grabbed: return if self.__shift_down: if value == 0: return self.song().overdub = not self.song().overdub else: self._rec_button.set_display_value(value > 0 and 127 or 0, True) if value > 0: self.canonical_parent.invoke_rec() def handle_edit_action(self, index, scale=None): if not self.__shift_down: return if index == 0: if self.song().can_undo == 1: self.song().undo() self.canonical_parent.show_message(str('UNDO')) else: if index == 1: if self.song().can_redo == 1: self.song().redo() self.canonical_parent.show_message(str('REDO')) else: if index == 2 or index == 3: clip = self.song().view.detail_clip if clip: clip.quantize(QUANT_CONST[self.__quantize_setting], index == 2 and 1.0 or 0.5) self.canonical_parent.show_message( 'Quantize Clip ' + clip.name + ' by ' + QUANT_STRING[self.__quantize_setting]) else: clip = self.song().view.detail_clip if clip and clip.is_midi_clip: track = clip.canonical_parent.canonical_parent drum_device = find_drum_device(track) if not drum_device: self.__transpose_clip(clip, TRANSPOSE[index], scale) def __transpose_clip(self, clip, amount, bn_scale): notes = clip.get_selected_notes() if len(notes) == 0: clip.select_all_notes() notes = clip.get_selected_notes() update_notes = [] for note in notes: pitch, pos, dur, vel, mute = note if bn_scale: basenote, scale = bn_scale pv = scale.transpose_by_scale(basenote, pitch, amount) else: pv = pitch + amount if pv < 0 or pv > 127: pv = pitch update_notes.append((pv, pos, dur, vel, mute)) clip.replace_selected_notes(tuple(update_notes)) def __handle_mode_scene_clip(self, clipslotcomp): if clipslotcomp._clip_slot is None: return clip_slot = clipslotcomp._clip_slot self.song().view.highlighted_clip_slot = clip_slot return def __handle_delete(self, clipslotcomp): if self.__shift_down: pass else: clipslotcomp._do_delete_clip() def __handle_duplicate(self, clipslotcomp): if self.__shift_down: pass else: self.duplicate_clip_slot(clipslotcomp._clip_slot) def __handle_new_action(self, clipslotcomp): song = self.song() clip_slot = clipslotcomp._clip_slot track = clip_slot.canonical_parent if clip_slot.clip == None and track.has_midi_input: try: clip_slot.create_clip(4.0) song.view.detail_clip = clip_slot.clip select_clip_slot(song, clip_slot) self.application().view.focus_view('Detail/Clip') self.canonical_parent.show_message( 'New Midi Clip ' + song.view.highlighted_clip_slot.clip.name) except Live.Base.LimitationError: pass except RuntimeError: pass return def double_clipslot(self, clip_slot): song = self.song() track = clip_slot.canonical_parent if clip_slot.clip is not None and track.has_midi_input: clip = clip_slot.clip if clip.length <= 2048.0: clip.duplicate_loop() self.canonical_parent.show_message('Double Loop : ' + str(int(clip.length / 4)) + ' Bars') song.view.detail_clip = clip self.application().view.focus_view('Detail/Clip') else: self.canonical_parent.show_message( 'Clip is to long to Duplicate') return def duplicate_clip_slot(self, clip_slot): if clip_slot.has_clip: try: track = clip_slot.canonical_parent index = list(track.clip_slots).index(clip_slot) track.duplicate_clip_slot(index) self.canonical_parent.show_message('Duplicate Clip ' + clip_slot.clip.name) select_clip_slot(self.song(), track.clip_slots[index + 1]) except Live.Base.LimitationError: pass except RuntimeError: pass def in_spec_mode(self): return self.__shift_down or self.__delete_down or self.__duplicate_down or self.__browse_down or self.__macro_down or self.__select_down def modifier_mask(self): return (self.__shift_down and MASK_SHIFT or 0) | (self.__browse_down and MASK_BROWSE or 0) | (self.__delete_down and MASK_CLEAR or 0) | ( self.__duplicate_down and MASK_DUPLICATE or 0) | (self.__macro_down and MASK_SPEC or 0) | ( self.__select_down and MASK_SELECT or 0) def is_select_down(self): return self.__select_down def is_browse_down(self): return self.__browse_down def is_shift_down(self): return self.__shift_down def is_delete_down(self): return self.__delete_down def is_duplicate_down(self): return self.__duplicate_down
class Mk2KnobControl: __module__ = __name__ __doc__ = 'Mk2 Module for Controlling Parameters with Master Knob' def __init__(self, parent): self._parent = parent self.master_track = parent.song().master_track self.volume_button = None self._set_volume_button(StateButton(True, MIDI_CC_TYPE, 3, 110)) self.the_slider = SliderElement(MIDI_CC_TYPE, 1, 86) self.the_slider.add_value_listener(self._do_main_slider, True) self.xfade_button = None self._set_xfade_button(StateButton(True, MIDI_CC_TYPE, 3, 116)) self.swing_button = None self._set_swing_button(StateButton(True, MIDI_CC_TYPE, 3, 111)) self.mode = KN2_MODE_VOLUME self.previous_mode = -1 self.tempo_button = None self._set_tempo_button(StateButton(True, MIDI_CC_TYPE, 3, 112)) self.push_button = None self._set_push_button(StateButton(True, MIDI_CC_TYPE, 1, 87)) self.clipn_v_button = None self.clipn_h_button = None self._set_clipn_h_button(StateButton(True, MIDI_CC_TYPE, 3, 114)) self._set_clipn_v_button(StateButton(True, MIDI_CC_TYPE, 3, 115)) self.toggle_buttons = [ self.volume_button, self.xfade_button, self.swing_button, self.tempo_button, self.clipn_h_button, self.clipn_v_button ] self.shift_button = None self._set_shift_button(StateButton(True, MIDI_CC_TYPE, 3, 113)) self.shift_on = False self.scroll_mod_left_button = None self.scroll_mod_right_button = None self._set_scroll_mod_left_button( StateButton(True, MIDI_CC_TYPE, 0, 105)) self._set_scroll_mod_right_button( StateButton(True, MIDI_CC_TYPE, 0, 106)) self._prev_mode = KN2_MODE_VOLUME self.lrmode = LR_CONTROL_CLIP self._challenge = Live.Application.get_random_int( 0, 400000000) & 2139062143 self.loop_div_index = 0 self.loop_incdex = 4.0 self.arrow_mode_button = ColorButton(True, MIDI_CC_TYPE, 30) self.arrow_mode_button.add_value_listener(self.toggle_arrow_mode) self.arrow_mode_button.send_color(LR_MODE_HUES[self.lrmode]) self.arrow_mode_button.send_value(127, True) self.navflags = 0 self.octave_mod_button = StateButton(True, MIDI_CC_TYPE, 1, 70) self.octave_mod_button.add_value_listener(self._action_octave) self.scale_mod_button = StateButton(True, MIDI_CC_TYPE, 1, 71) self.scale_mod_button.add_value_listener(self._action_scale) self.basenote_mod_button = StateButton(True, MIDI_CC_TYPE, 1, 72) self.basenote_mod_button.add_value_listener(self._action_base_note) self.keycolor_mod_button = StateButton(True, MIDI_CC_TYPE, 1, 73) self.keycolor_mod_button.add_value_listener(self._action_key_color) self.pad_to_mainknob_mode = 0 self._measure_left_click = 0 self._measure_right_click = 0 self.mode_assign_map = { KN2_MODE_VOLUME: (self.chg_volume, 0, 'Master Knob controls MASTER Volume', KN2_MODE_CUE), KN2_MODE_CUE: (self.chg_cue, 0, 'Master Knob controls Cue Level', KN2_MODE_VOLUME), KN2_MODE_TEMPO_COARSE: (self.chg_tempo, 3, 'Master Knob controls TEMPO Coarse', KN2_MODE_TEMPO_FINE), KN2_MODE_TEMPO_FINE: (self.chg_tempo_fine, 3, 'Master Knob controls TEMPO Fine', KN2_MODE_TEMPO_COARSE), KN2_MODE_XFADE: (self.chg_xfade, 1, 'Master Knob controls Crossfader', -1), KN2_MODE_QUANT: (self.chg_quant, 2, 'Master Knob controls Recording Quantize', KN2_MODE_CLIP_QUANT), KN2_MODE_CLIP_QUANT: (self.chg_clip_q, 2, 'Master Knob controls Clip Start Quantize', KN2_MODE_QUANT), KN2_MODE_CLIPN_HOR: (self.nav_c_hor, 4, 'Master Knob Clip View horizontally', -1), KN2_MODE_CLIPN_VER: (self.nav_c_ver, 5, 'Master Knob Clip View vertically', -1), KN2_MODE_GENERAL: (self.chg_general, -1, None, -1), KN2_P_SCALES: (self.modify_pad_scaling, -1, None, -1) } def start_up(self): self._set_mode(KN2_MODE_VOLUME) self.arrow_mode_button.send_value(127, True) def toggle_arrow_mode(self, value): if value > 0: self.lrmode = (self.lrmode + 1) % 4 self.arrow_mode_button.send_hue(LR_MODE_HUES[self.lrmode]) self._parent.show_message('Left/Right Buttons Control: ' + L_MODE_FUNCTION[self.lrmode] + ' / ' + R_MODE_FUNCTION[self.lrmode]) def switch_to_matrix_mode(self): if self.mode != KN2_MODE_GENERAL: self.previous_mode = self.mode self._set_mode(KN2_MODE_GENERAL) def exit_matrix_mode(self): if self.mode == KN2_MODE_GENERAL: self._set_mode(self.previous_mode) self.previous_mode = -1 def update_shift(self): if self.shift_on: self.shift_button.send_value(127, True) else: self.shift_button.send_value(0, True) def _set_mode(self, mode): if not mode in range(11): raise AssertionError self.update_shift() if mode == self.mode: return self._prev_mode = mode self.mode = mode self.switch_radio_buttons(self.mode_assign_map[self.mode][1]) message = self.mode_assign_map[self.mode][2] message != None and self._parent.show_message(message) def switch_radio_buttons(self, which): for index in range(len(self.toggle_buttons)): if index == which: self.toggle_buttons[index].send_value(127, True) else: self.toggle_buttons[index].send_value(0, True) def update(self): self.switch_radio_buttons(self.mode_assign_map[self.mode][1]) self.arrow_mode_button.send_color(LR_MODE_HUES[self.lrmode]) self.arrow_mode_button.send_value(127, True) def _do_main_slider(self, value, encoder): if not value in range(128): raise AssertionError if not isinstance(encoder, EncoderElement): raise AssertionError if value == 1: delta = 1 else: delta = -1 if self.pad_to_mainknob_mode != 0: self.mode_assign_map[KN2_P_SCALES][0](delta) elif self.navflags == 0: self.mode_assign_map[self.mode][0](delta) if self.lrmode == LR_CONTROL_CLIP: self.navflags & LEFT_DOWN != 0 and self.nav_c_hor(delta) self.navflags & RIGHT_DOWN != 0 and self.nav_c_ver(delta) elif self.lrmode == LR_CONTROL_SEL: if self.navflags & LEFT_DOWN != 0: self.nav_track(delta) if self.navflags & RIGHT_DOWN != 0: self._parent.scroll_scene(delta) elif self.lrmode == LR_CONTROL_DEV: if self.navflags & LEFT_DOWN != 0: self.nav_track(delta) if self.navflags & RIGHT_DOWN != 0: self._parent.scroll_device(delta) elif self.lrmode == LR_CONTROL_LOOP: if self.navflags & LEFT_DOWN != 0: self.adjust_loop_start(delta) if self.navflags & RIGHT_DOWN != 0: self.adjust_loop_length(delta) def modify_pad_scaling(self, delta): if self.pad_to_mainknob_mode & PAD_KNOB_OCTAVE != 0: self._parent.inc_octave(delta) if self.pad_to_mainknob_mode & PAD_KNOB_SCALE != 0: self._parent.inc_scale(delta) if self.pad_to_mainknob_mode & PAD_KNOB_BASEN != 0: self._parent.inc_base_note(delta) self._parent.update_transpose() def adjust_loop_start(self, delta): loopval = self._parent.song().loop_start loopval += self.loop_incdex * delta if loopval < 0: loopval = 0 elif loopval > 999: loopval = 999 self._parent.song().loop_start = loopval def adjust_loop_length(self, delta): loopval = self._parent.song().loop_length loopval += self.loop_incdex * delta if loopval < self.loop_incdex: loopval = self.loop_incdex elif loopval > 999: loopval = 999 self._parent.song().loop_length = loopval def chg_general(self, delta): self._parent._scenematrix.control_handler.mod_value( delta, self.shift_on) def nav_track(self, direction): if direction == 1: self._parent._a_trk_right(1) else: self._parent._a_trk_left(1) def nav_c_hor(self, direction): self._parent.move_view_horizontal(direction) def nav_c_ver(self, direction): if direction == 1: self._parent._session.bank_up() else: self._parent._session.bank_down() def chg_volume(self, diff): if self.shift_on: self.repeat(self.master_track.mixer_device.volume, diff) else: self.master_track.mixer_device.volume.value = self.calc_new_parm( self.master_track.mixer_device.volume, diff) def chg_xfade(self, diff): if self.shift_on: self.repeat(self.master_track.mixer_device.crossfader, diff) else: self.master_track.mixer_device.crossfader.value = self.calc_new_parm( self.master_track.mixer_device.crossfader, diff) def chg_cue(self, diff): if self.shift_on: self.repeat(self.master_track.mixer_device.cue_volume, diff) else: self.master_track.mixer_device.cue_volume.value = self.calc_new_parm( self.master_track.mixer_device.cue_volume, diff) def repeat(self, parm, delta): count = 0 while count < SHIFT_INC: parm.value = self.calc_new_parm(parm, delta) count += 1 def calc_new_parm(self, parm, delta): parm_range = parm.max - parm.min int_val = int((parm.value - parm.min) / parm_range * PARM_RANGE + 0.1) inc_val = min(PARM_RANGE, max(0, int_val + delta)) return float(inc_val) / float(PARM_RANGE) * parm_range + parm.min def chg_quant(self, diff): rec_quant = self._parent.song().midi_recording_quantization index = self.get_quant_index(rec_quant) new_index = index + diff if new_index >= 0 and new_index < len(QUANT_CONST): self._parent.song( ).midi_recording_quantization = QUANT_CONST[new_index] self._parent.show_message(QUANT_DESCR[new_index]) def chg_clip_q(self, diff): quant = self._parent.song().clip_trigger_quantization self._parent.song().clip_trigger_quantization = max( 0, min(13, quant + diff)) self._parent.show_message( 'Clip Quantize ' + CLIQ_DESCR[self._parent.song().clip_trigger_quantization]) def chg_tempo_fine(self, diff): if diff < 0: amount = -0.01 else: amount = 0.01 self.chg_tempo(amount) def chg_tempo(self, diff): self._parent.song().tempo = max( 20, min(999, self._parent.song().tempo + diff)) def get_quant_index(self, const): for index in range(len(QUANT_CONST)): if const == QUANT_CONST[index]: return index return -1 def _action_octave(self, value): if value != 0: self.pad_to_mainknob_mode |= PAD_KNOB_OCTAVE else: self.pad_to_mainknob_mode &= ~PAD_KNOB_OCTAVE def _action_scale(self, value): if value != 0: self.pad_to_mainknob_mode |= PAD_KNOB_SCALE else: self.pad_to_mainknob_mode &= ~PAD_KNOB_SCALE def _action_base_note(self, value): if value != 0: self.pad_to_mainknob_mode |= PAD_KNOB_BASEN else: self.pad_to_mainknob_mode &= ~PAD_KNOB_BASEN def _action_key_color(self, value): if value != 0: self._parent.step_key_color_mode() def _set_volume_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.volume_button != None: self.volume_button.remove_value_listener(self._action_volume) self.volume_button = button self.volume_button != None and self.volume_button.add_value_listener( self._action_volume) def _action_volume(self, value): if not self.volume_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_VOLUME and self._set_mode( KN2_MODE_VOLUME) def _set_xfade_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.xfade_button != None: self.xfade_button.remove_value_listener(self._action_xfade) self.xfade_button = button self.xfade_button != None and self.xfade_button.add_value_listener( self._action_xfade) def _action_xfade(self, value): if not self.xfade_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_XFADE and self._set_mode( KN2_MODE_XFADE) def _set_swing_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.swing_button != None: self.swing_button.remove_value_listener(self._action_swing) self.swing_button = button self.swing_button != None and self.swing_button.add_value_listener( self._action_swing) def _action_swing(self, value): if not self.swing_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_QUANT and self._set_mode( KN2_MODE_QUANT) def _set_tempo_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.tempo_button != None: self.tempo_button.remove_value_listener(self._action_tempo) self.tempo_button = button self.tempo_button != None and self.tempo_button.add_value_listener( self._action_tempo) def _action_tempo(self, value): if not self.tempo_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_TEMPO_COARSE and self._set_mode( KN2_MODE_TEMPO_COARSE) def _set_clipn_h_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.clipn_h_button != None: self.clipn_h_button.remove_value_listener(self._action_clipnh) self.clipn_h_button = button self.clipn_h_button != None and self.clipn_h_button.add_value_listener( self._action_clipnh) def _action_clipnh(self, value): if not self.clipn_h_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_CLIPN_HOR and self._set_mode( KN2_MODE_CLIPN_HOR) def _set_clipn_v_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.clipn_v_button != None: self.clipn_v_button.remove_value_listener(self._action_clipnv) self.clipn_v_button = button self.clipn_v_button != None and self.clipn_v_button.add_value_listener( self._action_clipnv) def _action_clipnv(self, value): if not self.clipn_v_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.mode != KN2_MODE_CLIPN_VER and self._set_mode( KN2_MODE_CLIPN_VER) def _set_shift_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.shift_button != None: self.shift_button.remove_value_listener(self._action_shift) self.shift_button = button self.shift_button != None and self.shift_button.add_value_listener( self._action_shift) def _action_shift(self, value): if not self.shift_button != None: raise AssertionError raise value in range(128) or AssertionError self.shift_on = value != 0 and not self.shift_on self.update_shift() def _set_scroll_mod_left_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.scroll_mod_left_button != None: self.scroll_mod_left_button.remove_value_listener( self._action_scroll_left) self.scroll_mod_left_button = button self.scroll_mod_left_button != None and self.scroll_mod_left_button.add_value_listener( self._action_scroll_left) def _set_scroll_mod_right_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.scroll_mod_right_button != None: self.scroll_mod_right_button.remove_value_listener( self._action_scroll_right) self.scroll_mod_right_button = button self.scroll_mod_right_button != None and self.scroll_mod_right_button.add_value_listener( self._action_scroll_right) def _action_scroll_left(self, value): if not self.scroll_mod_left_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.scroll_mod_left_button.send_value(127, True) self.navflags |= LEFT_DOWN self._measure_left_click = int(round(time.time() * 1000)) else: self.scroll_mod_left_button.send_value(0, True) self.navflags &= ~LEFT_DOWN clicktime = int(round( time.time() * 1000)) - self._measure_left_click if clicktime < CLICK_TIME: if self._parent._modifier_down: self._parent.modify_track_offset(-1) elif self._parent._mode == PAD_MODE: self._do_lr_as_scale_mode(-1) elif self._parent._mode == SCENE_MODE: self._parent.modify_scene_offset(-1) elif self._parent._mode == CLIP_MODE: self._parent.move_view_horizontal(-1) elif self._parent._mode == CONTROL_MODE: self._parent.move_view_horizontal(-1) def _action_scroll_right(self, value): if not self.scroll_mod_right_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.scroll_mod_right_button.send_value(127, True) self.navflags |= RIGHT_DOWN self._measure_right_click = int(round(time.time() * 1000)) else: self.scroll_mod_right_button.send_value(0, True) self.navflags &= ~RIGHT_DOWN clicktime = int(round( time.time() * 1000)) - self._measure_right_click if clicktime < CLICK_TIME: if self._parent._modifier_down: self._parent.modify_track_offset(1) elif self._parent._mode == PAD_MODE: self._do_lr_as_scale_mode(1) elif self._parent._mode == SCENE_MODE: self._parent.modify_scene_offset(1) elif self._parent._mode == CLIP_MODE: self._parent.move_view_horizontal(1) elif self._parent._mode == CONTROL_MODE: self._parent.move_view_horizontal(1) def _do_lr_as_scale_mode(self, delta): if self.pad_to_mainknob_mode == PAD_KNOB_SCALE: self._parent.inc_scale(delta) elif self.pad_to_mainknob_mode == PAD_KNOB_BASEN: self._parent.inc_base_note(delta) else: self._parent.inc_octave(delta) self._parent.update_transpose() def _set_push_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.push_button != None: self.push_button.remove_value_listener(self._action_push) self.push_button = button self.push_button != None and self.push_button.add_value_listener( self._action_push) def _action_push(self, value): if not self.push_button != None: raise AssertionError if not value in range(128): raise AssertionError next_mode = self.mode_assign_map[self.mode][3] next_mode != -1 and self._set_mode(next_mode) self.loop_div_index = self.lrmode == LR_CONTROL_LOOP and self.navflags != 0 and ( self.loop_div_index + 1) % len(LOOP_KNOB_DIVISION) self._parent.show_message( 'Loop Selection Granularity : ' + str(LOOP_KNOB_DIVISION[self.loop_div_index]) + ' beats ') self.loop_incdex = LOOP_KNOB_DIVISION[self.loop_div_index] def remove_listener(self, control, callback): if control != None and control.value_has_listener(callback): control.remove_value_listener(callback) control.disconnect() def disconnect(self): self.remove_listener(self.the_slider, self._do_main_slider) self.remove_listener(self.arrow_mode_button, self.toggle_arrow_mode) self.remove_listener(self.volume_button, self._action_volume) self.remove_listener(self.xfade_button, self._action_xfade) self.remove_listener(self.swing_button, self._action_swing) self.remove_listener(self.clipn_h_button, self._action_clipnh) self.remove_listener(self.clipn_v_button, self._action_clipnv) self.remove_listener(self.shift_button, self._action_shift) self.remove_listener(self.scroll_mod_left_button, self._action_scroll_left) self.remove_listener(self.scroll_mod_right_button, self._action_scroll_right) self.remove_listener(self.push_button, self._action_push) self.remove_listener(self.octave_mod_button, self._action_octave) self.remove_listener(self.scale_mod_button, self._action_scale) self.remove_listener(self.basenote_mod_button, self._action_base_note) self.remove_listener(self.keycolor_mod_button, self._action_key_color) self._parent = None self.master_track = None self.the_slider = None self.mode_assign_map = None
class MaschineJam(ControlSurface): """Control Script for Maschine JAM Controller""" __module__ = __name__ _midi_count = 0 _arm_exclusive = True _solo_exclusive = True _blink_state = 0 __midi_count = 0 __play_button = None __block_nav = False __matrix_state = None def __init__(self, c_instance): super(MaschineJam, self).__init__(c_instance) with self.component_guard(): self._suppress_send_midi = True register_sender(self) self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143 self._set_suppress_rebuild_requests(True) self._c_ref = c_instance self.request_rebuild_midi_map() self.__matrix_state = MatrixState(self) self._main_mode_container = JamModes(c_instance.note_repeat) self._set_suppress_rebuild_requests(False) self._active = True self._display_device_param = False self._setup_transport() self._setup_session() self._encoder_modes = EncoderComponent(self._session) self._encoder_modes.connect() self._encoder_modes.set_state_listener(self) self._modifier = ModifierComponent(self._session) self._connect_session() self._main_mode_container.bind_session(self.__matrix_state) self._main_mode_container.bind_modify_component(self._modifier) self._setup_mainjogwheel() self._init_m4l() self._init_settings() self.set_pad_translations(PAD_TRANSLATIONS) self.set_feedback_channels(FEEDBACK_CHANNELS) self._suppress_send_midi = False self._main_mode_container._step_mode.set_mode_elements(self._modifier, self._encoder_modes) self._main_mode_container._drum_step_mode.set_mode_elements(self._modifier) self._final_init() self.apply_preferences() def _init_m4l(self): self._bmatrix.set_user_unbind_listener(self._main_mode_container) def _init_settings(self): from pickle import loads, dumps from encodings import ascii nop(ascii) preferences = self._c_instance.preferences(self.preferences_name()) self._pref_dict = {} try: self._pref_dict = loads(str(preferences)) except Exception: pass pref_dict = self._pref_dict preferences.set_serializer(lambda : dumps(pref_dict)) def store_preferences(self): self._pref_dict['matrix_color_mode'] = self._session.get_color_mode() def apply_preferences(self): pref_dict = self._pref_dict if 'matrix_color_mode' in pref_dict: self._session.set_color_mode(pref_dict['matrix_color_mode']) def preferences_name(self): return 'MaschineJam' def _final_init(self): debug_out('########## LIVE 10 Maschine JAM V 1.3 #############') self._auto_button.set_display_value(self.song().session_automation_record and 127 or 0) self._main_mode_container.init_elements() def _init_map(self): msgsysex = [ 240, 0, 33, 9, 21, 0, 77, 80, 0, 1, 2] for _ in range(80): msgsysex.append(COLOR_BLACK) msgsysex.append(247) self._send_midi(tuple(msgsysex)) def _set_touch_strip_led(self): msgsysex = [ 240, 0, 33, 9, 21, 0, 77, 80, 0, 1, 4] for _ in range(8): msgsysex.append(0) msgsysex.append(247) self._send_midi(tuple(msgsysex)) def handle_sysex(self, midi_bytes): if len(midi_bytes) > 11 and midi_bytes[0:10] == (240, 0, 33, 9, 21, 0, 77, 80, 0, 1): msg, value = midi_bytes[10:12] if msg == 70: self.refresh_state() self._modifier.set_shiftstatus(1) elif msg == 77: self.shiftButton.notify_value(value == 1 and 127 or 0) if not self.shiftButton.is_grabbed: self._modifier.set_shiftstatus(value) def _setup_transport(self): is_momentary = True self.shiftButton = SysExButton(120, name='Shift_Button') self.__play_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 108, name='Play_Button') self._hand_play_pressed.subject = self.__play_button self._listen_playing.subject = self.song() self._channel_led_left = SliderElement(MIDI_CC_TYPE, 0, 38) self._channel_led_right = SliderElement(MIDI_CC_TYPE, 0, 39) self._channel_led_left.last_raw = 0.0 self._channel_led_left.last_send = 0 self._channel_led_right.last_raw = 0.0 self._channel_led_right.last_send = 0 self._listen_master_left.subject = self.song().master_track self._listen_master_right.subject = self.song().master_track self._auto_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 98, name='Auto_Button') self._listen_automation_record.subject = self.song() self._handle_automation_record.subject = self._auto_button self._do_direction_up.subject = StateButton(is_momentary, MIDI_CC_TYPE, 0, 40, name='Up_Arrow') self._do_direction_down.subject = StateButton(is_momentary, MIDI_CC_TYPE, 0, 41, name='Down_Arrow') self._do_direction_left.subject = StateButton(is_momentary, MIDI_CC_TYPE, 0, 42, name='Left_Arrow') self._do_direction_right.subject = StateButton(is_momentary, MIDI_CC_TYPE, 0, 43, name='Right_Arrow') @subject_slot('output_meter_left') def _listen_master_left(self): cvl = self.song().master_track.output_meter_left if cvl != self._channel_led_left.last_raw: val = cvl > 0.92 and 127 or int(127 * (cvl * cvl)) if val != self._channel_led_left.last_send: self._channel_led_left.last_raw = cvl self._channel_led_left.last_send = val self._channel_led_left.send_value(val, True) @subject_slot('output_meter_right') def _listen_master_right(self): cvl = self.song().master_track.output_meter_right if cvl != self._channel_led_right.last_raw: val = cvl > 0.92 and 127 or int(127 * (cvl * cvl)) if val != self._channel_led_right.last_send: self._channel_led_right.last_raw = cvl self._channel_led_right.last_send = val self._channel_led_right.send_value(val, True) def is_monochrome(self): return False def _send_midi(self, midi_bytes, **keys): self._c_ref.send_midi(midi_bytes) if self._midi_count > 2: time.sleep(0.001) self._midi_count = 0 self._midi_count += 1 return True def _setup_mainjogwheel(self): self._prev_mode = None return def is_shift_down(self): return self._modifier.is_shift_down() def modifier_mask(self): return self._modifier.modifier_mask() def _setup_session(self): self._session = JamSessionComponent() self._matrix = [] self._bmatrix = JamButtonMatrix(8, name='Button_Matrix') for sceneIndex in range(8): button_row = [] for trackindex in range(8): button = PadColorButton(True, 0, sceneIndex, trackindex, self._main_mode_container) button_row.append(button) self._matrix.append(tuple(button_row)) self._bmatrix.add_row(tuple(button_row)) self._session.set_matrix(self._bmatrix, self._matrix) self.__matrix_state.register_matrix(self._bmatrix) self._bmatrix.prepare_update() for button, (trackIndex, sceneIndex) in self._bmatrix.iterbuttons(): if button: scene = self._session.scene(sceneIndex) clip_slot = scene.clip_slot(trackIndex) clip_slot.set_launch_button(button) clip_slot.set_triggered_to_play_value(1) clip_slot.set_triggered_to_record_value(1) clip_slot.set_started_value(1) clip_slot.set_recording_value(1) clip_slot.set_stopped_value(1) self._session._link() self._bmatrix.commit_update() self.set_highlighting_session_component(self._session) def _connect_session(self): for sindex in range(self._session.height()): scene = self._session.scene(sindex) for cindex in range(self._session.width()): clip = scene.clip_slot(cindex) clip.set_modifier(self._modifier) clip.set_index((cindex, sindex)) def update_display(self): with self.component_guard(): self._main_mode_container.notify(self._blink_state) self._encoder_modes.notify(self._blink_state) self._blink_state = (self._blink_state + 1) % 4 def refresh_state(self): self._bmatrix.prepare_update() ControlSurface.refresh_state(self) self.update_hardware() self._bmatrix.commit_update() def update_hardware(self): self._session.update() self.__play_button.set_display_value(self.song().is_playing and 127 or 0, True) self._main_mode_container.refresh_state() self._encoder_modes.refresh_state() def invoke_nav_left(self): self._encoder_modes.invoke_nav_left() def invoke_nav_right(self): self._encoder_modes.invoke_nav_right() def invoke_rec(self): slot = self.song().view.highlighted_clip_slot if slot == None: return if slot.controls_other_clips: slot.fire() else: if slot.has_clip: track = slot.canonical_parent if track.can_be_armed: arm_exclusive(self.song(), track) self.song().overdub = True slot.fire() else: track = slot.canonical_parent if track.can_be_armed: arm_exclusive(self.song(), track) slot.fire() return @subject_slot('session_automation_record') def _listen_automation_record(self): self._auto_button.set_display_value(self.song().session_automation_record and 127 or 0, True) @subject_slot('value', identify_sender=True) def _handle_automation_record(self, value, sender): if value == 0 or sender.grabbed: return self.song().session_automation_record = not self.song().session_automation_record @subject_slot('is_playing') def _listen_playing(self): if self.song().is_playing: self.__play_button.set_display_value(127, True) else: self.__play_button.set_display_value(0, True) @subject_slot('value', identify_sender=True) def _hand_play_pressed(self, value, sender): if value == 0 or sender.grabbed: return if self.song().is_playing: if self._modifier.is_shift_down(): self.song().start_playing() else: self.song().stop_playing() else: self.song().start_playing() @subject_slot('value', identify_sender=True) def do_undo(self, value, sender): if value == 0 or sender.grabbed: return if self._modifier.is_shift_down(): if self.song().can_redo == 1: self.song().redo() self.show_message(str('REDO')) else: if self.song().can_undo == 1: self.song().undo() self.show_message(str('UNDO')) def notify_state(self, state, value): if state == 'controldown': self.__block_nav = value else: if state == 'step': self._main_mode_container.notify_state(state, value) @subject_slot('value', identify_sender=True) def _do_direction_up(self, value, sender): if value == 0 or sender.grabbed: return if not self.__block_nav: self._main_mode_container.navigate(-1, 1, self._modifier.is_shift_down(), NAV_SRC_BUTTON) else: self._encoder_modes.navigate(-1, 1, self._modifier.is_shift_down(), NAV_SRC_BUTTON) @subject_slot('value', identify_sender=True) def _do_direction_down(self, value, sender): if value == 0 or sender.grabbed: return if not self.__block_nav: self._main_mode_container.navigate(1, 1, self._modifier.is_shift_down(), NAV_SRC_BUTTON) else: self._encoder_modes.navigate(1, -1, self._modifier.is_shift_down(), NAV_SRC_BUTTON) @subject_slot('value', identify_sender=True) def _do_direction_left(self, value, sender): if value == 0 or sender.grabbed: return if not self.__block_nav: encoder_changed = self._main_mode_container.navigate(-1, 0, self._modifier.is_shift_down(), NAV_SRC_BUTTON) if encoder_changed: self._encoder_modes.navigate(-1, 0, self._modifier.is_shift_down(), NAV_SRC_BUTTON) else: self._encoder_modes.navigate(-1, 0, self._modifier.is_shift_down(), NAV_SRC_BUTTON) @subject_slot('value', identify_sender=True) def _do_direction_right(self, value, sender): if value == 0 or sender.grabbed: return if not self.__block_nav: encoder_changed = self._main_mode_container.navigate(1, 0, self._modifier.is_shift_down(), NAV_SRC_BUTTON) if encoder_changed: self._encoder_modes.navigate(1, 0, self._modifier.is_shift_down(), NAV_SRC_BUTTON) else: self._encoder_modes.navigate(1, 0, self._modifier.is_shift_down(), NAV_SRC_BUTTON) @property def selected_mode(self): return self._main_mode_container.selected_mode @selected_mode.setter def selected_mode(self, value): self._main_mode_container.selected_mode = value def get_session(self): return self._session def toggle_mode(self): self._session.set_color_mode() self.refresh_state() def get_button_matrix(self): return self._bmatrix def deassign_matrix(self): for scene_index in range(8): scene = self._session.scene(scene_index) for track_index in range(8): clip_slot = scene.clip_slot(track_index) clip_slot.set_launch_button(None) return def _pre_serialize(self): from pickle import dumps from encodings import ascii nop(ascii) preferences = self._c_instance.preferences('MaschineJam') self.store_preferences() dump = dumps(self._pref_dict) preferences.set_serializer(lambda : dump) def disconnect(self): self._pre_serialize() self._set_touch_strip_led() self._encoder_modes.turn_off_bars() self._init_map() self._channel_led_left.send_value(0, True) self._channel_led_right.send_value(0, True) self._active = False self._suppress_send_midi = True super(MaschineJam, self).disconnect() return
def __init__(self, parent): self._parent = parent self.master_track = parent.song().master_track self.volume_button = None self._set_volume_button(StateButton(True, MIDI_CC_TYPE, 3, 110)) self.the_slider = SliderElement(MIDI_CC_TYPE, 1, 86) self.the_slider.add_value_listener(self._do_main_slider, True) self.xfade_button = None self._set_xfade_button(StateButton(True, MIDI_CC_TYPE, 3, 116)) self.swing_button = None self._set_swing_button(StateButton(True, MIDI_CC_TYPE, 3, 111)) self.mode = KN2_MODE_VOLUME self.previous_mode = -1 self.tempo_button = None self._set_tempo_button(StateButton(True, MIDI_CC_TYPE, 3, 112)) self.push_button = None self._set_push_button(StateButton(True, MIDI_CC_TYPE, 1, 87)) self.clipn_v_button = None self.clipn_h_button = None self._set_clipn_h_button(StateButton(True, MIDI_CC_TYPE, 3, 114)) self._set_clipn_v_button(StateButton(True, MIDI_CC_TYPE, 3, 115)) self.toggle_buttons = [ self.volume_button, self.xfade_button, self.swing_button, self.tempo_button, self.clipn_h_button, self.clipn_v_button, ] self.shift_button = None self._set_shift_button(StateButton(True, MIDI_CC_TYPE, 3, 113)) self.shift_on = False self.scroll_mod_left_button = None self.scroll_mod_right_button = None self._set_scroll_mod_left_button(StateButton(True, MIDI_CC_TYPE, 0, 105)) self._set_scroll_mod_right_button(StateButton(True, MIDI_CC_TYPE, 0, 106)) self._prev_mode = KN2_MODE_VOLUME self.lrmode = LR_CONTROL_CLIP self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143 self.loop_div_index = 0 self.loop_incdex = 4.0 self.arrow_mode_button = ColorButton(True, MIDI_CC_TYPE, 30) self.arrow_mode_button.add_value_listener(self.toggle_arrow_mode) self.arrow_mode_button.send_color(LR_MODE_HUES[self.lrmode]) self.arrow_mode_button.send_value(127, True) self.navflags = 0 self.octave_mod_button = StateButton(True, MIDI_CC_TYPE, 1, 70) self.octave_mod_button.add_value_listener(self._action_octave) self.scale_mod_button = StateButton(True, MIDI_CC_TYPE, 1, 71) self.scale_mod_button.add_value_listener(self._action_scale) self.basenote_mod_button = StateButton(True, MIDI_CC_TYPE, 1, 72) self.basenote_mod_button.add_value_listener(self._action_base_note) self.keycolor_mod_button = StateButton(True, MIDI_CC_TYPE, 1, 73) self.keycolor_mod_button.add_value_listener(self._action_key_color) self.pad_to_mainknob_mode = 0 self._measure_left_click = 0 self._measure_right_click = 0 self.mode_assign_map = { KN2_MODE_VOLUME: (self.chg_volume, 0, "Master Knob controls MASTER Volume", KN2_MODE_CUE), KN2_MODE_CUE: (self.chg_cue, 0, "Master Knob controls Cue Level", KN2_MODE_VOLUME), KN2_MODE_TEMPO_COARSE: (self.chg_tempo, 3, "Master Knob controls TEMPO Coarse", KN2_MODE_TEMPO_FINE), KN2_MODE_TEMPO_FINE: (self.chg_tempo_fine, 3, "Master Knob controls TEMPO Fine", KN2_MODE_TEMPO_COARSE), KN2_MODE_XFADE: (self.chg_xfade, 1, "Master Knob controls Crossfader", -1), KN2_MODE_QUANT: (self.chg_quant, 2, "Master Knob controls Recording Quantize", KN2_MODE_CLIP_QUANT), KN2_MODE_CLIP_QUANT: (self.chg_clip_q, 2, "Master Knob controls Clip Start Quantize", KN2_MODE_QUANT), KN2_MODE_CLIPN_HOR: (self.nav_c_hor, 4, "Master Knob Clip View horizontally", -1), KN2_MODE_CLIPN_VER: (self.nav_c_ver, 5, "Master Knob Clip View vertically", -1), KN2_MODE_GENERAL: (self.chg_general, -1, None, -1), KN2_P_SCALES: (self.modify_pad_scaling, -1, None, -1), }
class Maschine(ControlSurface): """Basic Control Script for All Maschine Modell Mikro, Mikro Mk2, Mk1, Mk2, Studio""" __module__ = __name__ _has_stop_button = False use_shift_pads = False __shift_down = False __delete_down = False __duplicate_down = False __select_down = False __undo_state = 0 __redo_state = 0 __play_button = None __nudge_value = 0.25 / 2 __quantize_setting = 5 def __init__(self, c_instance): super(Maschine, self).__init__(c_instance) with self.component_guard(): register_sender(self) self.init_type() self._diplay_cache = ['', '', '', ''] self._timed_text = None self._suppress_send_midi = True self._modifier = None self._c_ref = c_instance self.display_task = DisplayTask() self._challenge = Live.Application.get_random_int( 0, 400000000) & 2139062143 self._active = False self._midi_pause_count = 0 self.blink_state = 0 self.send_slider_index = 0 self.nav_index = 0 self.arm_selected_track = False self._set_suppress_rebuild_requests(True) self._main_mode_container = ModeHandler(c_instance.note_repeat) self._setup_session() self.__track_buttons = TrackControlComponent( self._session, self, name='Track_Select_Button_Matrix') self.__track_buttons.assign_buttons() self._setup_transport() self._set_global_buttons() self._encoder_section = EncoderView() self._init_maschine() self._init_settings() self.set_pad_translations(PAD_TRANSLATIONS) self._on_selected_track_changed() self.show_message(str('')) self.request_rebuild_midi_map() self._set_suppress_rebuild_requests(False) self._active = True self._display_device_param = False self._session.set_track_offset_listener(self.__update_tracks) self.set_feedback_channels(FEEDBACK_CHANNELS) self._final_init() self._main_mode_container.init_elements() self._suppress_send_midi = False self.apply_preferences() self.init_text_display() return def init_type(self): """ Needs to be overridden by specific version to define certain specialized behavior """ pass def _init_maschine(self): pass def _final_init(self): self._encoder_section.connect() def create_pad_button(self, scene_index, track_index, color_source): pass def create_gated_button(self, identifier, hue): pass def apply_preferences(self): pref_dict = self._pref_dict def store_preferences(self): pass def _init_settings(self): from pickle import loads, dumps from encodings import ascii nop(ascii) preferences = self._c_instance.preferences(self.preferences_name()) self._pref_dict = {} try: self._pref_dict = loads(str(preferences)) except Exception: pass pref_dict = self._pref_dict preferences.set_serializer(lambda: dumps(pref_dict)) def preferences_name(self): return 'Maschine' def _pre_serialize(self): from pickle import dumps from encodings import ascii nop(ascii) preferences = self._c_instance.preferences('Maschine') self.store_preferences() dump = dumps(self._pref_dict) preferences.set_serializer(lambda: dump) def _setup_session(self): self._session = MaschineSessionComponent() self._matrix = [] self._bmatrix = MaschineButtonMatrix(4, name='Button_Matrix') for sceneIndex in range(4): button_row = [] for trackindex in range(4): button = PadColorButton(True, 0, sceneIndex, trackindex, self._main_mode_container) button_row.append(button) self._matrix.append(tuple(button_row)) self._bmatrix.add_row(tuple(button_row)) self._session.set_matrix(self._bmatrix, self._matrix) for button, (trackIndex, sceneIndex) in self._bmatrix.iterbuttons(): if button: scene = self._session.scene(sceneIndex) clip_slot = scene.clip_slot(trackIndex) clip_slot.set_launch_button(button) clip_slot.set_triggered_to_play_value(1) clip_slot.set_triggered_to_record_value(1) clip_slot.set_started_value(1) clip_slot.set_recording_value(1) clip_slot.set_stopped_value(1) for sindex in range(self._session.height()): scene = self._session.scene(sindex) for cindex in range(self._session.width()): clip = scene.clip_slot(cindex) clip.set_modifier(self) clip.set_index((cindex, sindex)) self.set_highlighting_session_component(self._session) def _set_global_buttons(self): self._undo_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_UNDO_BUTTON) self._do_undo.subject = self._undo_button self._redo_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_REDO_BUTTON) self._do_redo.subject = self._redo_button self._shift_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_SHIFT_BUTTON) self._do_shift.subject = self._shift_button self._erase_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_ERASE_BUTTON) self._do_erase.subject = self._erase_button self._duplicate_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_DUPLICATE_BUTTON) self._do_duplicate.subject = self._duplicate_button self._selectback_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_BACKSEL_BUTTON) self._do_selectback.subject = self._selectback_button self._event_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_EVENTS_BUTTON) self._do_event_button.subject = self._event_button self.__arrange_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_ARRANGE_BUTTON, name='Arrange_button') self.__arrange_button.view_mode = VM_SESSION self._do_arrange.subject = self.__arrange_button def _setup_transport(self): is_momentary = True transport = TransportComponent() self.__play_button = StateButton(is_momentary, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_PLAY_BUTTON, name='Play_Button') self.__restart_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_RESTART_BUTTON) stop_button = StateButton(not is_momentary, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_STOP_BUTTON, name='Stop_Button') self._rec_button = StateButton(is_momentary, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_RECORD_BUTTON, name='Record_Button') metrononme_button = StateButton(is_momentary, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_METRONOME_BUTTON, name='Metronome_Button') self._song_follow_button = StateButton(is_momentary, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_FOLLOW_BUTTON, name='Follow_Button') self._do_rec_button.subject = self._rec_button if self._has_stop_button: transport.set_play_button(self.__play_button) transport.set_stop_button(stop_button) else: self._hand_play_pressed.subject = self.__play_button self._listen_playing.subject = self.song() self._stopall_button = StateButton(True, MIDI_CC_TYPE, 0, CC_ALL_BUTTON) self._do_stop_all.subject = self._stopall_button self._auto_button = StateButton(True, MIDI_CC_TYPE, 0, CC_AUTO_BUTTON, name='Auto_Button') self._handle_automation_record.subject = self._auto_button self._listen_automation_record.subject = self.song() self._handle_restart_button.subject = self.__restart_button self._handle_follows_button.subject = self._song_follow_button self._follow_song_changed.subject = self.song().view transport.set_metronome_button(metrononme_button) self._listen_overdub.subject = self.song() def toggle_nav_mode(self): self._session.switch_step_advance() self.show_message(' View Navigation in steps of ' + str(self._session.get_step_advance())) def _update_hardware(self): self._session.update() self.update_undo_redo(True) self.__track_buttons.refresh_state() self._encoder_section.refresh_state() def refresh_state(self): ControlSurface.refresh_state(self) self._update_hardware() def _send_midi(self, midi_bytes, **keys): self._c_ref.send_midi(midi_bytes) return True def timed_display(self, text, grid): self.timed_message(grid, text, False) def init_text_display(self): pass def _on_selected_track_changed(self): super(Maschine, self)._on_selected_track_changed() self.set_controlled_track(self.song().view.selected_track) self._on_devices_changed.subject = self.song().view.selected_track @subject_slot('devices') def _on_devices_changed(self): pass def update(self): self.set_feedback_channels(FEEDBACK_CHANNELS) super(Maschine, self).update() def is_monochrome(self): return False def has_separate_pad_mode_buttons(self): return False def get_session(self): return self._session def handle_track_select(self, track): if not track: return if self.is_delete_down(): index = vindexof(self.song().tracks, track) self.song().delete_track(index) else: if self.is_duplicate_down(): index = vindexof(self.song().tracks, track) self.song().duplicate_track(index) else: if self.is_select_down(): if track.is_foldable: track.fold_state = track.fold_state == 0 and 1 or 0 else: if self.is_shift_down(): self.song().view.selected_track = track else: self.song().view.selected_track = track arm_exclusive(self.song(), track) def get_button_matrix(self): return self._bmatrix def deassign_matrix(self): for scene_index in range(4): scene = self._session.scene(scene_index) for track_index in range(4): clip_slot = scene.clip_slot(track_index) clip_slot.set_launch_button(None) return def update_display(self): with self.component_guard(): with self._is_sending_scheduled_messages(): self._task_group.update(0.1) self._main_mode_container.notify(self.blink_state) self.__track_buttons.notify(self.blink_state) self.blink_state = (self.blink_state + 1) % 4 self.display_task.tick() self.update_undo_redo(False) if self.blink_state == 0: self.update_arrange_button() def handle_notify(self, blink_state): pass def __update_tracks(self, track_offset): self.__track_buttons.assign_buttons() self._encoder_section.handle_offset_changed() def update_undo_redo(self, force=False): if force: self.__undo_state = self.song().can_undo self.__redo_state = self.song().can_redo if self.song().can_undo != self.__undo_state: self.__undo_state = self.song().can_undo self._undo_button.send_value(self.__undo_state == 1 and 127 or 0) if self.song().can_redo != self.__redo_state: self.__redo_state = self.song().can_redo self._redo_button.send_value(self.__redo_state == 1 and 127 or 0) def navigate(self, nav_dir, modifier, alt_modifier=False): self._main_mode_container.navigate(nav_dir, modifier, alt_modifier) self._encoder_section.navigate(nav_dir, modifier, alt_modifier) def handle_edit_action(self, grid, scale=None): if not self.is_shift_down(): return if grid == (0, 3): if self.song().can_undo == 1: self.song().undo() self.show_message(str('UNDO')) else: if grid == (1, 3): if self.song().can_redo == 1: self.song().redo() self.show_message(str('REDO')) else: if grid == (2, 3): clip = self.song().view.detail_clip if clip and clip.is_midi_clip: clip.select_all_notes() else: if grid == (3, 3): clip = self.song().view.detail_clip if clip and clip.is_midi_clip: clip.deselect_all_notes() else: if grid == (0, 2) or grid == (1, 2): clip = self.song().view.detail_clip if clip: clip.quantize( QUANT_CONST[self.__quantize_setting], grid[0] == 0 and 1.0 or 0.5) self.show_message( 'Quantize Clip ' + clip.name + ' by ' + QUANT_STRING[self.__quantize_setting]) else: if grid == (2, 2): clip = self.song().view.detail_clip if clip and clip.is_midi_clip: self.application().view.show_view( 'Detail/Clip') nudge_notes_in_clip( clip, clip.get_selected_notes(), self.__nudge_value * -1) else: if grid == (3, 2): clip = self.song().view.detail_clip if clip and clip.is_midi_clip: self.application().view.show_view( 'Detail/Clip') nudge_notes_in_clip( clip, clip.get_selected_notes(), self.__nudge_value) else: if grid == (0, 1): clip = self.song().view.detail_clip if clip and clip.is_midi_clip: clip.replace_selected_notes( tuple([])) else: if grid == (1, 1): clip = self.song().view.detail_clip if clip: clip.has_envelopes and clip.clear_all_envelopes( ) else: if grid[1] == 0: clip = self.song( ).view.detail_clip if clip and clip.is_midi_clip: track = clip.canonical_parent.canonical_parent drum_device = find_drum_device( track) if not drum_device: notes = clip.get_selected_notes( ) transpose_notes_in_clip( clip, notes, TRANSPOSE[grid[0]], None) return @subject_slot('is_playing') def _listen_playing(self): if self.song().is_playing: self.__play_button.set_display_value(127, True) else: self.__play_button.set_display_value(0, True) @subject_slot('value') def _hand_play_pressed(self, value): if value != 0: if self.song().is_playing: if self.is_shift_down(): self.song().start_playing() else: self.song().stop_playing() else: self.song().start_playing() @subject_slot('value') def _do_undo(self, value): if value != 0: if self.use_layered_buttons() and self.is_shift_down(): if self.song().can_redo == 1: self.song().redo() self.show_message(str('REDO')) elif self.song().can_undo == 1: self.song().undo() self.show_message(str('UNDO')) @subject_slot('value') def _do_redo(self, value): if value != 0: if self.song().can_redo == 1: self.song().redo() self.show_message(str('REDO')) def handle_modifier(self, value): self._main_mode_container.handle_modifier(value) self._encoder_section.notify_shift(value) def notify_shift(self, value): self.__shift_down = value self.handle_modifier(self.get_modifier_state()) @subject_slot('value') def _do_shift(self, value): self._shift_button.send_value(value) self.__shift_down = value > 0 self.handle_modifier(self.get_modifier_state()) @subject_slot('value') def _do_erase(self, value): self._erase_button.send_value(value) self.__delete_down = value > 0 @subject_slot('value') def _do_duplicate(self, value): self._duplicate_button.send_value(value) self.__duplicate_down = value > 0 @subject_slot('value') def _do_selectback(self, value): self._selectback_button.send_value(value) self.__select_down = value > 0 @subject_slot('overdub') def _listen_overdub(self): self._rec_button.set_display_value(self.song().overdub and 127 or 0, True) @subject_slot('value') def _do_rec_button(self, value): if self.is_shift_down(): if value != 0: self.song().overdub = not self.song().overdub else: self.invoke_rec() def invoke_rec(self): slot = self.song().view.highlighted_clip_slot if slot == None: return if slot.controls_other_clips: slot.fire() else: if slot.has_clip: track = slot.canonical_parent if track.can_be_armed: arm_exclusive(self.song(), track) self.song().overdub = True slot.fire() else: track = slot.canonical_parent if track.can_be_armed: arm_exclusive(self.song(), track) slot.fire() return @subject_slot('value') def _do_fire_button(self, value): assert self._fire_button != None assert value in range(128) if value != 0: if self.is_shift_down(): self.song().tap_tempo() else: clip_slot = self.song().view.highlighted_clip_slot if clip_slot: clip_slot.fire() return @subject_slot('value') def _do_stop_all(self, value): self._do_stop_all.send_value(value) if value != 0: if self.is_shift_down(): self.song().stop_all_clips(0) else: self.song().stop_all_clips(1) @subject_slot('value') def _do_test(self, value): pass @subject_slot('value') def _do_arrange(self, value): if value != 0: appv = self.application().view if appv.is_view_visible('Arranger'): self.application().view.show_view('Session') else: self.application().view.show_view('Arranger') self.update_arrange_button() def update_arrange_button(self): appv = self.application().view if appv.is_view_visible('Arranger'): if self.__arrange_button.view_mode == VM_SESSION: self.__arrange_button.set_display_value(127, True) self.__arrange_button.view_mode = VM_ARRANGE else: if self.__arrange_button.view_mode == VM_ARRANGE: self.__arrange_button.set_display_value(0, True) self.__arrange_button.view_mode = VM_SESSION @subject_slot('session_automation_record') def _listen_automation_record(self): self._auto_button.set_display_value( self.song().session_automation_record and 127 or 0, True) @subject_slot('value') def _do_event_button(self, value): self._event_button.send_value(value) if value != 0: if self.is_shift_down(): clip = self.song().view.detail_clip if clip and clip.is_midi_clip: clip.select_all_notes() @subject_slot('value') def _handle_follows_button(self, value): if value != 0: self.song().view.follow_song = not self.song().view.follow_song @subject_slot('follow_song') def _follow_song_changed(self): self._song_follow_button.send_value( self.song().view.follow_song and 127 or 0) @subject_slot('value') def _handle_restart_button(self, value): self.__restart_button.send_value(value) if value != 0: self.song().stop_playing() self.song().stop_playing() @subject_slot('value') def _handle_automation_record(self, value): if value > 0: self.song().session_automation_record = not self.song( ).session_automation_record def handle_edit(self, clipslotcomp, value): self._main_mode_container.handle_edit(clipslotcomp, value) def do_midi_launch(self, clipslotcomp, value): if self.is_shift_down(): clipslotcomp._do_launch_clip(value) else: if clipslotcomp._clip_slot.has_clip: clipslotcomp._do_launch_clip(value) else: clipslotcomp._clip_slot.create_clip(DEFAULT_CLIP_INIT_SIZE) clipslotcomp._do_launch_clip(value) def is_select_down(self): return self.__select_down def is_shift_down(self): return self.__shift_down def is_delete_down(self): return self.__delete_down def is_duplicate_down(self): return self.__duplicate_down def get_modifier_state(self): return (self.__shift_down and MODIFIER_SHIFT) | ( self.__select_down and MODIFIER_SELECT) | (self.__delete_down and MODIFIER_DELETE) | ( self.__duplicate_down and MODIFIER_DUPLICATE) def get_track_buttons(self): return self.__track_buttons def in_spec_mode(self): """ If Some Modifier is being held down. This concerns only the grid matrix. In Cases where Shift + Pad Button do not call a function (Maschine Studio only) Nothing should happen just like with the Maschine Software """ return self.__shift_down or self.__delete_down or self.__duplicate_down def use_shift_matrix(self): return False def use_layered_buttons(self): return False def to_color_edit_mode(self, active): pass def clear_display_all(self): self.send_to_display('', 0) self.send_to_display('', 1) self.send_to_display('', 2) self.send_to_display('', 3) def clear_display(self, grid): if self._timed_text: self.send_to_display(self._timed_text, grid) else: self.send_to_display('', grid) def timed_message(self, grid, text, hold=False): if USE_DISPLAY == False: self.show_message(text) else: if not self.display_task.active(grid): self._timed_text = self._diplay_cache[grid] self.display_task.set_func(self.clear_display, grid) self.send_to_display(text, grid) if hold: self.display_task.hold() self.display_task.start() def timed_message_release(self): self.display_task.release() def update_bank_display(self): if USE_DISPLAY: name, bank = self._device._current_bank_details() if self._display_device_param: prms = len(bank) d1 = '' for i in range(4): parm = bank[i] if parm: name = parm.name d1 += name[:6] + (i < 3 and '|' or '') else: d1 += ' ' + (i < 3 and '|' or '') self.send_to_display(d1, 2) d1 = '' for i in range(4): parm = bank[i + 4] if parm: name = parm.name d1 += name[:6] + (i < 3 and '|' or '') else: d1 += ' ' + (i < 3 and '|' or '') self.send_to_display(d1, 4) else: self.timed_message(2, 'Bank: ' + name) def display_parameters(self, paramlist): if USE_DISPLAY == False: return def send_to_display(self, text, grid=0, force=False): if USE_DISPLAY == False: return if not force and self._diplay_cache[grid] == text: return self._diplay_cache[grid] = text if len(text) > 28: text = text[:27] msgsysex = [240, 0, 0, 102, 23, 18, min(grid, 3) * 28] filled = text.ljust(28) for c in filled: msgsysex.append(ord(c)) msgsysex.append(247) self._send_midi(tuple(msgsysex)) def cleanup(self): pass def disconnect(self): self._pre_serialize() self.clear_display_all() for button, (track_index, _) in self._bmatrix.iterbuttons(): if button: button.turn_off() time.sleep(0.2) self._active = False self._suppress_send_midi = True super(Maschine, self).disconnect() return
def _setup_transport(self): is_momentary = True transport = TransportComponent() studiotransport = MaschineTransport() playButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 108) stopButton = StateButton(not is_momentary, MIDI_CC_TYPE, 0, 110) recordButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 109) overdubButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 107) metrononmeButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 104) eventRecButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 98) playButton.name = 'Play' stopButton.name = 'Stop' recordButton.name = 'Record' overdubButton.name = 'Overdub' metrononmeButton.name = 'Metronome' transport.set_play_button(playButton) transport.set_stop_button(stopButton) transport.set_record_button(recordButton) transport.set_overdub_button(overdubButton) transport.set_metronome_button(metrononmeButton) studiotransport.set_session_auto_button(eventRecButton) studiotransport.set_arrangement_overdub_button( StateButton(is_momentary, MIDI_CC_TYPE, 0, 106)) studiotransport.set_back_arrange_button( StateButton(is_momentary, MIDI_CC_TYPE, 0, 105)) transport.set_nudge_buttons( StateButton(is_momentary, MIDI_CC_TYPE, 1, 51), StateButton(is_momentary, MIDI_CC_TYPE, 1, 50)) punchinbutton = ToggleButton(MIDI_CC_TYPE, 1, 52) punchoutbutton = ToggleButton(MIDI_CC_TYPE, 1, 53) punchinbutton.name = 'Punch In' punchoutbutton.name = 'Punch Out' transport.set_punch_buttons(punchinbutton, punchoutbutton) transport.set_loop_button( StateButton(is_momentary, MIDI_CC_TYPE, 1, 54)) self.song_follow_button = ButtonElement(True, MIDI_CC_TYPE, 2, 98) self._do_song_follow.subject = self.song_follow_button self._song_follow_changed.subject = self.song().view self._song_follow_changed() self.transp_ff_button = ButtonElement(True, MIDI_CC_TYPE, 1, 59) self.transp_rw_button = ButtonElement(True, MIDI_CC_TYPE, 1, 58) transport.set_seek_buttons(self.transp_ff_button, self.transp_rw_button) self.xfadeKnob = SliderElement(MIDI_CC_TYPE, 1, 105) self.xfadeKnob.connect_to( self.song().master_track.mixer_device.crossfader) self.master_knob = SliderElement(MIDI_CC_TYPE, 0, 99) self.master_knob.connect_to( self.song().master_track.mixer_device.volume) self.tap_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 88) self._do_tap_tempo.subject = self.tap_button self.cue_add_delete_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 55) self.cue_prev_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 56) self.cue_next_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 57) self._do_toggle_cue.subject = self.cue_add_delete_button self._do_toggle_prev_cue.subject = self.cue_prev_button self._do_toggle_next_cue.subject = self.cue_next_button
class MaschineMk3(Maschine): """Control Script for Maschine Studio""" __module__ = __name__ _gated_buttons = [] def __init__(self, c_instance): super(MaschineMk3, self).__init__(c_instance) def init_type(self): """ Needs to be overridden by specific version to define certain specialized behavior """ self._has_stop_button = True def _init_maschine(self): self.__jog_wheel_section = JogWheelSection() self.__metro_tap_button = StateButton(True, MIDI_CC_TYPE, BASE_CONTROL_CHANNEL, CC_TAP_METRO_BUTTON, name='Tap_metro_button') self._do_tap_metro.subject = self.__metro_tap_button self.update_arrange_button() def _final_init(self): debug_out('########## LIVE 9 MASCHINE Mk3 V 0.50 ############# ') super(MaschineMk3, self)._final_init() def use_shift_matrix(self): return True def has_separate_pad_mode_buttons(self): return True def handle_sysex(self, midi_bytes): if len(midi_bytes) > 11 and midi_bytes[0:10] == (240, 0, 33, 9, 22, 0, 77, 80, 0, 1): msg, value = midi_bytes[10:12] if msg == 70: self.refresh_state() self.notify_shift(True) elif msg == 77: self.notify_shift(value == 1) def _click_measure(self): pass def preferences_name(self): return 'MaschineMk3' def apply_preferences(self): super(MaschineMk3, self).apply_preferences() def store_preferences(self): super(MaschineMk3, self).store_preferences() def _send_midi(self, midi_bytes, **keys): self._c_ref.send_midi(midi_bytes) time.sleep(0.001) return True @subject_slot('value') def _do_tap_metro(self, value): if self.is_shift_down(): if value == 0: return self.song().metronome = not self.song().metronome else: if value != 0: self.song().tap_tempo() self.__metro_tap_button.send_value(value) @subject_slot('value') def _do_stop_all(self, value): if value != 0: if self.isShiftDown(): self.song().stop_all_clips(0) else: self.song().stop_all_clips(1) def to_color_edit_mode(self, active): if self._editsection.is_color_edit() != active: self._editsection.set_color_edit(active) def cleanup(self): for button in self._gated_buttons: button.switch_off()
class Maschine(ControlSurface): """Basic Control Script for All Maschine Modell Mikro, Mikro Mk2, Mk1, Mk2, Studio""" __module__ = __name__ def __init__(self, c_instance): super(Maschine, self).__init__(c_instance) with self.component_guard(): register_sender(self) self._diplay_cache = ['', '', '', ''] self._suppress_send_midi = True is_momentary = True self._c_ref = c_instance self.display_task = DisplayTask() self._challenge = Live.Application.get_random_int( 0, 400000000) & 2139062143 self._active = False self._midi_pause_count = 0 self.blink_state = 0 self.send_slider_index = 0 self.nav_index = 0 self.arm_selected_track = False self.undo_state = 0 self.redo_state = 0 self._set_suppress_rebuild_requests(True) self._modeselect = ModeSelector(self.is_monochrome()) self._device = self._set_up_device_control() self._set_up_session(self._modeselect) self._set_up_mixer() self._setup_transport() self._set_global_buttons() self._editsection = EditSection() self._editsection.connect_session(self._session) self._editsection.set_mode_selector(self._modeselect) self._session.set_mode(self._modeselect._clip_mode) self._audio_clip_editor = AudioClipEditComponent() self._note_repeater = NoteRepeatComponent(c_instance.note_repeat) self._midi_edit = MidiEditSection() self._init_settings() self._init_maschine() self.set_highlighting_session_component(self._session) self.set_pad_translations(PAD_TRANSLATIONS) self._on_selected_track_changed() self.set_up_function_buttons() self.show_message(str('')) self.request_rebuild_midi_map() self._set_suppress_rebuild_requests(False) self._active = True self._display_device_param = False self.set_feedback_channels(FEEDBACK_CHANNELS) self._final_init() self._suppress_send_midi = False self.apply_preferences() self.init_text_display() self._on_appointed_device_changed.subject = self.song() def _init_maschine(self): pass def _final_init(self): pass def create_pad_button(self, scene_index, track_index, color_source): pass def create_gated_button(self, identifier, hue): pass def apply_preferences(self): pref_dict = self._pref_dict if 'step_advance' in pref_dict: self._session.set_step_advance(pref_dict['step_advance']) if 'solo_exclusive' in pref_dict: self._modeselect.set_solo_exclusive(pref_dict['solo_exclusive']) else: self._modeselect.set_solo_exclusive(True) if 'arm_exclusive' in pref_dict: self._modeselect.set_arm_exclusive(pref_dict['arm_exclusive']) else: self._modeselect.set_arm_exclusive(True) if 'quantize_val' in pref_dict: self._editsection.quantize = pref_dict['quantize_val'] else: self._editsection.quantize = 5 if 'initial_cliplen' in pref_dict: self._editsection.initial_clip_len = pref_dict['initial_cliplen'] else: self._editsection.initial_clip_len = 4.0 if 'auto_arm_sel_track' in pref_dict: self.arm_selected_track = pref_dict['auto_arm_sel_track'] else: self.arm_selected_track = False if 'note_color_mode' in pref_dict: self._modeselect._pad_mode._note_display_mode = pref_dict[ 'note_color_mode'] else: self._modeselect._pad_mode._note_display_mode = ND_KEYBOARD1 self._pref_dict[ 'note_color_mode'] = self._modeselect._pad_mode._note_display_mode self.set_sel_arm_button.send_value( self.arm_selected_track and 127 or 0, True) self._note_repeater.recall_values(self._pref_dict) def store_preferences(self): self._pref_dict['step_advance'] = self._session.get_step_advance() self._pref_dict['solo_exclusive'] = self._modeselect.is_solo_exclusive( ) self._pref_dict['arm_exclusive'] = self._modeselect.is_arm_exclusive() self._pref_dict['quantize_val'] = self._editsection.quantize self._pref_dict['initial_cliplen'] = self._editsection.initial_clip_len self._pref_dict['auto_arm_sel_track'] = self.arm_selected_track self._pref_dict[ 'note_color_mode'] = self._modeselect._pad_mode._note_display_mode self._note_repeater.store_values(self._pref_dict) def _init_settings(self): from pickle import loads, dumps from encodings import ascii nop(ascii) preferences = self._c_instance.preferences(self.preferences_name()) self._pref_dict = {} try: self._pref_dict = loads(str(preferences)) except Exception: pass pref_dict = self._pref_dict preferences.set_serializer(lambda: dumps(pref_dict)) def preferences_name(self): return 'Maschine' def _pre_serialize(self): from pickle import dumps from encodings import ascii nop(ascii) preferences = self._c_instance.preferences('Maschine') self.store_preferences() dump = dumps(self._pref_dict) preferences.set_serializer(lambda: dump) def toggle_nav_mode(self): self._session.switch_step_advance() self.show_message(' View Navigation in steps of ' + str(self._session.get_step_advance())) def _set_up_session(self, mode_selector): is_momentary = True self._session = MaschineSessionComponent() self._session.set_color_manager(mode_selector.get_color_manager()) self.nav_buttons = (self.create_gated_button(92, COLOR_HUE_NAV), self.create_gated_button(81, COLOR_HUE_NAV), self.create_gated_button(93, COLOR_HUE_NAV), self.create_gated_button(91, COLOR_HUE_NAV)) self._session.set_scene_bank_buttons(self.nav_buttons[0], self.nav_buttons[1]) self._session.set_track_bank_buttons(self.nav_buttons[2], self.nav_buttons[3]) track_stop_buttons = [ StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, index + STOP_CC_OFF) for index in range(4) ] self._session.set_stop_track_clip_buttons(tuple(track_stop_buttons)) self._matrix = [] self._bmatrix = ButtonMatrixElement() for scene_index in range(4): button_row = [] for track_index in range(4): button = self.create_pad_button(scene_index, track_index, mode_selector) button_row.append(button) self._matrix.append(tuple(button_row)) self._bmatrix.add_row(tuple(button_row)) self._session.set_matrix(self._matrix) for button, (track_index, scene_index) in self._bmatrix.iterbuttons(): if button: scene = self._session.scene(scene_index) clip_slot = scene.clip_slot(track_index) clip_slot.set_launch_button(button) clip_slot.set_triggered_to_play_value(1) clip_slot.set_triggered_to_record_value(1) clip_slot.set_started_value(1) clip_slot.set_recording_value(1) clip_slot.set_stopped_value(1) self._session._link() def _set_up_mixer(self): is_momentary = True self._mixer = MaschineMixerComponent(8) self.send_sliders = [] for track in range(8): self.send_sliders.append( SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, SEND_CC_OFF + track)) for track in range(8): strip = self._mixer.channel_strip(track) strip.set_arm_button( StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, ARM_CC_OFF + track)) strip.set_solo_button( StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, SOLO_CC_OFF + track)) strip.set_mute_button( StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, MUTE_CC_OFF + track)) strip.set_volume_control( SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, LEVEL_CC_OFF + track)) strip.set_pan_control( SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, PAN_CC_OFF + track)) strip.set_select_button( StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, SELECT_CC_OFF + track)) st = tuple([self.send_sliders[track]]) strip.set_send_controls(st) self.send_slider_toggle_button = StateButton(False, MIDI_CC_TYPE, 0, 90) self._do_toggle_send.subject = self.send_slider_toggle_button self._session.set_mixer(self._mixer) def _set_global_buttons(self): is_momentary = True self._undo_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 85) self._do_undo.subject = self._undo_button self._redo_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 87) self._do_redo.subject = self._redo_button self._stop_all_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 111) self._do_stop_all.subject = self._stop_all_button self._toggle_detail_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1, 121) self._action_toogle_detail_view.subject = self._toggle_detail_button self._fire_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 9) self._do_fire_button.subject = self._fire_button self._g_clear_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1, 106) self._hold_clear_action.subject = self._g_clear_button self._g_duplicate_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1, 107) self._hold_duplicate_action.subject = self._g_duplicate_button self.track_left_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 120) self.track_right_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 121) self.set_sel_arm_button = StateButton(is_momentary, MIDI_CC_TYPE, 2, 56) self._reenable_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1, 120) self._do_auto_reenable.subject = self._reenable_button self._on_change_reenabled.subject = self.song() self._on_change_reenabled() self._a_trk_left.subject = self.track_left_button self._a_trk_right.subject = self.track_right_button self._a_sel_arm.subject = self.set_sel_arm_button def _set_up_device_control(self): is_momentary = True device = MaschineDeviceComponent() param_controls = [] for index in range(8): param_controls.append( SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_CC_OFF + index)) device.set_parameter_controls(tuple(param_controls)) self.device_control = param_controls device.set_on_off_button( StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF)) device.set_bank_nav_buttons( StateButton(is_momentary, MIDI_CC_TYPE, 3, 104), ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 105)) self._device_nav_button_left = StateButton(is_momentary, MIDI_CC_TYPE, 3, 106) self._device_nav_button_right = StateButton(is_momentary, MIDI_CC_TYPE, 3, 107) self._navigate_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 127) self._nav_value_left.subject = self._device_nav_button_left self._nav_value_right.subject = self._device_nav_button_right self._do_focus_navigate.subject = self._navigate_button self.set_device_component(device) return device def _setup_transport(self): is_momentary = True transport = TransportComponent() studiotransport = MaschineTransport() playButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 108) stopButton = StateButton(not is_momentary, MIDI_CC_TYPE, 0, 110) recordButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 109) overdubButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 107) metrononmeButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 104) eventRecButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 98) playButton.name = 'Play' stopButton.name = 'Stop' recordButton.name = 'Record' overdubButton.name = 'Overdub' metrononmeButton.name = 'Metronome' transport.set_play_button(playButton) transport.set_stop_button(stopButton) transport.set_record_button(recordButton) transport.set_overdub_button(overdubButton) transport.set_metronome_button(metrononmeButton) studiotransport.set_session_auto_button(eventRecButton) studiotransport.set_arrangement_overdub_button( StateButton(is_momentary, MIDI_CC_TYPE, 0, 106)) studiotransport.set_back_arrange_button( StateButton(is_momentary, MIDI_CC_TYPE, 0, 105)) transport.set_nudge_buttons( StateButton(is_momentary, MIDI_CC_TYPE, 1, 51), StateButton(is_momentary, MIDI_CC_TYPE, 1, 50)) punchinbutton = ToggleButton(MIDI_CC_TYPE, 1, 52) punchoutbutton = ToggleButton(MIDI_CC_TYPE, 1, 53) punchinbutton.name = 'Punch In' punchoutbutton.name = 'Punch Out' transport.set_punch_buttons(punchinbutton, punchoutbutton) transport.set_loop_button( StateButton(is_momentary, MIDI_CC_TYPE, 1, 54)) self.song_follow_button = ButtonElement(True, MIDI_CC_TYPE, 2, 98) self._do_song_follow.subject = self.song_follow_button self._song_follow_changed.subject = self.song().view self._song_follow_changed() self.transp_ff_button = ButtonElement(True, MIDI_CC_TYPE, 1, 59) self.transp_rw_button = ButtonElement(True, MIDI_CC_TYPE, 1, 58) transport.set_seek_buttons(self.transp_ff_button, self.transp_rw_button) self.xfadeKnob = SliderElement(MIDI_CC_TYPE, 1, 105) self.xfadeKnob.connect_to( self.song().master_track.mixer_device.crossfader) self.master_knob = SliderElement(MIDI_CC_TYPE, 0, 99) self.master_knob.connect_to( self.song().master_track.mixer_device.volume) self.tap_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 88) self._do_tap_tempo.subject = self.tap_button self.cue_add_delete_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 55) self.cue_prev_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 56) self.cue_next_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 57) self._do_toggle_cue.subject = self.cue_add_delete_button self._do_toggle_prev_cue.subject = self.cue_prev_button self._do_toggle_next_cue.subject = self.cue_next_button def set_up_function_buttons(self): is_momentary = True self.keycolor_mod_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 73) self._do_key_color.subject = self.keycolor_mod_button self._update_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 86) self._do_update_display.subject = self._update_button @subject_slot('appointed_device') def _on_appointed_device_changed(self): self._modeselect._device_changed() def _update_hardware(self): self._session.update() self._modeselect.refresh() self.update_undo_redo(True) def refresh_state(self): ControlSurface.refresh_state(self) self._update_hardware() def _send_midi(self, midi_bytes, **keys): self._c_ref.send_midi(midi_bytes) return True def init_text_display(self): if USE_DISPLAY: self._modeselect._pad_mode.update_text_display() def _on_selected_track_changed(self): super(Maschine, self)._on_selected_track_changed() self.set_controlled_track(self.song().view.selected_track) self._on_devices_changed.subject = self.song().view.selected_track @subject_slot('devices') def _on_devices_changed(self): pass def update(self): self.set_feedback_channels(FEEDBACK_CHANNELS) super(Maschine, self).update() def is_monochrome(self): return False def _deassign_matrix(self): for scene_index in range(4): scene = self._session.scene(scene_index) for track_index in range(4): clip_slot = scene.clip_slot(track_index) clip_slot.set_launch_button(None) return def update_display(self): with self.component_guard(): with self._is_sending_scheduled_messages(): self._task_group.update(0.1) self._modeselect.notify(self.blink_state) self.blink_state = (self.blink_state + 1) % 4 self.display_task.tick() self.update_undo_redo(False) def update_undo_redo(self, force=False): if force: self.undo_state = self.song().can_undo self.redo_state = self.song().can_redo if self.song().can_undo != self.undo_state: self.undo_state = self.song().can_undo self._undo_button.send_value(self.undo_state == 1 and 127 or 0) if self.song().can_redo != self.redo_state: self.redo_state = self.song().can_redo self._redo_button.send_value(self.redo_state == 1 and 127 or 0) def adjust_loop_start(self, delta): loopval = self.song().loop_start self.song().loop_start = min(self.song().song_length, max(0, loopval + delta)) def adjust_loop_length(self, delta): loopval = self.song().loop_length self.song().loop_length = min(self.song().song_length, max(abs(delta), loopval + delta)) def _do_armsolo_mode(self, value): pass @subject_slot('value') def _do_fire_button(self, value): assert self._fire_button != None assert value in range(128) if value != 0: if self.isShiftDown(): self.song().tap_tempo() else: clip_slot = self.song().view.highlighted_clip_slot if clip_slot: clip_slot.fire() return @subject_slot('value') def _do_undo(self, value): if value != 0: if self.use_layered_buttons() and self.isShiftDown(): if self.song().can_redo == 1: self.song().redo() self.show_message(str('REDO')) elif self.song().can_undo == 1: self.song().undo() self.show_message(str('UNDO')) @subject_slot('value') def _do_redo(self, value): if value != 0: if self.song().can_redo == 1: self.song().redo() self.show_message(str('REDO')) @subject_slot('value') def _do_stop_all(self, value): if value != 0: if self.use_layered_buttons() and self.isShiftDown(): self.song().stop_all_clips(0) else: self.song().stop_all_clips(1) def isShiftDown(self): return self._editsection.isShiftdown() def modifiers(self): return self._editsection.modifiers() def use_layered_buttons(self): return False def _handle_base_note(self, diff): self._modeselect._pad_mode.inc_base_note(diff) def _handle_octave(self, diff): self._modeselect._pad_mode.inc_octave(diff) octave_val = self._modeselect._pad_mode def _handle_scale(self, diff): self._modeselect._pad_mode.inc_scale(diff) @subject_slot('value') def _do_update_display(self, value): if value != 0: self.refresh_state() @subject_slot('value') def _do_key_color(self, value): assert value in range(128) if value != 0: self._modeselect._pad_mode.step_key_color_mode() @subject_slot('value') def _do_tap_tempo(self, value): assert value in range(128) if value != 0: self.song().tap_tempo() @subject_slot('value') def _do_toggle_cue(self, value): assert value in range(128) if value != 0: self.song().set_or_delete_cue() @subject_slot('value') def _do_toggle_prev_cue(self, value): assert value in range(128) if value != 0: self.song().jump_to_prev_cue() @subject_slot('value') def _do_toggle_next_cue(self, value): assert value in range(128) if value != 0: self.song().jump_to_next_cue() @subject_slot('value') def _do_toggle_send(self, value): assert value in range(128) if self.isShiftDown(): if value != 0: self.refresh_state() self.show_message('Refresh Display') else: nr_of_tracks = len(self.song().return_tracks) if value == 0 or nr_of_tracks < 1: return prev = self.send_slider_index self.send_slider_index += 1 if self.send_slider_index >= nr_of_tracks: self.send_slider_index = 0 self.show_message(' Set Send ' + str(SENDS[self.send_slider_index])) self.timed_message( 2, ' Set Send ' + str(SENDS[self.send_slider_index])) if prev != self.send_slider_index: for track in range(8): strip = self._mixer.channel_strip(track) slider_list = [] for index in range(self.send_slider_index + 1): if index < self.send_slider_index - 1: slider_list.append(None) else: slider_list.append(self.send_sliders[track]) strip.set_send_controls(tuple(slider_list)) return @subject_slot('value') def _a_trk_left(self, value): assert value in range(128) if value != 0: if self.application().view.is_view_visible('Session'): direction = Live.Application.Application.View.NavDirection.left self.application().view.scroll_view(direction, 'Session', True) track = self.song().view.selected_track self.timed_message(2, 'T:' + track.name, False) if self.arm_selected_track and track.can_be_armed: arm_exclusive(self.song(), track) @subject_slot('value') def _a_trk_right(self, value): assert value in range(128) if value != 0: if self.application().view.is_view_visible('Session'): direction = Live.Application.Application.View.NavDirection.right self.application().view.scroll_view(direction, 'Session', True) track = self.song().view.selected_track self.timed_message(2, 'T:' + track.name, False) if self.arm_selected_track and track.can_be_armed: arm_exclusive(self.song(), track) @subject_slot('value') def _a_sel_arm(self, value): if value != 0: if self.arm_selected_track: self.arm_selected_track = False self.set_sel_arm_button.send_value(0, True) else: self.arm_selected_track = True self.set_sel_arm_button.send_value(127, True) @subject_slot('value') def _nav_value_left(self, value): assert self._device_nav_button_left != None assert value in range(128) modifier_pressed = True if value != 0: if not self.application().view.is_view_visible( 'Detail') or not self.application().view.is_view_visible( 'Detail/DeviceChain'): self.application().view.show_view('Detail') self.application().view.show_view('Detail/DeviceChain') else: direction = Live.Application.Application.View.NavDirection.left self.application().view.scroll_view(direction, 'Detail/DeviceChain', not modifier_pressed) return @subject_slot('value') def _nav_value_right(self, value): assert self._device_nav_button_right != None assert value in range(128) if value != 0: modifier_pressed = True if not self.application().view.is_view_visible( 'Detail') or not self.application().view.is_view_visible( 'Detail/DeviceChain'): self.application().view.show_view('Detail') self.application().view.show_view('Detail/DeviceChain') else: direction = Live.Application.Application.View.NavDirection.right self.application().view.scroll_view(direction, 'Detail/DeviceChain', not modifier_pressed) return @subject_slot('value') def _do_focus_navigate(self, value): assert self._navigate_button != None assert value in range(128) if value != 0: self.nav_index = (self.nav_index + 1) % len(VIEWS_ALL) self.application().view.focus_view(VIEWS_ALL[self.nav_index]) self.show_message('Focus on : ' + str(VIEWS_ALL[self.nav_index])) return def focus_clip_detail(self): self.application().view.focus_view('Detail/Clip') @subject_slot('follow_song') def _song_follow_changed(self): view = self.song().view if view.follow_song: self.song_follow_button.send_value(1, True) else: self.song_follow_button.send_value(0, True) @subject_slot('value') def _do_song_follow(self, value): if value != 0: view = self.song().view if view.follow_song: view.follow_song = False self.song_follow_button.send_value(0, True) else: view.follow_song = True self.song_follow_button.send_value(1, True) @subject_slot('value') def _hold_duplicate_action(self, value): if value != 0: pass @subject_slot('value') def _hold_clear_action(self, value): if value != 0: self._mixer.enter_clear_mode() self._device_component.enter_clear_mode() else: self._mixer.exit_clear_mode() self._device_component.exit_clear_mode() @subject_slot('value') def _action_toogle_main_view(self, value): if value != 0: appv = self.application().view if appv.is_view_visible('Arranger'): appv.show_view('Session') else: appv.show_view('Arranger') @subject_slot('value') def _action_toogle_detail_view(self, value): if value != 0: appv = self.application().view if self.isShiftDown(): if appv.is_view_visible('Arranger'): appv.show_view('Session') else: appv.show_view('Arranger') elif appv.is_view_visible('Detail/Clip'): appv.show_view('Detail/DeviceChain') else: appv.show_view('Detail/Clip') @subject_slot('re_enable_automation_enabled') def _on_change_reenabled(self): if self.song().re_enable_automation_enabled: self._reenable_button.turn_on() else: self._reenable_button.turn_off() @subject_slot('value') def _do_auto_reenable(self, value): if value != 0: self.song().re_enable_automation() def to_color_edit_mode(self, active): pass def clear_display_all(self): self.send_to_display('', 0) self.send_to_display('', 1) self.send_to_display('', 2) self.send_to_display('', 3) def clear_display(self, grid): self.send_to_display('', grid) def timed_message(self, grid, text, hold=False): if USE_DISPLAY == False: self.show_message(text) else: self.display_task.set_func(self.clear_display, grid) self.send_to_display(text, grid) if hold: self.display_task.hold() self.display_task.start() def timed_message_release(self): self.display_task.release() def update_bank_display(self): if USE_DISPLAY: name, bank = self._device._current_bank_details() if self._display_device_param: prms = len(bank) d1 = '' for i in range(4): parm = bank[i] if parm: name = parm.name d1 += name[:6] + (i < 3 and '|' or '') else: d1 += ' ' + (i < 3 and '|' or '') self.send_to_display(d1, 2) d1 = '' for i in range(4): parm = bank[i + 4] if parm: name = parm.name d1 += name[:6] + (i < 3 and '|' or '') else: d1 += ' ' + (i < 3 and '|' or '') self.send_to_display(d1, 4) else: self.timed_message(2, 'Bank: ' + name) def display_parameters(self, paramlist): if USE_DISPLAY == False: return def send_to_display(self, text, grid=0): if USE_DISPLAY == False: return if self._diplay_cache[grid] == text: return self._diplay_cache[grid] = text if len(text) > 28: text = text[:27] msgsysex = [240, 0, 0, 102, 23, 18, min(grid, 3) * 28] filled = text.ljust(28) for c in filled: msgsysex.append(ord(c)) msgsysex.append(247) self._send_midi(tuple(msgsysex)) def cleanup(self): pass def disconnect(self): self._pre_serialize() self.clear_display_all() for button, (track_index, scene_index) in self._bmatrix.iterbuttons(): if button: button.send_color_direct(PColor.OFF[0]) time.sleep(0.2) self._active = False self._suppress_send_midi = True super(Maschine, self).disconnect() return
class JogWheelSection(CompoundComponent): def __init__(self, modeselector, editsection, *a, **k): super(CompoundComponent, self).__init__(*a, **k) self._modesel = modeselector self._editsection = editsection is_momentary = True self._do_push_button.subject = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 82) self._do_edit_slider.subject = SliderElement(MIDI_CC_TYPE, 1, 81) self._do_channel_slider.subject = SliderElement(MIDI_CC_TYPE, 1, 83) self._do_channel_button.subject = ButtonElement( is_momentary, MIDI_CC_TYPE, 1, 63) self._do_req_quantize.subject = SliderElement(MIDI_CC_TYPE, 1, 100) self._do_browse.subject = SliderElement(MIDI_CC_TYPE, 1, 84) self._do_tempo.subject = SliderElement(MIDI_CC_TYPE, 1, 101) self._do_volume.subject = SliderElement(MIDI_CC_TYPE, 1, 103) self._do_dedicated_rec_quantize.subject = SliderElement( MIDI_CC_TYPE, 2, 112) self._do_dedicated_clip_quantize.subject = SliderElement( MIDI_CC_TYPE, 2, 113) self.set_up_function_buttons() self._wheel_overide = None self.scrub_mode = True self.select_arm_mode = True self._push_down = False return def set_up_function_buttons(self): is_momentary = True self._do_octave_button.subject = StateButton(is_momentary, MIDI_CC_TYPE, 1, 70) self._do_scale_button.subject = StateButton(is_momentary, MIDI_CC_TYPE, 1, 71) self._do_note_button.subject = StateButton(is_momentary, MIDI_CC_TYPE, 1, 72) self._do_loop_mod.subject = StateButton(is_momentary, MIDI_CC_TYPE, 1, 69) self._color_edit_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 114) self._do_color_button.subject = self._color_edit_button self.scrub_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 2, 53) self._action_scrub_mode.subject = self.scrub_mode_button self._action_loop_button.subject = StateButton(is_momentary, MIDI_CC_TYPE, 2, 54) self._action_quant_button.subject = StateButton( is_momentary, MIDI_CC_TYPE, 2, 55) def set_overide(self, overide_callback): self._wheel_overide = overide_callback def reset_overide(self): self._wheel_overide = None if self._editsection.is_color_edit(): self._color_edit_button.send_value(0, True) self._editsection.knob_pad_action(False) self._editsection.set_color_edit(False) return def message(self, message): self.canonical_parent.show_message(message) def use_scrub_mode(self): return self.scrub_mode def set_scrub_mode(self, value): self.scrub_mode = value self.scrub_mode_button.send_value(value and 127 or 0) def modifier1(self): return self._push_down def modifier2(self): return self._editsection.isShiftdown() def modifier3(self): return self._editsection.isAltdown() @subject_slot('value') def _do_push_button(self, value): if value != 0: self._push_down = True else: self._push_down = False self._modesel.handle_push(value != 0) @subject_slot('value') def _action_scrub_mode(self, value): if value > 0: self.set_scrub_mode(not self.scrub_mode) def _action_set_quant(self, diff): val = self._editsection.quantize self._editsection.quantize = max(1, min(len(QUANT_CONST) - 1, val + diff)) self.canonical_parent.timed_message( 2, 'Quantize: ' + QUANT_STRING[self._editsection.quantize], True) def _action_init_loop(self, diff): val = self._editsection.initial_clip_len self._editsection.initial_clip_len = max(1.0, min(64.0, val + diff)) self.canonical_parent.timed_message( 2, 'Init Clip Len: ' + str(self._editsection.initial_clip_len), True) @subject_slot('value') def _action_loop_button(self, value): if value > 0: self.canonical_parent.timed_message( 2, 'Init Clip Len: ' + str(self._editsection.initial_clip_len), True) self.set_overide(self._action_init_loop) else: self.canonical_parent.timed_message_release() self.reset_overide() @subject_slot('value') def _action_quant_button(self, value): if value > 0: self.canonical_parent.timed_message( 2, 'Quantize: ' + QUANT_STRING[self._editsection.quantize], True) self.set_overide(self._action_set_quant) else: self.canonical_parent.timed_message_release() self.reset_overide() def chg_tempo(self, diff): self.song().tempo = max(20, min(999, self.song().tempo + diff)) self.canonical_parent.timed_message( 2, 'Tempo: ' + str(round(self.song().tempo, 2))) @subject_slot('value') def _do_edit_slider(self, value): diff = value == 127 and -1 or 1 if self._wheel_overide: self._wheel_overide(diff) else: self._modesel.navigate(diff, self.modifier1(), self.modifier2()) @subject_slot('value') def _do_channel_slider(self, value): if self._wheel_overide: self._wheel_overide(value == 127 and -1 or 1) else: song = self.song() if self.modifier1(): dir = value == 127 and -1 or 1 scenes = song.scenes scene = song.view.selected_scene sindex = vindexof(scenes, scene) sel_scene = sindex + dir if sel_scene >= 0 and sel_scene < len(scenes): song.view.selected_scene = scenes[sel_scene] else: if self.modifier2(): dir = value == 127 and Live.Application.Application.View.NavDirection.left or Live.Application.Application.View.NavDirection.right self.application().view.scroll_view( dir, 'Detail/DeviceChain', True) else: dir = value == 127 and -1 or 1 tracks = song.tracks direction = value == 127 and Live.Application.Application.View.NavDirection.left or Live.Application.Application.View.NavDirection.right self.application().view.scroll_view( direction, 'Session', True) if self.select_arm_mode: arm_exclusive(song) @subject_slot('value') def _do_channel_button(self, value): arm_exclusive(self.song()) @subject_slot('value') def _do_browse(self, value): diff = value == 127 and -1 or 1 if self._wheel_overide: self._wheel_overide(diff) else: step = 1.0 if self.modifier1(): step = 0.25 else: if self.modifier2(): step = 4.0 if self.scrub_mode: self.song().scrub_by(step * diff) else: self.song().jump_by(step * diff) @subject_slot('value') def _do_tempo(self, value): diff = value == 127 and -1 or 1 if self._wheel_overide: self._wheel_overide(diff) else: if self.modifier1(): self.chg_tempo(diff * 0.01) else: if self.modifier2(): self.chg_tempo(diff * 0.1) else: self.chg_tempo(diff) @subject_slot('value') def _do_req_quantize(self, value): diff = value == 127 and -1 or 1 if self._wheel_overide: self._wheel_overide(diff) else: song = self.song() if self.modifier2(): swing = song.swing_amount song.swing_amount = max(0.0, min(1, swing + diff * 0.01)) msg = 'Swing Amount: ' + str(int( song.swing_amount * 100)) + '%' self.message(msg) self.canonical_parent.timed_message(2, msg) else: if self.modifier1(): quant = song.clip_trigger_quantization song.clip_trigger_quantization = max( 0, min(13, quant + diff)) self.message('Clip Quantize ' + CLIQ_DESCR[song.clip_trigger_quantization]) self.canonical_parent.timed_message( 2, 'Clip Quantize: ' + CLIQ_DESCR[song.clip_trigger_quantization]) else: rec_quant = song.midi_recording_quantization index = QUANT_CONST.index(rec_quant) + diff if index >= 0 and index < len(QUANT_CONST): song.midi_recording_quantization = QUANT_CONST[index] self.message(QUANT_DESCR[index]) self.canonical_parent.timed_message( 2, 'Rec Quantize: ' + QUANT_STRING[index]) @subject_slot('value') def _do_dedicated_clip_quantize(self, value): diff = value == REL_KNOB_DOWN and -1 or 1 song = self.song() quant = song.clip_trigger_quantization song.clip_trigger_quantization = max(0, min(13, quant + diff)) self.message('Clip Quantize ' + CLIQ_DESCR[song.clip_trigger_quantization]) self.canonical_parent.timed_message( 2, 'Clip Quantize: ' + CLIQ_DESCR[song.clip_trigger_quantization]) @subject_slot('value') def _do_dedicated_rec_quantize(self, value): diff = value == REL_KNOB_DOWN and -1 or 1 song = self.song() rec_quant = song.midi_recording_quantization index = QUANT_CONST.index(rec_quant) + diff if index >= 0 and index < len(QUANT_CONST): song.midi_recording_quantization = QUANT_CONST[index] self.message(QUANT_DESCR[index]) self.canonical_parent.timed_message( 2, 'Rec Quantize: ' + QUANT_STRING[index]) @subject_slot('value') def _do_volume(self, value): diff = value == 127 and -1 or 1 if self._wheel_overide: self._wheel_overide(diff) else: if self.modifier2(): self.chg_cue(diff) else: self.chg_volume(diff) @subject_slot('value') def _do_color_button(self, value): if value > 0: if self._editsection.is_color_edit(): self.reset_overide() else: self._color_edit_button.send_value(1, True) self._editsection.knob_pad_action(True) self._editsection.set_color_edit(True) def set_color_edit(self, active): if active: self.set_overide(self._color_change) else: self.reset_overide() def _color_change(self, value): diff = value == 127 and -1 or 1 self._editsection.edit_colors(diff) @subject_slot('value') def _do_note_button(self, value): assert value in range(128) if value > 0: self.set_overide(self.canonical_parent._handle_base_note) else: self.reset_overide() @subject_slot('value') def _do_octave_button(self, value): assert value in range(128) if value > 0: self.set_overide(self.canonical_parent._handle_octave) else: self.reset_overide() @subject_slot('value') def _do_scale_button(self, value): assert value in range(128) if value > 0: self.set_overide(self.canonical_parent._handle_scale) else: self.reset_overide() def _handle_loop_mod(self, diff): factor = (self.modifier1() and 1.0 or 4.0) * diff if self.modifier2(): self.canonical_parent.adjust_loop_length(factor) else: self.canonical_parent.adjust_loop_start(factor) @subject_slot('value') def _do_loop_mod(self, value): assert value in range(128) if value > 0: self.set_overide(self._handle_loop_mod) else: self.reset_overide() def chg_volume(self, diff): mdevice = self.song().master_track.mixer_device if self.modifier2(): mdevice.volume.value = calc_new_parm(mdevice.volume, diff) else: repeat(mdevice.volume, diff) def chg_cue(self, diff): mdevice = self.song().master_track.mixer_device if self.modifier2(): mdevice.cue_volume.value = calc_new_parm(mdevice.cue_volume, diff) else: repeat(mdevice.cue_volume, diff) def update(self): pass def refresh(self): pass def disconnect(self): super(JogWheelSection, self).disconnect()