class VUMeter(ControlSurfaceComponent): _active_instances = [] def __init__(self, parent): ControlSurfaceComponent.__init__(self) VUMeter._active_instances.append(self) self.slider = None self._parent = parent self._vu_meter = None self.frames = [0.0] * RMS_FRAMES self.increments = CHANNEL_SCALE_INCREMENTS self.top = CHANNEL_SCALE_MAX self.bottom = CHANNEL_SCALE_MIN self.multiplier = self.calculate_multiplier(self.top, self.bottom, self.increments) self.current_level = 0 def disconnect(self): VUMeter._active_instances.remove(self) if self._vu_meter != None: self._vu_meter.remove_output_meter_left_listener(self.observe) self._vu_meter = None def observe(self): new_frame = self.mean_peak() self.store_frame(new_frame) self.level = self.scale(new_frame) if self.level != self.current_level: self.current_level = self.level self.send_vu_value(self.level) else: None def store_frame(self, frame): self.frames.pop(0) self.frames.append(frame) def rms(self, frames): return math.sqrt(sum((frame * frame for frame in frames)) / len(frames)) def mean_peak(self): return (self._vu_meter.output_meter_left + self._vu_meter.output_meter_right) / 2 def scale(self, value): if value > self.top: value = self.top elif value < self.bottom: value = self.bottom value = value - self.bottom value = value * self.multiplier return int(round(value)) def calculate_multiplier(self, top, bottom, increments): return increments / (top - bottom) def set_vu_meter(self, track): self.set_led_slider(track) self._vu_meter = self.song().tracks[track] if self._vu_meter != None: self._vu_meter.add_output_meter_left_listener(self.observe) else: None def set_led_slider(self, track): self.slider = SliderElement(MIDI_CC_TYPE, SLIDER_CHANNEL, track + 1) def send_vu_value(self, level): if level != None: if level < 1: None else: self.slider.send_value(level, True) else: None def update(self): pass
class AudioClipEditComponent(CompoundComponent): """ classdocs """ 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 and 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 and 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): if not (value == 1 and 1): inc = -1 val = self.inc_index + inc self.inc_index = val >= 0 and val < len(INC_STEPS) and 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) elif not (value == 1 and 1): inc = -1 clip = self.selected_clip_slot and self.selected_clip_slot.has_clip and 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) elif not (value == 1 and 1): inc = -1 clip = self.selected_clip_slot and self.selected_clip_slot.has_clip and 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): if not (value == 1 and 1): 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) clip.loop_end = inc > 0 and 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): if not (value == 1 and 1): 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 clip.end_marker = self.mv_loop and 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 and cs.has_clip and 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 and cs.has_clip and 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 and cs.has_clip and 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) elif 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 and 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 and cs.has_clip and 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 and cs.has_clip and 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 and cs.has_clip and 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 and cs.has_clip and cs.clip.is_audio_clip: self._gain_slider.send_value(gain_to_midi(cs.clip.gain))
class VUMeter(ControlSurfaceComponent): _active_instances = [] def __init__(self, parent): ControlSurfaceComponent.__init__(self) VUMeter._active_instances.append(self) self.slider = None self._parent = parent self._vu_meter = None self.frames = [0.0] * RMS_FRAMES self.increments = CHANNEL_SCALE_INCREMENTS self.top = CHANNEL_SCALE_MAX self.bottom = CHANNEL_SCALE_MIN self.multiplier = self.calculate_multiplier(self.top, self.bottom, self.increments) self.current_level = 0 def disconnect(self): VUMeter._active_instances.remove(self) if self._vu_meter != None: self._vu_meter.remove_output_meter_left_listener(self.observe) self._vu_meter = None def observe(self): new_frame = self.mean_peak() self.store_frame(new_frame) self.level = self.scale(new_frame) if self.level != self.current_level: self.current_level = self.level self.send_vu_value(self.level) else: None def store_frame(self, frame): self.frames.pop(0) self.frames.append(frame) def rms(self, frames): return math.sqrt( sum((frame * frame for frame in frames)) / len(frames)) def mean_peak(self): return (self._vu_meter.output_meter_left + self._vu_meter.output_meter_right) / 2 def scale(self, value): if value > self.top: value = self.top elif value < self.bottom: value = self.bottom value = value - self.bottom value = value * self.multiplier return int(round(value)) def calculate_multiplier(self, top, bottom, increments): return increments / (top - bottom) def set_vu_meter(self, track): self.set_led_slider(track) self._vu_meter = self.song().tracks[track] if self._vu_meter != None: self._vu_meter.add_output_meter_left_listener(self.observe) else: None def set_led_slider(self, track): self.slider = SliderElement(MIDI_CC_TYPE, SLIDER_CHANNEL, track + 1) def send_vu_value(self, level): if level != None: if level < 1: None else: self.slider.send_value(level, True) else: None def update(self): pass
class AudioClipEditComponent(CompoundComponent): """ classdocs """ 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() return @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 and 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 and 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 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]) @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 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)) @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 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)) @subject_slot('value') def _action_loop_start(self, value): inc = value == 1 and 1 or -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)) @subject_slot('value') def _action_loop_end(self, value): inc = value == 1 and 1 or -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)) def update(self): pass @subject_slot('value') 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) @subject_slot('value') 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) @subject_slot('value') 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) 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 return 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 and 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 and cs.has_clip and 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 and cs.has_clip and 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 and cs.has_clip and 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 and cs.has_clip and cs.clip.is_audio_clip: self._gain_slider.send_value(gain_to_midi(cs.clip.gain))
class MaschineJam(ControlSurface): """Control Script for Maschine JAM Controller""" __module__ = __name__ _midi_count = 0 _arm_exclusive = True _solo_exclusive = True _blink_state = 0 __midi_count = 0 __play_button = None __block_nav = False __matrix_state = None def __init__(self, c_instance): super(MaschineJam, self).__init__(c_instance) with self.component_guard(): self._suppress_send_midi = True register_sender(self) self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143 self._set_suppress_rebuild_requests(True) self._c_ref = c_instance self.request_rebuild_midi_map() self.__matrix_state = MatrixState(self) self._main_mode_container = JamModes(c_instance.note_repeat) self._set_suppress_rebuild_requests(False) self._active = True self._display_device_param = False self._setup_transport() self._setup_session() self._encoder_modes = EncoderComponent(self._session) self._encoder_modes.connect() self._encoder_modes.set_state_listener(self) self._modifier = ModifierComponent(self._session) self._connect_session() self._main_mode_container.bind_session(self.__matrix_state) self._main_mode_container.bind_modify_component(self._modifier) self._setup_mainjogwheel() self._init_m4l() self._init_settings() self.set_pad_translations(PAD_TRANSLATIONS) self.set_feedback_channels(FEEDBACK_CHANNELS) self._suppress_send_midi = False self._main_mode_container._step_mode.set_mode_elements(self._modifier, self._encoder_modes) self._main_mode_container._drum_step_mode.set_mode_elements(self._modifier) self._final_init() self.apply_preferences() def _init_m4l(self): self._bmatrix.set_user_unbind_listener(self._main_mode_container) def _init_settings(self): from pickle import loads, dumps from encodings import ascii nop(ascii) preferences = self._c_instance.preferences(self.preferences_name()) self._pref_dict = {} try: self._pref_dict = loads(str(preferences)) except Exception: pass pref_dict = self._pref_dict preferences.set_serializer(lambda : dumps(pref_dict)) def store_preferences(self): self._pref_dict['matrix_color_mode'] = self._session.get_color_mode() def apply_preferences(self): pref_dict = self._pref_dict if 'matrix_color_mode' in pref_dict: self._session.set_color_mode(pref_dict['matrix_color_mode']) def preferences_name(self): return 'MaschineJam' def _final_init(self): debug_out('########## LIVE 10 Maschine JAM V 1.3 #############') self._auto_button.set_display_value(self.song().session_automation_record and 127 or 0) self._main_mode_container.init_elements() def _init_map(self): msgsysex = [ 240, 0, 33, 9, 21, 0, 77, 80, 0, 1, 2] for _ in range(80): msgsysex.append(COLOR_BLACK) msgsysex.append(247) self._send_midi(tuple(msgsysex)) def _set_touch_strip_led(self): msgsysex = [ 240, 0, 33, 9, 21, 0, 77, 80, 0, 1, 4] for _ in range(8): msgsysex.append(0) msgsysex.append(247) self._send_midi(tuple(msgsysex)) def handle_sysex(self, midi_bytes): if len(midi_bytes) > 11 and midi_bytes[0:10] == (240, 0, 33, 9, 21, 0, 77, 80, 0, 1): msg, value = midi_bytes[10:12] if msg == 70: self.refresh_state() self._modifier.set_shiftstatus(1) elif msg == 77: self.shiftButton.notify_value(value == 1 and 127 or 0) if not self.shiftButton.is_grabbed: self._modifier.set_shiftstatus(value) def _setup_transport(self): is_momentary = True self.shiftButton = SysExButton(120, name='Shift_Button') self.__play_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 108, name='Play_Button') self._hand_play_pressed.subject = self.__play_button self._listen_playing.subject = self.song() self._channel_led_left = SliderElement(MIDI_CC_TYPE, 0, 38) self._channel_led_right = SliderElement(MIDI_CC_TYPE, 0, 39) self._channel_led_left.last_raw = 0.0 self._channel_led_left.last_send = 0 self._channel_led_right.last_raw = 0.0 self._channel_led_right.last_send = 0 self._listen_master_left.subject = self.song().master_track self._listen_master_right.subject = self.song().master_track self._auto_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 98, name='Auto_Button') self._listen_automation_record.subject = self.song() self._handle_automation_record.subject = self._auto_button self._do_direction_up.subject = StateButton(is_momentary, MIDI_CC_TYPE, 0, 40, name='Up_Arrow') self._do_direction_down.subject = StateButton(is_momentary, MIDI_CC_TYPE, 0, 41, name='Down_Arrow') self._do_direction_left.subject = StateButton(is_momentary, MIDI_CC_TYPE, 0, 42, name='Left_Arrow') self._do_direction_right.subject = StateButton(is_momentary, MIDI_CC_TYPE, 0, 43, name='Right_Arrow') @subject_slot('output_meter_left') def _listen_master_left(self): cvl = self.song().master_track.output_meter_left if cvl != self._channel_led_left.last_raw: val = cvl > 0.92 and 127 or int(127 * (cvl * cvl)) if val != self._channel_led_left.last_send: self._channel_led_left.last_raw = cvl self._channel_led_left.last_send = val self._channel_led_left.send_value(val, True) @subject_slot('output_meter_right') def _listen_master_right(self): cvl = self.song().master_track.output_meter_right if cvl != self._channel_led_right.last_raw: val = cvl > 0.92 and 127 or int(127 * (cvl * cvl)) if val != self._channel_led_right.last_send: self._channel_led_right.last_raw = cvl self._channel_led_right.last_send = val self._channel_led_right.send_value(val, True) def is_monochrome(self): return False def _send_midi(self, midi_bytes, **keys): self._c_ref.send_midi(midi_bytes) if self._midi_count > 2: time.sleep(0.001) self._midi_count = 0 self._midi_count += 1 return True def _setup_mainjogwheel(self): self._prev_mode = None return def is_shift_down(self): return self._modifier.is_shift_down() def modifier_mask(self): return self._modifier.modifier_mask() def _setup_session(self): self._session = JamSessionComponent() self._matrix = [] self._bmatrix = JamButtonMatrix(8, name='Button_Matrix') for sceneIndex in range(8): button_row = [] for trackindex in range(8): button = PadColorButton(True, 0, sceneIndex, trackindex, self._main_mode_container) button_row.append(button) self._matrix.append(tuple(button_row)) self._bmatrix.add_row(tuple(button_row)) self._session.set_matrix(self._bmatrix, self._matrix) self.__matrix_state.register_matrix(self._bmatrix) self._bmatrix.prepare_update() for button, (trackIndex, sceneIndex) in self._bmatrix.iterbuttons(): if button: scene = self._session.scene(sceneIndex) clip_slot = scene.clip_slot(trackIndex) clip_slot.set_launch_button(button) clip_slot.set_triggered_to_play_value(1) clip_slot.set_triggered_to_record_value(1) clip_slot.set_started_value(1) clip_slot.set_recording_value(1) clip_slot.set_stopped_value(1) self._session._link() self._bmatrix.commit_update() self.set_highlighting_session_component(self._session) def _connect_session(self): for sindex in range(self._session.height()): scene = self._session.scene(sindex) for cindex in range(self._session.width()): clip = scene.clip_slot(cindex) clip.set_modifier(self._modifier) clip.set_index((cindex, sindex)) def update_display(self): with self.component_guard(): self._main_mode_container.notify(self._blink_state) self._encoder_modes.notify(self._blink_state) self._blink_state = (self._blink_state + 1) % 4 def refresh_state(self): self._bmatrix.prepare_update() ControlSurface.refresh_state(self) self.update_hardware() self._bmatrix.commit_update() def update_hardware(self): self._session.update() self.__play_button.set_display_value(self.song().is_playing and 127 or 0, True) self._main_mode_container.refresh_state() self._encoder_modes.refresh_state() def invoke_nav_left(self): self._encoder_modes.invoke_nav_left() def invoke_nav_right(self): self._encoder_modes.invoke_nav_right() def invoke_rec(self): slot = self.song().view.highlighted_clip_slot if slot == None: return if slot.controls_other_clips: slot.fire() else: if slot.has_clip: track = slot.canonical_parent if track.can_be_armed: arm_exclusive(self.song(), track) self.song().overdub = True slot.fire() else: track = slot.canonical_parent if track.can_be_armed: arm_exclusive(self.song(), track) slot.fire() return @subject_slot('session_automation_record') def _listen_automation_record(self): self._auto_button.set_display_value(self.song().session_automation_record and 127 or 0, True) @subject_slot('value', identify_sender=True) def _handle_automation_record(self, value, sender): if value == 0 or sender.grabbed: return self.song().session_automation_record = not self.song().session_automation_record @subject_slot('is_playing') def _listen_playing(self): if self.song().is_playing: self.__play_button.set_display_value(127, True) else: self.__play_button.set_display_value(0, True) @subject_slot('value', identify_sender=True) def _hand_play_pressed(self, value, sender): if value == 0 or sender.grabbed: return if self.song().is_playing: if self._modifier.is_shift_down(): self.song().start_playing() else: self.song().stop_playing() else: self.song().start_playing() @subject_slot('value', identify_sender=True) def do_undo(self, value, sender): if value == 0 or sender.grabbed: return if self._modifier.is_shift_down(): if self.song().can_redo == 1: self.song().redo() self.show_message(str('REDO')) else: if self.song().can_undo == 1: self.song().undo() self.show_message(str('UNDO')) def notify_state(self, state, value): if state == 'controldown': self.__block_nav = value else: if state == 'step': self._main_mode_container.notify_state(state, value) @subject_slot('value', identify_sender=True) def _do_direction_up(self, value, sender): if value == 0 or sender.grabbed: return if not self.__block_nav: self._main_mode_container.navigate(-1, 1, self._modifier.is_shift_down(), NAV_SRC_BUTTON) else: self._encoder_modes.navigate(-1, 1, self._modifier.is_shift_down(), NAV_SRC_BUTTON) @subject_slot('value', identify_sender=True) def _do_direction_down(self, value, sender): if value == 0 or sender.grabbed: return if not self.__block_nav: self._main_mode_container.navigate(1, 1, self._modifier.is_shift_down(), NAV_SRC_BUTTON) else: self._encoder_modes.navigate(1, -1, self._modifier.is_shift_down(), NAV_SRC_BUTTON) @subject_slot('value', identify_sender=True) def _do_direction_left(self, value, sender): if value == 0 or sender.grabbed: return if not self.__block_nav: encoder_changed = self._main_mode_container.navigate(-1, 0, self._modifier.is_shift_down(), NAV_SRC_BUTTON) if encoder_changed: self._encoder_modes.navigate(-1, 0, self._modifier.is_shift_down(), NAV_SRC_BUTTON) else: self._encoder_modes.navigate(-1, 0, self._modifier.is_shift_down(), NAV_SRC_BUTTON) @subject_slot('value', identify_sender=True) def _do_direction_right(self, value, sender): if value == 0 or sender.grabbed: return if not self.__block_nav: encoder_changed = self._main_mode_container.navigate(1, 0, self._modifier.is_shift_down(), NAV_SRC_BUTTON) if encoder_changed: self._encoder_modes.navigate(1, 0, self._modifier.is_shift_down(), NAV_SRC_BUTTON) else: self._encoder_modes.navigate(1, 0, self._modifier.is_shift_down(), NAV_SRC_BUTTON) @property def selected_mode(self): return self._main_mode_container.selected_mode @selected_mode.setter def selected_mode(self, value): self._main_mode_container.selected_mode = value def get_session(self): return self._session def toggle_mode(self): self._session.set_color_mode() self.refresh_state() def get_button_matrix(self): return self._bmatrix def deassign_matrix(self): for scene_index in range(8): scene = self._session.scene(scene_index) for track_index in range(8): clip_slot = scene.clip_slot(track_index) clip_slot.set_launch_button(None) return def _pre_serialize(self): from pickle import dumps from encodings import ascii nop(ascii) preferences = self._c_instance.preferences('MaschineJam') self.store_preferences() dump = dumps(self._pref_dict) preferences.set_serializer(lambda : dump) def disconnect(self): self._pre_serialize() self._set_touch_strip_led() self._encoder_modes.turn_off_bars() self._init_map() self._channel_led_left.send_value(0, True) self._channel_led_right.send_value(0, True) self._active = False self._suppress_send_midi = True super(MaschineJam, self).disconnect() return