class ModClipSlotComponent(ClipSlotComponent): ''' Clip Slot Component for Maschine ''' def __init__(self, *a, **k): super(ModClipSlotComponent, self).__init__(*a, **a) def set_modifier(self, modifier): self._modifier = modifier def _launch_button_value(self, value): if self.is_enabled(): if self._modifier and self._modifier.hasModification(CLIP_MODE): self._modifier.edit_clip_slot(self, value) elif self._clip_slot != None and self._modifier and self._modifier.isShiftdown( ) and value != 0: track = self._clip_slot.canonical_parent scenes = self.song().scenes index = vindexof(track.clip_slots, self._clip_slot) scenes[index].fire() elif self._clip_slot != None and self._modifier and self._modifier.isClipAltDown( ) and value != 0: track = self._clip_slot.canonical_parent if track.is_foldable and value != 0: if track.fold_state == 0: track.fold_state = 1 else: track.fold_state = 0 elif self._clip_slot != None: self._do_launch_clip(value) _launch_button_value = subject_slot('value')(_launch_button_value) def get_launch_button(self): return self._launch_button_value_slot.subject
class Maschine(ControlSurface): __module__ = __name__ '''Basic Control Script for All Maschine Modell Mikro, Mikro Mk2, Mk1, Mk2, Studio''' def __init__(self, c_instance): super(Maschine, self).__init__(c_instance) self.component_guard().__enter__() try: 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() finally: pass 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 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 if not self.arm_selected_track or 127: pass self.set_sel_arm_button.send_value(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): loads = loads dumps = dumps import pickle ascii = ascii import encodings 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 (None, preferences.set_serializer)(lambda: dumps(pref_dict)) def preferences_name(self): return 'Maschine' def _pre_serialize(self): dumps = dumps import pickle ascii = ascii import encodings 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]) continue 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 (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) continue 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 def _on_appointed_device_changed(self): self._modeselect._device_changed() _on_appointed_device_changed = subject_slot('appointed_device')( _on_appointed_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 def _on_devices_changed(self): pass _on_devices_changed = subject_slot('devices')(_on_devices_changed) 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): self.component_guard().__enter__() try: self._is_sending_scheduled_messages().__enter__() try: self._task_group.update(0.1) finally: pass self._modeselect.notify(self.blink_state) self.blink_state = (self.blink_state + 1) % 4 self.display_task.tick() self.update_undo_redo(False) finally: pass 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 if not self.undo_state == 1 or 127: pass self._undo_button.send_value(0) if self.song().can_redo != self.redo_state: self.redo_state = self.song().can_redo if not self.redo_state == 1 or 127: pass self._redo_button.send_value(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 def _do_fire_button(self, value): if not self._fire_button != None: raise AssertionError if not value in range(128): raise 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() _do_fire_button = subject_slot('value')(_do_fire_button) 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')) _do_undo = subject_slot('value')(_do_undo) def _do_redo(self, value): if value != 0: if self.song().can_redo == 1: self.song().redo() self.show_message(str('REDO')) _do_redo = subject_slot('value')(_do_redo) 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) _do_stop_all = subject_slot('value')(_do_stop_all) 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) def _do_update_display(self, value): if value != 0: self.refresh_state() _do_update_display = subject_slot('value')(_do_update_display) def _do_key_color(self, value): if not value in range(128): raise AssertionError if value != 0: self._modeselect._pad_mode.step_key_color_mode() _do_key_color = subject_slot('value')(_do_key_color) def _do_tap_tempo(self, value): if not value in range(128): raise AssertionError if value != 0: self.song().tap_tempo() _do_tap_tempo = subject_slot('value')(_do_tap_tempo) def _do_toggle_cue(self, value): if not value in range(128): raise AssertionError if value != 0: self.song().set_or_delete_cue() _do_toggle_cue = subject_slot('value')(_do_toggle_cue) def _do_toggle_prev_cue(self, value): if not value in range(128): raise AssertionError if value != 0: self.song().jump_to_prev_cue() _do_toggle_prev_cue = subject_slot('value')(_do_toggle_prev_cue) def _do_toggle_next_cue(self, value): if not value in range(128): raise AssertionError if value != 0: self.song().jump_to_next_cue() _do_toggle_next_cue = subject_slot('value')(_do_toggle_next_cue) def _do_toggle_send(self, value): if not value in range(128): raise AssertionError 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 None 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)) _do_toggle_send = subject_slot('value')(_do_toggle_send) 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) if self.arm_selected_track and track.can_be_armed: arm_exclusive(self.song(), track) _a_trk_left = subject_slot('value')(_a_trk_left) 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) if self.arm_selected_track and track.can_be_armed: arm_exclusive(self.song(), track) _a_trk_right = subject_slot('value')(_a_trk_right) 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) _a_sel_arm = subject_slot('value')(_a_sel_arm) 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 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) _nav_value_left = subject_slot('value')(_nav_value_left) def _nav_value_right(self, value): if not self._device_nav_button_right != None: raise AssertionError if not value in range(128): raise AssertionError 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) _nav_value_right = subject_slot('value')(_nav_value_right) def _do_focus_navigate(self, value): if not self._navigate_button != None: raise AssertionError if not value in range(128): raise AssertionError 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])) _do_focus_navigate = subject_slot('value')(_do_focus_navigate) def focus_clip_detail(self): self.application().view.focus_view('Detail/Clip') 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) _song_follow_changed = subject_slot('follow_song')(_song_follow_changed) 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) _do_song_follow = subject_slot('value')(_do_song_follow) def _hold_duplicate_action(self, value): if value != 0: pass 1 _hold_duplicate_action = subject_slot('value')(_hold_duplicate_action) 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() _hold_clear_action = subject_slot('value')(_hold_clear_action) 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') _action_toogle_main_view = subject_slot('value')(_action_toogle_main_view) 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') _action_toogle_detail_view = subject_slot('value')( _action_toogle_detail_view) def _on_change_reenabled(self): if self.song().re_enable_automation_enabled: self._reenable_button.turn_on() else: self._reenable_button.turn_off() _on_change_reenabled = subject_slot('re_enable_automation_enabled')( _on_change_reenabled) def _do_auto_reenable(self, value): if value != 0: self.song().re_enable_automation() _do_auto_reenable = subject_slot('value')(_do_auto_reenable) 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 if not i < 3 or '|': pass d1 += name[:6] + '' continue if not i < 3 or '|': pass d1 += ' ' + '' self.send_to_display(d1, 2) d1 = '' for i in range(4): parm = bank[i + 4] if parm: name = parm.name if not i < 3 or '|': pass d1 += name[:6] + '' continue if not i < 3 or '|': pass d1 += ' ' + '' self.send_to_display(d1, 4) else: self.timed_message(2, 'Bank: ' + name) def display_parameters(self, paramlist): if USE_DISPLAY == False: return None def send_to_display(self, text, grid=0): if USE_DISPLAY == False: return None if self._diplay_cache[grid] == text: return None 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 (track_index, scene_index) in self._bmatrix.iterbuttons(): if button: button.send_color_direct(PColor.OFF[0]) continue time.sleep(0.2) self._active = False self._suppress_send_midi = True super(Maschine, self).disconnect()
class ModeSelector(CompoundComponent): ''' Class Handling the switch between Modes. ''' __module__ = __name__ mikro_shift = False _md_select_mode = None _md_solo_mode = None _md_mute_mode = None _knob_section = None _clip_mode_down = False def __init__(self, monochrome=False, *a, **k): super(ModeSelector, self).__init__(*a, **a) is_momentary = True 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 def mode(self): return self._mode def update(self): pass def get_color_manager(self): return self._color_select_mode def get_color(self, value, column_index, row_index): return self._mode.get_color(value, column_index, row_index) def connect_main_knob(self, knobsection): self._control_mode.connect_main_knob(knobsection) def assign_edit_section(self, editsection): self._scene_mode.set_edit_mode(editsection) self._pad_mode.set_edit_mode(editsection) self._drum_mode.set_edit_mode(editsection) def navigate(self, dir, modifier, alt_modifier=False): self._mode.navigate(dir, modifier, alt_modifier) def notify(self, blink_state): self._mode.notify(blink_state) if self._mode == self._clip_mode or self._mode == self._color_select_mode: if self.canonical_parent._editsection.is_color_edit(): if self._color_select_mode.in_track_scene_mode(): bval = blink_state % 2 else: bval = blink_state / 2 self._clip_mode_button.send_value(bval) else: self._clip_mode_button.send_value(1) def notify_mono(self, blink_state): self._mode.notify_mono(blink_state) def enter_edit_mode(self, type): self._mode.enter_edit_mode(type) def exit_edit_mode(self, type): self._mode.exit_edit_mode(type) def enter_clear_state(self): self._mode.enter_clear_state() def exit_clear_state(self): self._mode.exit_clear_state() def _device_changed(self): self._mode._device_changed() def refresh(self): self._mode.refresh() self._stop_button.activate() self._arm_button.activate() self._xfade_button.activate() def rebuild(self): self.canonical_parent._set_suppress_rebuild_requests(True) yield None self.canonical_parent._set_suppress_rebuild_requests(False) self.canonical_parent.request_rebuild_midi_map() rebuild = contextmanager(rebuild) def _light_button(self, which): if not which == 0 or 1: pass self._scene_mode_button.send_value(0, True) if not which == 1 or 1: pass self._clip_mode_button.send_value(0, True) if not which == 2 or 1: pass self._pad_mode_button.send_value(0, True) def change_mode(self, nextmode): if not self._mode != nextmode and self._mode == None: pass return self._mode.is_lock_mode() def set_shift_state(self, state): self.mikro_shift = state def show_messsage(self, msg): self.canonical_parent.show_message(msg) def handle_push(self, value): if self._mode: self._mode.handle_push(value) def pick_color(self, cscomponent): shift_down = self.canonical_parent.isShiftDown() def set_color(rgb_value): if self.canonical_parent.isShiftDown(): if shift_down: track = cscomponent._clip_slot.canonical_parent scenes = self.song().scenes index = vindexof(track.clip_slots, cscomponent._clip_slot) scenes[index].color = rgb_value else: track = cscomponent._clip_slot.canonical_parent for cs in track.clip_slots: if cs.has_clip: cs.clip.color = rgb_value continue elif shift_down: track = cscomponent._clip_slot.canonical_parent track.color = rgb_value elif cscomponent._clip_slot.clip != None: cscomponent._clip_slot.clip.color = rgb_value def color_picked(color_rgb): set_color(color_rgb) if self._mode == self._color_select_mode: self.rebuild().__enter__() try: self._mode.exit() self._mode = self._clip_mode self._mode.enter() finally: pass self._color_select_mode.set_pick_callback(color_picked, shift_down) self._into_mode(self._color_select_mode, 'Color Chooser') def _into_mode(self, mode, info): if self._mode != None and self._mode != mode and not self._mode.is_lock_mode( ): return None self.rebuild().__enter__() try: self._return_mode = self._mode self._mode.exit() self._mode = mode self._mode.enter() finally: pass def _select_scene_mode(self, value): if value > 0: if self.mikro_shift: if self.change_mode(self._control_mode): self.rebuild().__enter__() try: self._mode.exit() self._mode = self._control_mode self._light_button(0) self._mode.enter() finally: pass elif self.change_mode(self._scene_mode): self.rebuild().__enter__() try: self._mode.exit() self._mode = self._scene_mode self._light_button(0) self._mode.enter() finally: pass _select_scene_mode = subject_slot('value')(_select_scene_mode) def _select_clip_mode(self, value): click = value != 0 if click and self._mode == self._color_select_mode: self._into_mode(self._clip_mode, 'CLIP MODE') return None if click: if self.change_mode(self._clip_mode): self.rebuild().__enter__() try: self._mode.exit() self._mode = self._clip_mode self._light_button(1) self._mode.enter() finally: pass if self.canonical_parent.isShiftDown() or self.mikro_shift: self.canonical_parent.to_color_edit_mode(True) self._clip_mode_button.send_value(1, True) else: self.canonical_parent.to_color_edit_mode(False) self._clip_mode_down = click _select_clip_mode = subject_slot('value')(_select_clip_mode) def _select_pad_mode(self, value): if value > 0 and self.change_mode(self._pad_mode): track = self.song().view.selected_track newmode = self._pad_mode.fitting_mode(track) self.rebuild().__enter__() try: self._mode.exit() self._mode = newmode self._light_button(2) self._mode.enter() finally: pass _select_pad_mode = subject_slot('value')(_select_pad_mode) def _select_drum_mode(self, value): if value > 0 and self.change_mode(self._drum_mode): self.rebuild().__enter__() try: self._mode.exit() self._mode = self._drum_mode self._light_button(2) self._mode.enter() finally: pass def _into_hold_mode(self, value, button, mode, info): if self._mode != None and self._mode != mode and not self._mode.is_lock_mode( ): return None button.send_value(value, True) if value > 0 and self._mode != mode: self.rebuild().__enter__() try: self._mode.exit() self._return_mode = self._mode self._mode = mode self._mode.enter() finally: pass elif value == 0 and self._mode == mode: self.rebuild().__enter__() try: self._mode.exit() self._mode = self._return_mode self._return_mode = None self._mode.enter() finally: pass def _select_arm(self, value): if value != 0: self.show_messsage('Current Mode : Track ARM') self._into_hold_mode(value, self._arm_button, self._arm_mode, 'ARM') _select_arm = subject_slot('value')(_select_arm) def _select_stop(self, value): if value != 0: self.show_messsage('Current Mode : Track STOP') self._into_hold_mode(value, self._stop_button, self._stop_mode, 'STOP') _select_stop = subject_slot('value')(_select_stop) def _select_solo(self, value): if value != 0: if self.mikro_shift: self._into_hold_mode(value, self._solo_button, self._stop_mode, 'STOP') self._md_solo_mode = self._stop_mode self.show_messsage('Current Mode : Track STOP') else: self._into_hold_mode(value, self._solo_button, self._solo_mode, 'SOLO') self._md_solo_mode = self._solo_mode self.show_messsage('Current Mode : Track SOLO') else: self._into_hold_mode(value, self._solo_button, self._md_solo_mode, 'SOLO') _select_solo = subject_slot('value')(_select_solo) def _select_mute(self, value): if value != 0: if self.mikro_shift: self._into_hold_mode(value, self._mute_button, self._arm_mode, 'ARM') self.show_messsage('Current Mode : Track ARM') self._md_mute_mode = self._arm_mode else: self._into_hold_mode(value, self._mute_button, self._mute_mode, 'Mute') self.show_messsage('Current Mode : Track MUTE') self._md_mute_mode = self._mute_mode else: self._into_hold_mode(value, self._mute_button, self._md_mute_mode, 'SOLO') _select_mute = subject_slot('value')(_select_mute) def _select_select(self, value): if value != 0: if self.mikro_shift: self._md_select_mode = self._xfade_mode self._into_hold_mode(value, self._select_button, self._xfade_mode, 'XFADE') self.show_messsage('Current Mode : Track Crossfader Assign') else: self._md_select_mode = self._select_mode self._into_hold_mode(value, self._select_button, self._select_mode, 'Select') self.show_messsage('Current Mode : Track SELECT') else: self._into_hold_mode(value, self._select_button, self._md_select_mode, 'Select') _select_select = subject_slot('value')(_select_select) def _select_xfade(self, value): if value != 0: self.show_messsage('Current Mode : Track Crossfader Assign') self._into_hold_mode(value, self._xfade_button, self._xfade_mode, 'XFADE') _select_xfade = subject_slot('value')(_select_xfade) def _action_octave(self, value): pass def _action_scale(self, value): pass def _action_base_note(self, value): pass def isClipDown(self): return self._clip_mode_down def _action_key_color(self, value): pass def is_solo_exclusive(self): return self._solo_mode.exclusive def is_arm_exclusive(self): return self._arm_mode.exclusive def set_solo_exclusive(self, value): self._solo_mode.exclusive = value if not value > 0 or 127: pass self._solo_exclusive_button.send_value(0, True) def set_arm_exclusive(self, value): self._arm_mode.exclusive = value if not value > 0 or 127: pass self._arm_exclusive_button.send_value(0, True) def _action_arm_exclusive(self, value): if value > 0: self.set_arm_exclusive(not (self._arm_mode.exclusive)) _action_arm_exclusive = subject_slot('value')(_action_arm_exclusive) def _action_solo_exclusive(self, value): if value > 0: self.set_solo_exclusive(not (self._solo_mode.exclusive)) _action_solo_exclusive = subject_slot('value')(_action_solo_exclusive) def on_selected_scene_changed(self): pass def on_selected_track_changed(self): track = self.song().view.selected_track newmode = self._mode.fitting_mode(track) if track and newmode != self._mode: self.rebuild().__enter__() try: self._light_button(newmode.button_index) self._mode.exit() self._mode = newmode self._mode.enter() finally: pass def disconnect(self): self._clip_mode.unbind() self._drum_mode.unbind() self._scene_mode.unbind() self._pad_mode.unbind() super(ModeSelector, self).disconnect() def on_selected_scene_changed(self): pass
class ControlMode(MaschineMode): _mode = CM_LEVEL _track_sel_index = 0 _track_off = 0 _knob_section = None _parm_raster_value = 1 _parm = None _parm_is_quant = False _selected_sends_index = 0 _bank_index = 0 _parm_index = 0 _device_parm = None _banks = None _device = None _device_list = None _in_clear_mode = False def __init__(self, button_index, mono_chrome = False, *a, **k): super(ControlMode, self).__init__(button_index, *a, **a) self._device_bank_registry = DeviceBankRegistry() self._device_bank_registry.add_device_bank_listener(self._on_device_bank_changed) self.track_selections = tuple(lambda .0: for idx in .0: ControlTrackElement(idx)(range(8))) self._is_monochrome = mono_chrome self.main_buttons = ([ None, self._do_select_level], [ None, self._do_select_pan], [ None, self._do_select_send], [ None, self._do_select_device]) self.nav_buttons = ([ None, self._do_nav1], [ None, self._do_nav2], [ None, self._do_nav3], [ None, self._do_nav4]) self.song().add_return_tracks_listener(self.return_tracks_changed) def connect_main_knob(self, knobsection): self._knob_section = knobsection def knob_adjust(self, inc, shift, pushdown): if self._parm: if pushdown: value = self.change_parm(inc, self._parm, False) self._parm.value = value else: count = 0 while count < 4: value = self.change_parm(inc, self._parm, False) self._parm.value = value count += 1 elif self._device_parm: if self._parm_is_quant: val = self.change_parm(inc, self._device_parm, True) self._device_parm.value = val else: new_value = self.change_parm(inc, self._device_parm, False) self._device_parm.value = new_value if not is_equal(self._device_parm.value, new_value): self.parm_is_quant = True if not (self.parm_is_quant) and not pushdown: count = 0 while count < 3: value = self.change_parm(inc, self._device_parm, False) self._device_parm.value = value count += 1 def change_parm(self, delta, parm, is_quant): if is_quant: parm_range = (parm.max - parm.min) + 1 new_val = min(parm.max, max(parm.min, parm.value + delta)) return float(new_val) else: parm_range = parm.max - parm.min self._parm_raster_value = min(N_PARM_RANGE, max(0, self._parm_raster_value + delta)) return (float(self._parm_raster_value) / float(N_PARM_RANGE)) * parm_range + parm.min def get_mode_id(self): return CONTROL_MODE def navigate(self, dir, modifier, alt_modifier = False): tracks = self.song().tracks nr_of_tracks = len(tracks) new_off = self._track_off + dir if new_off >= 0 and new_off + 8 <= nr_of_tracks: self._track_off = new_off self._track_sel_index += dir self.canonical_parent.show_message('Control assigned to Tracks ' + str(self._track_off + 1) + ' to ' + str(self._track_off + 9)) self._assign(False) def unbind(self): pass def nr_of_parms_in_bank(self, device, bank_index): if device == None: return 0 nr_of_parms = len(device.parameters) bip = nr_of_parms - 8 * bank_index if bip < 8: return bip return 8 def _assign(self, register = True): tracks = self.song().tracks bmatrix = self.canonical_parent._bmatrix for (column, row) in bmatrix.iterbuttons(): if button: if register: self.canonical_parent._forwarding_registry[(MIDI_NOTE_ON_STATUS, button.get_identifier())] = button self.canonical_parent._forwarding_registry[(MIDI_NOTE_OFF_STATUS, button.get_identifier())] = button button.set_to_notemode(False) if row < 2: index = row * 4 + column tindex = index + self._track_off track = None if tindex < len(tracks): track = tracks[tindex] self.track_selections[index].set_button(button, self._do_track_selection) self.track_selections[index].set_track(track) elif row < 3: if not self.main_buttons[column][0]: self.main_buttons[column][0] = button button.add_value_listener(self.main_buttons[column][1]) elif not self.nav_buttons[column][0]: self.nav_buttons[column][0] = button button.add_value_listener(self.nav_buttons[column][1]) if self._mode == CM_LEVEL or self._mode == CM_PAN: button.send_color_direct(PColor.OFF[1]) self._mode == CM_PAN self._mode_sel() def _set_send_color(self, nr_ret_tracks, index, button): if index == 3: button.send_color_direct(PColor.OFF[0]) if nr_ret_tracks > index: col = max(21, (21 + (self._selected_sends_index - 3) * 20) % 127) if self._selected_sends_index >= 3: col = max(21, (21 + (self._selected_sends_index - 3) * 20) % 127) button.send_color_direct((col, 120, 127, 1, 0)) else: button.send_color_direct((21, 120, 20, 0, 0)) elif nr_ret_tracks > index: if index == self._selected_sends_index: button.send_color_direct(PColor.MIX_SELECT_SEND[0]) else: button.send_color_direct(PColor.MIX_SELECT_SEND[1]) else: button.send_color_direct(PColor.OFF[0]) def _turn_off_nav_buttons(self): for (button, callback) in self.nav_buttons: if button: button.send_color_direct(PColor.OFF[0]) continue def _set_up_control_send(self): nr_of_tracks = len(self.song().return_tracks) for idx in range(4): self._set_send_color(nr_of_tracks, idx, self.nav_buttons[idx][0]) def _assign_device_nav(self): if self._device: idx = list(self._device_list).index(self._device) nr_of_dev = len(self._device_list) if idx > 0: self.nav_buttons[0][0].send_color_direct(PColor.DEVICE_LEFT[0]) else: self.nav_buttons[0][0].send_color_direct(PColor.DEVICE_LEFT[1]) if idx < nr_of_dev - 1: self.nav_buttons[1][0].send_color_direct(PColor.DEVICE_RIGHT[0]) else: self.nav_buttons[1][0].send_color_direct(PColor.DEVICE_RIGHT[1]) nr_of_banks = len(self._banks) if self._bank_index > 0: self.nav_buttons[2][0].send_color_direct(PColor.BANK_LEFT[0]) else: self.nav_buttons[2][0].send_color_direct(PColor.BANK_LEFT[1]) if self._bank_index < nr_of_banks - 1: self.nav_buttons[3][0].send_color_direct(PColor.BANK_RIGHT[0]) else: self.nav_buttons[3][0].send_color_direct(PColor.BANK_RIGHT[1]) else: self.nav_buttons[0][0].send_color_direct(PColor.DEVICE_LEFT[1]) self.nav_buttons[1][0].send_color_direct(PColor.DEVICE_RIGHT[1]) self.nav_buttons[2][0].send_color_direct(PColor.BANK_LEFT[1]) self.nav_buttons[3][0].send_color_direct(PColor.BANK_RIGHT[1]) def _assign_device_selection(self): if not self._device: self._update_device() device = self._device self._parm = None self._device_parm = None if device: is_on = device.parameters[0].value == 1 if len(self._banks) > 0: bank = self._banks[self._bank_index] for (parameter, track_sel) in zip(bank, self.track_selections): track_sel.set_parm(parameter) if parameter: if not is_on or PColor.MIX_MODE_DEVICE: pass track_sel.set_color(PColor.MIX_MODE_DEVICE_OFF) if self._parm_index == track_sel._index: track_sel.turn_on() self._assign_device_parm(parameter) else: track_sel.turn_off() self._parm_index == track_sel._index track_sel.set_color(PColor.OFF) track_sel.turn_off() else: for track_sel in self.track_selections: track_sel.set_parm(None) track_sel.set_color(PColor.OFF) track_sel.turn_off() else: for track_sel in self.track_selections: track_sel.set_color(PColor.OFF) track_sel.turn_off() self._assign_device_nav() def _mode_sel(self): if not self._mode == CM_LEVEL or PColor.MIX_MODE_VOLUME[0]: pass self.main_buttons[0][0].send_color_direct(PColor.MIX_MODE_VOLUME[1]) if not self._mode == CM_PAN or PColor.MIX_MODE_PANNING[0]: pass self.main_buttons[1][0].send_color_direct(PColor.MIX_MODE_PANNING[1]) if not self._mode == CM_SEND or PColor.MIX_MODE_SEND[0]: pass self.main_buttons[2][0].send_color_direct(PColor.MIX_MODE_SEND[1]) if not self._mode == CM_DEVICE or PColor.MIX_MODE_DEVICE[0]: pass self.main_buttons[3][0].send_color_direct(PColor.MIX_MODE_DEVICE[1]) reassign_parms = False if self._mode <= CM_SEND: max_index = 0 for track_sel in self.track_selections: if track_sel._track: max_index = track_sel._index continue if self._track_sel_index > max_index: self._track_sel_index = max_index reassign_parms = True for track_sel in self.track_selections: if track_sel._track: track_sel.set_color(BASIC_COLORS[self._mode]) else: track_sel.set_color(PColor.OFF) if track_sel._index == self._track_sel_index: track_sel.turn_on() continue track_sel.turn_off() if self._mode == CM_SEND: nr_of_tracks = len(self.song().return_tracks) if self._selected_sends_index > nr_of_tracks - 1: reassign_parms = True self._selected_sends_index = nr_of_tracks - 1 for idx in range(4): self._set_send_color(nr_of_tracks, idx, self.nav_buttons[idx][0]) else: self._turn_off_nav_buttons() else: self._assign_device_selection() if reassign_parms: self._assign_parameters() def _assign_device_parm(self, param): self.parm_device_message(param) self._device_parm = param if param.is_quantized: self._parm_is_quant = True else: self._parm_is_quant = False parm_range = param.max - param.min self._parm_raster_value = int(((param.value - param.min) / parm_range) * N_PARM_RANGE + 0.1) def parm_device_message(self, param): self.canonical_parent.show_message(' Control ' + str(param.name)) def _get_mixer_parm(self, track): if self._mode == CM_LEVEL: return track.mixer_device.volume elif self._mode == CM_PAN: return track.mixer_device.panning elif self._mode == CM_SEND: nr_of_ret_tracks = len(track.mixer_device.sends) if self._selected_sends_index < nr_of_ret_tracks and self._selected_sends_index != -1: return track.mixer_device.sends[self._selected_sends_index] def _assign_mixer_parm(self, track): self._device_parm = None if self._mode == CM_LEVEL: self._parm = track.mixer_device.volume elif self._mode == CM_PAN: self._parm = track.mixer_device.panning elif self._mode == CM_SEND: self._device_parm = None nr_of_ret_tracks = len(track.mixer_device.sends) if self._selected_sends_index < nr_of_ret_tracks and self._selected_sends_index != -1: self._parm = track.mixer_device.sends[self._selected_sends_index] self.parm_is_quant = False if self._parm: parm_range = self._parm.max - self._parm.min self._parm_raster_value = int(((self._parm.value - self._parm.min) / parm_range) * N_PARM_RANGE + 0.1) def _assign_parameters(self): current = self.track_selections[self._track_sel_index] track = current._track if track: self._assign_mixer_parm(track) def _do_track_selection(self, button_index): self._knob_section.set_override(self.knob_adjust) track_sel = self.track_selections[button_index] if self._mode == CM_DEVICE: if track_sel._dev_param: if self._in_clear_mode: cs = self.song().view.highlighted_clip_slot if cs and cs.has_clip: cs.clip.clear_envelope(track_sel._dev_param) else: current = self.track_selections[self._parm_index] current.turn_off() self._parm_index = button_index track_sel.turn_on() self._assign_device_parm(track_sel._dev_param) else: current = self.track_selections[self._track_sel_index] if self._in_clear_mode and track_sel._track: parm = self._get_mixer_parm(track_sel._track) cs = self.song().view.highlighted_clip_slot if parm and cs and cs.has_clip: cs.clip.clear_envelope(parm) elif button_index != self._track_sel_index and track_sel._track: current.turn_off() track_sel.turn_on() current = track_sel self._track_sel_index = button_index self._assign_mixer_parm(track_sel._track) def _do_select_level(self, value): self._knob_section.set_override(self.knob_adjust) if value > 0 and self._mode != CM_LEVEL: self._mode = CM_LEVEL self._mode_sel() self._assign_parameters() if self.canonical_parent.is_monochrome(): self.canonical_parent.show_message('Control Mode Focus: Track Levels') def _do_select_pan(self, value): self._knob_section.set_override(self.knob_adjust) if value > 0 and self._mode != CM_PAN: self._mode = CM_PAN self._mode_sel() self._assign_parameters() if self.canonical_parent.is_monochrome(): self.canonical_parent.show_message('Control Mode Focus: Track Panning') def _do_select_send(self, value): self._knob_section.set_override(self.knob_adjust) if value > 0 and self._mode != CM_SEND: self._mode = CM_SEND self._mode_sel() self._assign_parameters() if self.canonical_parent.is_monochrome(): self.canonical_parent.show_message('Control Mode Focus: Track Sends') def _do_select_device(self, value): self._knob_section.set_override(self.knob_adjust) if value > 0 and self._mode == CM_DEVICE and self.isShiftDown(): if self._device: parm = self._device.parameters[0] if parm.value == 0: parm.value = 1 else: parm.value = 0 if value > 0 and self._mode != CM_DEVICE: self._mode = CM_DEVICE self._mode_sel() self._assign_device_selection() if self.canonical_parent.is_monochrome(): self.canonical_parent.show_message('Control Mode Focus: Device') def _do_nav1(self, value): self._knob_section.set_override(self.knob_adjust) if value > 0: if self._mode == CM_SEND: nr_of_tracks = len(self.song().return_tracks) if nr_of_tracks > 0: self._selected_sends_index = 0 self._set_up_control_send() self._assign_parameters() self.canonical_parent.show_message('Control Mode Focus: Send A') elif self._mode == CM_DEVICE and self._device: 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') direction = Live.Application.Application.View.NavDirection.left self.application().view.scroll_view(direction, 'Detail/DeviceChain', False) def _do_nav2(self, value): self._knob_section.set_override(self.knob_adjust) if value > 0: if self._mode == CM_SEND: nr_of_tracks = len(self.song().return_tracks) if nr_of_tracks > 1: self._selected_sends_index = 1 self._set_up_control_send() self._assign_parameters() self.canonical_parent.show_message('Control Mode Focus: Send B') elif self._mode == CM_DEVICE and self._device: 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') direction = Live.Application.Application.View.NavDirection.right self.application().view.scroll_view(direction, 'Detail/DeviceChain', False) def _do_nav3(self, value): self._knob_section.set_override(self.knob_adjust) if value > 0: if self._mode == CM_SEND: nr_of_tracks = len(self.song().return_tracks) if nr_of_tracks > 2: self._selected_sends_index = 2 self._set_up_control_send() self._assign_parameters() self.canonical_parent.show_message('Control Mode Focus: Send C') elif self._mode == CM_DEVICE and self._device and len(self._banks) > 0: self._bank_index = max(0, self._bank_index - 1) bank = self._banks[self._bank_index] name = self._parameter_bank_names()[self._bank_index] self._device_bank_registry.set_device_bank(self._device, self._bank_index) self._assign_device_selection() self.canonical_parent.show_message(' Bank : ' + name) def _do_nav4(self, value): self._knob_section.set_override(self.knob_adjust) if value > 0: if self._mode == CM_SEND: nr_of_tracks = len(self.song().return_tracks) if nr_of_tracks > 3: if self._selected_sends_index < 3 or self._selected_sends_index + 1 == nr_of_tracks: self._selected_sends_index = 3 else: self._selected_sends_index += 1 self._set_up_control_send() self._assign_parameters() self.canonical_parent.show_message('Control Mode Focus: Send ' + SENDS[self._selected_sends_index]) elif self._mode == CM_DEVICE and self._device and len(self._banks) > 0: max_bank = len(self._banks) - 1 self._bank_index = min(max_bank, self._bank_index + 1) name = self._parameter_bank_names()[self._bank_index] self._device_bank_registry.set_device_bank(self._device, self._bank_index) self._assign_device_selection() self.canonical_parent.show_message(' Bank : ' + name) def _release(self): for track_sel in self.track_selections: track_sel.release() for (button, callback) in self.main_buttons: if button: button.remove_value_listener(callback) continue for (button, callback) in self.nav_buttons: if button: button.remove_value_listener(callback) continue for idx in range(4): self.main_buttons[idx][0] = None self.nav_buttons[idx][0] = None self._device_parameters_changed.subject = None self._device_active_changed.subject = None def _on_device_bank_changed(self, device, bank): if device == self._device: self._bank_index = bank self._assign_device_selection() def _update_device(self): self._device = self.song().appointed_device if self._device: self._parm_index = 0 track = self._device.canonical_parent devices = track.devices self._device_list = track.devices self._device_parameters_changed.subject = self._device self._device_active_changed.subject = self._device.parameters[0] self._banks = parameter_banks(self._device) self._bank_index = self._device_bank_registry.get_device_bank(self._device) else: self._device_parameters_changed.subject = None self._device_active_changed.subject = None def _device_changed(self): if self._active: self._bank_index = 0 if self._mode == CM_DEVICE: self._update_device() self._assign_device_selection() def return_tracks_changed(self): if self._active: self._assign(False) def _device_parameters_changed(self): if self._active and self._mode == CM_DEVICE: self._banks = parameter_banks(self._device) self._bank_index = self._device_bank_registry.get_device_bank(self._device) self._assign_device_selection() _device_parameters_changed = subject_slot('parameters')(_device_parameters_changed) def _device_active_changed(self): if self._active and self._mode == CM_DEVICE: self._assign_device_selection() _device_active_changed = subject_slot('value')(_device_active_changed) def on_track_list_changed(self): if self._active: for track_sel in self.track_selections: track_sel.release() self._assign(False) def _parameter_bank_names(self): return parameter_bank_names(self._device) def enter(self): self._active = True self._assign() if self._knob_section: self._knob_section.set_override(self.knob_adjust) self._assign_parameters() def exit(self): self._active = False self._release() if self._knob_section: self._knob_section.reset_overide() def enter_clear_state(self): self._in_clear_mode = True def exit_clear_state(self): self._in_clear_mode = False def disconnect(self): if self._active: self._release() self.song().remove_return_tracks_listener(self.return_tracks_changed) self._device_bank_registry.remove_device_bank_listener(self._on_device_bank_changed) self._device_parameters_changed.subject = None super(MaschineMode, self).disconnect()
class DrumMode(MaschineMode): __subject_events__ = ('pressed_pads',) def __init__(self, button_index, monochrome = False, *a, **k): super(DrumMode, self).__init__(button_index, *a, **a) self.track = None self.device = None self._is_monochrome = monochrome if monochrome: self._update_pad_edit = self._update_pad_edit_mono else: self._update_pad_edit = self._update_pad_edit_color self._visible_drum_pad_slots = None self._visible_drum_pads = None self._pads = tuple(lambda .0: for index in .0: DrumPad(index)(range(16))) self._selected_pad = None self._in_edit_mode = False self._editmode = None if self.canonical_parent.is_monochrome(): self.pad_to_color = self._DrumMode__pad_to_onoff else: self.pad_to_color = self._DrumMode__pad_to_color def set_edit_mode(self, editmode): self._editmode = editmode def get_color(self, value, column, row): if not value != 0 or 1: pass indx = 0 note_index = row * 4 + column return self._pads[note_index].get_color() def get_mode_id(self): return PAD_MODE def _DrumMode__pad_to_onoff(self, pad): if pad: if len(pad.chains) == 0: return ((0, 0, 0, 0, 0), (0, 0, 0, 0, 0)) else: return ((0, 0, 0, 1, 0), (0, 0, 0, 1, 0)) else: return ((0, 0, 0, 0, 0), (0, 0, 0, 0, 0)) def _DrumMode__pad_to_color(self, pad): if pad: chains = pad.chains name = pad.name if len(chains) == 0: return ((0, 0, 1), (0, 0, 127)) else: return color_by_name(name) return ((0, 90, 70), (0, 127, 127)) def navigate(self, dir, modifier, alt_modifier = False): if self.device and self.device.view: self.device.view.drum_pads_scroll_position = max(0, min(28, self.device.view.drum_pads_scroll_position + dir)) def enter(self): self._active = True self.assign_track_device() self._in_edit_mode = False for (column, row) in self.canonical_parent._bmatrix.iterbuttons(): if button: note_index = row * 4 + column pad_index = (3 - row) * 4 + column pad = self._pads[pad_index] button.set_to_notemode(True) self.canonical_parent._forwarding_registry[(MIDI_NOTE_ON_STATUS, button.get_identifier())] = button self.canonical_parent._forwarding_registry[(MIDI_NOTE_OFF_STATUS, button.get_identifier())] = button button.set_send_note(PAD_TRANSLATIONS[note_index][2]) button.send_color_direct(pad.get_color()) continue self.track = self.song().view.selected_track self._on_name_changed.subject = self.device.view.selected_drum_pad def _get_note_set(self): in_notes = set() cs = self.song().view.highlighted_clip_slot if cs.has_clip and cs.clip.is_midi_clip: notes = cs.clip.get_notes(0, 0, cs.clip.length, 127) for note in notes: in_notes.add(note[0]) return in_notes def _update_pad_edit_color(self, pad, in_notes): if pad._pad.note in in_notes: pad._button.send_color_direct(pad._color[1]) else: pad._button.send_color_direct(pad._color[0]) def _update_pad_edit_mono(self, pad, in_notes): if pad._pad.note in in_notes: pad._button.send_value(127, True) else: pad._button.send_value(0, True) def _on_notes_changed(self): cs = self.song().view.highlighted_clip_slot if self._in_edit_mode: if cs.has_clip and cs.clip.is_midi_clip: in_notes = set() notes = cs.clip.get_notes(0, 0, cs.clip.length, 127) for note in notes: in_notes.add(note[0]) for pad in self._pads: self._update_pad_edit(pad, in_notes) _on_notes_changed = subject_slot('notes')(_on_notes_changed) def _action_clear(self, value, button): if value > 0: pad = self._pads[button.get_identifier() - 12] self._editmode.edit_note(pad._pad.note) def enter_clear_state(self): cs = self.song().view.highlighted_clip_slot in_notes = set() if cs.has_clip and cs.clip.is_midi_clip: clip = cs.clip notes = clip.get_notes(0, 0, clip.length, 127) self._on_notes_changed.subject = clip for note in notes: in_notes.add(note[0]) else: self._on_notes_changed.subject = None self._in_edit_mode = True for (column, row) in self.canonical_parent._bmatrix.iterbuttons(): if button: note_index = row * 4 + column pad_index = (3 - row) * 4 + column pad = self._pads[pad_index] self._update_pad_edit(pad, in_notes) button.set_to_notemode(False) button.add_value_listener(self._action_clear, True) continue def exit_clear_state(self): self._in_edit_mode = False self._on_notes_changed.subject = None for (column, row) in self.canonical_parent._bmatrix.iterbuttons(): if button: note_index = row * 4 + column pad_index = (3 - row) * 4 + column pad = self._pads[pad_index] button.set_to_notemode(True) button.send_color_direct(pad.get_color()) button.remove_value_listener(self._action_clear) continue def update_pads(self): if self._active: if self._in_edit_mode: in_notes = self._get_note_set() for pad in self._pads: self._update_pad_edit(pad, in_notes) else: for dpad in self._pads: dpad.send_color() def refresh(self): if self._active: for dpad in self._pads: dpad._button.reset() dpad.send_color() def assign_pads(self): self._visible_drum_pads = None self._selected_pad = None if self.device: self._visible_drum_pads = self.device.visible_drum_pads selected_drum_pad = self.device.view.selected_drum_pad self._on_name_changed.subject = selected_drum_pad index = 0 for pad in self._visible_drum_pads: if pad == selected_drum_pad: self._pads[index].selected = True self._selected_pad = self._pads[index] else: self._pads[index].selected = False self._pads[index].set_color(self.pad_to_color(pad)) self._pads[index].set_pad(pad) index += 1 else: for dpad in self._pads: dpad.set_color(((0, 0, 40), (0, 0, 40))) dpad.set_pad(None) for (column, row) in self.canonical_parent._bmatrix.iterbuttons(): pad_index = (3 - row) * 4 + column self._pads[pad_index].set_button(button) if not self._in_edit_mode: self._pads[pad_index].send_color() continue def assign_track_device(self): if self.device and self.device.view: self._on_scroll_index_changed.subject = None self._on_selected_drum_pad_changed.subject = None self._on_chains_changed.subject = None self._on_name_changed.subject = None self.track = self.song().view.selected_track self.device = find_drum_device(self.track) if self.device: self._on_scroll_index_changed.subject = self.device.view self._on_selected_drum_pad_changed.subject = self.device.view self._on_chains_changed.subject = self.device self._on_name_changed.subject = self.device self.assign_pads() def index_of(self, pad): for index in range(16): if self._pads[index]._pad == pad: return index continue return -1 def _on_name_changed(self): if self._active and self.device: self.assign_pads() self.update_pads() _on_name_changed = subject_slot('name')(_on_name_changed) def _device_changed(self): if self._active: self.assign_track_device() self.update_pads() def _on_chains_changed(self): if self._active and self.device: self.assign_pads() self.update_pads() _on_chains_changed = subject_slot('chains')(_on_chains_changed) def _on_selected_drum_pad_changed(self): if self._active and self.device: if self._selected_pad: self._selected_pad.selected = False self._selected_pad.send_color() selected_drum_pad = self.device.view.selected_drum_pad self._on_name_changed.subject = selected_drum_pad new_index = self.index_of(selected_drum_pad) if new_index in range(16): self._selected_pad = self._pads[new_index] self._selected_pad.selected = True self._selected_pad.send_color() _on_selected_drum_pad_changed = subject_slot('selected_drum_pad')(_on_selected_drum_pad_changed) def _on_scroll_index_changed(self): if self._active and self.device: self.assign_pads() self.update_pads() _on_scroll_index_changed = subject_slot('drum_pads_scroll_position')(_on_scroll_index_changed) def fitting_mode(self, track): if not track: return self drum_device = find_drum_device(track) if drum_device == None and self._alternate_mode != None: return self._alternate_mode return self def on_selected_track_changed(self): if self._active: self.track = self.song().view.selected_track self.assign_track_device() self.update_pads() def exit(self): self._active = False self._on_scroll_index_changed.subject = None self._on_selected_drum_pad_changed.subject = None self._on_chains_changed.subject = None self._on_name_changed.subject = None self.device = None self.track = None def disconnect(self): self.exit() self.track = None self.device = None self._visible_drum_pad_slots = None self._visible_drum_pads = None self._pads = None self._selected_pad = None self._in_edit_mode = False self._editmode = None super(MaschineMode, self).disconnect()
class NoteRepeatComponent(CompoundComponent): __module__ = __name__ ''' Noter Repeat Handler''' _knob_handler = None def __init__(self, note_repeat=None, *a, **k): super(NoteRepeatComponent, self).__init__(*a, **a) self._note_repeat = note_repeat self._adjust_cfg_value.subject = SliderElement(MIDI_CC_TYPE, 2, 105) self._note_repeat_button = ButtonElement(True, MIDI_CC_TYPE, 0, 102) self._do_note_repeat.subject = self._note_repeat_button self._cfg_adjust_button = ButtonElement(True, MIDI_CC_TYPE, 2, 106) self._cfg_adjust_button.add_value_listener(self._do_cfg_button) self._cfg_down = False self._hold_mode = False self.nr_down = False self._current_nr_button = None self._do_change_nr_1.subject = SliderElement(MIDI_CC_TYPE, 1, 76) self._do_change_nr_2.subject = SliderElement(MIDI_CC_TYPE, 1, 77) self._do_change_nr_3.subject = SliderElement(MIDI_CC_TYPE, 1, 78) self._do_change_nr_4.subject = SliderElement(MIDI_CC_TYPE, 1, 79) def createButton(ccindenfier, nr_freq): button = ButtonElement(True, MIDI_CC_TYPE, 1, ccindenfier) button.add_value_listener(self._select_value, True) button.active = False button.freq = nr_freq button.cfg = False button.hold = False return button def createCfgButton(ccindenfier, nr_freq_idx): button = ButtonElement(True, MIDI_CC_TYPE, 2, ccindenfier) button.add_value_listener(self._select_value, True) button.active = False button.fr_idx = nr_freq_idx button.freq = CFG_REPEAT_FREQUENCIES[nr_freq_idx] button.cfg = True button.hold = False return button continue self._cfg_buttons = [ createCfgButton(assign[0], assign[1]) for assign in CTRL_CFG_TO_FREQ ] for button in self._cfg_buttons: if not button.active or 1: pass button.send_value(0, True) self.nr_frq = CTRL_TO_FREQ[4][1] self._note_repeat.repeat_rate = (1 / self.nr_frq) * 4 continue self.buttons = [ createButton(assign[0], assign[1]) for assign in CTRL_TO_FREQ ] self.buttons[4].active = True self._previous_button = self.buttons[4] self._last_active_button = self.buttons[4] for button in self.buttons: if not button.active or 1: pass button.send_value(0, True) def update(self): pass def store_values(self, dict): for (button, idx) in zip(self._cfg_buttons, range(len(self._cfg_buttons))): dict['cofig-nr-val' + str(idx)] = button.fr_idx def recall_values(self, dict): for (button, idx) in zip(self._cfg_buttons, range(len(self._cfg_buttons))): key = 'cofig-nr-val' + str(idx) if key in dict: fqidx = dict[key] button.fr_idx = fqidx button.freq = CFG_REPEAT_FREQUENCIES[fqidx] continue def registerKnobHandler(self, handler): self._knob_handler = handler def show_note_rates(self): rates = '' for (button, idx) in zip(self._cfg_buttons, range(len(self._cfg_buttons))): rates += ' ' + CFG_REPEAT_DISPLAY[button.fr_idx].ljust(5) if idx < 3: rates += '|' continue self.canonical_parent.timed_message(2, rates) def mod_button(self, button, inc, which): cindex = button.fr_idx maxindex = len(CFG_REPEAT_FREQUENCIES) - 1 minindex = 0 if self.canonical_parent.isShiftDown(): inc *= 2 if not cindex % 2 == 0 or maxindex: pass maxindex = maxindex - 1 minindex = cindex % 2 new_idx = max(minindex, min(maxindex, cindex + inc)) if new_idx != cindex: self.canonical_parent.show_message('Note Repeat Button ' + str(which) + ' : ' + CFG_REPEAT_DISPLAY[new_idx]) button.fr_idx = new_idx button.freq = CFG_REPEAT_FREQUENCIES[new_idx] if button.active: self.nr_frq = CFG_REPEAT_FREQUENCIES[new_idx] self._note_repeat.repeat_rate = (1 / self.nr_frq) * 4 def _do_change_nr_1(self, value): if not value == 0 or -1: pass self.mod_button(self._cfg_buttons[0], 1, 1) self.show_note_rates() _do_change_nr_1 = subject_slot('value')(_do_change_nr_1) def _do_change_nr_2(self, value): if not value == 0 or -1: pass self.mod_button(self._cfg_buttons[1], 1, 2) self.show_note_rates() _do_change_nr_2 = subject_slot('value')(_do_change_nr_2) def _do_change_nr_3(self, value): if not value == 0 or -1: pass self.mod_button(self._cfg_buttons[2], 1, 3) self.show_note_rates() _do_change_nr_3 = subject_slot('value')(_do_change_nr_3) def _do_change_nr_4(self, value): if not value == 0 or -1: pass self.mod_button(self._cfg_buttons[3], 1, 4) self.show_note_rates() _do_change_nr_4 = subject_slot('value')(_do_change_nr_4) def _do_cfg_button(self, value): if value != 0: self._cfg_down = True button = self._current_nr_button if button and button.cfg and button.fr_idx >= 0: self.canonical_parent.show_message( 'Note Repeat ' + CFG_REPEAT_DISPLAY[button.fr_idx]) else: self._cfg_down = False if self._knob_handler: self._knob_handler.do_main_push(value) def _adjust_cfg_value(self, value): button = self._current_nr_button if button and button.cfg: if (self.nr_down and button.hold or self._hold_mode) and button.active: if not value == 127 or -1: pass inc = 1 cindex = button.fr_idx maxindex = len(CFG_REPEAT_FREQUENCIES) - 1 minindex = 0 if self._cfg_down: inc *= 2 if not cindex % 2 == 0 or maxindex: pass maxindex = maxindex - 1 minindex = cindex % 2 new_idx = max(minindex, min(maxindex, cindex + inc)) self.canonical_parent.show_message('Note Repeat ' + CFG_REPEAT_DISPLAY[new_idx]) button.fr_idx = new_idx button.freq = CFG_REPEAT_FREQUENCIES[new_idx] self.nr_frq = CFG_REPEAT_FREQUENCIES[new_idx] self._note_repeat.repeat_rate = (1 / self.nr_frq) * 4 elif self._knob_handler: self._knob_handler.do_main(value) _adjust_cfg_value = subject_slot('value')(_adjust_cfg_value) def _select_value(self, value, button): if value != 0: self._current_nr_button = button button.hold = True self.show_note_rates() if self._hold_mode: if self._previous_button == button: button.send_value(0, True) button.active = False self._last_active_button = button button.active = False self._note_repeat.repeat_rate = 32 self._previous_button = None elif self._previous_button == None or self._previous_button != button: button.send_value(1, True) button.active = True self.nr_frq = button.freq self._note_repeat.repeat_rate = (1 / self.nr_frq) * 4 if not self._note_repeat.enabled: self._note_repeat.enabled = True if self._previous_button != None: self._previous_button.active = False self._previous_button.send_value(0, True) self._previous_button = button else: button.send_value(1, True) button.active = True self.nr_frq = button.freq self._note_repeat.repeat_rate = (1 / self.nr_frq) * 4 if self._previous_button != None and self._previous_button != button: self._previous_button.active = False self._previous_button.send_value(0, True) self._previous_button = button else: button.hold = False def _do_note_repeat(self, value): self.nr_down = value > 0 if self._hold_mode: if value > 0: self._note_repeat_button.send_value(0) self._note_repeat.enabled = False self._hold_mode = False if self._previous_button == None and self._last_active_button != None: self._previous_button = self._last_active_button self._last_active_button.send_value(1) self._last_active_button.active = True self.nr_frq = self._last_active_button.freq self._note_repeat.repeat_rate = (1 / self.nr_frq) * 4 elif self.canonical_parent.isShiftDown() and value > 0: self._note_repeat_button.send_value(1) self._note_repeat.enabled = True self._hold_mode = True self._note_repeat.repeat_rate = (1 / self.nr_frq) * 4 elif value == 0: self._note_repeat.enabled = False self._note_repeat_button.send_value(0) else: self._note_repeat_button.send_value(1) self._note_repeat.repeat_rate = (1 / self.nr_frq) * 4 self._note_repeat.enabled = True _do_note_repeat = subject_slot('value')(_do_note_repeat) def disconnect(self): super(NoteRepeatComponent, self).disconnect()
class MaschineSessionComponent(SessionComponent): __module__ = __name__ '''Session Component for Maschine''' scene_component_type = ModSceneComponent _session_mode = None _advance = STEP1 _matrix = None _color_manager = None def __init__(self): SessionComponent.__init__(self, 4, 4) self._mode_button = ButtonElement(False, MIDI_CC_TYPE, 2, 50) self._do_matrix_adv_mode.subject = self._mode_button self._mode_button.send_value(0, True) self._track_banking_increment = 1 self._c_mode_button = ButtonElement(True, MIDI_CC_TYPE, 2, 90) self._change_color_mode.subject = self._c_mode_button self._c_mode_button.send_value(0, True) self.notify = self.notify_standard self.get_color = self.get_color_standard self._nav_color_button = self.canonical_parent.create_gated_button( 8, 110) self._toggle_step_advance.subject = self._nav_color_button self._nav_color_button.switch_off() self._color_manager = self def set_mode(self, mode): self._session_mode = mode def set_color_manager(self, manager): if manager: self._color_manager = manager def _change_color_mode(self, value): if value > 0: if self.is_color_mode(): self.set_color_mode(False) self._session_mode.refresh() self._c_mode_button.send_value(0, True) else: self.set_color_mode(True) self._session_mode.refresh() self._c_mode_button.send_value(1, True) _change_color_mode = subject_slot('value')(_change_color_mode) def set_color_mode(self, colormode): if colormode: self.notify = self.notify_cmode self.get_color = self.get_color_cmode else: self.notify = self.notify_standard self.get_color = self.get_color_standard def is_color_mode(self): return self.notify == self.notify_cmode def start_up(self): self.set_enabled(True) def update_nav_button(self): if not self._advance == STEP4 or COLOR_HUE_NAV4: pass color = COLOR_HUE_NAV self._bank_up_button.hue = color self._bank_down_button.hue = color self._bank_left_button.hue = color self._bank_right_button.hue = color self._horizontal_banking.update() self._vertical_banking.update() def _toggle_step_advance(self, value): if value != 0: if not self._advance == STEP4 or STEP1: pass self.set_step_advance(STEP4) _toggle_step_advance = subject_slot('value')(_toggle_step_advance) def switch_step_advance(self): if not self._advance == STEP4 or STEP1: pass self.set_step_advance(STEP4) def set_step_advance(self, value): self._advance = value if self._advance == STEP4: self._mode_button.send_value(127, True) self._nav_color_button.turn_on() else: self._mode_button.send_value(0, True) self._nav_color_button.switch_off() self.set_track_banking_increment(self._advance) self.update_nav_button() def get_step_advance(self): return self._advance def _link(self): pass def get_track_offset(self): return self._track_offset def get_scene_offset(self): return self._scene_offset def set_matrix(self, matrix): self._matrix = matrix def set_track_banking_increment(self, increment): self._track_banking_increment = increment def _do_matrix_adv_mode(self, value): if not self._mode_button != None: raise AssertionError if not value in range(128): raise AssertionError if value != 0: if self._advance == STEP1: self._advance = STEP4 self._mode_button.send_value(127, True) self._nav_color_button.turn_on() self.set_track_banking_increment(STEP4) else: self._advance = STEP1 self._mode_button.send_value(0, True) self._nav_color_button.switch_off() self.set_track_banking_increment(STEP1) _do_matrix_adv_mode = subject_slot('value')(_do_matrix_adv_mode) def update(self): SessionComponent.update(self) try: pass except AttributeError: pass if self._advance == STEP4: self._mode_button.send_value(127, True) else: self._mode_button.send_value(0, True) def get_controled_clip_slots(self, clip_slot): if clip_slot.controls_other_clips: track = clip_slot.canonical_parent if track.is_foldable: song = self.song() index = vindex(song.tracks, track) if index >= 0: count = index done = False result = [] while not done: count += 1 if count == len(song.tracks): done = True continue ctrack = song.tracks[count] def get_color_cmode(self, clip_slot): if clip_slot == None: return PColor.OFF color = self.get_color_cmode_base(clip_slot) oncolor = color[0] offcolor = color[1] if clip_slot.has_clip: if clip_slot.clip.is_recording or clip_slot.clip.will_record_on_start: return (oncolor, oncolor) elif clip_slot.clip.is_triggered: return (oncolor, oncolor) elif clip_slot.clip.is_playing: return (oncolor, oncolor) else: return (offcolor, offcolor) elif clip_slot.will_record_on_start: return CLR_REC elif clip_slot.is_playing: return PColor.CLIP_GROUP_PLAY elif clip_slot.controls_other_clips: return PColor.CLIP_GROUP_CONTROL elif clip_slot.is_triggered: return CLR_TRIGG return PColor.OFF def get_color_standard(self, clip_slot): if not clip_slot: return PColor.OFF if clip_slot.has_clip: if clip_slot.clip.is_recording or clip_slot.clip.will_record_on_start: if clip_slot.clip.is_triggered: return PColor.CLIP_RECORD_TRIGGER else: return PColor.CLIP_RECORD if clip_slot.clip.is_playing: return PColor.CLIP_PLAY elif clip_slot.clip.is_triggered: return PColor.CLIP_PLAY_TRIGGER else: return PColor.CLIP_STOPPED elif clip_slot.will_record_on_start: return PColor.CLIP_RECORD_TRIGGER elif clip_slot.is_playing: return PColor.CLIP_GROUP_PLAY elif clip_slot.controls_other_clips: return PColor.CLIP_GROUP_CONTROL elif clip_slot.is_triggered: return PColor.CLIP_GROUP_TRIGGER return PColor.OFF def get_mono_state(self, clip_slot): if not clip_slot: return (0, 0) if clip_slot.has_clip: if clip_slot.clip.is_recording or clip_slot.clip.will_record_on_start: if clip_slot.clip.is_triggered: return (1, 2) else: return (1, 1) if clip_slot.clip.is_playing: return (1, 1) elif clip_slot.clip.is_triggered: return (1, 2) else: return (1, 0) elif clip_slot.will_record_on_start: return (1, 2) elif clip_slot.is_playing: return (1, 1) elif clip_slot.controls_other_clips: return (1, 0) elif clip_slot.is_triggered: return (1, 2) return (0, 0) def notify_standard(self, blink): index = blink / 2 for scene_index in range(4): scene = self.scene(scene_index) for track_index in range(4): clip_slot = scene.clip_slot(track_index)._clip_slot if clip_slot: button = self._matrix[scene_index][track_index] color = self.get_color_standard(clip_slot) if button != None and clip_slot.has_clip: if clip_slot.clip.is_triggered: button.send_color_direct(color[index]) elif clip_slot.is_triggered: button.send_color_direct(color[index]) def notify_cmode(self, blink): sblink = blink / 2 fblink = blink % 2 for scene_index in range(4): scene = self.scene(scene_index) for track_index in range(4): clip_slot = scene.clip_slot(track_index)._clip_slot if clip_slot: button = self._matrix[scene_index][track_index] color = self.get_color_cmode_base(clip_slot) if clip_slot.has_clip: if clip_slot.clip.is_recording or clip_slot.clip.will_record_on_start: if not sblink == 0 or color[0]: pass button.send_color_direct(REC) elif clip_slot.clip.is_triggered: button.send_color_direct(color[sblink]) elif clip_slot.clip.is_playing: button.send_color_direct(color[0]) else: button.send_color_direct(color[1]) elif clip_slot.will_record_on_start: if not sblink == 0 or REC: pass button.send_color_direct(REC_DIM) elif clip_slot.is_playing: button.send_color_direct(PColor.CLIP_GROUP_PLAY[0]) elif clip_slot.controls_other_clips: button.send_color_direct(PColor.CLIP_GROUP_CONTROL[0]) elif clip_slot.is_triggered: if not sblink == 0 or TRIGG: pass button.send_color_direct(TRIGG_DIM) def convertToHSB(self, rgb_color): return toHSB(rgb_color) def get_color_cmode_base(self, clip_slot): if clip_slot != None: if clip_slot.has_clip: rgb = clip_slot.clip.color color = self._color_manager.convertToHSB(clip_slot.clip.color) return color elif clip_slot.controls_other_clips: pass return PColor.OFF def notify_mono(self, blink): sblink = blink / 2 fblink = blink % 2 for scene_index in range(4): scene = self.scene(scene_index) for track_index in range(4): clip_slot = scene.clip_slot(track_index)._clip_slot button = self._matrix[scene_index][track_index] if clip_slot != None: state = self.get_mono_state(clip_slot) if state: val = state[0] bval = state[1] if bval == 0: if val == 1: button.turn_on() else: button.turn_off() elif bval == 1: if sblink == 0: button.turn_on() else: button.turn_off() elif bval == 2: if fblink == 0: button.turn_on() else: button.turn_off() else: button.turn_off() button.turn_off() def on_track_list_changed(self): num_tracks = len(self.tracks_to_use()) new_track_offset = self.track_offset() if new_track_offset >= num_tracks: new_track_offset = num_tracks - 1 new_track_offset -= new_track_offset % self._track_banking_increment self._reassign_tracks() self.set_offsets(new_track_offset, self.scene_offset()) def update(self): SessionComponent.update(self) self._bank_up_button.update() self._bank_down_button.update() self._bank_left_button.update() self._bank_right_button.update() def _bank_right(self): return self.set_offsets( self.track_offset() + self._track_banking_increment, self.scene_offset()) def _bank_left(self): return self.set_offsets( max(self.track_offset() - self._track_banking_increment, 0), self.scene_offset()) def bank_down(self): if self.is_enabled(): newoff = max(0, self._scene_offset - 1) self.set_offsets(self._track_offset, newoff) def bank_up(self): if self.is_enabled(): self.set_offsets(self._track_offset, self._scene_offset + 1) def bank_left(self): if self.is_enabled(): self.set_offsets(max(0, self._track_offset - 1), self._scene_offset) def bank_right(self): if self.is_enabled(): self.set_offsets(self._track_offset + 1, self._scene_offset) def _allow_updates(self): return True def disconnect(self): self._matrix = None self._mode_button = None SessionComponent.disconnect(self)
class PadMode(MaschineMode): def __init__(self, button_index, monochrome = False, *a, **k): super(PadMode, self).__init__(button_index, *a, **a) self._note_display_mode = ND_KEYBOARD1 self.current_scale_index = 0 self._scale = None self._base_note = 0 self._octave = 0.55 self.current_scale_index = 0 self._in_edit_mode = False self._editmode = None self._is_monochrome = monochrome if not monochrome or self.assign_edit_mono: pass self._color_edit_assign = self.assign_edit_color self.assign_transpose(SCALES[self.current_scale_index]) is_momentary = True self.octave_down_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 120) self.octave_up_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 121) self.base_down_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 124) self.base_up_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 125) self.scale_down_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 118) self.scale_up_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 119) self._adjust_scale.subject = SliderElement(MIDI_CC_TYPE, 2, 116) self._adjust_octav.subject = SliderElement(MIDI_CC_TYPE, 2, 115) self._adjust_basem.subject = SliderElement(MIDI_CC_TYPE, 2, 117) self._do_oct_down.subject = self.octave_down_button self._do_oct_up.subject = self.octave_up_button self._do_base_down.subject = self.base_down_button self._do_base_up.subject = self.base_up_button self._do_scale_down.subject = self.scale_down_button self._do_scale_up.subject = self.scale_up_button self._seg_display = None def set_edit_mode(self, editmode): self._editmode = editmode def set_segment_display(self, displayer): self._seg_display = displayer def get_color(self, value, column, row): button = self.canonical_parent._bmatrix.get_button(column, row) if button != None: midi_note = button.get_identifier() on = value != 0 return self.get_color_by_note_mode(midi_note, on) 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 step_key_color_mode(self): self._note_display_mode = (self._note_display_mode + 1) % len(KEY_COLOR_MODES_STRINGS) self.canonical_parent.show_message('Note Mode Key Color: ' + KEY_COLOR_MODES_STRINGS[self._note_display_mode]) self.canonical_parent.timed_message(2, 'Note Col: ' + KEY_COLOR_MODES_STRINGS[self._note_display_mode]) if self._active: self.assign_transpose(SCALES[self.current_scale_index]) def update_text_display(self): self.text_current_scale() def navigate(self, dir, modifier, alt_modifier = False): if modifier: self.inc_scale(dir) elif alt_modifier: self.inc_base_note(dir) else: self.inc_octave(dir) def _adjust_scale(self, value): if not value == 0 or -1: pass self.inc_scale(1) _adjust_scale = subject_slot('value')(_adjust_scale) def _adjust_octav(self, value): if not value == 0 or -1: pass self.inc_octave(1) _adjust_octav = subject_slot('value')(_adjust_octav) def _adjust_basem(self, value): if not value == 0 or -1: pass self.inc_base_note(1) _adjust_basem = subject_slot('value')(_adjust_basem) def _do_oct_up(self, value): if value != 0: self.inc_octave(1) _do_oct_up = subject_slot('value')(_do_oct_up) def _do_oct_down(self, value): if value != 0: self.inc_octave(-1) _do_oct_down = subject_slot('value')(_do_oct_down) def _do_base_up(self, value): if value != 0: self.inc_base_note(1) _do_base_up = subject_slot('value')(_do_base_up) def _do_base_down(self, value): if value != 0: self.inc_base_note(-1) _do_base_down = subject_slot('value')(_do_base_down) def _do_scale_up(self, value): if value != 0: self.inc_scale(1) _do_scale_up = subject_slot('value')(_do_scale_up) def _do_scale_down(self, value): if value != 0: self.inc_scale(-1) _do_scale_down = subject_slot('value')(_do_scale_down) def get_mode_id(self): return PAD_MODE def text_current_scale(self): scale = SCALES[self.current_scale_index] text = scale.name + ' ' + BASE_NOTE[self._base_note] + str(scale.to_octave(self._octave) - 2) self.canonical_parent.send_to_display(text) def inc_base_note(self, inc): prev_value = self._base_note self._base_note = min(11, max(0, self._base_note + inc)) if prev_value != self._base_note: scale = SCALES[self.current_scale_index] self.canonical_parent.show_message(' Base Note ' + BASE_NOTE[self._base_note] + ' to ' + scale.name) self.text_current_scale() self.update_transpose() if self._seg_display: self._seg_display.timed_segment(self._base_note) def inc_scale(self, inc): nr_of_scales = len(SCALES) - 1 prev_value = self.current_scale_index self.current_scale_index = min(nr_of_scales, max(0, self.current_scale_index + inc)) if prev_value != self.current_scale_index: newscale = SCALES[self.current_scale_index] self.canonical_parent.show_message(' PAD Scale ' + newscale.name + ' ' + BASE_NOTE[self._base_note] + str(newscale.to_octave(self._octave) - 2)) self.text_current_scale() self.update_transpose() if self._seg_display: self._seg_display.timed_segment(self.current_scale_index) 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.canonical_parent.show_message(' OCTAVE ' + BASE_NOTE[self._base_note] + str(newoctave - 2) + ' to ' + scale.name) self.text_current_scale() self.update_transpose() if self._seg_display: val = newoctave - 2 if val < 0: val = 100 + abs(val) self._seg_display.timed_segment(val) def get_octave(self): return SCALES[self.current_scale_index].to_octave(self._octave) def update_transpose(self): if self._active: self.assign_transpose(SCALES[self.current_scale_index]) self.canonical_parent._set_suppress_rebuild_requests(True) self.canonical_parent.request_rebuild_midi_map() self.canonical_parent._set_suppress_rebuild_requests(False) def fitting_mode(self, track): if not track: return self drum_device = find_drum_device(track) if drum_device != None and self._alternate_mode != None: return self._alternate_mode return self def refresh(self): if self._active: scale_len = len(self._scale.notevalues) octave = self._scale.to_octave(self._octave) for (column, row) in self.canonical_parent._bmatrix.iterbuttons(): if button: note_index = (3 - row) * 4 + column scale_index = note_index % scale_len octave_offset = note_index / scale_len note_value = self._scale.notevalues[scale_index] + self._base_note + octave * 12 + octave_offset * 12 button.reset() button.send_color_direct(self.get_color_by_note_mode(note_value, False)) continue def assign_edit_color(self, in_notes, button, note_value): if in_notes: if note_value in in_notes: button.send_color_direct(self.get_color_by_note_mode(note_value, True)) else: button.send_color_direct(self.get_color_by_note_mode(note_value, False)) else: button.send_color_direct(self.get_color_by_note_mode(note_value, False)) def assign_edit_mono(self, in_notes, button, note_value): if in_notes: if note_value in in_notes: button.send_value(127, True) else: button.send_value(0, True) else: button.send_value(0, True) def get_in_notes(self): cs = self.song().view.highlighted_clip_slot if cs.has_clip and cs.clip.is_midi_clip: in_notes = set() notes = cs.clip.get_notes(0, 0, cs.clip.length, 127) for note in notes: in_notes.add(note[0]) return in_notes def assign_transpose(self, scale): if not isinstance(scale, PadScale): raise AssertionError self._scale = scale scale_len = len(scale.notevalues) octave = scale.to_octave(self._octave) last_note_val = None if self._active: if not self._in_edit_mode or self.get_in_notes(): pass in_notes = None for (column, row) in self.canonical_parent._bmatrix.iterbuttons(): if button: note_index = (3 - row) * 4 + column 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._in_edit_mode: self._color_edit_assign(in_notes, button, note_value) else: button.send_color_direct(self.get_color_by_note_mode(note_value, False)) def auto_select(self): return True def _on_notes_changed(self): if self._in_edit_mode: in_notes = self.get_in_notes() if in_notes: for (column, row) in self.canonical_parent._bmatrix.iterbuttons(): if button: if button._msg_identifier in in_notes: button.send_value(127, True) else: button.send_value(0, True) button._msg_identifier in in_notes else: for (column, row) in self.canonical_parent._bmatrix.iterbuttons(): button.send_value(0, True) _on_notes_changed = subject_slot('notes')(_on_notes_changed) def enter_clear_state(self): self._in_edit_mode = True cs = self.song().view.highlighted_clip_slot in_notes = set() if cs != None and cs.has_clip and cs.clip.is_midi_clip: clip = cs.clip notes = clip.get_notes(0, 0, clip.length, 127) self._on_notes_changed.subject = clip for note in notes: in_notes.add(note[0]) else: self._on_notes_changed.subject = None for (column, row) in self.canonical_parent._bmatrix.iterbuttons(): if button: if button._msg_identifier in in_notes: button.send_value(127, True) else: button.send_value(0, True) button.set_to_notemode(False) button.add_value_listener(self._action_clear, True) continue def exit_clear_state(self): self._in_edit_mode = False self._on_notes_changed.subject = None scale_len = len(self._scale.notevalues) octave = self._scale.to_octave(self._octave) for (column, row) in self.canonical_parent._bmatrix.iterbuttons(): if button: note_index = (3 - row) * 4 + column scale_index = note_index % scale_len octave_offset = note_index / scale_len button.send_value(0, True) note_value = self._scale.notevalues[scale_index] + self._base_note + octave * 12 + octave_offset * 12 button.send_color_direct(self.get_color_by_note_mode(note_value, False)) button.set_to_notemode(True) button.remove_value_listener(self._action_clear) continue def _action_clear(self, value, button): if value != 0: self._editmode.edit_note(button._msg_identifier) def enter(self): self._active = True for (column, row) in self.canonical_parent._bmatrix.iterbuttons(): if button: button.send_value(0, True) button.set_to_notemode(True) self.canonical_parent._forwarding_registry[(MIDI_NOTE_ON_STATUS, button.get_identifier())] = button self.canonical_parent._forwarding_registry[(MIDI_NOTE_OFF_STATUS, button.get_identifier())] = button continue self.update_transpose() def exit(self): self._active = False
class AudioClipEditComponent(CompoundComponent): ''' classdocs ''' def __init__(self, *a, **k): super(AudioClipEditComponent, self).__init__(*a, **a) self._loop_start_slider = SliderElement(MIDI_CC_TYPE, 2, 60) self._action_loop_start.subject = self._loop_start_slider self._loop_end_slider = SliderElement(MIDI_CC_TYPE, 2, 61) self._action_loop_end.subject = self._loop_end_slider self._mark_start_slider = SliderElement(MIDI_CC_TYPE, 2, 62) self._action_mark_start.subject = self._mark_start_slider self._mark_end_slider = SliderElement(MIDI_CC_TYPE, 2, 63) self._action_mark_end.subject = self._mark_end_slider self._pitch_c_slider = SliderElement(MIDI_CC_TYPE, 2, 64) self._pitch_f_slider = SliderElement(MIDI_CC_TYPE, 2, 65) self._gain_slider = SliderElement(MIDI_CC_TYPE, 2, 66) self._action_pitch_c.subject = self._pitch_c_slider self._action_pitch_f.subject = self._pitch_f_slider self._action_gain.subject = self._gain_slider self._loop_inc_slider = SliderElement(MIDI_CC_TYPE, 2, 67) self._action_loop_inc.subject = self._loop_inc_slider self._loop_move_button = ButtonElement(False, MIDI_CC_TYPE, 2, 74) self._action_mv_loop.subject = self._loop_move_button self._loop_set_button = ButtonElement(False, MIDI_CC_TYPE, 2, 70) self._action_loop_toggle.subject = self._loop_set_button self._warp_set_button = ButtonElement(False, MIDI_CC_TYPE, 2, 71) self._action_warp_toggle.subject = self._warp_set_button self._zoom_scroll_button = ButtonElement(False, MIDI_CC_TYPE, 2, 73) self._action_scroll_mode.subject = self._zoom_scroll_button self.selected_clip_slot = None self.inc_index = 4 self.loop_inc = INC_STEPS[self.inc_index] self.start_inc = INC_STEPS[self.inc_index] self.mv_loop = False self._on_pitch_c_changed.subject = None self._on_pitch_f_changed.subject = None self._on_gain_changed.subject = None self._scroll_mode = False self.update_selected_clip() def _action_scroll_mode(self, value): if value > 0: self._scroll_mode = True else: self._scroll_mode = False _action_scroll_mode = subject_slot('value')(_action_scroll_mode) def _action_warp_toggle(self, value): if value > 0: if self.selected_clip_slot and self.selected_clip_slot.has_clip: clip = self.selected_clip_slot.clip if clip.is_audio_clip: clip.warping = not (clip.warping) if not clip.warping or 127: pass self._warp_set_button.send_value(0, True) _action_warp_toggle = subject_slot('value')(_action_warp_toggle) def _action_loop_toggle(self, value): if value > 0: if self.selected_clip_slot and self.selected_clip_slot.has_clip: clip = self.selected_clip_slot.clip clip.looping = not (clip.looping) if not clip.looping or 127: pass self._loop_set_button.send_value(0, True) _action_loop_toggle = subject_slot('value')(_action_loop_toggle) def _action_loop_inc(self, value): if not value == 1 or 1: pass inc = -1 val = self.inc_index + inc if val >= 0 and val < len(INC_STEPS): self.inc_index = val self.loop_inc = INC_STEPS[val] self.start_inc = INC_STEPS[val] self.canonical_parent.timed_message( 2, 'Loop Adjust: ' + INC_DISP[val]) self.canonical_parent.show_message('Loop Adjust: ' + INC_DISP[val]) _action_loop_inc = subject_slot('value')(_action_loop_inc) def _action_mv_loop(self, value): if value > 0: if self.mv_loop: self._loop_move_button.send_value(0, True) self.mv_loop = False else: self._loop_move_button.send_value(127, True) self.mv_loop = True _action_mv_loop = subject_slot('value')(_action_mv_loop) def _action_mark_start(self, value): if self._scroll_mode: if not value == 1 or 3: pass scroll = 2 self.application().view.scroll_view(scroll, 'Detail/Clip', False) elif not value == 1 or 1: pass inc = -1 if self.selected_clip_slot and self.selected_clip_slot.has_clip: clip = self.selected_clip_slot.clip ls = clip.start_marker le = clip.end_marker ls = max(0, min(le - self.start_inc, ls + inc * self.start_inc)) clip.start_marker = ls bars_to_measure(ls, clip.signature_denominator, clip.signature_numerator) self.canonical_parent.timed_message( 2, 'Clip Start: ' + bars_to_measure( ls, clip.signature_denominator, clip.signature_numerator)) _action_mark_start = subject_slot('value')(_action_mark_start) def _action_mark_end(self, value): if self._scroll_mode: if not value == 1 or 3: pass scroll = 2 self.application().view.zoom_view(scroll, 'Detail/Clip', False) elif not value == 1 or 1: pass inc = -1 if self.selected_clip_slot and self.selected_clip_slot.has_clip: clip = self.selected_clip_slot.clip ls = clip.start_marker le = clip.end_marker le = max(ls + self.start_inc, le + inc * self.start_inc) clip.end_marker = le self.canonical_parent.timed_message( 2, 'Clip End: ' + bars_to_measure( le, clip.signature_denominator, clip.signature_numerator)) _action_mark_end = subject_slot('value')(_action_mark_end) def _action_loop_start(self, value): if not value == 1 or 1: pass inc = -1 if self.selected_clip_slot and self.selected_clip_slot.has_clip: clip = self.selected_clip_slot.clip ls = clip.loop_start le = clip.loop_end if self.mv_loop: diff = le - ls ls = max(0, ls + inc * self.loop_inc) if inc > 0: clip.loop_end = ls + diff clip.end_marker = ls + diff clip.loop_start = ls clip.start_marker = ls else: clip.loop_start = ls clip.start_marker = ls clip.loop_end = ls + diff clip.end_marker = ls + diff self.canonical_parent.timed_message(2, loop_str(clip)) else: ls = max(0, min(le - self.loop_inc, ls + inc * self.loop_inc)) clip.loop_start = ls self.canonical_parent.timed_message(2, loop_str(clip)) _action_loop_start = subject_slot('value')(_action_loop_start) def _action_loop_end(self, value): if not value == 1 or 1: pass inc = -1 if self.selected_clip_slot and self.selected_clip_slot.has_clip: clip = self.selected_clip_slot.clip ls = clip.loop_start le = clip.loop_end le = max(ls + self.loop_inc, le + inc * self.loop_inc) clip.loop_end = le if self.mv_loop: clip.end_marker = le self.canonical_parent.timed_message(2, loop_str(clip)) _action_loop_end = subject_slot('value')(_action_loop_end) def update(self): pass def _action_pitch_c(self, value): cs = self.selected_clip_slot if cs and cs.has_clip and cs.clip.is_audio_clip: cs.clip.pitch_coarse = midi_to_pitchc(value) _action_pitch_c = subject_slot('value')(_action_pitch_c) def _action_pitch_f(self, value): cs = self.selected_clip_slot if cs and cs.has_clip and cs.clip.is_audio_clip: cs.clip.pitch_fine = midi_to_pitchf(value) _action_pitch_f = subject_slot('value')(_action_pitch_f) def _action_gain(self, value): cs = self.selected_clip_slot if cs and cs.has_clip and cs.clip.is_audio_clip: cs.clip.gain = midi_to_gain(value) _action_gain = subject_slot('value')(_action_gain) def _update_clip_name(self): cs = self.song().view.highlighted_clip_slot if not cs: track = self.song().view.selected_track self.canonical_parent.send_to_display('Rt Trck: ' + track.name, 3) elif cs.has_clip: if not cs.clip.is_audio_clip or 'A': pass self.canonical_parent.send_to_display('M' + ':' + cs.clip.name, 3) else: track = cs.canonical_parent index = list(track.clip_slots).index(cs) scene = self.song().scenes[index] self.canonical_parent.send_to_display( 'E<' + str(scene.name) + '> T:' + track.name, 3) def _on_has_clip_changed(self): self._update_clip_name() _on_has_clip_changed = subject_slot('has_clip')(_on_has_clip_changed) def _on_name_changed(self): self._update_clip_name() _on_name_changed = subject_slot('name')(_on_name_changed) def update_selected_clip(self): cs = self.song().view.highlighted_clip_slot if cs != self.selected_clip_slot: self.selected_clip_slot = cs self._update_clip_name() if cs and cs.has_clip and cs.clip.is_audio_clip: self._on_pitch_c_changed.subject = cs.clip self._on_pitch_f_changed.subject = cs.clip self._on_gain_changed.subject = cs.clip self._on_warp_changed.subject = cs.clip self._gain_slider.send_value(gain_to_midi(cs.clip.gain)) self._pitch_c_slider.send_value( pitchc_to_midi(cs.clip.pitch_coarse)) self._pitch_f_slider.send_value( pitchf_to_midi(cs.clip.pitch_fine)) if not cs.clip.warping or 127: pass self._warp_set_button.send_value(0, True) else: self._on_pitch_c_changed.subject = None self._on_pitch_f_changed.subject = None self._on_gain_changed.subject = None self._on_warp_changed.subject = None self._on_loop_changed.subject = None if cs and cs.has_clip: self._on_loop_changed.subject = cs.clip self._on_name_changed.subject = cs.clip if not cs.clip.looping or 127: pass self._loop_set_button.send_value(0, True) else: self._on_name_changed.subject = None self._on_loop_changed.subject = None self._on_has_clip_changed.subject = cs def on_selected_track_changed(self): self.update_selected_clip() def on_selected_scene_changed(self): self.update_selected_clip() def _on_loop_changed(self): cs = self.song().view.highlighted_clip_slot if cs and cs.has_clip: if not cs.clip.looping or 127: pass self._loop_set_button.send_value(0, True) _on_loop_changed = subject_slot('looping')(_on_loop_changed) def _on_warp_changed(self): cs = self.song().view.highlighted_clip_slot if cs and cs.has_clip and cs.clip.is_audio_clip: if not cs.clip.warping or 127: pass self._warp_set_button.send_value(0, True) _on_warp_changed = subject_slot('warping')(_on_warp_changed) def _on_pitch_c_changed(self): cs = self.song().view.highlighted_clip_slot if cs and cs.has_clip and cs.clip.is_audio_clip: self._pitch_c_slider.send_value( pitchc_to_midi(cs.clip.pitch_coarse)) _on_pitch_c_changed = subject_slot('pitch_coarse')(_on_pitch_c_changed) def _on_pitch_f_changed(self): cs = self.song().view.highlighted_clip_slot if cs and cs.has_clip and cs.clip.is_audio_clip: self._pitch_f_slider.send_value(pitchf_to_midi(cs.clip.pitch_fine)) _on_pitch_f_changed = subject_slot('pitch_fine')(_on_pitch_f_changed) def _on_gain_changed(self): cs = self.song().view.highlighted_clip_slot if cs and cs.has_clip and cs.clip.is_audio_clip: self._gain_slider.send_value(gain_to_midi(cs.clip.gain)) _on_gain_changed = subject_slot('gain')(_on_gain_changed)
class EditSection(CompoundComponent): def __init__(self, *a, **k): super(EditSection, self).__init__(*a, **a) 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 self.initial_clip_len = 4 self._focused_clip = None self._focused_c_index = None self._color_edit = False self.nav_index = 0 def disconnect(self): super(EditSection, self).disconnect() def init(self): self._color_edit_button.send_value(0, True) def set_color_edit(self, val): self._color_edit = val def is_color_edit(self): return self._color_edit def connect_session(self, session): for sindex in range(session.height()): scene = session.scene(sindex) for cindex in range(session.width()): clip = scene.clip_slot(cindex) clip.set_modifier(self) def set_mode_selector(self, mode_selector): self._mode_selector = mode_selector self._mode_selector.assign_edit_section(self) def _do_shift_mikro(self, value): self.mikro_shift = value != 0 self.shiftdown = value != 0 if self._mode_selector: self._mode_selector.set_shift_state(self.mikro_shift) _do_shift_mikro = subject_slot('value')(_do_shift_mikro) def _do_shift(self, value): self.shiftdown = value != 0 _do_shift = subject_slot('value')(_do_shift) def _do_alt(self, value): self.altdown = value != 0 _do_alt = subject_slot('value')(_do_alt) def modifiers(self): if self.shiftdown: pass if self.altdown: pass return 1 | 1 << 1 def isShiftdown(self): return self.shiftdown def isAltdown(self): return self.altdown def isClipAltDown(self): if not self.altdown: pass return self._mode_selector.isClipDown() def hasModification(self, mode): if mode == SCENE_MODE: return self.edit_state != ES_NONE elif mode == CLIP_MODE: if self.edit_state != ES_NONE: return True elif self._color_edit: return True return False def update(self): pass def _get_current_slot(self, song): scene = song.view.selected_scene track = song.view.selected_track clip_slot = song.view.highlighted_clip_slot scenes = song.scenes tracks = song.tracks sindex = vindexof(scenes, scene) tindex = vindexof(tracks, track) return (clip_slot, track, scenes, tindex, sindex) def do_message(self, msg, statusbarmsg = None): if statusbarmsg == None: self.canonical_parent.show_message(msg) else: self.canonical_parent.show_message(statusbarmsg) self.canonical_parent.timed_message(2, msg) def edit_note(self, note_value): self.pad_action = True if self.edit_state == ES_CLEAR: cs = self.song().view.highlighted_clip_slot if cs and cs.has_clip and cs.clip.is_midi_clip: if self.shiftdown: cs.clip.remove_notes(0, 0, cs.clip.length, 127) else: cs.clip.remove_notes(0, note_value, cs.clip.length, 1) def edit_scene_slot(self, scene, index): self.pad_action = True if scene != None: song = self.song() if self.edit_state == ES_DUPLICATE: self.do_message('Duplicate Scene ' + str(scene.name)) song.duplicate_scene(index) elif self.edit_state == ES_NEW: idx = 1 if self.shiftdown: idx = 0 song.create_scene(index + idx) self.do_message('Create Scene ' + str(self.song().view.selected_scene.name)) elif self.edit_state == ES_CLEAR: self.do_message('Delete Scene ' + str(scene.name)) song.delete_scene(index) elif self.edit_state == ES_DOUBLE: song.capture_and_insert_scene() scene = self.song().view.selected_scene self.do_message('Capture to ' + scene.name) elif self.edit_state == ES_NUDGE: self.clear_auto_scene(scene, index) self.do_message('Clr Env in Scene ' + scene.name) elif self.edit_state == ES_QUANT: pass elif self.edit_state == ES_NAVIGATE: self.song().view.selected_scene = scene def duplciate_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.do_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 _action_set_quant(self, value): if not value == 0 or -1: pass self.mod_quant_size(1) _action_set_quant = subject_slot('value')(_action_set_quant) def _action_init_loop(self, value): if not value == 0 or -1: pass self.mod_new_initlen(1) _action_init_loop = subject_slot('value')(_action_init_loop) def mod_new_initlen(self, diff): if abs(diff) == 4: newval = self.initial_clip_len + diff newval = int(newval / 4) * 4 self.initial_clip_len = max(4, min(64, newval)) else: self.initial_clip_len = max(1, min(64, self.initial_clip_len + diff)) self.canonical_parent.timed_message(2, 'Init Clip Len: ' + str(int(self.initial_clip_len)) + ' Beats', True) self.canonical_parent.show_message('Initial Clip Length : ' + str(int(self.initial_clip_len)) + ' beats') def mod_quant_size(self, diff): self.quantize = max(1, min(len(QUANT_CONST) - 1, self.quantize + diff)) self.canonical_parent.timed_message(2, 'Quantize: ' + QUANT_STRING[self.quantize], True) self.canonical_parent.show_message('Quantize set to : ' + QUANT_STRING[self.quantize]) def knob_pad_action(self, activate): if activate: self.pad_wheel_action = True self.edit_state = ES_KNOB self._focused_clip = None else: self.pad_wheel_action = False self.edit_state = ES_NONE self._focused_clip = None def edit_colors(self, diff, jump_selection = False): pass def edit_clip_slot(self, clipslot_component, value): if self._color_edit: if value != 0: if clipslot_component._clip_slot != None: self._focused_clip = clipslot_component self._mode_selector.pick_color(clipslot_component) else: self._focused_clip = None else: self.pad_action = True if value != 0 and clipslot_component._clip_slot != None: clip_slot = clipslot_component._clip_slot if self.edit_state == ES_DUPLICATE: if self.shiftdown: self.duplicate_track_cs(clip_slot) else: self.duplciate_clip_slot(clip_slot) elif self.edit_state == ES_NEW: if self.shiftdown: self.create_new_midi_track(clip_slot) else: self.create_new_clip(clip_slot) elif self.edit_state == ES_CLEAR: if self.altdown: if clip_slot.clip != None: clip = clip_slot.clip if clip.is_midi_clip: self.do_message('Clear all Notes in Clip') clip.remove_notes(0, 0, clip.length, 127) elif self.shiftdown: self.delete_track_cs(clip_slot) elif clip_slot.clip: self.do_message('Delete Clip ' + clip_slot.clip.name) clipslot_component._do_delete_clip() elif self.edit_state == ES_DOUBLE: if self.shiftdown: self.create_new_audio_track(clip_slot) else: self.double_clipslot(clip_slot) elif self.edit_state == ES_NUDGE: if self.shiftdown: self._new_return_track() else: self.clear_automation(clip_slot) elif self.edit_state == ES_QUANT: self.quantize_clisplot(clipslot_component._clip_slot) elif self.edit_state == ES_NAVIGATE: clipslot_component._do_select_clip(clipslot_component._clip_slot) if self.canonical_parent.arm_selected_track: arm_exclusive(self.song()) def _new_return_track(self): song = self.song() song.create_return_track() self.do_message('New Return Track') def _new_scene(self): song = self.song() scene = song.view.selected_scene sindex = vindexof(song.scenes, scene) if not sindex >= 0 or sindex: pass sindex = 0 song.create_scene(sindex + 1) new_scene = song.view.selected_scene self.do_message('New Scene ' + new_scene.name) def _new_audio_track(self): song = self.song() track = song.view.selected_track tindex = 0 if not track.can_be_armed: tindex = len(song.tracks) - 1 else: tindex = vindexof(song.tracks, track) if not tindex >= 0 or tindex: pass tindex = 0 song.create_audio_track(tindex + 1) track = song.view.selected_track self.do_message('New Audio Track ' + track.name) def _new_midi_track(self): song = self.song() track = song.view.selected_track tindex = 0 if not track.can_be_armed: tindex = len(song.tracks) - 1 else: tindex = vindexof(song.tracks, track) if not tindex >= 0 or tindex: pass tindex = 0 song.create_midi_track(tindex + 1) track = song.view.selected_track self.do_message('New MIDI Track ' + track.name) def _new_midi_clip(self): song = self.song() if song.view.selected_track.has_midi_input: clip_slot = song.view.highlighted_clip_slot if clip_slot != None and not (clip_slot.has_clip): clip_slot.create_clip(self.initial_clip_len) song.view.detail_clip = clip_slot.clip self.do_message('New MIDI Clip ' + clip_slot.clip.name) self.application().view.show_view('Detail') def quantize_scene(self, scene, index, fiftyPerc): tracks = self.song().tracks for track in tracks: clipslots = track.clip_slots if len(clipslots) >= index and clipslots[index].clip != None: if not self.shiftdown or 0.5: pass clipslots[index].clip.quantize(QUANT_CONST[self.quantize], 1) continue def clear_auto_scene(self, scene, index): tracks = self.song().tracks for track in tracks: clipslots = track.clip_slots if len(clipslots) >= index and clipslots[index].clip != None: clipslots[index].clip.clear_all_envelopes() continue def _capture_new_scene(self): self.song().capture_and_insert_scene() scene = self.song().view.selected_scene self.do_message('Capture to ' + scene.name) def _duplicate_selected_scene(self): song = self.song() scene = song.view.selected_scene sindex = vindexof(song.scenes, scene) if scene and sindex >= 0: self.do_message('Duplicate Scene ' + scene.name) song.duplicate_scene(sindex) def _duplicate_selected_track(self): song = self.song() track = song.view.selected_track t_index = track_index(song, track) if track and t_index and t_index[1] == TYPE_TRACK_SESSION: tindex = t_index[0] self.do_message('Dupl. Track ' + track.name, 'Duplicate Track ' + track.name) song.duplicate_track(tindex) def _duplicate_selected_clip(self): song = self.song() (clip_slot, track, scenes, tindex, sindex) = self._get_current_slot(song) if clip_slot != None and clip_slot.clip != None: self.do_message('Duplicate ' + clip_slot.clip.name, 'Duplicate Clip ' + clip_slot.clip.name) track.duplicate_clip_slot(sindex) index = sindex + 1 if index >= 0 and index < len(scenes): song.view.selected_scene = scenes[index] def duplicate_track_cs(self, clip_slot): if clip_slot != None: song = self.song() track = clip_slot.canonical_parent t_index = track_index(song, track) if track and t_index and t_index[1] == TYPE_TRACK_SESSION: tindex = t_index[0] self.do_message('Duplicate Track ' + track.name) song.duplicate_track(tindex) def clear_automation(self, clip_slot): song = self.song() if clip_slot != None and clip_slot.clip != None: self.do_message('Clr.Env. ' + clip_slot.clip.name, 'Clear Envelopes ' + clip_slot.clip.name) clip_slot.clip.clear_all_envelopes() def quantize_clisplot(self, clip_slot): if clip_slot.clip != None: if not self.shiftdown or ' 50%': pass self.do_message('Quantize Clip: ' + clip_slot.clip.name + '') if not self.shiftdown or 0.5: pass clip_slot.clip.quantize(QUANT_CONST[self.quantize], 1) self.song().view.detail_clip = clip_slot.clip self.canonical_parent.focus_clip_detail() def double_clipslot(self, clip_slot): song = self.song() track = clip_slot.canonical_parent if clip_slot.clip != None and track.has_midi_input: clip = clip_slot.clip if clip.length <= 2048: clip.duplicate_loop() self.do_message('Dupl. Lp: ' + str(int(clip.length / 4)) + ' Bars') song.view.detail_clip = clip self.canonical_parent.focus_clip_detail() else: self.do_message('Clip is to long to Duplicate') def create_new_clip(self, clip_slot): song = self.song() track = clip_slot.canonical_parent if clip_slot.clip == None and track.has_midi_input: clip_slot.create_clip(self.initial_clip_len) song.view.detail_clip = clip_slot.clip select_clip_slot(song, clip_slot) self.canonical_parent.focus_clip_detail() self.do_message('New Midi Clip ' + song.view.highlighted_clip_slot.clip.name) def create_new_midi_track(self, clip_slot): if clip_slot != None: song = self.song() track = clip_slot.canonical_parent tindex = vindexof(song.tracks, track) if not tindex >= 0 or tindex: pass tindex = 0 song.create_midi_track(tindex + 1) track = song.view.selected_track self.do_message('New Midi Track ' + track.name) def create_new_audio_track(self, clip_slot): if clip_slot != None: song = self.song() track = clip_slot.canonical_parent tindex = vindexof(song.tracks, track) if not tindex >= 0 or tindex: pass tindex = 0 song.create_audio_track(tindex + 1) track = song.view.selected_track self.do_message('New Audio Track ' + track.name) def delete_track_cs(self, clip_slot): if clip_slot != None: song = self.song() track = clip_slot.canonical_parent t_index = track_index(song, track) if track and len(song.tracks) > 1 and t_index and t_index[1] == TYPE_TRACK_SESSION: self.do_message('Delete Track ' + track.name) song.delete_track(t_index[0]) def _double_selected_clip(self): song = self.song() clip_slot = song.view.highlighted_clip_slot if clip_slot != None and clip_slot.clip != None and song.view.selected_track.has_midi_input: clip = clip_slot.clip if clip.length <= 2048: clip_slot.clip.duplicate_loop() self.do_message('Dupl. Lp ' + str(int(clip_slot.clip.length / 4)) + ' Bars') song.view.detail_clip = clip_slot.clip self.canonical_parent.focus_clip_detail() else: self.do_message('Clip is to long to Duplicate') def _clear_events(self): song = self.song() clip_slot = song.view.highlighted_clip_slot if clip_slot != None and clip_slot.clip != None: self.do_message('Clr.Env. ' + clip_slot.clip.name, 'Clear Envelopes ' + clip_slot.clip.name) clip_slot.clip.clear_all_envelopes() def _delete_current_clip(self): song = self.song() clip_slot = song.view.highlighted_clip_slot if clip_slot != None and clip_slot.clip != None: self.do_message('Delete Clip ' + clip_slot.clip.name) clip_slot.delete_clip() def _delete_selected_track(self): song = self.song() track = song.view.selected_track t_index = track_index(song, track) if track and len(song.tracks) > 1 and t_index and t_index[1] == TYPE_TRACK_SESSION: self.do_message('Delete Track ' + track.name) song.delete_track(t_index[0]) def _delete_selected_scene(self): song = self.song() scene = song.view.selected_scene sindex = vindexof(song.scenes, scene) if scene and len(song.scenes) > 1 and sindex >= 0: self.do_message('Delete Scene ' + scene.name) song.delete_scene(sindex) def _click_duplicate(self): modifiers = self.modifiers() if modifiers == 0: self._duplicate_selected_clip() elif modifiers == 1: self._duplicate_selected_track() elif modifiers == 2: self._duplicate_selected_scene() def _click_new(self): modifiers = self.modifiers() if modifiers == 0: self._new_midi_clip() elif modifiers == 1: self._new_midi_track() elif modifiers == 2: self._new_scene() def _click_double(self): modifiers = self.modifiers() if modifiers == 0: self._double_selected_clip() elif modifiers == 1: self._new_audio_track() elif modifiers == 2: self._capture_new_scene() def _click_clear(self): modifiers = self.modifiers() if modifiers == 0: self._delete_current_clip() elif modifiers == 1: self._delete_selected_track() elif modifiers == 2: self._delete_selected_scene() def _click_quantize(self): song = self.song() clip_slot = song.view.highlighted_clip_slot if clip_slot != None: self.quantize_clisplot(clip_slot) def _click_nudge(self): modifiers = self.modifiers() if modifiers == 0: self._clear_events() elif modifiers == 1: self._new_return_track() elif modifiers == 2: pass def _select(self, button): if self._down_button: self._down_button.turn_off() button.turn_on() self._down_button = button self.action_time = int(round(time.time() * 1000)) def _deselect(self, button): if button == self._clear_button: self._mode_selector.exit_clear_state() if self._down_button == button: self._down_button.turn_off() self._down_button = None prev_state = self.edit_state self.edit_state = ES_NONE modeid = self._mode_selector.mode().get_mode_id() if self.pad_action: self.pad_action = False return False if modeid == CLIP_MODE or modeid == SCENE_MODE: return False if (modeid == PAD_MODE or modeid == CONTROL_MODE) and prev_state == ES_CLEAR: return False else: return True self.pad_action = False return False def _action_navigate(self, value): if self.isShiftdown() and value != 0: self.nav_index = (self.nav_index + 1) % len(VIEWS_ALL) self.application().view.focus_view(VIEWS_ALL[self.nav_index]) self.canonical_parent.show_message('Focus on : ' + str(VIEWS_ALL[self.nav_index])) elif value != 0: self._select(self._nav_button) self.edit_state = ES_NAVIGATE else: self._deselect(self._nav_button) _action_navigate = subject_slot('value')(_action_navigate) def _action_duplicate(self, value): if value != 0: self._select(self._copy_button) self.edit_state = ES_DUPLICATE elif self._deselect(self._copy_button): self._click_duplicate() _action_duplicate = subject_slot('value')(_action_duplicate) def _action_new(self, value): if value != 0: self._select(self._paste_button) self.edit_state = ES_NEW elif self._deselect(self._paste_button): self._click_new() _action_new = subject_slot('value')(_action_new) def _action_note(self, value): if value != 0: self._select(self._note_button) self.edit_state = ES_DOUBLE elif self._deselect(self._note_button): self._click_double() _action_note = subject_slot('value')(_action_note) def _action_clear(self, value): self.canonical_parent._hold_clear_action(value) if value != 0: self._mode_selector.enter_clear_state() self._select(self._clear_button) self.edit_state = ES_CLEAR elif self._deselect(self._clear_button): self._click_clear() _action_clear = subject_slot('value')(_action_clear) def _action_nudge_button(self, value): if value != 0: self._select(self._nudge_button) self.edit_state = ES_NUDGE elif self._deselect(self._nudge_button): self._click_nudge() _action_nudge_button = subject_slot('value')(_action_nudge_button) def _action_quantize(self, value): if value != 0: self._select(self._quantize_button) self.edit_state = ES_QUANT elif self._deselect(self._quantize_button): self._click_quantize() _action_quantize = subject_slot('value')(_action_quantize) def _toggle_color_mode(self, value): if value != 0: session = self.canonical_parent._session if session.is_color_mode(): self._color_mode_button.switch_off() session._change_color_mode(1) else: self._color_mode_button.send_color(1) session._change_color_mode(1) _toggle_color_mode = subject_slot('value')(_toggle_color_mode)
class MidiEditSection(CompoundComponent): _current_clip = None _split_value = 4 _base_note = None _gate = 1 _selected_note = None _note_pos = None _note_len = 0 _bend_val = 0 _offset = 0 _transpose = 0 _vel_fade = 0 _fade_mode = FADE_TIME _note_set = None _note_index = 0 def __init__(self, *a, **k): super(MidiEditSection, self).__init__(*a, **a) is_momentary = True self.split_knob = SliderElement(MIDI_CC_TYPE, 5, 70) self.gate_knob = SliderElement(MIDI_CC_TYPE, 5, 71) self.bend_knob = SliderElement(MIDI_CC_TYPE, 5, 72) self.offset_knob = SliderElement(MIDI_CC_TYPE, 5, 73) self.strech_knob = SliderElement(MIDI_CC_TYPE, 5, 74) self.fade_knob = SliderElement(MIDI_CC_TYPE, 5, 75) self.transpose_knob = SliderElement(MIDI_CC_TYPE, 5, 77) self.edit_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 5, 60) self.split_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 5, 61) self.init_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 5, 62) self.delete_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 5, 63) self.select_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 5, 64) self._do_edit_button.subject = self.edit_button self._do_split_button.subject = self.split_button self._do_delete.subject = self.delete_button self._do_init.subject = self.init_button self._do_select.subject = self.select_button self._do_split.subject = self.split_knob self._do_gate.subject = self.gate_knob self._do_bend.subject = self.bend_knob self._do_offset.subject = self.offset_knob self._do_strech.subject = self.strech_knob self._do_fade.subject = self.fade_knob self._do_transpose.subject = self.transpose_knob def do_message(self, msg, statusbarmsg = None): if statusbarmsg == None: self.canonical_parent.show_message(msg) else: self.canonical_parent.show_message(statusbarmsg) self.canonical_parent.timed_message(2, msg) def _init_value(self): self._split_value = 4 def select_note(self, note): if self._current_clip and self._note_set: self._note_index = 0 self.set_notes(tuple(self._note_set[self._note_index])) def _do_select(self, value): if value == 0: clip_slot = self.song().view.highlighted_clip_slot if clip_slot and clip_slot.has_clip and clip_slot.clip.is_midi_clip: clip = clip_slot.clip self._notes_changed.subject = clip self._current_clip = clip self._note_set = clip.get_notes(0, 0, clip.length, 127) if self._note_index == None: self._note_index = 0 else: self._note_index = (self._note_index + 1) % len(self._note_set) ls = [] selnote = self._note_set[self._note_index] ls.append(selnote) clip.remove_notes(selnote[1], selnote[0], selnote[2], 1) clip.deselect_all_notes() clip.set_notes(tuple(ls)) clip.replace_selected_notes(tuple(ls)) _do_select = subject_slot('value')(_do_select) def _do_delete(self, value): if value != 0: self._selected_note = None self.edit_button.send_value(0, True) if self._current_clip: selected = self._current_clip.get_selected_notes() for note in selected: pitch = note[0] self._current_clip.remove_notes(note[1], pitch, note[2], 1) _do_delete = subject_slot('value')(_do_delete) def _do_init(self, value): if value != 0: self._transpose = 0 self._offset = 0 self._bend_val = 0 self._split_value = 4 self._vel_fade = 0 self._gate = 1 self.canonical_parent.timed_message(2, 'SPLIT:' + str(self._split_value)) _do_init = subject_slot('value')(_do_init) def _do_edit_button(self, value): if value > 0: note = self.get_selected_note() self._transpose = 0 if note: self.edit_button.send_value(127, True) else: self.edit_button.send_value(0, True) _do_edit_button = subject_slot('value')(_do_edit_button) def get_selected_note(self): clip_slot = self.song().view.highlighted_clip_slot if clip_slot and clip_slot.has_clip and clip_slot.clip.is_midi_clip: self._notes_changed.subject = clip_slot.clip self._current_clip = clip_slot.clip notes = self._current_clip.get_selected_notes() if len(notes) == 1: self._selected_note = notes[0] self._base_note = self._selected_note[0] self._note_len = self._selected_note[2] self._note_pos = self._selected_note[1] return notes[0] def execute_transpose(self, dir): clip_slot = self.song().view.highlighted_clip_slot if clip_slot and clip_slot.has_clip and clip_slot.clip.is_midi_clip: clip = clip_slot.clip notes = clip.get_selected_notes() if len(notes) > 0: list = [] for note in notes: pitch = min(max(note[0] + dir, 0), 127) list.append((note[0] + dir, note[1], note[2], note[3], note[4])) clip.replace_selected_notes(tuple(list)) def execute_split(self): selected_note = self._selected_note if selected_note: notelen = self._note_len note = min(max(0, self._base_note + self._transpose), 127) vel = self._selected_note[3] mute = self._selected_note[4] sp = self._note_pos pos = self._note_pos if self._vel_fade < 0: endvel = vel startvel = vel - vel * abs(self._vel_fade) else: startvel = vel endvel = vel - vel * self._vel_fade list = [] divList = self.get_interval(notelen, self._split_value, self._bend_val) off = int(self._split_value * self._offset) velinc = (endvel - startvel) / self._split_value vel = startvel for index in range(self._split_value): pcl = int((index + off) % self._split_value) div = divList[pcl] notvlen = div * self._gate if notvlen > 0: list.append((note, pos, notvlen, vel, mute)) pos += div if self._fade_mode == FADE_EVENT: vel += velinc continue rp = (pos - sp) / notelen vel = startvel + (endvel - startvel) * rp self._current_clip.replace_selected_notes(tuple(list)) def _do_transpose(self, value): if not value == 0 or -1: pass diff = 1 self.execute_transpose(diff) _do_transpose = subject_slot('value')(_do_transpose) def _do_fade(self, value): if self.canonical_parent.isShiftDown(): if not value == 0 or -0.01: pass diff = 0.01 elif not value == 0 or -0.1: pass diff = 0.1 newvale = self._vel_fade + diff if newvale >= -1 and newvale <= 1: self._vel_fade = newvale self.canonical_parent.timed_message(2, 'FADE:' + str(int(round(self._vel_fade * 100, 0))) + '%') self.canonical_parent.show_message('Split Fade: ' + str(int(round(self._vel_fade * 100, 0))) + '%') self.execute_split() _do_fade = subject_slot('value')(_do_fade) def _do_strech(self, value): if not value == 0 or -1: pass diff = 1 if self.canonical_parent.isShiftDown(): newval = self._note_len + diff * STRECH_INC_PLS else: newval = self._note_len + diff * STRECH_INC if newval > 0: self._note_len = newval self.execute_split() self.canonical_parent.timed_message(2, 'LENGTH:' + str(self._note_len) + ' BEATS') self.canonical_parent.show_message('Set Length TO : ' + str(self._note_len) + ' beats') _do_strech = subject_slot('value')(_do_strech) def _do_offset(self, value): if not value == 0 or -0.01: pass diff = 0.01 newval = self._offset + diff if newval >= 0 and newval <= 1: self._offset = newval self.canonical_parent.timed_message(2, 'OFF:' + str(round(self._offset, 2))) self.canonical_parent.show_message('Split Offset : ' + str(round(self._offset, 2))) self.execute_split() _do_offset = subject_slot('value')(_do_offset) def _do_split_button(self, value): if value != 0: self.execute_split() _do_split_button = subject_slot('value')(_do_split_button) def _notes_changed(self): pass _notes_changed = subject_slot('notes')(_notes_changed) def _do_split(self, value): if not value == 0 or -1: pass diff = 1 newval = self._split_value + diff if newval > 0 and newval <= 128: self._split_value = newval self.canonical_parent.timed_message(2, 'SPLIT:' + str(self._split_value)) self.canonical_parent.show_message('Splits : ' + str(self._split_value)) self.execute_split() _do_split = subject_slot('value')(_do_split) def _do_gate(self, value): if not value == 0 or -0.01: pass diff = 0.01 newval = self._gate + diff if newval > 0.1 and newval <= 1: self._gate = newval self.canonical_parent.timed_message(2, 'GATE:' + str(int(round(self._gate * 100, 0))) + '%') self.canonical_parent.show_message('Split Gate: ' + str(int(round(self._gate * 100, 0))) + '%') self.execute_split() _do_gate = subject_slot('value')(_do_gate) def get_interval__(self, notelen): div = notelen / self._split_value n = self._split_value ls = [] sum = 0 ct = self._split_value rl = notelen bv = self._bend_val / 100 param = abs(bv) * (self._split_value / 2) for i in range(n): div = rl / ct sz = div * (1 + param) ls.append(sz) ct -= 1 rl -= sz sum = 0 for v in ls: sum += v ratio = notelen / sum for i in range(len(ls)): ls[i] = ls[i] * ratio if not self._bend_val < 0 or ls.reverse(): pass return ls def get_interval(self, notelen, splits, bend_val): div = notelen / splits n = splits ls = [] param = abs(bend_val / 100) spl = 2 for i in range(n): sec = notelen / spl ls.append(sec) if i < n - 2: spl *= 1 + param continue acc = 0 for v in ls: acc += v ratio = notelen / acc for i in range(len(ls)): ls[i] = ls[i] * ratio if not bend_val < 0 or ls.reverse(): pass return ls def _do_bend(self, value): if not value == 0 or -1: pass diff = 1 newval = self._bend_val + diff if newval >= -100 and newval <= 100 and self._selected_note: self._bend_val = newval self.canonical_parent.timed_message(2, 'BEND:' + str(self._bend_val) + '%') self.canonical_parent.show_message('Split Bend: ' + str(self._bend_val) + '%') list = self.get_interval(self._selected_note[2], self._split_value, self._bend_val) self.execute_split() _do_bend = subject_slot('value')(_do_bend) def _on_selected_track_changed(self): debug_out(' Selected Track Changed ') def update(self): pass def refresh(self): pass