Exemplo n.º 1
0
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)
Exemplo n.º 2
0
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()
Exemplo n.º 3
0
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))
Exemplo n.º 4
0
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
Exemplo n.º 5
0
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)
Exemplo n.º 7
0
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()
Exemplo n.º 8
0
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))