class MaschineSessionComponent(SessionComponent): __doc__ = 'Session Component for Maschine' __module__ = __name__ 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 @subject_slot('value') 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) 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): color = self._advance == STEP4 and COLOR_HUE_NAV4 or 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() @subject_slot('value') def _toggle_step_advance(self, value): if value != 0: self.set_step_advance(self._advance == STEP4 and STEP1 or STEP4) def switch_step_advance(self): self.set_step_advance(self._advance == STEP4 and STEP1 or 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 @subject_slot('value') def _do_matrix_adv_mode(self, value): if not self._mode_button is not None: raise AssertionError else: assert value in range(128) 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) def update(self): SessionComponent.update(self) try: self._advance 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 else: ctrack = song.tracks[count] def get_color_cmode(self, clip_slot): if clip_slot is None: return PColor.OFF color = self.get_color_cmode_base(clip_slot) oncolor = color[0] offcolor = color[1] if clip_slot.has_clip and not clip_slot.clip.is_recording: if clip_slot.clip.will_record_on_start: return (oncolor, oncolor) if clip_slot.clip.is_triggered: return (oncolor, oncolor) if clip_slot.clip.is_playing: return (oncolor, oncolor) return (offcolor, offcolor) else: if clip_slot.will_record_on_start: return CLR_REC if clip_slot.is_playing: return PColor.CLIP_GROUP_PLAY if clip_slot.controls_other_clips: return PColor.CLIP_GROUP_CONTROL if 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 and not clip_slot.clip.is_recording: if clip_slot.clip.will_record_on_start: if clip_slot.clip.is_triggered: return PColor.CLIP_RECORD_TRIGGER return PColor.CLIP_RECORD if clip_slot.clip.is_playing: return PColor.CLIP_PLAY if clip_slot.clip.is_triggered: return PColor.CLIP_PLAY_TRIGGER return PColor.CLIP_STOPPED if clip_slot.will_record_on_start: return PColor.CLIP_RECORD_TRIGGER if clip_slot.is_playing: return PColor.CLIP_GROUP_PLAY if clip_slot.controls_other_clips: return PColor.CLIP_GROUP_CONTROL if 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 and not clip_slot.clip.is_recording: if clip_slot.clip.will_record_on_start: if clip_slot.clip.is_triggered: return (1, 2) return (1, 1) if clip_slot.clip.is_playing: return (1, 1) if clip_slot.clip.is_triggered: return (1, 2) return (1, 0) if clip_slot.will_record_on_start: return (1, 2) if clip_slot.is_playing: return (1, 1) if clip_slot.controls_other_clips: return (1, 0) if 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 is not None and clip_slot.has_clip: if clip_slot.clip.is_triggered: button.send_color_direct(color[int(index)]) elif clip_slot.is_triggered: button.send_color_direct(color[int(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: button.send_color_direct(sblink == 0 and color[0] or REC) else: if clip_slot.clip.is_triggered: button.send_color_direct(color[sblink]) else: if 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: button.send_color_direct(sblink == 0 and REC or 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: button.send_color_direct(sblink == 0 and TRIGG or TRIGG_DIM) def convertToHSB(self, rgb_color): return toHSB(rgb_color) def get_color_cmode_base(self, clip_slot): if clip_slot is not None: if clip_slot.has_clip: rgb = clip_slot.clip.color color = self._color_manager.convertToHSB(clip_slot.clip.color) return color if 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 is not 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() else: 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 LaunchMod(Launchpad): def __init__(self, *a, **k): ControlSurface.__init__(self, *a, **k) with self.component_guard(): self._monomod_version = 'b996' self._host_name = 'LaunchMod' self._color_type = 'Launchpad' self._timer = 0 self._suppress_send_midi = True self._suppress_session_highlight = True self._suppress_highlight = False is_momentary = True self._suggested_input_port = 'Launchpad' self._suggested_output_port = 'Launchpad' self._control_is_with_automap = False self._user_byte_write_button = ButtonElement( is_momentary, MIDI_CC_TYPE, 0, 16) self._user_byte_write_button.name = 'User_Byte_Button' self._user_byte_write_button.send_value(1) self._user_byte_write_button.add_value_listener( self._user_byte_value) self._wrote_user_byte = False self._challenge = Live.Application.get_random_int( 0, 400000000) & 2139062143 matrix = ButtonMatrixElement() matrix.name = 'Button_Matrix' for row in range(8): button_row = [ ConfigurableButtonElement( is_momentary, MIDI_NOTE_TYPE, 0, row * 16 + column, str(column) + '_Clip_' + str(row) + '_Button', self) for column in range(8) ] matrix.add_row(tuple(button_row)) self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0, optimized_send_midi=False) self._config_button.add_value_listener(self._config_value) top_button_names = [ 'Bank_Select_Up_Button', 'Bank_Select_Down_Button', 'Bank_Select_Left_Button', 'Bank_Select_Right_Button', 'Session_Button', 'User1_Button', 'User2_Button', 'Mixer_Button' ] side_button_names = [ 'Vol_Button', 'Pan_Button', 'SndA_Button', 'SndB_Button', 'Stop_Button', 'Trk_On_Button', 'Solo_Button', 'Arm_Button' ] top_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0, 104 + index, top_button_names[index], self) for index in range(8) ] side_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index], side_button_names[index], self) for index in range(8) ] self._side_buttons = ButtonMatrixElement() self._side_buttons.add_row(side_buttons) self._setup_monobridge() self._setup_mod() self._selector = MainSelectorComponent(self, matrix, tuple(top_buttons), tuple(side_buttons), self._config_button) self._selector.name = 'Main_Modes' for control in self.controls: isinstance(control, MonoButtonElement) and control.add_value_listener( self._button_value) self.set_highlighting_session_component( self._selector.session_component()) self._suppress_session_highlight = False self.log_message('--------------= ' + str(self._monomod_version) + ' log opened =--------------') """Mono overrides and additions""" def _setup_monobridge(self): self._monobridge = MonoBridgeElement(self) self._monobridge.name = 'MonoBridge' def _setup_mod(self): self.monomodular = get_monomodular(self) self.monomodular.name = 'monomodular_switcher' self.modhandler = LaunchModHandler(self) self.modhandler.name = 'ModHandler' #self.modhandler.layer = Layer( lock_button = self._note_mode_button, push_grid = self._matrix, shift_button = self._shift_button, alt_button = self._select_button, key_buttons = self._track_state_buttons) #self.modhandler.layer.priority = 4 #self.modhandler.nav_buttons_layer = AddLayerMode( self.modhandler, Layer(nav_up_button = self._nav_up_button, nav_down_button = self._nav_down_button, nav_left_button = self._nav_left_button, nav_right_button = self._nav_right_button) ) def update_display(self): ControlSurface.update_display(self) self._timer = (self._timer + 1) % 256 self.flash() def flash(self): if self.modhandler.is_enabled(): for control in self.controls: if isinstance(control, MonoButtonElement): control.flash(self._timer) def disconnect(self): super(LaunchMod, self).disconnect() rebuild_sys()
class AudioClipEditComponent(CompoundComponent): __doc__ = '\n classdocs\n ' def __init__(self, *a, **k): (super(AudioClipEditComponent, self).__init__)(*a, **k) 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() @subject_slot('value') def _action_scroll_mode(self, value): if value > 0: self._scroll_mode = True else: self._scroll_mode = False @subject_slot('value') def _action_warp_toggle(self, value): if value > 0: if self.selected_clip_slot: if self.selected_clip_slot.has_clip: clip = self.selected_clip_slot.clip if clip.is_audio_clip: clip.warping = not clip.warping self._warp_set_button.send_value( clip.warping and 127 or 0, True) @subject_slot('value') def _action_loop_toggle(self, value): if value > 0: if self.selected_clip_slot: if self.selected_clip_slot.has_clip: clip = self.selected_clip_slot.clip clip.looping = not clip.looping self._loop_set_button.send_value(clip.looping and 127 or 0, True) @subject_slot('value') def _action_loop_inc(self, value): inc = value == 1 and 1 or -1 val = self.inc_index + inc if val >= 0: if 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]) @subject_slot('value') 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 @subject_slot('value') def _action_mark_start(self, value): if self._scroll_mode: scroll = value == 1 and 3 or 2 self.application().view.scroll_view(scroll, 'Detail/Clip', False) else: inc = value == 1 and 1 or -1 if self.selected_clip_slot: if 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)) @subject_slot('value') def _action_mark_end(self, value): if self._scroll_mode: scroll = value == 1 and 3 or 2 self.application().view.zoom_view(scroll, 'Detail/Clip', False) else: inc = value == 1 and 1 or -1 if self.selected_clip_slot: if 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)) @subject_slot('value') def _action_loop_start(self, value): inc = value == 1 and 1 or -1 if self.selected_clip_slot: if 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)) @subject_slot('value') def _action_loop_end(self, value): inc = value == 1 and 1 or -1 if self.selected_clip_slot: if 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)) def update(self): pass @subject_slot('value') def _action_pitch_c(self, value): cs = self.selected_clip_slot if cs: if cs.has_clip: if cs.clip.is_audio_clip: cs.clip.pitch_coarse = midi_to_pitchc(value) @subject_slot('value') def _action_pitch_f(self, value): cs = self.selected_clip_slot if cs: if cs.has_clip: if cs.clip.is_audio_clip: cs.clip.pitch_fine = midi_to_pitchf(value) @subject_slot('value') def _action_gain(self, value): cs = self.selected_clip_slot if cs: if cs.has_clip: if cs.clip.is_audio_clip: cs.clip.gain = midi_to_gain(value) 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) else: if cs.has_clip: self.canonical_parent.send_to_display( (cs.clip.is_audio_clip and 'A' or '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) @subject_slot('has_clip') def _on_has_clip_changed(self): self._update_clip_name() @subject_slot('name') def _on_name_changed(self): self._update_clip_name() 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)) self._warp_set_button.send_value(cs.clip.warping and 127 or 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 self._loop_set_button.send_value(cs.clip.looping and 127 or 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() @subject_slot('looping') def _on_loop_changed(self): cs = self.song().view.highlighted_clip_slot if cs: if cs.has_clip: self._loop_set_button.send_value(cs.clip.looping and 127 or 0, True) @subject_slot('warping') def _on_warp_changed(self): cs = self.song().view.highlighted_clip_slot if cs: if cs.has_clip: if cs.clip.is_audio_clip: self._warp_set_button.send_value( cs.clip.warping and 127 or 0, True) @subject_slot('pitch_coarse') def _on_pitch_c_changed(self): cs = self.song().view.highlighted_clip_slot if cs: if cs.has_clip: if cs.clip.is_audio_clip: self._pitch_c_slider.send_value( pitchc_to_midi(cs.clip.pitch_coarse)) @subject_slot('pitch_fine') def _on_pitch_f_changed(self): cs = self.song().view.highlighted_clip_slot if cs: if cs.has_clip: if cs.clip.is_audio_clip: self._pitch_f_slider.send_value( pitchf_to_midi(cs.clip.pitch_fine)) @subject_slot('gain') def _on_gain_changed(self): cs = self.song().view.highlighted_clip_slot if cs: if cs.has_clip: if cs.clip.is_audio_clip: self._gain_slider.send_value(gain_to_midi(cs.clip.gain))
class MidiEditSection(CompoundComponent): _current_clip = None _split_value = 4 _base_note = None _gate = 1.0 _selected_note = None _note_pos = None _note_len = 0.0 _bend_val = 0 _offset = 0.0 _transpose = 0 _vel_fade = 0 _fade_mode = FADE_TIME _note_set = None _note_index = 0 def __init__(self, *a, **k): (super().__init__)(*a, **k) 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 is 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: if self._note_set: self._note_index = 0 self.set_notes(tuple(self._note_set[self._note_index])) @subject_slot('value') def _do_select(self, value): if value == 0: clip_slot = self.song().view.highlighted_clip_slot if clip_slot: if clip_slot.has_clip: if 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, 0, clip.length, 127) if self._note_index is 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)) @subject_slot('value') 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_extended() for note in selected: self._current_clip.remove_notes_extended( note.pitch, 1, note.start_time, note.duration) @subject_slot('value') def _do_init(self, value): if value != 0: self._transpose = 0 self._offset = 0.0 self._bend_val = 0 self._split_value = 4 self._vel_fade = 0.0 self._gate = 1.0 self.canonical_parent.timed_message( 2, 'SPLIT:' + str(self._split_value)) @subject_slot('value') 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) def get_selected_note(self): clip_slot = self.song().view.highlighted_clip_slot if clip_slot: if clip_slot.has_clip: if 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_extended() if len(notes) == 1: self._selected_note = notes[0] self._base_note = self._selected_note.pitch self._note_len = self._selected_note.duration self._note_pos = self._selected_note.start_time return notes[0] def execute_transpose(self, dir): clip_slot = self.song().view.highlighted_clip_slot if clip_slot: if clip_slot.has_clip: if clip_slot.clip.is_midi_clip: clip = clip_slot.clip notes = clip.get_selected_notes_extended() if len(notes) > 0: for note in notes: if note.pitch + dir < 128: note.pitch = note.pitch + dir notes.append(note) clip.apply_note_modifications(notes) def execute_split(self): selected_notes = self._current_clip.get_selected_notes_extended() for selected_note in selected_notes: if selected_note: splited_notes = [] note_len = selected_note.duration note_pitch = min(max(0, selected_note.pitch + self._transpose), 127) velocity = selected_note.velocity mute = selected_note.mute sp = selected_note.start_time pos = selected_note.start_time test = self._current_clip.get_selected_notes_extended() test.extend([selected_note]) if velocity < 0: endvel = velocity startvel = velocity - velocity * abs(self._vel_fade) else: startvel = velocity endvel = velocity - velocity * self._vel_fade divList = self.get_interval(note_len, self._split_value, self._bend_val) off = int(self._split_value * self._offset) velinc = (endvel - startvel) / self._split_value velocity = 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.0: note_specification = Live.Clip.MidiNoteSpecification( note_pitch, pos, notvlen, velocity, mute, selected_note.probability, selected_note.velocity_deviation, selected_note.release_velocity) splited_notes.append(note_specification) pos += div if self._fade_mode == FADE_EVENT: velocity += velinc else: rp = (pos - sp) / note_len velocity = startvel + (endvel - startvel) * rp self._current_clip.add_new_notes(splited_notes) @subject_slot('value') def _do_transpose(self, value): diff = value == REL_KNOB_DOWN and -1 or 1 self.execute_transpose(diff) @subject_slot('value') def _do_fade(self, value): if self.canonical_parent.isShiftDown(): diff = value == REL_KNOB_DOWN and -0.01 or 0.01 else: diff = value == REL_KNOB_DOWN and -0.1 or 0.1 newvale = self._vel_fade + diff if newvale >= -1.0: if newvale <= 1.0: 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() @subject_slot('value') def _do_strech(self, value): diff = value == REL_KNOB_DOWN and -1 or 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') @subject_slot('value') def _do_offset(self, value): diff = value == REL_KNOB_DOWN and -0.01 or 0.01 newval = self._offset + diff if newval >= 0.0: if newval <= 1.0: 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() @subject_slot('value') def _do_split_button(self, value): if value != 0: self.execute_split() @subject_slot('notes') def _notes_changed(self): pass @subject_slot('value') def _do_split(self, value): diff = value == REL_KNOB_DOWN and -1 or 1 newval = self._split_value + diff if newval > 0: if 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() @subject_slot('value') def _do_gate(self, value): diff = value == REL_KNOB_DOWN and -0.01 or 0.01 newval = self._gate + diff if newval > 0.1: if newval <= 1.0: 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() 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.0 param = abs(bv) * (self._split_value / 2) for i in range(n): div = rl / ct sz = div * (1.0 + 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 return self._bend_val < 0 and ls.reverse() or ls def get_interval(self, notelen, splits, bend_val): div = notelen / splits n = splits ls = [] param = abs(bend_val / 100.0) spl = 2 for i in range(n): sec = notelen / spl ls.append(sec) if i < n - 2: spl *= 1.0 + param acc = 0 for v in ls: acc += v ratio = notelen / acc for i in range(len(ls)): ls[i] = ls[i] * ratio return bend_val < 0.0 and ls.reverse() or ls @subject_slot('value') def _do_bend(self, value): diff = value == REL_KNOB_DOWN and -1 or 1 newval = self._bend_val + diff if newval >= -100: if newval <= 100: if 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.duration, self._split_value, self._bend_val) self.execute_split() def _on_selected_track_changed(self): debug_out(' Selected Track Changed ') def update(self): pass def refresh(self): pass
class LaunchMod(Launchpad): def __init__(self, *a, **k): ControlSurface.__init__(self, *a, **k) with self.component_guard(): self._monomod_version = 'b996' self._host_name = 'LaunchMod' self._color_type = 'Launchpad' self._timer = 0 self._suppress_send_midi = True self._suppress_session_highlight = True self._suppress_highlight = False is_momentary = True self._suggested_input_port = 'Launchpad' self._suggested_output_port = 'Launchpad' self._control_is_with_automap = False self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16) self._user_byte_write_button.name = 'User_Byte_Button' self._user_byte_write_button.send_value(1) self._user_byte_write_button.add_value_listener(self._user_byte_value) self._wrote_user_byte = False self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143 matrix = ButtonMatrixElement() matrix.name = 'Button_Matrix' for row in range(8): button_row = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, row * 16 + column, str(column) + '_Clip_' + str(row) + '_Button', self) for column in range(8) ] matrix.add_row(tuple(button_row)) self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0, optimized_send_midi=False) self._config_button.add_value_listener(self._config_value) top_button_names = ['Bank_Select_Up_Button', 'Bank_Select_Down_Button', 'Bank_Select_Left_Button', 'Bank_Select_Right_Button', 'Session_Button', 'User1_Button', 'User2_Button', 'Mixer_Button'] side_button_names = ['Vol_Button', 'Pan_Button', 'SndA_Button', 'SndB_Button', 'Stop_Button', 'Trk_On_Button', 'Solo_Button', 'Arm_Button'] top_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0, 104 + index, top_button_names[index], self) for index in range(8) ] side_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index], side_button_names[index], self) for index in range(8) ] self._side_buttons = ButtonMatrixElement() self._side_buttons.add_row(side_buttons) self._setup_monobridge() self._setup_mod() self._selector = MainSelectorComponent(self, matrix, tuple(top_buttons), tuple(side_buttons), self._config_button) self._selector.name = 'Main_Modes' for control in self.controls: isinstance(control, MonoButtonElement) and control.add_value_listener(self._button_value) self.set_highlighting_session_component(self._selector.session_component()) self._suppress_session_highlight = False self.log_message('--------------= ' + str(self._monomod_version) + ' log opened =--------------') """Mono overrides and additions""" def _setup_monobridge(self): self._monobridge = MonoBridgeElement(self) self._monobridge.name = 'MonoBridge' def _setup_mod(self): self.monomodular = get_monomodular(self) self.monomodular.name = 'monomodular_switcher' self.modhandler = LaunchModHandler(self) self.modhandler.name = 'ModHandler' #self.modhandler.layer = Layer( lock_button = self._note_mode_button, push_grid = self._matrix, shift_button = self._shift_button, alt_button = self._select_button, key_buttons = self._track_state_buttons) #self.modhandler.layer.priority = 4 #self.modhandler.nav_buttons_layer = AddLayerMode( self.modhandler, Layer(nav_up_button = self._nav_up_button, nav_down_button = self._nav_down_button, nav_left_button = self._nav_left_button, nav_right_button = self._nav_right_button) ) def update_display(self): ControlSurface.update_display(self) self._timer = (self._timer + 1) % 256 self.flash() def flash(self): if self.modhandler.is_enabled(): for control in self.controls: if isinstance(control, MonoButtonElement): control.flash(self._timer) def disconnect(self): super(LaunchMod, self).disconnect() rebuild_sys()
class MaschineSessionComponent(SessionComponent): __module__ = __name__ __doc__ = '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 @subject_slot('value') 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) 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): color = self._advance == STEP4 and COLOR_HUE_NAV4 or 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() @subject_slot('value') def _toggle_step_advance(self, value): if value != 0: self.set_step_advance(self._advance == STEP4 and STEP1 or STEP4) def switch_step_advance(self): self.set_step_advance(self._advance == STEP4 and STEP1 or 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 @subject_slot('value') def _do_matrix_adv_mode(self, value): if not self._mode_button != None: raise AssertionError if not value in range(128): raise AssertionError self._advance = value != 0 and self._advance == STEP1 and 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) def update(self): SessionComponent.update(self) try: self._advance except AttributeError: pass else: 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 else: 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: button.send_color_direct(sblink == 0 and color[0] or 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: button.send_color_direct(sblink == 0 and REC or 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: button.send_color_direct(sblink == 0 and TRIGG or 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() else: 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 JogWheelSection(CompoundComponent): def __init__(self, modeselector, editsection, *a, **k): (super().__init__)(*a, **k) self._modesel = modeselector self._editsection = editsection is_momentary = True self._do_push_button.subject = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 82) self._do_edit_slider.subject = SliderElement(MIDI_CC_TYPE, 1, 81) self._do_channel_slider.subject = SliderElement(MIDI_CC_TYPE, 1, 83) self._do_channel_button.subject = ButtonElement( is_momentary, MIDI_CC_TYPE, 1, 63) self._do_req_quantize.subject = SliderElement(MIDI_CC_TYPE, 1, 100) self._do_browse.subject = SliderElement(MIDI_CC_TYPE, 1, 84) self._do_tempo.subject = SliderElement(MIDI_CC_TYPE, 1, 101) self._do_volume.subject = SliderElement(MIDI_CC_TYPE, 1, 103) self._do_dedicated_rec_quantize.subject = SliderElement( MIDI_CC_TYPE, 2, 112) self._do_dedicated_clip_quantize.subject = SliderElement( MIDI_CC_TYPE, 2, 113) self.set_up_function_buttons() self._wheel_overide = None self.scrub_mode = True self.select_arm_mode = True self._push_down = False def set_up_function_buttons(self): is_momentary = True self._do_octave_button.subject = StateButton(is_momentary, MIDI_CC_TYPE, 1, 70) self._do_scale_button.subject = StateButton(is_momentary, MIDI_CC_TYPE, 1, 71) self._do_note_button.subject = StateButton(is_momentary, MIDI_CC_TYPE, 1, 72) self._do_loop_mod.subject = StateButton(is_momentary, MIDI_CC_TYPE, 1, 69) self._color_edit_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 114) self._do_color_button.subject = self._color_edit_button self.scrub_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 2, 53) self._action_scrub_mode.subject = self.scrub_mode_button self._action_loop_button.subject = StateButton(is_momentary, MIDI_CC_TYPE, 2, 54) self._action_quant_button.subject = StateButton( is_momentary, MIDI_CC_TYPE, 2, 55) def set_overide(self, overide_callback): self._wheel_overide = overide_callback def reset_overide(self): self._wheel_overide = None if self._editsection.is_color_edit(): self._color_edit_button.send_value(0, True) self._editsection.knob_pad_action(False) self._editsection.set_color_edit(False) def message(self, message): self.canonical_parent.show_message(message) def use_scrub_mode(self): return self.scrub_mode def set_scrub_mode(self, value): self.scrub_mode = value self.scrub_mode_button.send_value(value and 127 or 0) def modifier1(self): return self._push_down def modifier2(self): return self._editsection.isShiftdown() def modifier3(self): return self._editsection.isAltdown() @subject_slot('value') def _do_push_button(self, value): if value != 0: self._push_down = True else: self._push_down = False self._modesel.handle_push(value != 0) @subject_slot('value') def _action_scrub_mode(self, value): if value > 0: self.set_scrub_mode(not self.scrub_mode) def _action_set_quant(self, diff): val = self._editsection.quantize self._editsection.quantize = max(1, min(len(QUANT_CONST) - 1, val + diff)) self.canonical_parent.timed_message( 2, 'Quantize: ' + QUANT_STRING[self._editsection.quantize], True) def _action_init_loop(self, diff): val = self._editsection.initial_clip_len self._editsection.initial_clip_len = max(1.0, min(64.0, val + diff)) self.canonical_parent.timed_message( 2, 'Init Clip Len: ' + str(self._editsection.initial_clip_len), True) @subject_slot('value') def _action_loop_button(self, value): if value > 0: self.canonical_parent.timed_message( 2, 'Init Clip Len: ' + str(self._editsection.initial_clip_len), True) self.set_overide(self._action_init_loop) else: self.canonical_parent.timed_message_release() self.reset_overide() @subject_slot('value') def _action_quant_button(self, value): if value > 0: self.canonical_parent.timed_message( 2, 'Quantize: ' + QUANT_STRING[self._editsection.quantize], True) self.set_overide(self._action_set_quant) else: self.canonical_parent.timed_message_release() self.reset_overide() def chg_tempo(self, diff): self.song().tempo = max(20, min(999, self.song().tempo + diff)) self.canonical_parent.timed_message( 2, 'Tempo: ' + str(round(self.song().tempo, 2))) @subject_slot('value') def _do_edit_slider(self, value): diff = value == 127 and -1 or 1 if self._wheel_overide: self._wheel_overide(diff) else: self._modesel.navigate(diff, self.modifier1(), self.modifier2()) @subject_slot('value') def _do_channel_slider(self, value): if self._wheel_overide: self._wheel_overide(value == 127 and -1 or 1) else: song = self.song() if self.modifier1(): dir = value == 127 and -1 or 1 scenes = song.scenes scene = song.view.selected_scene sindex = vindexof(scenes, scene) sel_scene = sindex + dir if sel_scene >= 0: if sel_scene < len(scenes): song.view.selected_scene = scenes[sel_scene] else: if self.modifier2(): dir = value == 127 and Live.Application.Application.View.NavDirection.left or Live.Application.Application.View.NavDirection.right self.application().view.scroll_view(dir, 'Detail/DeviceChain', True) else: dir = value == 127 and -1 or 1 tracks = song.tracks direction = value == 127 and Live.Application.Application.View.NavDirection.left or Live.Application.Application.View.NavDirection.right self.application().view.scroll_view(direction, 'Session', True) if self.select_arm_mode: arm_exclusive(song) @subject_slot('value') def _do_channel_button(self, value): arm_exclusive(self.song()) @subject_slot('value') def _do_browse(self, value): diff = value == 127 and -1 or 1 if self._wheel_overide: self._wheel_overide(diff) else: step = 1.0 if self.modifier1(): step = 0.25 else: if self.modifier2(): step = 4.0 elif self.scrub_mode: self.song().scrub_by(step * diff) else: self.song().jump_by(step * diff) @subject_slot('value') def _do_tempo(self, value): diff = value == 127 and -1 or 1 if self._wheel_overide: self._wheel_overide(diff) else: if self.modifier1(): self.chg_tempo(diff * 0.01) else: if self.modifier2(): self.chg_tempo(diff * 0.1) else: self.chg_tempo(diff) @subject_slot('value') def _do_req_quantize(self, value): diff = value == 127 and -1 or 1 if self._wheel_overide: self._wheel_overide(diff) else: song = self.song() if self.modifier2(): swing = song.swing_amount song.swing_amount = max(0.0, min(1, swing + diff * 0.01)) msg = 'Swing Amount: ' + str(int(song.swing_amount * 100)) + '%' self.message(msg) self.canonical_parent.timed_message(2, msg) else: if self.modifier1(): quant = song.clip_trigger_quantization song.clip_trigger_quantization = max(0, min(13, quant + diff)) self.message('Clip Quantize ' + CLIQ_DESCR[song.clip_trigger_quantization]) self.canonical_parent.timed_message( 2, 'Clip Quantize: ' + CLIQ_DESCR[song.clip_trigger_quantization]) else: rec_quant = song.midi_recording_quantization index = QUANT_CONST.index(rec_quant) + diff if index >= 0: if index < len(QUANT_CONST): song.midi_recording_quantization = QUANT_CONST[index] self.message(QUANT_DESCR[index]) self.canonical_parent.timed_message( 2, 'Rec Quantize: ' + QUANT_STRING[index]) @subject_slot('value') def _do_dedicated_clip_quantize(self, value): diff = value == REL_KNOB_DOWN and -1 or 1 song = self.song() quant = song.clip_trigger_quantization song.clip_trigger_quantization = max(0, min(13, quant + diff)) self.message('Clip Quantize ' + CLIQ_DESCR[song.clip_trigger_quantization]) self.canonical_parent.timed_message( 2, 'Clip Quantize: ' + CLIQ_DESCR[song.clip_trigger_quantization]) @subject_slot('value') def _do_dedicated_rec_quantize(self, value): diff = value == REL_KNOB_DOWN and -1 or 1 song = self.song() rec_quant = song.midi_recording_quantization index = QUANT_CONST.index(rec_quant) + diff if index >= 0: if index < len(QUANT_CONST): song.midi_recording_quantization = QUANT_CONST[index] self.message(QUANT_DESCR[index]) self.canonical_parent.timed_message( 2, 'Rec Quantize: ' + QUANT_STRING[index]) @subject_slot('value') def _do_volume(self, value): diff = value == 127 and -1 or 1 if self._wheel_overide: self._wheel_overide(diff) else: if self.modifier2(): self.chg_cue(diff) else: self.chg_volume(diff) @subject_slot('value') def _do_color_button(self, value): if value > 0: if self._editsection.is_color_edit(): self.reset_overide() else: self._color_edit_button.send_value(1, True) self._editsection.knob_pad_action(True) self._editsection.set_color_edit(True) def set_color_edit(self, active): if active: self.set_overide(self._color_change) else: self.reset_overide() def _color_change(self, value): diff = value == 127 and -1 or 1 self._editsection.edit_colors(diff) @subject_slot('value') def _do_note_button(self, value): if not value in range(128): raise AssertionError elif value > 0: self.set_overide(self.canonical_parent._handle_base_note) else: self.reset_overide() @subject_slot('value') def _do_octave_button(self, value): if not value in range(128): raise AssertionError elif value > 0: self.set_overide(self.canonical_parent._handle_octave) else: self.reset_overide() @subject_slot('value') def _do_scale_button(self, value): if not value in range(128): raise AssertionError elif value > 0: self.set_overide(self.canonical_parent._handle_scale) else: self.reset_overide() def _handle_loop_mod(self, diff): factor = (self.modifier1() and 1.0 or 4.0) * diff if self.modifier2(): self.canonical_parent.adjust_loop_length(factor) else: self.canonical_parent.adjust_loop_start(factor) @subject_slot('value') def _do_loop_mod(self, value): if not value in range(128): raise AssertionError elif value > 0: self.set_overide(self._handle_loop_mod) else: self.reset_overide() def chg_volume(self, diff): mdevice = self.song().master_track.mixer_device if self.modifier2(): mdevice.volume.value = calc_new_parm(mdevice.volume, diff) else: repeat(mdevice.volume, diff) def chg_cue(self, diff): mdevice = self.song().master_track.mixer_device if self.modifier2(): mdevice.cue_volume.value = calc_new_parm(mdevice.cue_volume, diff) else: repeat(mdevice.cue_volume, diff) def update(self): pass def refresh(self): pass def disconnect(self): super().disconnect()
class KnobSection(CompoundComponent): _wheel_overide = None _mode = KSM_SCROLL _push_down = False scrub_mode = True alt_mode = False def __init__(self, modeselector, editsection, *a, **k): (super(KnobSection, self).__init__)(*a, **k) self._modesel = modeselector self._editsection = editsection self._modesel.connect_main_knob(self) is_momentary = True self.main_knob = SliderElement(MIDI_CC_TYPE, 1, 85) self.push_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1, 87) self.volume_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 110) self.swing_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 111) self.tempo_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 112) self.xfade_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 116) self._mode_button = self.canonical_parent.create_gated_button(80, KSM_HUES[0]) self._color_edit_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 113) self._set_inicliplen_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 122) self._set_quantize_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 126) self.do_main.subject = self.main_knob self.do_main_push.subject = self.push_button self._do_volume.subject = self.volume_button self._do_swing.subject = self.swing_button self._do_tempo.subject = self.tempo_button self._do_xfade.subject = self.xfade_button self._do_toggle_mode.subject = self._mode_button self._do_color_button.subject = self._color_edit_button self._do_mikr_cliplen.subject = self._set_inicliplen_button self._do_mikr_quantize.subject = self._set_quantize_button self._do_dedicated_rec_quantize.subject = SliderElement(MIDI_CC_TYPE, 2, 112) self._do_dedicated_clip_quantize.subject = SliderElement(MIDI_CC_TYPE, 2, 113) self._radio_buttons = ( self.volume_button, self.swing_button, self.tempo_button, self.xfade_button, self._color_edit_button) self._do_button_left.subject = ButtonElement(is_momentary, MIDI_CC_TYPE, 2, 120) self._do_button_right.subject = ButtonElement(is_momentary, MIDI_CC_TYPE, 2, 121) self.volume_button.send_value(0, True) self._mode_button.set_color(KSM_HUES[0]) self.knob_action = self._scroll_action self._prev_mode = None self._prev_action = None 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 use_scrub_mode(self): return self.scrub_mode def set_scrub_mode(self, value): self.scrub_mode = value self.scrub_mode_button.send_value(value and 127 or 0) def set_override(self, overide_callback): if self._wheel_overide != overide_callback: self._wheel_overide = overide_callback self.volume_button.send_value(0, True) self.swing_button.send_value(0, True) self.tempo_button.send_value(0, True) self._mode_button.switch_off() self._mode = None def reset_overide(self): if self._wheel_overide: self._wheel_overide = None def _scroll_action(self, value): inc = value == 1 and 1 or -1 self._modesel.navigate(inc, self._push_down, self._editsection.isShiftdown()) def _do_channel_slider(self, value): song = self.song() if self._editsection.isShiftdown(): dir = value == 127 and Live.Application.Application.View.NavDirection.left or Live.Application.Application.View.NavDirection.right self.application().view.scroll_view(dir, 'Detail/DeviceChain', True) else: if self._push_down: dir = value == 127 and -1 or 1 scenes = song.scenes scene = song.view.selected_scene sindex = list(scenes).index(scene) sel_scene = sindex + dir if sel_scene >= 0 and sel_scene < len(scenes): song.view.selected_scene = scenes[sel_scene] else: direction = value == 127 and Live.Application.Application.View.NavDirection.left or Live.Application.Application.View.NavDirection.right self.application().view.scroll_view(direction, 'Session', True) if self.canonical_parent.arm_selected_track: arm_exclusive(song) def _do_transport(self, value): diff = value == 127 and -1 or 1 jump = 4.0 if self._push_down: if self._editsection.isShiftdown(): jump = 0.25 else: jump = 1.0 elif self._editsection.isShiftdown(): jump = 0.5 if self.scrub_mode: self.song().scrub_by(jump * diff) else: self.song().jump_by(jump * diff) @subject_slot('value') def do_main(self, value): if self._wheel_overide: self._wheel_overide(value == 1 and 1 or -1, self._editsection.isShiftdown(), self._push_down) else: if self.knob_action: self.knob_action(value) def _disable_radio_button(self): for button in self._radio_buttons: button.send_value(0, True) def enter_toggle_mode(self, mode=None): self.reset_overide() self.switch_pad_wheel_edit(False) self.alt_mode = False if self._mode < KSM_SCROLL or mode != None: if mode == None: self.switch_pad_wheel_edit(False) self._mode = KSM_SCROLL else: self._mode = mode self._disable_radio_button() else: modeval = self._mode + 1 if modeval > KSM_TRANSPORT: modeval = KSM_SCROLL self._mode = modeval if self._mode == KSM_SCROLL: self.knob_action = self._scroll_action self.do_message('Main Knob -> Navigate') else: if self._mode == KSM_SELECT: self.knob_action = self._do_channel_slider self.do_message('Main Knob -> Select') else: if self._mode == KSM_TRANSPORT: self.knob_action = self._do_transport self.do_message('Main Knob -> Transport') self._mode_button.set_color(KSM_HUES[(self._mode - KSM_SCROLL)]) @subject_slot('value') def _do_toggle_mode(self, value): if value > 0: if self._editsection.isShiftdown(): self.canonical_parent.toggle_nav_mode() else: self.enter_toggle_mode() def _scroll_xfade(self, value): diff = value == 127 and -1 or 1 if self._wheel_overide: self._wheel_overide(diff, self._editsection.isShiftdown(), self._push_down) else: self.chg_xfade(diff) def _scroll_volume(self, value): diff = value == 127 and -1 or 1 if self._wheel_overide: self._wheel_overide(diff, self._editsection.isShiftdown(), self._push_down) else: if self._editsection.isShiftdown(): self.chg_cue(diff) else: self.chg_volume(diff) def _scroll_tempo(self, value): diff = value == 127 and -1 or 1 if self._wheel_overide: self._wheel_overide(diff, self._editsection.isShiftdown(), self._push_down) else: if self._push_down: self.chg_tempo(diff * 0.1) else: if self._editsection.isShiftdown(): self.chg_tempo(diff * 0.01) else: self.chg_tempo(diff) def _scroll_req_quantize(self, value): diff = value == 127 and -1 or 1 if self._wheel_overide: self._wheel_overide(diff, self._editsection.isShiftdown(), self._push_down) else: song = self.song() if self._editsection.isShiftdown(): quant = song.clip_trigger_quantization song.clip_trigger_quantization = max(0, min(13, quant + diff)) self.do_message('Clip Quantize ' + CLIQ_DESCR[song.clip_trigger_quantization]) else: rec_quant = song.midi_recording_quantization index = QUANT_CONST.index(rec_quant) + diff if index >= 0: if index < len(QUANT_CONST): song.midi_recording_quantization = QUANT_CONST[index] self.do_message(QUANT_DESCR[index]) @subject_slot('value') def do_main_push(self, value): if value != 0: self.alt_mode = not self.alt_mode self._push_down = value != 0 self._modesel.handle_push(value != 0) def switch_pad_wheel_edit(self, activate): if activate: self._color_edit_button.send_value(1, True) self._editsection.set_color_edit(True) else: self._color_edit_button.send_value(0, True) self._editsection.set_color_edit(False) def invoke_color_mode(self, active): if active and self._mode != KSM_EDIT: self._prev_mode = self._mode self._to_mode(KSM_EDIT) else: if not active: if self._prev_mode != None: self.switch_pad_wheel_edit(False) self._to_mode(self._prev_mode) self._prev_mode = None @subject_slot('value') def _do_color_button(self, value, force=False): if value > 0: if self._mode != KSM_EDIT: self._prev_mode = self._mode self.reset_overide() self._to_mode(KSM_EDIT) else: if self._prev_mode != None: self.switch_pad_wheel_edit(False) self._to_mode(self._prev_mode) self._prev_mode = None def _to_mode(self, mode): button = None if mode == KSM_VOLUME: button = self.volume_button self.knob_action = self._scroll_volume self.switch_pad_wheel_edit(False) else: if mode == KSM_SWING: button = self.swing_button self.knob_action = self._scroll_req_quantize self.switch_pad_wheel_edit(False) else: if mode == KSM_TEMPO: button = self.tempo_button self.knob_action = self._scroll_tempo self.switch_pad_wheel_edit(False) else: if mode == KSM_XFADE: button = self.xfade_button self.knob_action = self._scroll_xfade self.switch_pad_wheel_edit(False) else: if mode == KSM_EDIT: self._editsection.set_color_edit(True) else: self.enter_toggle_mode(mode) self._mode = mode for rbutton in self._radio_buttons: if rbutton != button: rbutton.send_value(0) if button: self._mode_button.switch_off() button.send_value(127, True) def _edit_color(self, value): diff = value == 127 and -1 or 1 if self._wheel_overide: self._wheel_overide(diff, self._editsection.isShiftdown(), self._push_down) else: self._editsection.edit_colors(diff) @subject_slot('value') def _do_button_left(self, value): if value != 0: self._modesel.navigate(-1, self._editsection.isShiftdown(), False) @subject_slot('value') def _do_button_right(self, value): if value != 0: self._modesel.navigate(1, self._editsection.isShiftdown(), False) @subject_slot('value') def _do_mikr_cliplen(self, value): if value == 0: self.knob_action = self._prev_action else: self._prev_action = self.knob_action self.knob_action = self._modify_init_cliplen @subject_slot('value') def _do_mikr_quantize(self, value): if value == 0: self.knob_action = self._prev_action else: self._prev_action = self.knob_action self.knob_action = self._modify_quant_grid def _modify_init_cliplen(self, value): if self._push_down: self._editsection.mod_new_initlen(value == 1 and 1 or -1) else: self._editsection.mod_new_initlen(value == 1 and 4 or -4) def _modify_quant_grid(self, value): self._editsection.mod_quant_size(value == 1 and 1 or -1) @subject_slot('value') def _do_xfade(self, value): if value > 0: if self._mode != KSM_XFADE: self.reset_overide() self._to_mode(KSM_XFADE) @subject_slot('value') def _do_volume(self, value): if value > 0: if self._mode != KSM_VOLUME: self.reset_overide() self._to_mode(KSM_VOLUME) @subject_slot('value') def _do_swing(self, value): if value > 0: if self._mode != KSM_SWING: self.reset_overide() self._to_mode(KSM_SWING) @subject_slot('value') def _do_tempo(self, value): if value > 0: if self._mode != KSM_TEMPO: self.reset_overide() self._to_mode(KSM_TEMPO) @subject_slot('value') def _do_dedicated_clip_quantize(self, value): diff = value == 127 and -1 or 1 song = self.song() quant = song.clip_trigger_quantization song.clip_trigger_quantization = max(0, min(13, quant + diff)) self.do_message('Clip Quantize ' + CLIQ_DESCR[song.clip_trigger_quantization]) @subject_slot('value') def _do_dedicated_rec_quantize(self, value): diff = value == 127 and -1 or 1 song = self.song() rec_quant = song.midi_recording_quantization index = QUANT_CONST.index(rec_quant) + diff if 0 <= index < len(QUANT_CONST): song.midi_recording_quantization = QUANT_CONST[index] self.do_message('Rec Quantize: ' + QUANT_STRING[index]) def chg_tempo(self, diff): self.song().tempo = max(20, min(999, self.song().tempo + diff)) self.canonical_parent.timed_message(2, 'Tempo: ' + str(round(self.song().tempo, 2))) def chg_volume(self, diff): if self._push_down: self.song().master_track.mixer_device.volume.value = calc_new_parm(self.song().master_track.mixer_device.volume, diff) else: repeat(self.song().master_track.mixer_device.volume, diff) def chg_xfade(self, diff): if self._push_down: self.song().master_track.mixer_device.crossfader.value = calc_new_parm(self.song().master_track.mixer_device.crossfader, diff) else: repeat(self.song().master_track.mixer_device.crossfader, diff) def chg_cue(self, diff): if self._push_down: self.song().master_track.mixer_device.cue_volume.value = calc_new_parm(self.song().master_track.mixer_device.cue_volume, diff) else: repeat(self.song().master_track.mixer_device.cue_volume, diff) def update(self): pass def refresh(self): pass
class AxiomPro(ControlSurface): def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): is_momentary = True self.set_pad_translations(PAD_TRANSLATIONS) self._suggested_input_port = 'HyperControl' self._suggested_output_port = 'HyperControl' self._display_on_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, 15, 79) self._waiting_for_first_response = True mixer1 = DisplayingMixerComponent(0) mixer1.set_select_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 111), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 110)) mixer1.set_mute_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 12)) mixer1.set_solo_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 13)) mixer2 = NotifyingMixerComponent(8) mixer2.set_bank_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 15), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 14)) mixer2.master_strip().set_volume_control(SliderElement(MIDI_CC_TYPE, 15, 41)) for index in range(8): mixer2.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, 15, 33 + index)) device = PageableDeviceComponent(device_selection_follows_track_selection=True) self.set_device_component(device) ffwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 115) rwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 114) loop_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 113) transport = TransportComponent() transport.set_stop_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 116)) transport.set_play_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 117)) transport.set_record_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 118)) session = SessionComponent(0, 0) transport_view_modes = TransportViewModeSelector(transport, session, ffwd_button, rwd_button, loop_button) select_button_modes = SelectButtonModeSelector(mixer2, tuple([ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 49 + offset) for offset in range(8)])) select_button_modes.set_mode_toggle(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 57)) self._mixer_encoder_modes = EncoderMixerModeSelector(mixer2) encoders = [] for offset in range(8): encoders.append(PeekableEncoderElement(MIDI_CC_TYPE, 15, 17 + offset, Live.MidiMap.MapMode.relative_smooth_two_compliment)) encoders[(-1)].set_feedback_delay(-1) mixer_or_device = MixerOrDeviceModeSelector(self._mixer_encoder_modes, device, tuple(encoders), tuple([ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 74 + offset) for offset in range(4)])) mixer_or_device.set_mode_toggle(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 109)) mixer_or_device.set_peek_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 78)) self._track_display = PhysicalDisplayElement(8, 1) self._track_display.set_clear_all_message(SYSEX_START + (16, 247)) self._track_display.set_message_parts(SYSEX_START + (17, 1, 0, 0), (247, )) self._track_display.segment(0).set_data_source(mixer1.selected_strip().track_name_data_source()) device_display = PhysicalDisplayElement(8, 1) device_display.set_message_parts(SYSEX_START + (17, 1, 0, 10), (247, )) parameter_display = PhysicalDisplayElement(16, 1) parameter_display.set_message_parts(SYSEX_START + (17, 2, 0, 0), (247, )) select_button_modes.set_mode_display(parameter_display) mixer1.set_display(parameter_display) mixer2.set_bank_display(parameter_display) page_displays = [] for index in range(4): page_displays.append(PhysicalDisplayElement(5, 1)) page_displays[(-1)].set_message_parts(SYSEX_START + (17, 4, index, 0), (247, )) encoder_display = PhysicalDisplayElement(80, 8) encoder_display.set_message_parts(SYSEX_START + (17, 3), (247, )) for index in range(8): pos_id = tuple() if index != 0: pos_id += (0, ) else: if index > 3: pos_id += (index % 4, 13) else: pos_id += (index % 4, 0) encoder_display.segment(index).set_position_identifier(pos_id) mixer_or_device.set_displays(encoder_display, parameter_display, device_display, tuple(page_displays)) for component in self.components: component.set_enabled(False) def refresh_state(self): ControlSurface.refresh_state(self) self._waiting_for_first_response = True self.schedule_message(10, self._send_midi, SYSEX_START + (32, 46, 247)) def handle_sysex(self, midi_bytes): if midi_bytes[0:-2] == SYSEX_START + (32, ): msg_id_byte = midi_bytes[(-2)] is_setup_response = msg_id_byte in (46, 38) has_sliders = msg_id_byte == 46 if is_setup_response: if self._waiting_for_first_response: self._waiting_for_first_response = False self._display_on_button.send_value(0) for component in self.components: component.set_enabled(True) self._display_on_button.send_value(127) self._send_midi(SYSEX_START + (16, 247)) self._send_midi(SYSEX_START + (17, 3, 0, 1, 65, 98, 108, 101, 116, 111, 110, 32, 76, 105, 118, 101, 32, 67, 111, 110, 116, 114, 111, 108, 32, 0, 1, 4, 83, 117, 114, 102, 97, 99, 101, 32, 118, 49, 46, 48, 46, 48, 46, 247)) self._mixer_encoder_modes.set_show_volume_page(not has_sliders) for display in self._displays: display.set_block_messages(False) self.schedule_message(25, self._refresh_displays) elif msg_id_byte == 43: self._send_midi(SYSEX_START + (16, 247)) for display in self._displays: if display is self._track_display: display.update() else: display.set_block_messages(True) def disconnect(self): ControlSurface.disconnect(self) self._send_midi(SYSEX_START + (32, 0, 247)) self._send_midi(SYSEX_START + (16, 247)) self._send_midi(SYSEX_START + (17, 3, 0, 4, 65, 98, 108, 101, 116, 111, 110, 32, 76, 105, 118, 101, 32, 67, 111, 110, 116, 114, 111, 108, 32, 0, 1, 4, 83, 117, 114, 102, 97, 99, 101, 32, 67, 108, 111, 115, 101, 100, 46, 247))