예제 #1
0
class ModClipSlotComponent(ClipSlotComponent):
    '''
    Clip Slot Component for Maschine
    '''
    def __init__(self, *a, **k):
        super(ModClipSlotComponent, self).__init__(*a, **a)

    def set_modifier(self, modifier):
        self._modifier = modifier

    def _launch_button_value(self, value):
        if self.is_enabled():
            if self._modifier and self._modifier.hasModification(CLIP_MODE):
                self._modifier.edit_clip_slot(self, value)
            elif self._clip_slot != None and self._modifier and self._modifier.isShiftdown(
            ) and value != 0:
                track = self._clip_slot.canonical_parent
                scenes = self.song().scenes
                index = vindexof(track.clip_slots, self._clip_slot)
                scenes[index].fire()
            elif self._clip_slot != None and self._modifier and self._modifier.isClipAltDown(
            ) and value != 0:
                track = self._clip_slot.canonical_parent
                if track.is_foldable and value != 0:
                    if track.fold_state == 0:
                        track.fold_state = 1
                    else:
                        track.fold_state = 0

            elif self._clip_slot != None:
                self._do_launch_clip(value)

    _launch_button_value = subject_slot('value')(_launch_button_value)

    def get_launch_button(self):
        return self._launch_button_value_slot.subject
예제 #2
0
class Maschine(ControlSurface):
    __module__ = __name__
    '''Basic Control Script for All Maschine Modell Mikro, Mikro Mk2, Mk1, Mk2, Studio'''
    def __init__(self, c_instance):
        super(Maschine, self).__init__(c_instance)
        self.component_guard().__enter__()

        try:
            register_sender(self)
            self._diplay_cache = ['', '', '', '']
            self._suppress_send_midi = True
            is_momentary = True
            self._c_ref = c_instance
            self.display_task = DisplayTask()
            self._challenge = Live.Application.get_random_int(
                0, 400000000) & 2139062143
            self._active = False
            self._midi_pause_count = 0
            self.blink_state = 0
            self.send_slider_index = 0
            self.nav_index = 0
            self.arm_selected_track = False
            self.undo_state = 0
            self.redo_state = 0
            self._set_suppress_rebuild_requests(True)
            self._modeselect = ModeSelector(self.is_monochrome())
            self._device = self._set_up_device_control()
            self._set_up_session(self._modeselect)
            self._set_up_mixer()
            self._setup_transport()
            self._set_global_buttons()
            self._editsection = EditSection()
            self._editsection.connect_session(self._session)
            self._editsection.set_mode_selector(self._modeselect)
            self._session.set_mode(self._modeselect._clip_mode)
            self._audio_clip_editor = AudioClipEditComponent()
            self._note_repeater = NoteRepeatComponent(c_instance.note_repeat)
            self._midi_edit = MidiEditSection()
            self._init_settings()
            self._init_maschine()
            self.set_highlighting_session_component(self._session)
            self.set_pad_translations(PAD_TRANSLATIONS)
            self._on_selected_track_changed()
            self.set_up_function_buttons()
            self.show_message(str(''))
            self.request_rebuild_midi_map()
            self._set_suppress_rebuild_requests(False)
            self._active = True
            self._display_device_param = False
            self.set_feedback_channels(FEEDBACK_CHANNELS)
            self._final_init()
            self._suppress_send_midi = False
            self.apply_preferences()
            self.init_text_display()
            self._on_appointed_device_changed.subject = self.song()
        finally:
            pass

    def _init_maschine(self):
        pass

    def _final_init(self):
        pass

    def create_pad_button(self, scene_index, track_index, color_source):
        pass

    def create_gated_button(self, identifier, hue):
        pass

    def apply_preferences(self):
        pref_dict = self._pref_dict
        if 'step_advance' in pref_dict:
            self._session.set_step_advance(pref_dict['step_advance'])

        if 'solo_exclusive' in pref_dict:
            self._modeselect.set_solo_exclusive(pref_dict['solo_exclusive'])
        else:
            self._modeselect.set_solo_exclusive(True)
        if 'arm_exclusive' in pref_dict:
            self._modeselect.set_arm_exclusive(pref_dict['arm_exclusive'])
        else:
            self._modeselect.set_arm_exclusive(True)
        if 'quantize_val' in pref_dict:
            self._editsection.quantize = pref_dict['quantize_val']
        else:
            self._editsection.quantize = 5
        if 'initial_cliplen' in pref_dict:
            self._editsection.initial_clip_len = pref_dict['initial_cliplen']
        else:
            self._editsection.initial_clip_len = 4
        if 'auto_arm_sel_track' in pref_dict:
            self.arm_selected_track = pref_dict['auto_arm_sel_track']
        else:
            self.arm_selected_track = False
        if 'note_color_mode' in pref_dict:
            self._modeselect._pad_mode._note_display_mode = pref_dict[
                'note_color_mode']
        else:
            self._modeselect._pad_mode._note_display_mode = ND_KEYBOARD1
        self._pref_dict[
            'note_color_mode'] = self._modeselect._pad_mode._note_display_mode
        if not self.arm_selected_track or 127:
            pass
        self.set_sel_arm_button.send_value(0, True)
        self._note_repeater.recall_values(self._pref_dict)

    def store_preferences(self):
        self._pref_dict['step_advance'] = self._session.get_step_advance()
        self._pref_dict['solo_exclusive'] = self._modeselect.is_solo_exclusive(
        )
        self._pref_dict['arm_exclusive'] = self._modeselect.is_arm_exclusive()
        self._pref_dict['quantize_val'] = self._editsection.quantize
        self._pref_dict['initial_cliplen'] = self._editsection.initial_clip_len
        self._pref_dict['auto_arm_sel_track'] = self.arm_selected_track
        self._pref_dict[
            'note_color_mode'] = self._modeselect._pad_mode._note_display_mode
        self._note_repeater.store_values(self._pref_dict)

    def _init_settings(self):
        loads = loads
        dumps = dumps
        import pickle
        ascii = ascii
        import encodings
        nop(ascii)
        preferences = self._c_instance.preferences(self.preferences_name())
        self._pref_dict = {}

        try:
            self._pref_dict = loads(str(preferences))
        except Exception:
            pass

        pref_dict = self._pref_dict
        (None, preferences.set_serializer)(lambda: dumps(pref_dict))

    def preferences_name(self):
        return 'Maschine'

    def _pre_serialize(self):
        dumps = dumps
        import pickle
        ascii = ascii
        import encodings
        nop(ascii)
        preferences = self._c_instance.preferences('Maschine')
        self.store_preferences()
        dump = dumps(self._pref_dict)
        (preferences.set_serializer, )(lambda: dump)

    def toggle_nav_mode(self):
        self._session.switch_step_advance()
        self.show_message(' View Navigation in steps of ' +
                          str(self._session.get_step_advance()))

    def _set_up_session(self, mode_selector):
        is_momentary = True
        self._session = MaschineSessionComponent()
        self._session.set_color_manager(mode_selector.get_color_manager())
        self.nav_buttons = (self.create_gated_button(92, COLOR_HUE_NAV),
                            self.create_gated_button(81, COLOR_HUE_NAV),
                            self.create_gated_button(93, COLOR_HUE_NAV),
                            self.create_gated_button(91, COLOR_HUE_NAV))
        self._session.set_scene_bank_buttons(self.nav_buttons[0],
                                             self.nav_buttons[1])
        self._session.set_track_bank_buttons(self.nav_buttons[2],
                                             self.nav_buttons[3])
        continue
        track_stop_buttons = [
            StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL,
                        index + STOP_CC_OFF) for index in range(4)
        ]
        self._session.set_stop_track_clip_buttons(tuple(track_stop_buttons))
        self._matrix = []
        self._bmatrix = ButtonMatrixElement()
        for scene_index in range(4):
            button_row = []
            for track_index in range(4):
                button = self.create_pad_button(scene_index, track_index,
                                                mode_selector)
                button_row.append(button)

            self._matrix.append(tuple(button_row))
            self._bmatrix.add_row(tuple(button_row))

        self._session.set_matrix(self._matrix)
        for (track_index, scene_index) in self._bmatrix.iterbuttons():
            if button:
                scene = self._session.scene(scene_index)
                clip_slot = scene.clip_slot(track_index)
                clip_slot.set_launch_button(button)
                clip_slot.set_triggered_to_play_value(1)
                clip_slot.set_triggered_to_record_value(1)
                clip_slot.set_started_value(1)
                clip_slot.set_recording_value(1)
                clip_slot.set_stopped_value(1)
                continue

        self._session._link()

    def _set_up_mixer(self):
        is_momentary = True
        self._mixer = MaschineMixerComponent(8)
        self.send_sliders = []
        for track in range(8):
            self.send_sliders.append(
                SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL,
                              SEND_CC_OFF + track))

        for track in range(8):
            strip = self._mixer.channel_strip(track)
            strip.set_arm_button(
                StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL,
                            ARM_CC_OFF + track))
            strip.set_solo_button(
                StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL,
                            SOLO_CC_OFF + track))
            strip.set_mute_button(
                StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL,
                            MUTE_CC_OFF + track))
            strip.set_volume_control(
                SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL,
                              LEVEL_CC_OFF + track))
            strip.set_pan_control(
                SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, PAN_CC_OFF + track))
            strip.set_select_button(
                StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL,
                            SELECT_CC_OFF + track))
            st = tuple([self.send_sliders[track]])
            strip.set_send_controls(st)

        self.send_slider_toggle_button = StateButton(False, MIDI_CC_TYPE, 0,
                                                     90)
        self._do_toggle_send.subject = self.send_slider_toggle_button
        self._session.set_mixer(self._mixer)

    def _set_global_buttons(self):
        is_momentary = True
        self._undo_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 85)
        self._do_undo.subject = self._undo_button
        self._redo_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 87)
        self._do_redo.subject = self._redo_button
        self._stop_all_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 111)
        self._do_stop_all.subject = self._stop_all_button
        self._toggle_detail_button = ButtonElement(is_momentary, MIDI_CC_TYPE,
                                                   1, 121)
        self._action_toogle_detail_view.subject = self._toggle_detail_button
        self._fire_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 9)
        self._do_fire_button.subject = self._fire_button
        self._g_clear_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1,
                                             106)
        self._hold_clear_action.subject = self._g_clear_button
        self._g_duplicate_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1,
                                                 107)
        self._hold_duplicate_action.subject = self._g_duplicate_button
        self.track_left_button = StateButton(is_momentary, MIDI_CC_TYPE, 0,
                                             120)
        self.track_right_button = StateButton(is_momentary, MIDI_CC_TYPE, 0,
                                              121)
        self.set_sel_arm_button = StateButton(is_momentary, MIDI_CC_TYPE, 2,
                                              56)
        self._reenable_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1,
                                              120)
        self._do_auto_reenable.subject = self._reenable_button
        self._on_change_reenabled.subject = self.song()
        self._on_change_reenabled()
        self._a_trk_left.subject = self.track_left_button
        self._a_trk_right.subject = self.track_right_button
        self._a_sel_arm.subject = self.set_sel_arm_button

    def _set_up_device_control(self):
        is_momentary = True
        device = MaschineDeviceComponent()
        param_controls = []
        for index in range(8):
            param_controls.append(
                SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL,
                              DEVICE_CC_OFF + index))

        device.set_parameter_controls(tuple(param_controls))
        self.device_control = param_controls
        device.set_on_off_button(
            StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL,
                        DEVICE_BUTTON_CC_OFF))
        device.set_bank_nav_buttons(
            StateButton(is_momentary, MIDI_CC_TYPE, 3, 104),
            ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 105))
        self._device_nav_button_left = StateButton(is_momentary, MIDI_CC_TYPE,
                                                   3, 106)
        self._device_nav_button_right = StateButton(is_momentary, MIDI_CC_TYPE,
                                                    3, 107)
        self._navigate_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 127)
        self._nav_value_left.subject = self._device_nav_button_left
        self._nav_value_right.subject = self._device_nav_button_right
        self._do_focus_navigate.subject = self._navigate_button
        self.set_device_component(device)
        return device

    def _setup_transport(self):
        is_momentary = True
        transport = TransportComponent()
        studiotransport = MaschineTransport()
        playButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 108)
        stopButton = StateButton(not is_momentary, MIDI_CC_TYPE, 0, 110)
        recordButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 109)
        overdubButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 107)
        metrononmeButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 104)
        eventRecButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 98)
        playButton.name = 'Play'
        stopButton.name = 'Stop'
        recordButton.name = 'Record'
        overdubButton.name = 'Overdub'
        metrononmeButton.name = 'Metronome'
        transport.set_play_button(playButton)
        transport.set_stop_button(stopButton)
        transport.set_record_button(recordButton)
        transport.set_overdub_button(overdubButton)
        transport.set_metronome_button(metrononmeButton)
        studiotransport.set_session_auto_button(eventRecButton)
        studiotransport.set_arrangement_overdub_button(
            StateButton(is_momentary, MIDI_CC_TYPE, 0, 106))
        studiotransport.set_back_arrange_button(
            StateButton(is_momentary, MIDI_CC_TYPE, 0, 105))
        transport.set_nudge_buttons(
            StateButton(is_momentary, MIDI_CC_TYPE, 1, 51),
            StateButton(is_momentary, MIDI_CC_TYPE, 1, 50))
        punchinbutton = ToggleButton(MIDI_CC_TYPE, 1, 52)
        punchoutbutton = ToggleButton(MIDI_CC_TYPE, 1, 53)
        punchinbutton.name = 'Punch In'
        punchoutbutton.name = 'Punch Out'
        transport.set_punch_buttons(punchinbutton, punchoutbutton)
        transport.set_loop_button(
            StateButton(is_momentary, MIDI_CC_TYPE, 1, 54))
        self.song_follow_button = ButtonElement(True, MIDI_CC_TYPE, 2, 98)
        self._do_song_follow.subject = self.song_follow_button
        self._song_follow_changed.subject = self.song().view
        self._song_follow_changed()
        self.prehear_knob = SliderElement(MIDI_CC_TYPE, 0, 41)
        self.prehear_knob.connect_to(
            self.song().master_track.mixer_device.cue_volume)
        self.transp_ff_button = ButtonElement(True, MIDI_CC_TYPE, 1, 59)
        self.transp_rw_button = ButtonElement(True, MIDI_CC_TYPE, 1, 58)
        transport.set_seek_buttons(self.transp_ff_button,
                                   self.transp_rw_button)
        self.xfadeKnob = SliderElement(MIDI_CC_TYPE, 1, 105)
        self.xfadeKnob.connect_to(
            self.song().master_track.mixer_device.crossfader)
        self.master_knob = SliderElement(MIDI_CC_TYPE, 0, 99)
        self.master_knob.connect_to(
            self.song().master_track.mixer_device.volume)
        self.tap_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 88)
        self._do_tap_tempo.subject = self.tap_button
        self.cue_add_delete_button = StateButton(is_momentary, MIDI_CC_TYPE, 1,
                                                 55)
        self.cue_prev_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 56)
        self.cue_next_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 57)
        self._do_toggle_cue.subject = self.cue_add_delete_button
        self._do_toggle_prev_cue.subject = self.cue_prev_button
        self._do_toggle_next_cue.subject = self.cue_next_button

    def set_up_function_buttons(self):
        is_momentary = True
        self.keycolor_mod_button = StateButton(is_momentary, MIDI_CC_TYPE, 1,
                                               73)
        self._do_key_color.subject = self.keycolor_mod_button
        self._update_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 86)
        self._do_update_display.subject = self._update_button

    def _on_appointed_device_changed(self):
        self._modeselect._device_changed()

    _on_appointed_device_changed = subject_slot('appointed_device')(
        _on_appointed_device_changed)

    def _update_hardware(self):
        self._session.update()
        self._modeselect.refresh()
        self.update_undo_redo(True)

    def refresh_state(self):
        ControlSurface.refresh_state(self)
        self._update_hardware()

    def _send_midi(self, midi_bytes, **keys):
        self._c_ref.send_midi(midi_bytes)
        return True

    def init_text_display(self):
        if USE_DISPLAY:
            self._modeselect._pad_mode.update_text_display()

    def _on_selected_track_changed(self):
        super(Maschine, self)._on_selected_track_changed()
        self.set_controlled_track(self.song().view.selected_track)
        self._on_devices_changed.subject = self.song().view.selected_track

    def _on_devices_changed(self):
        pass

    _on_devices_changed = subject_slot('devices')(_on_devices_changed)

    def update(self):
        self.set_feedback_channels(FEEDBACK_CHANNELS)
        super(Maschine, self).update()

    def is_monochrome(self):
        return False

    def _deassign_matrix(self):
        for scene_index in range(4):
            scene = self._session.scene(scene_index)
            for track_index in range(4):
                clip_slot = scene.clip_slot(track_index)
                clip_slot.set_launch_button(None)

    def update_display(self):
        self.component_guard().__enter__()

        try:
            self._is_sending_scheduled_messages().__enter__()

            try:
                self._task_group.update(0.1)
            finally:
                pass

            self._modeselect.notify(self.blink_state)
            self.blink_state = (self.blink_state + 1) % 4
            self.display_task.tick()
            self.update_undo_redo(False)
        finally:
            pass

    def update_undo_redo(self, force=False):
        if force:
            self.undo_state = self.song().can_undo
            self.redo_state = self.song().can_redo

        if self.song().can_undo != self.undo_state:
            self.undo_state = self.song().can_undo
            if not self.undo_state == 1 or 127:
                pass
            self._undo_button.send_value(0)

        if self.song().can_redo != self.redo_state:
            self.redo_state = self.song().can_redo
            if not self.redo_state == 1 or 127:
                pass
            self._redo_button.send_value(0)

    def adjust_loop_start(self, delta):
        loopval = self.song().loop_start
        self.song().loop_start = min(self.song().song_length,
                                     max(0, loopval + delta))

    def adjust_loop_length(self, delta):
        loopval = self.song().loop_length
        self.song().loop_length = min(self.song().song_length,
                                      max(abs(delta), loopval + delta))

    def _do_armsolo_mode(self, value):
        pass

    def _do_fire_button(self, value):
        if not self._fire_button != None:
            raise AssertionError
        if not value in range(128):
            raise AssertionError
        if value != 0:
            if self.isShiftDown():
                self.song().tap_tempo()
            else:
                clip_slot = self.song().view.highlighted_clip_slot
                if clip_slot:
                    clip_slot.fire()

    _do_fire_button = subject_slot('value')(_do_fire_button)

    def _do_undo(self, value):
        if value != 0:
            if self.use_layered_buttons() and self.isShiftDown():
                if self.song().can_redo == 1:
                    self.song().redo()
                    self.show_message(str('REDO'))

            elif self.song().can_undo == 1:
                self.song().undo()
                self.show_message(str('UNDO'))

    _do_undo = subject_slot('value')(_do_undo)

    def _do_redo(self, value):
        if value != 0:
            if self.song().can_redo == 1:
                self.song().redo()
                self.show_message(str('REDO'))

    _do_redo = subject_slot('value')(_do_redo)

    def _do_stop_all(self, value):
        if value != 0:
            if self.use_layered_buttons() and self.isShiftDown():
                self.song().stop_all_clips(0)
            else:
                self.song().stop_all_clips(1)

    _do_stop_all = subject_slot('value')(_do_stop_all)

    def isShiftDown(self):
        return self._editsection.isShiftdown()

    def modifiers(self):
        return self._editsection.modifiers()

    def use_layered_buttons(self):
        return False

    def _handle_base_note(self, diff):
        self._modeselect._pad_mode.inc_base_note(diff)

    def _handle_octave(self, diff):
        self._modeselect._pad_mode.inc_octave(diff)
        octave_val = self._modeselect._pad_mode

    def _handle_scale(self, diff):
        self._modeselect._pad_mode.inc_scale(diff)

    def _do_update_display(self, value):
        if value != 0:
            self.refresh_state()

    _do_update_display = subject_slot('value')(_do_update_display)

    def _do_key_color(self, value):
        if not value in range(128):
            raise AssertionError
        if value != 0:
            self._modeselect._pad_mode.step_key_color_mode()

    _do_key_color = subject_slot('value')(_do_key_color)

    def _do_tap_tempo(self, value):
        if not value in range(128):
            raise AssertionError
        if value != 0:
            self.song().tap_tempo()

    _do_tap_tempo = subject_slot('value')(_do_tap_tempo)

    def _do_toggle_cue(self, value):
        if not value in range(128):
            raise AssertionError
        if value != 0:
            self.song().set_or_delete_cue()

    _do_toggle_cue = subject_slot('value')(_do_toggle_cue)

    def _do_toggle_prev_cue(self, value):
        if not value in range(128):
            raise AssertionError
        if value != 0:
            self.song().jump_to_prev_cue()

    _do_toggle_prev_cue = subject_slot('value')(_do_toggle_prev_cue)

    def _do_toggle_next_cue(self, value):
        if not value in range(128):
            raise AssertionError
        if value != 0:
            self.song().jump_to_next_cue()

    _do_toggle_next_cue = subject_slot('value')(_do_toggle_next_cue)

    def _do_toggle_send(self, value):
        if not value in range(128):
            raise AssertionError
        if self.isShiftDown():
            if value != 0:
                self.refresh_state()
                self.show_message('Refresh Display')

        else:
            nr_of_tracks = len(self.song().return_tracks)
            if value == 0 or nr_of_tracks < 1:
                return None

            prev = self.send_slider_index
            self.send_slider_index += 1
            if self.send_slider_index >= nr_of_tracks:
                self.send_slider_index = 0

            self.show_message(' Set Send ' +
                              str(SENDS[self.send_slider_index]))
            self.timed_message(
                2, ' Set Send ' + str(SENDS[self.send_slider_index]))
            if prev != self.send_slider_index:
                for track in range(8):
                    strip = self._mixer.channel_strip(track)
                    slider_list = []
                    for index in range(self.send_slider_index + 1):
                        if index < self.send_slider_index - 1:
                            slider_list.append(None)
                        else:
                            slider_list.append(self.send_sliders[track])
                        strip.set_send_controls(tuple(slider_list))

    _do_toggle_send = subject_slot('value')(_do_toggle_send)

    def _a_trk_left(self, value):
        if not value in range(128):
            raise AssertionError
        if value != 0:
            if self.application().view.is_view_visible('Session'):
                direction = Live.Application.Application.View.NavDirection.left
                self.application().view.scroll_view(direction, 'Session', True)
                track = self.song().view.selected_track
                self.timed_message(2, 'T:' + track.name, False)
                if self.arm_selected_track and track.can_be_armed:
                    arm_exclusive(self.song(), track)

    _a_trk_left = subject_slot('value')(_a_trk_left)

    def _a_trk_right(self, value):
        if not value in range(128):
            raise AssertionError
        if value != 0:
            if self.application().view.is_view_visible('Session'):
                direction = Live.Application.Application.View.NavDirection.right
                self.application().view.scroll_view(direction, 'Session', True)
                track = self.song().view.selected_track
                self.timed_message(2, 'T:' + track.name, False)
                if self.arm_selected_track and track.can_be_armed:
                    arm_exclusive(self.song(), track)

    _a_trk_right = subject_slot('value')(_a_trk_right)

    def _a_sel_arm(self, value):
        if value != 0:
            if self.arm_selected_track:
                self.arm_selected_track = False
                self.set_sel_arm_button.send_value(0, True)
            else:
                self.arm_selected_track = True
                self.set_sel_arm_button.send_value(127, True)

    _a_sel_arm = subject_slot('value')(_a_sel_arm)

    def _nav_value_left(self, value):
        if not self._device_nav_button_left != None:
            raise AssertionError
        if not value in range(128):
            raise AssertionError
        modifier_pressed = True
        if value != 0:
            if not self.application().view.is_view_visible(
                    'Detail') or not self.application().view.is_view_visible(
                        'Detail/DeviceChain'):
                self.application().view.show_view('Detail')
                self.application().view.show_view('Detail/DeviceChain')
            else:
                direction = Live.Application.Application.View.NavDirection.left
                self.application().view.scroll_view(direction,
                                                    'Detail/DeviceChain',
                                                    not modifier_pressed)

    _nav_value_left = subject_slot('value')(_nav_value_left)

    def _nav_value_right(self, value):
        if not self._device_nav_button_right != None:
            raise AssertionError
        if not value in range(128):
            raise AssertionError
        if value != 0:
            modifier_pressed = True
            if not self.application().view.is_view_visible(
                    'Detail') or not self.application().view.is_view_visible(
                        'Detail/DeviceChain'):
                self.application().view.show_view('Detail')
                self.application().view.show_view('Detail/DeviceChain')
            else:
                direction = Live.Application.Application.View.NavDirection.right
                self.application().view.scroll_view(direction,
                                                    'Detail/DeviceChain',
                                                    not modifier_pressed)

    _nav_value_right = subject_slot('value')(_nav_value_right)

    def _do_focus_navigate(self, value):
        if not self._navigate_button != None:
            raise AssertionError
        if not value in range(128):
            raise AssertionError
        if value != 0:
            self.nav_index = (self.nav_index + 1) % len(VIEWS_ALL)
            self.application().view.focus_view(VIEWS_ALL[self.nav_index])
            self.show_message('Focus on : ' + str(VIEWS_ALL[self.nav_index]))

    _do_focus_navigate = subject_slot('value')(_do_focus_navigate)

    def focus_clip_detail(self):
        self.application().view.focus_view('Detail/Clip')

    def _song_follow_changed(self):
        view = self.song().view
        if view.follow_song:
            self.song_follow_button.send_value(1, True)
        else:
            self.song_follow_button.send_value(0, True)

    _song_follow_changed = subject_slot('follow_song')(_song_follow_changed)

    def _do_song_follow(self, value):
        if value != 0:
            view = self.song().view
            if view.follow_song:
                view.follow_song = False
                self.song_follow_button.send_value(0, True)
            else:
                view.follow_song = True
                self.song_follow_button.send_value(1, True)

    _do_song_follow = subject_slot('value')(_do_song_follow)

    def _hold_duplicate_action(self, value):
        if value != 0:
            pass
        1

    _hold_duplicate_action = subject_slot('value')(_hold_duplicate_action)

    def _hold_clear_action(self, value):
        if value != 0:
            self._mixer.enter_clear_mode()
            self._device_component.enter_clear_mode()
        else:
            self._mixer.exit_clear_mode()
            self._device_component.exit_clear_mode()

    _hold_clear_action = subject_slot('value')(_hold_clear_action)

    def _action_toogle_main_view(self, value):
        if value != 0:
            appv = self.application().view
            if appv.is_view_visible('Arranger'):
                appv.show_view('Session')
            else:
                appv.show_view('Arranger')

    _action_toogle_main_view = subject_slot('value')(_action_toogle_main_view)

    def _action_toogle_detail_view(self, value):
        if value != 0:
            appv = self.application().view
            if self.isShiftDown():
                if appv.is_view_visible('Arranger'):
                    appv.show_view('Session')
                else:
                    appv.show_view('Arranger')
            elif appv.is_view_visible('Detail/Clip'):
                appv.show_view('Detail/DeviceChain')
            else:
                appv.show_view('Detail/Clip')

    _action_toogle_detail_view = subject_slot('value')(
        _action_toogle_detail_view)

    def _on_change_reenabled(self):
        if self.song().re_enable_automation_enabled:
            self._reenable_button.turn_on()
        else:
            self._reenable_button.turn_off()

    _on_change_reenabled = subject_slot('re_enable_automation_enabled')(
        _on_change_reenabled)

    def _do_auto_reenable(self, value):
        if value != 0:
            self.song().re_enable_automation()

    _do_auto_reenable = subject_slot('value')(_do_auto_reenable)

    def to_color_edit_mode(self, active):
        pass

    def clear_display_all(self):
        self.send_to_display('', 0)
        self.send_to_display('', 1)
        self.send_to_display('', 2)
        self.send_to_display('', 3)

    def clear_display(self, grid):
        self.send_to_display('', grid)

    def timed_message(self, grid, text, hold=False):
        if USE_DISPLAY == False:
            self.show_message(text)
        else:
            self.display_task.set_func(self.clear_display, grid)
            self.send_to_display(text, grid)
            if hold:
                self.display_task.hold()

            self.display_task.start()

    def timed_message_release(self):
        self.display_task.release()

    def update_bank_display(self):
        if USE_DISPLAY:
            (name, bank) = self._device._current_bank_details()
            if self._display_device_param:
                prms = len(bank)
                d1 = ''
                for i in range(4):
                    parm = bank[i]
                    if parm:
                        name = parm.name
                        if not i < 3 or '|':
                            pass
                        d1 += name[:6] + ''
                        continue
                    if not i < 3 or '|':
                        pass
                    d1 += '      ' + ''

                self.send_to_display(d1, 2)
                d1 = ''
                for i in range(4):
                    parm = bank[i + 4]
                    if parm:
                        name = parm.name
                        if not i < 3 or '|':
                            pass
                        d1 += name[:6] + ''
                        continue
                    if not i < 3 or '|':
                        pass
                    d1 += '      ' + ''

                self.send_to_display(d1, 4)
            else:
                self.timed_message(2, 'Bank: ' + name)

    def display_parameters(self, paramlist):
        if USE_DISPLAY == False:
            return None

    def send_to_display(self, text, grid=0):
        if USE_DISPLAY == False:
            return None

        if self._diplay_cache[grid] == text:
            return None

        self._diplay_cache[grid] = text
        if len(text) > 28:
            text = text[:27]

        msgsysex = [240, 0, 0, 102, 23, 18, min(grid, 3) * 28]
        filled = text.ljust(28)
        for c in filled:
            msgsysex.append(ord(c))

        msgsysex.append(247)
        self._send_midi(tuple(msgsysex))

    def cleanup(self):
        pass

    def disconnect(self):
        self._pre_serialize()
        self.clear_display_all()
        for (track_index, scene_index) in self._bmatrix.iterbuttons():
            if button:
                button.send_color_direct(PColor.OFF[0])
                continue

        time.sleep(0.2)
        self._active = False
        self._suppress_send_midi = True
        super(Maschine, self).disconnect()
class ModeSelector(CompoundComponent):
    '''
    Class Handling the switch between Modes.
    '''
    __module__ = __name__
    mikro_shift = False
    _md_select_mode = None
    _md_solo_mode = None
    _md_mute_mode = None
    _knob_section = None
    _clip_mode_down = False

    def __init__(self, monochrome=False, *a, **k):
        super(ModeSelector, self).__init__(*a, **a)
        is_momentary = True
        self._scene_mode = SceneMode(0)
        self._clip_mode = StudioClipMode(1)
        self._pad_mode = PadMode(2, monochrome)
        self._drum_mode = DrumMode(2, monochrome)
        self._control_mode = ControlMode(2, monochrome)
        self._pad_mode.set_alternate_mode(self._drum_mode)
        self._drum_mode.set_alternate_mode(self._pad_mode)
        self._tracks_assign = TrackAssign()
        self._arm_mode = TrackArmMode(self._tracks_assign)
        self._solo_mode = TrackSoloMode(self._tracks_assign)
        self._stop_mode = TrackStopMode(self._tracks_assign)
        self._mute_mode = TrackMuteMode(self._tracks_assign)
        self._select_mode = TrackSelectMode(self._tracks_assign)
        self._xfade_mode = TrackXFadeMode(self._tracks_assign)
        self._color_select_mode = MaschineColorSelectMode(5)
        self._mode = self._clip_mode
        self._return_mode = None

        def create_button(ccval, channel=(0, )):
            return StateButton(is_momentary, MIDI_CC_TYPE, channel, ccval)

        self._scene_mode_button = create_button(112)
        self._clip_mode_button = create_button(113)
        self._pad_mode_button = create_button(114)
        self._select_button = create_button(117)
        self._solo_button = create_button(118)
        self._mute_button = create_button(119)
        self._xfade_button = self.canonical_parent.create_gated_button(84, 5)
        self._stop_button = self.canonical_parent.create_gated_button(94, 16)
        self._arm_button = self.canonical_parent.create_gated_button(83, 0)
        self._solo_button = StateButton(False, MIDI_CC_TYPE, 0, 118)
        self._clip_mode_button.send_value(127, True)
        self._select_clip_mode.subject = self._clip_mode_button
        self._select_scene_mode.subject = self._scene_mode_button
        self._select_pad_mode.subject = self._pad_mode_button
        self._select_arm.subject = self._arm_button
        self._select_solo.subject = self._solo_button
        self._select_stop.subject = self._stop_button
        self._select_xfade.subject = self._xfade_button
        self._select_mute.subject = self._mute_button
        self._select_select.subject = self._select_button
        self._arm_exclusive_button = create_button(51, 2)
        self._action_arm_exclusive.subject = self._arm_exclusive_button
        self._solo_exclusive_button = create_button(52, 2)
        self._action_solo_exclusive.subject = self._solo_exclusive_button
        self._scene_mode_button.send_value(0, True)
        self._clip_mode_button.send_value(1, True)
        self._pad_mode_button.send_value(0, True)
        self._mode._active = True

    def mode(self):
        return self._mode

    def update(self):
        pass

    def get_color_manager(self):
        return self._color_select_mode

    def get_color(self, value, column_index, row_index):
        return self._mode.get_color(value, column_index, row_index)

    def connect_main_knob(self, knobsection):
        self._control_mode.connect_main_knob(knobsection)

    def assign_edit_section(self, editsection):
        self._scene_mode.set_edit_mode(editsection)
        self._pad_mode.set_edit_mode(editsection)
        self._drum_mode.set_edit_mode(editsection)

    def navigate(self, dir, modifier, alt_modifier=False):
        self._mode.navigate(dir, modifier, alt_modifier)

    def notify(self, blink_state):
        self._mode.notify(blink_state)
        if self._mode == self._clip_mode or self._mode == self._color_select_mode:
            if self.canonical_parent._editsection.is_color_edit():
                if self._color_select_mode.in_track_scene_mode():
                    bval = blink_state % 2
                else:
                    bval = blink_state / 2
                self._clip_mode_button.send_value(bval)
            else:
                self._clip_mode_button.send_value(1)

    def notify_mono(self, blink_state):
        self._mode.notify_mono(blink_state)

    def enter_edit_mode(self, type):
        self._mode.enter_edit_mode(type)

    def exit_edit_mode(self, type):
        self._mode.exit_edit_mode(type)

    def enter_clear_state(self):
        self._mode.enter_clear_state()

    def exit_clear_state(self):
        self._mode.exit_clear_state()

    def _device_changed(self):
        self._mode._device_changed()

    def refresh(self):
        self._mode.refresh()
        self._stop_button.activate()
        self._arm_button.activate()
        self._xfade_button.activate()

    def rebuild(self):
        self.canonical_parent._set_suppress_rebuild_requests(True)
        yield None
        self.canonical_parent._set_suppress_rebuild_requests(False)
        self.canonical_parent.request_rebuild_midi_map()

    rebuild = contextmanager(rebuild)

    def _light_button(self, which):
        if not which == 0 or 1:
            pass
        self._scene_mode_button.send_value(0, True)
        if not which == 1 or 1:
            pass
        self._clip_mode_button.send_value(0, True)
        if not which == 2 or 1:
            pass
        self._pad_mode_button.send_value(0, True)

    def change_mode(self, nextmode):
        if not self._mode != nextmode and self._mode == None:
            pass
        return self._mode.is_lock_mode()

    def set_shift_state(self, state):
        self.mikro_shift = state

    def show_messsage(self, msg):
        self.canonical_parent.show_message(msg)

    def handle_push(self, value):
        if self._mode:
            self._mode.handle_push(value)

    def pick_color(self, cscomponent):
        shift_down = self.canonical_parent.isShiftDown()

        def set_color(rgb_value):
            if self.canonical_parent.isShiftDown():
                if shift_down:
                    track = cscomponent._clip_slot.canonical_parent
                    scenes = self.song().scenes
                    index = vindexof(track.clip_slots, cscomponent._clip_slot)
                    scenes[index].color = rgb_value
                else:
                    track = cscomponent._clip_slot.canonical_parent
                    for cs in track.clip_slots:
                        if cs.has_clip:
                            cs.clip.color = rgb_value
                            continue

            elif shift_down:
                track = cscomponent._clip_slot.canonical_parent
                track.color = rgb_value
            elif cscomponent._clip_slot.clip != None:
                cscomponent._clip_slot.clip.color = rgb_value

        def color_picked(color_rgb):
            set_color(color_rgb)
            if self._mode == self._color_select_mode:
                self.rebuild().__enter__()

                try:
                    self._mode.exit()
                    self._mode = self._clip_mode
                    self._mode.enter()
                finally:
                    pass

        self._color_select_mode.set_pick_callback(color_picked, shift_down)
        self._into_mode(self._color_select_mode, 'Color Chooser')

    def _into_mode(self, mode, info):
        if self._mode != None and self._mode != mode and not self._mode.is_lock_mode(
        ):
            return None

        self.rebuild().__enter__()

        try:
            self._return_mode = self._mode
            self._mode.exit()
            self._mode = mode
            self._mode.enter()
        finally:
            pass

    def _select_scene_mode(self, value):
        if value > 0:
            if self.mikro_shift:
                if self.change_mode(self._control_mode):
                    self.rebuild().__enter__()

                    try:
                        self._mode.exit()
                        self._mode = self._control_mode
                        self._light_button(0)
                        self._mode.enter()
                    finally:
                        pass

            elif self.change_mode(self._scene_mode):
                self.rebuild().__enter__()

                try:
                    self._mode.exit()
                    self._mode = self._scene_mode
                    self._light_button(0)
                    self._mode.enter()
                finally:
                    pass

    _select_scene_mode = subject_slot('value')(_select_scene_mode)

    def _select_clip_mode(self, value):
        click = value != 0
        if click and self._mode == self._color_select_mode:
            self._into_mode(self._clip_mode, 'CLIP MODE')
            return None

        if click:
            if self.change_mode(self._clip_mode):
                self.rebuild().__enter__()

                try:
                    self._mode.exit()
                    self._mode = self._clip_mode
                    self._light_button(1)
                    self._mode.enter()
                finally:
                    pass

            if self.canonical_parent.isShiftDown() or self.mikro_shift:
                self.canonical_parent.to_color_edit_mode(True)
                self._clip_mode_button.send_value(1, True)
            else:
                self.canonical_parent.to_color_edit_mode(False)

        self._clip_mode_down = click

    _select_clip_mode = subject_slot('value')(_select_clip_mode)

    def _select_pad_mode(self, value):
        if value > 0 and self.change_mode(self._pad_mode):
            track = self.song().view.selected_track
            newmode = self._pad_mode.fitting_mode(track)
            self.rebuild().__enter__()

            try:
                self._mode.exit()
                self._mode = newmode
                self._light_button(2)
                self._mode.enter()
            finally:
                pass

    _select_pad_mode = subject_slot('value')(_select_pad_mode)

    def _select_drum_mode(self, value):
        if value > 0 and self.change_mode(self._drum_mode):
            self.rebuild().__enter__()

            try:
                self._mode.exit()
                self._mode = self._drum_mode
                self._light_button(2)
                self._mode.enter()
            finally:
                pass

    def _into_hold_mode(self, value, button, mode, info):
        if self._mode != None and self._mode != mode and not self._mode.is_lock_mode(
        ):
            return None

        button.send_value(value, True)
        if value > 0 and self._mode != mode:
            self.rebuild().__enter__()

            try:
                self._mode.exit()
                self._return_mode = self._mode
                self._mode = mode
                self._mode.enter()
            finally:
                pass

        elif value == 0 and self._mode == mode:
            self.rebuild().__enter__()

            try:
                self._mode.exit()
                self._mode = self._return_mode
                self._return_mode = None
                self._mode.enter()
            finally:
                pass

    def _select_arm(self, value):
        if value != 0:
            self.show_messsage('Current Mode : Track ARM')

        self._into_hold_mode(value, self._arm_button, self._arm_mode, 'ARM')

    _select_arm = subject_slot('value')(_select_arm)

    def _select_stop(self, value):
        if value != 0:
            self.show_messsage('Current Mode : Track STOP')

        self._into_hold_mode(value, self._stop_button, self._stop_mode, 'STOP')

    _select_stop = subject_slot('value')(_select_stop)

    def _select_solo(self, value):
        if value != 0:
            if self.mikro_shift:
                self._into_hold_mode(value, self._solo_button, self._stop_mode,
                                     'STOP')
                self._md_solo_mode = self._stop_mode
                self.show_messsage('Current Mode : Track STOP')
            else:
                self._into_hold_mode(value, self._solo_button, self._solo_mode,
                                     'SOLO')
                self._md_solo_mode = self._solo_mode
                self.show_messsage('Current Mode : Track SOLO')
        else:
            self._into_hold_mode(value, self._solo_button, self._md_solo_mode,
                                 'SOLO')

    _select_solo = subject_slot('value')(_select_solo)

    def _select_mute(self, value):
        if value != 0:
            if self.mikro_shift:
                self._into_hold_mode(value, self._mute_button, self._arm_mode,
                                     'ARM')
                self.show_messsage('Current Mode : Track ARM')
                self._md_mute_mode = self._arm_mode
            else:
                self._into_hold_mode(value, self._mute_button, self._mute_mode,
                                     'Mute')
                self.show_messsage('Current Mode : Track MUTE')
                self._md_mute_mode = self._mute_mode
        else:
            self._into_hold_mode(value, self._mute_button, self._md_mute_mode,
                                 'SOLO')

    _select_mute = subject_slot('value')(_select_mute)

    def _select_select(self, value):
        if value != 0:
            if self.mikro_shift:
                self._md_select_mode = self._xfade_mode
                self._into_hold_mode(value, self._select_button,
                                     self._xfade_mode, 'XFADE')
                self.show_messsage('Current Mode : Track Crossfader Assign')
            else:
                self._md_select_mode = self._select_mode
                self._into_hold_mode(value, self._select_button,
                                     self._select_mode, 'Select')
                self.show_messsage('Current Mode : Track SELECT')
        else:
            self._into_hold_mode(value, self._select_button,
                                 self._md_select_mode, 'Select')

    _select_select = subject_slot('value')(_select_select)

    def _select_xfade(self, value):
        if value != 0:
            self.show_messsage('Current Mode : Track Crossfader Assign')

        self._into_hold_mode(value, self._xfade_button, self._xfade_mode,
                             'XFADE')

    _select_xfade = subject_slot('value')(_select_xfade)

    def _action_octave(self, value):
        pass

    def _action_scale(self, value):
        pass

    def _action_base_note(self, value):
        pass

    def isClipDown(self):
        return self._clip_mode_down

    def _action_key_color(self, value):
        pass

    def is_solo_exclusive(self):
        return self._solo_mode.exclusive

    def is_arm_exclusive(self):
        return self._arm_mode.exclusive

    def set_solo_exclusive(self, value):
        self._solo_mode.exclusive = value
        if not value > 0 or 127:
            pass
        self._solo_exclusive_button.send_value(0, True)

    def set_arm_exclusive(self, value):
        self._arm_mode.exclusive = value
        if not value > 0 or 127:
            pass
        self._arm_exclusive_button.send_value(0, True)

    def _action_arm_exclusive(self, value):
        if value > 0:
            self.set_arm_exclusive(not (self._arm_mode.exclusive))

    _action_arm_exclusive = subject_slot('value')(_action_arm_exclusive)

    def _action_solo_exclusive(self, value):
        if value > 0:
            self.set_solo_exclusive(not (self._solo_mode.exclusive))

    _action_solo_exclusive = subject_slot('value')(_action_solo_exclusive)

    def on_selected_scene_changed(self):
        pass

    def on_selected_track_changed(self):
        track = self.song().view.selected_track
        newmode = self._mode.fitting_mode(track)
        if track and newmode != self._mode:
            self.rebuild().__enter__()

            try:
                self._light_button(newmode.button_index)
                self._mode.exit()
                self._mode = newmode
                self._mode.enter()
            finally:
                pass

    def disconnect(self):
        self._clip_mode.unbind()
        self._drum_mode.unbind()
        self._scene_mode.unbind()
        self._pad_mode.unbind()
        super(ModeSelector, self).disconnect()

    def on_selected_scene_changed(self):
        pass
class ControlMode(MaschineMode):
    _mode = CM_LEVEL
    _track_sel_index = 0
    _track_off = 0
    _knob_section = None
    _parm_raster_value = 1
    _parm = None
    _parm_is_quant = False
    _selected_sends_index = 0
    _bank_index = 0
    _parm_index = 0
    _device_parm = None
    _banks = None
    _device = None
    _device_list = None
    _in_clear_mode = False
    
    def __init__(self, button_index, mono_chrome = False, *a, **k):
        super(ControlMode, self).__init__(button_index, *a, **a)
        self._device_bank_registry = DeviceBankRegistry()
        self._device_bank_registry.add_device_bank_listener(self._on_device_bank_changed)
        self.track_selections = tuple(lambda .0: for idx in .0:
ControlTrackElement(idx)(range(8)))
        self._is_monochrome = mono_chrome
        self.main_buttons = ([
            None,
            self._do_select_level], [
            None,
            self._do_select_pan], [
            None,
            self._do_select_send], [
            None,
            self._do_select_device])
        self.nav_buttons = ([
            None,
            self._do_nav1], [
            None,
            self._do_nav2], [
            None,
            self._do_nav3], [
            None,
            self._do_nav4])
        self.song().add_return_tracks_listener(self.return_tracks_changed)

    
    def connect_main_knob(self, knobsection):
        self._knob_section = knobsection

    
    def knob_adjust(self, inc, shift, pushdown):
        if self._parm:
            if pushdown:
                value = self.change_parm(inc, self._parm, False)
                self._parm.value = value
            else:
                count = 0
                while count < 4:
                    value = self.change_parm(inc, self._parm, False)
                    self._parm.value = value
                    count += 1
        elif self._device_parm:
            if self._parm_is_quant:
                val = self.change_parm(inc, self._device_parm, True)
                self._device_parm.value = val
            else:
                new_value = self.change_parm(inc, self._device_parm, False)
                self._device_parm.value = new_value
                if not is_equal(self._device_parm.value, new_value):
                    self.parm_is_quant = True
                
                if not (self.parm_is_quant) and not pushdown:
                    count = 0
                    while count < 3:
                        value = self.change_parm(inc, self._device_parm, False)
                        self._device_parm.value = value
                        count += 1
                
        

    
    def change_parm(self, delta, parm, is_quant):
        if is_quant:
            parm_range = (parm.max - parm.min) + 1
            new_val = min(parm.max, max(parm.min, parm.value + delta))
            return float(new_val)
        else:
            parm_range = parm.max - parm.min
            self._parm_raster_value = min(N_PARM_RANGE, max(0, self._parm_raster_value + delta))
            return (float(self._parm_raster_value) / float(N_PARM_RANGE)) * parm_range + parm.min

    
    def get_mode_id(self):
        return CONTROL_MODE

    
    def navigate(self, dir, modifier, alt_modifier = False):
        tracks = self.song().tracks
        nr_of_tracks = len(tracks)
        new_off = self._track_off + dir
        if new_off >= 0 and new_off + 8 <= nr_of_tracks:
            self._track_off = new_off
            self._track_sel_index += dir
            self.canonical_parent.show_message('Control assigned to Tracks ' + str(self._track_off + 1) + ' to ' + str(self._track_off + 9))
            self._assign(False)
        

    
    def unbind(self):
        pass

    
    def nr_of_parms_in_bank(self, device, bank_index):
        if device == None:
            return 0
        
        nr_of_parms = len(device.parameters)
        bip = nr_of_parms - 8 * bank_index
        if bip < 8:
            return bip
        
        return 8

    
    def _assign(self, register = True):
        tracks = self.song().tracks
        bmatrix = self.canonical_parent._bmatrix
        for (column, row) in bmatrix.iterbuttons():
            if button:
                if register:
                    self.canonical_parent._forwarding_registry[(MIDI_NOTE_ON_STATUS, button.get_identifier())] = button
                    self.canonical_parent._forwarding_registry[(MIDI_NOTE_OFF_STATUS, button.get_identifier())] = button
                    button.set_to_notemode(False)
                
                if row < 2:
                    index = row * 4 + column
                    tindex = index + self._track_off
                    track = None
                    if tindex < len(tracks):
                        track = tracks[tindex]
                    
                    self.track_selections[index].set_button(button, self._do_track_selection)
                    self.track_selections[index].set_track(track)
                elif row < 3:
                    if not self.main_buttons[column][0]:
                        self.main_buttons[column][0] = button
                        button.add_value_listener(self.main_buttons[column][1])
                    
                elif not self.nav_buttons[column][0]:
                    self.nav_buttons[column][0] = button
                    button.add_value_listener(self.nav_buttons[column][1])
                
                if self._mode == CM_LEVEL or self._mode == CM_PAN:
                    button.send_color_direct(PColor.OFF[1])
                
            self._mode == CM_PAN
        
        self._mode_sel()

    
    def _set_send_color(self, nr_ret_tracks, index, button):
        if index == 3:
            button.send_color_direct(PColor.OFF[0])
            if nr_ret_tracks > index:
                col = max(21, (21 + (self._selected_sends_index - 3) * 20) % 127)
                if self._selected_sends_index >= 3:
                    col = max(21, (21 + (self._selected_sends_index - 3) * 20) % 127)
                    button.send_color_direct((col, 120, 127, 1, 0))
                else:
                    button.send_color_direct((21, 120, 20, 0, 0))
            
        elif nr_ret_tracks > index:
            if index == self._selected_sends_index:
                button.send_color_direct(PColor.MIX_SELECT_SEND[0])
            else:
                button.send_color_direct(PColor.MIX_SELECT_SEND[1])
        else:
            button.send_color_direct(PColor.OFF[0])

    
    def _turn_off_nav_buttons(self):
        for (button, callback) in self.nav_buttons:
            if button:
                button.send_color_direct(PColor.OFF[0])
                continue
        

    
    def _set_up_control_send(self):
        nr_of_tracks = len(self.song().return_tracks)
        for idx in range(4):
            self._set_send_color(nr_of_tracks, idx, self.nav_buttons[idx][0])
        

    
    def _assign_device_nav(self):
        if self._device:
            idx = list(self._device_list).index(self._device)
            nr_of_dev = len(self._device_list)
            if idx > 0:
                self.nav_buttons[0][0].send_color_direct(PColor.DEVICE_LEFT[0])
            else:
                self.nav_buttons[0][0].send_color_direct(PColor.DEVICE_LEFT[1])
            if idx < nr_of_dev - 1:
                self.nav_buttons[1][0].send_color_direct(PColor.DEVICE_RIGHT[0])
            else:
                self.nav_buttons[1][0].send_color_direct(PColor.DEVICE_RIGHT[1])
            nr_of_banks = len(self._banks)
            if self._bank_index > 0:
                self.nav_buttons[2][0].send_color_direct(PColor.BANK_LEFT[0])
            else:
                self.nav_buttons[2][0].send_color_direct(PColor.BANK_LEFT[1])
            if self._bank_index < nr_of_banks - 1:
                self.nav_buttons[3][0].send_color_direct(PColor.BANK_RIGHT[0])
            else:
                self.nav_buttons[3][0].send_color_direct(PColor.BANK_RIGHT[1])
        else:
            self.nav_buttons[0][0].send_color_direct(PColor.DEVICE_LEFT[1])
            self.nav_buttons[1][0].send_color_direct(PColor.DEVICE_RIGHT[1])
            self.nav_buttons[2][0].send_color_direct(PColor.BANK_LEFT[1])
            self.nav_buttons[3][0].send_color_direct(PColor.BANK_RIGHT[1])

    
    def _assign_device_selection(self):
        if not self._device:
            self._update_device()
        
        device = self._device
        self._parm = None
        self._device_parm = None
        if device:
            is_on = device.parameters[0].value == 1
            if len(self._banks) > 0:
                bank = self._banks[self._bank_index]
                for (parameter, track_sel) in zip(bank, self.track_selections):
                    track_sel.set_parm(parameter)
                    if parameter:
                        if not is_on or PColor.MIX_MODE_DEVICE:
                            pass
                        track_sel.set_color(PColor.MIX_MODE_DEVICE_OFF)
                        if self._parm_index == track_sel._index:
                            track_sel.turn_on()
                            self._assign_device_parm(parameter)
                        else:
                            track_sel.turn_off()
                    self._parm_index == track_sel._index
                    track_sel.set_color(PColor.OFF)
                    track_sel.turn_off()
                
            else:
                for track_sel in self.track_selections:
                    track_sel.set_parm(None)
                    track_sel.set_color(PColor.OFF)
                    track_sel.turn_off()
                
        else:
            for track_sel in self.track_selections:
                track_sel.set_color(PColor.OFF)
                track_sel.turn_off()
            
        self._assign_device_nav()

    
    def _mode_sel(self):
        if not self._mode == CM_LEVEL or PColor.MIX_MODE_VOLUME[0]:
            pass
        self.main_buttons[0][0].send_color_direct(PColor.MIX_MODE_VOLUME[1])
        if not self._mode == CM_PAN or PColor.MIX_MODE_PANNING[0]:
            pass
        self.main_buttons[1][0].send_color_direct(PColor.MIX_MODE_PANNING[1])
        if not self._mode == CM_SEND or PColor.MIX_MODE_SEND[0]:
            pass
        self.main_buttons[2][0].send_color_direct(PColor.MIX_MODE_SEND[1])
        if not self._mode == CM_DEVICE or PColor.MIX_MODE_DEVICE[0]:
            pass
        self.main_buttons[3][0].send_color_direct(PColor.MIX_MODE_DEVICE[1])
        reassign_parms = False
        if self._mode <= CM_SEND:
            max_index = 0
            for track_sel in self.track_selections:
                if track_sel._track:
                    max_index = track_sel._index
                    continue
            
            if self._track_sel_index > max_index:
                self._track_sel_index = max_index
                reassign_parms = True
            
            for track_sel in self.track_selections:
                if track_sel._track:
                    track_sel.set_color(BASIC_COLORS[self._mode])
                else:
                    track_sel.set_color(PColor.OFF)
                if track_sel._index == self._track_sel_index:
                    track_sel.turn_on()
                    continue
                track_sel.turn_off()
            
            if self._mode == CM_SEND:
                nr_of_tracks = len(self.song().return_tracks)
                if self._selected_sends_index > nr_of_tracks - 1:
                    reassign_parms = True
                    self._selected_sends_index = nr_of_tracks - 1
                
                for idx in range(4):
                    self._set_send_color(nr_of_tracks, idx, self.nav_buttons[idx][0])
                
            else:
                self._turn_off_nav_buttons()
        else:
            self._assign_device_selection()
        if reassign_parms:
            self._assign_parameters()
        

    
    def _assign_device_parm(self, param):
        self.parm_device_message(param)
        self._device_parm = param
        if param.is_quantized:
            self._parm_is_quant = True
        else:
            self._parm_is_quant = False
            parm_range = param.max - param.min
            self._parm_raster_value = int(((param.value - param.min) / parm_range) * N_PARM_RANGE + 0.1)

    
    def parm_device_message(self, param):
        self.canonical_parent.show_message(' Control ' + str(param.name))

    
    def _get_mixer_parm(self, track):
        if self._mode == CM_LEVEL:
            return track.mixer_device.volume
        elif self._mode == CM_PAN:
            return track.mixer_device.panning
        elif self._mode == CM_SEND:
            nr_of_ret_tracks = len(track.mixer_device.sends)
            if self._selected_sends_index < nr_of_ret_tracks and self._selected_sends_index != -1:
                return track.mixer_device.sends[self._selected_sends_index]
            
        

    
    def _assign_mixer_parm(self, track):
        self._device_parm = None
        if self._mode == CM_LEVEL:
            self._parm = track.mixer_device.volume
        elif self._mode == CM_PAN:
            self._parm = track.mixer_device.panning
        elif self._mode == CM_SEND:
            self._device_parm = None
            nr_of_ret_tracks = len(track.mixer_device.sends)
            if self._selected_sends_index < nr_of_ret_tracks and self._selected_sends_index != -1:
                self._parm = track.mixer_device.sends[self._selected_sends_index]
            
        
        self.parm_is_quant = False
        if self._parm:
            parm_range = self._parm.max - self._parm.min
            self._parm_raster_value = int(((self._parm.value - self._parm.min) / parm_range) * N_PARM_RANGE + 0.1)
        

    
    def _assign_parameters(self):
        current = self.track_selections[self._track_sel_index]
        track = current._track
        if track:
            self._assign_mixer_parm(track)
        

    
    def _do_track_selection(self, button_index):
        self._knob_section.set_override(self.knob_adjust)
        track_sel = self.track_selections[button_index]
        if self._mode == CM_DEVICE:
            if track_sel._dev_param:
                if self._in_clear_mode:
                    cs = self.song().view.highlighted_clip_slot
                    if cs and cs.has_clip:
                        cs.clip.clear_envelope(track_sel._dev_param)
                    
                else:
                    current = self.track_selections[self._parm_index]
                    current.turn_off()
                    self._parm_index = button_index
                    track_sel.turn_on()
                    self._assign_device_parm(track_sel._dev_param)
            
        else:
            current = self.track_selections[self._track_sel_index]
            if self._in_clear_mode and track_sel._track:
                parm = self._get_mixer_parm(track_sel._track)
                cs = self.song().view.highlighted_clip_slot
                if parm and cs and cs.has_clip:
                    cs.clip.clear_envelope(parm)
                
            elif button_index != self._track_sel_index and track_sel._track:
                current.turn_off()
                track_sel.turn_on()
                current = track_sel
                self._track_sel_index = button_index
                self._assign_mixer_parm(track_sel._track)
            

    
    def _do_select_level(self, value):
        self._knob_section.set_override(self.knob_adjust)
        if value > 0 and self._mode != CM_LEVEL:
            self._mode = CM_LEVEL
            self._mode_sel()
            self._assign_parameters()
            if self.canonical_parent.is_monochrome():
                self.canonical_parent.show_message('Control Mode Focus: Track Levels')
            
        

    
    def _do_select_pan(self, value):
        self._knob_section.set_override(self.knob_adjust)
        if value > 0 and self._mode != CM_PAN:
            self._mode = CM_PAN
            self._mode_sel()
            self._assign_parameters()
            if self.canonical_parent.is_monochrome():
                self.canonical_parent.show_message('Control Mode Focus: Track Panning')
            
        

    
    def _do_select_send(self, value):
        self._knob_section.set_override(self.knob_adjust)
        if value > 0 and self._mode != CM_SEND:
            self._mode = CM_SEND
            self._mode_sel()
            self._assign_parameters()
            if self.canonical_parent.is_monochrome():
                self.canonical_parent.show_message('Control Mode Focus: Track Sends')
            
        

    
    def _do_select_device(self, value):
        self._knob_section.set_override(self.knob_adjust)
        if value > 0 and self._mode == CM_DEVICE and self.isShiftDown():
            if self._device:
                parm = self._device.parameters[0]
                if parm.value == 0:
                    parm.value = 1
                else:
                    parm.value = 0
            
        
        if value > 0 and self._mode != CM_DEVICE:
            self._mode = CM_DEVICE
            self._mode_sel()
            self._assign_device_selection()
            if self.canonical_parent.is_monochrome():
                self.canonical_parent.show_message('Control Mode Focus: Device')
            
        

    
    def _do_nav1(self, value):
        self._knob_section.set_override(self.knob_adjust)
        if value > 0:
            if self._mode == CM_SEND:
                nr_of_tracks = len(self.song().return_tracks)
                if nr_of_tracks > 0:
                    self._selected_sends_index = 0
                    self._set_up_control_send()
                    self._assign_parameters()
                    self.canonical_parent.show_message('Control Mode Focus: Send A')
                
            elif self._mode == CM_DEVICE and self._device:
                if not self.application().view.is_view_visible('Detail') or not self.application().view.is_view_visible('Detail/DeviceChain'):
                    self.application().view.show_view('Detail')
                    self.application().view.show_view('Detail/DeviceChain')
                
                direction = Live.Application.Application.View.NavDirection.left
                self.application().view.scroll_view(direction, 'Detail/DeviceChain', False)
            
        

    
    def _do_nav2(self, value):
        self._knob_section.set_override(self.knob_adjust)
        if value > 0:
            if self._mode == CM_SEND:
                nr_of_tracks = len(self.song().return_tracks)
                if nr_of_tracks > 1:
                    self._selected_sends_index = 1
                    self._set_up_control_send()
                    self._assign_parameters()
                    self.canonical_parent.show_message('Control Mode Focus: Send B')
                
            elif self._mode == CM_DEVICE and self._device:
                if not self.application().view.is_view_visible('Detail') or not self.application().view.is_view_visible('Detail/DeviceChain'):
                    self.application().view.show_view('Detail')
                    self.application().view.show_view('Detail/DeviceChain')
                
                direction = Live.Application.Application.View.NavDirection.right
                self.application().view.scroll_view(direction, 'Detail/DeviceChain', False)
            
        

    
    def _do_nav3(self, value):
        self._knob_section.set_override(self.knob_adjust)
        if value > 0:
            if self._mode == CM_SEND:
                nr_of_tracks = len(self.song().return_tracks)
                if nr_of_tracks > 2:
                    self._selected_sends_index = 2
                    self._set_up_control_send()
                    self._assign_parameters()
                    self.canonical_parent.show_message('Control Mode Focus: Send C')
                
            elif self._mode == CM_DEVICE and self._device and len(self._banks) > 0:
                self._bank_index = max(0, self._bank_index - 1)
                bank = self._banks[self._bank_index]
                name = self._parameter_bank_names()[self._bank_index]
                self._device_bank_registry.set_device_bank(self._device, self._bank_index)
                self._assign_device_selection()
                self.canonical_parent.show_message(' Bank : ' + name)
            
        

    
    def _do_nav4(self, value):
        self._knob_section.set_override(self.knob_adjust)
        if value > 0:
            if self._mode == CM_SEND:
                nr_of_tracks = len(self.song().return_tracks)
                if nr_of_tracks > 3:
                    if self._selected_sends_index < 3 or self._selected_sends_index + 1 == nr_of_tracks:
                        self._selected_sends_index = 3
                    else:
                        self._selected_sends_index += 1
                    self._set_up_control_send()
                    self._assign_parameters()
                    self.canonical_parent.show_message('Control Mode Focus: Send ' + SENDS[self._selected_sends_index])
                
            elif self._mode == CM_DEVICE and self._device and len(self._banks) > 0:
                max_bank = len(self._banks) - 1
                self._bank_index = min(max_bank, self._bank_index + 1)
                name = self._parameter_bank_names()[self._bank_index]
                self._device_bank_registry.set_device_bank(self._device, self._bank_index)
                self._assign_device_selection()
                self.canonical_parent.show_message(' Bank : ' + name)
            
        

    
    def _release(self):
        for track_sel in self.track_selections:
            track_sel.release()
        
        for (button, callback) in self.main_buttons:
            if button:
                button.remove_value_listener(callback)
                continue
        
        for (button, callback) in self.nav_buttons:
            if button:
                button.remove_value_listener(callback)
                continue
        
        for idx in range(4):
            self.main_buttons[idx][0] = None
            self.nav_buttons[idx][0] = None
        
        self._device_parameters_changed.subject = None
        self._device_active_changed.subject = None

    
    def _on_device_bank_changed(self, device, bank):
        if device == self._device:
            self._bank_index = bank
            self._assign_device_selection()
        

    
    def _update_device(self):
        self._device = self.song().appointed_device
        if self._device:
            self._parm_index = 0
            track = self._device.canonical_parent
            devices = track.devices
            self._device_list = track.devices
            self._device_parameters_changed.subject = self._device
            self._device_active_changed.subject = self._device.parameters[0]
            self._banks = parameter_banks(self._device)
            self._bank_index = self._device_bank_registry.get_device_bank(self._device)
        else:
            self._device_parameters_changed.subject = None
            self._device_active_changed.subject = None

    
    def _device_changed(self):
        if self._active:
            self._bank_index = 0
            if self._mode == CM_DEVICE:
                self._update_device()
                self._assign_device_selection()
            
        

    
    def return_tracks_changed(self):
        if self._active:
            self._assign(False)
        

    
    def _device_parameters_changed(self):
        if self._active and self._mode == CM_DEVICE:
            self._banks = parameter_banks(self._device)
            self._bank_index = self._device_bank_registry.get_device_bank(self._device)
            self._assign_device_selection()
        

    _device_parameters_changed = subject_slot('parameters')(_device_parameters_changed)
    
    def _device_active_changed(self):
        if self._active and self._mode == CM_DEVICE:
            self._assign_device_selection()
        

    _device_active_changed = subject_slot('value')(_device_active_changed)
    
    def on_track_list_changed(self):
        if self._active:
            for track_sel in self.track_selections:
                track_sel.release()
            
            self._assign(False)
        

    
    def _parameter_bank_names(self):
        return parameter_bank_names(self._device)

    
    def enter(self):
        self._active = True
        self._assign()
        if self._knob_section:
            self._knob_section.set_override(self.knob_adjust)
            self._assign_parameters()
        

    
    def exit(self):
        self._active = False
        self._release()
        if self._knob_section:
            self._knob_section.reset_overide()
        

    
    def enter_clear_state(self):
        self._in_clear_mode = True

    
    def exit_clear_state(self):
        self._in_clear_mode = False

    
    def disconnect(self):
        if self._active:
            self._release()
        
        self.song().remove_return_tracks_listener(self.return_tracks_changed)
        self._device_bank_registry.remove_device_bank_listener(self._on_device_bank_changed)
        self._device_parameters_changed.subject = None
        super(MaschineMode, self).disconnect()
예제 #5
0
class DrumMode(MaschineMode):
    __subject_events__ = ('pressed_pads',)
    
    def __init__(self, button_index, monochrome = False, *a, **k):
        super(DrumMode, self).__init__(button_index, *a, **a)
        self.track = None
        self.device = None
        self._is_monochrome = monochrome
        if monochrome:
            self._update_pad_edit = self._update_pad_edit_mono
        else:
            self._update_pad_edit = self._update_pad_edit_color
        self._visible_drum_pad_slots = None
        self._visible_drum_pads = None
        self._pads = tuple(lambda .0: for index in .0:
DrumPad(index)(range(16)))
        self._selected_pad = None
        self._in_edit_mode = False
        self._editmode = None
        if self.canonical_parent.is_monochrome():
            self.pad_to_color = self._DrumMode__pad_to_onoff
        else:
            self.pad_to_color = self._DrumMode__pad_to_color

    
    def set_edit_mode(self, editmode):
        self._editmode = editmode

    
    def get_color(self, value, column, row):
        if not value != 0 or 1:
            pass
        indx = 0
        note_index = row * 4 + column
        return self._pads[note_index].get_color()

    
    def get_mode_id(self):
        return PAD_MODE

    
    def _DrumMode__pad_to_onoff(self, pad):
        if pad:
            if len(pad.chains) == 0:
                return ((0, 0, 0, 0, 0), (0, 0, 0, 0, 0))
            else:
                return ((0, 0, 0, 1, 0), (0, 0, 0, 1, 0))
        else:
            return ((0, 0, 0, 0, 0), (0, 0, 0, 0, 0))

    
    def _DrumMode__pad_to_color(self, pad):
        if pad:
            chains = pad.chains
            name = pad.name
            if len(chains) == 0:
                return ((0, 0, 1), (0, 0, 127))
            else:
                return color_by_name(name)
        
        return ((0, 90, 70), (0, 127, 127))

    
    def navigate(self, dir, modifier, alt_modifier = False):
        if self.device and self.device.view:
            self.device.view.drum_pads_scroll_position = max(0, min(28, self.device.view.drum_pads_scroll_position + dir))
        

    
    def enter(self):
        self._active = True
        self.assign_track_device()
        self._in_edit_mode = False
        for (column, row) in self.canonical_parent._bmatrix.iterbuttons():
            if button:
                note_index = row * 4 + column
                pad_index = (3 - row) * 4 + column
                pad = self._pads[pad_index]
                button.set_to_notemode(True)
                self.canonical_parent._forwarding_registry[(MIDI_NOTE_ON_STATUS, button.get_identifier())] = button
                self.canonical_parent._forwarding_registry[(MIDI_NOTE_OFF_STATUS, button.get_identifier())] = button
                button.set_send_note(PAD_TRANSLATIONS[note_index][2])
                button.send_color_direct(pad.get_color())
                continue
        
        self.track = self.song().view.selected_track
        self._on_name_changed.subject = self.device.view.selected_drum_pad

    
    def _get_note_set(self):
        in_notes = set()
        cs = self.song().view.highlighted_clip_slot
        if cs.has_clip and cs.clip.is_midi_clip:
            notes = cs.clip.get_notes(0, 0, cs.clip.length, 127)
            for note in notes:
                in_notes.add(note[0])
            
        
        return in_notes

    
    def _update_pad_edit_color(self, pad, in_notes):
        if pad._pad.note in in_notes:
            pad._button.send_color_direct(pad._color[1])
        else:
            pad._button.send_color_direct(pad._color[0])

    
    def _update_pad_edit_mono(self, pad, in_notes):
        if pad._pad.note in in_notes:
            pad._button.send_value(127, True)
        else:
            pad._button.send_value(0, True)

    
    def _on_notes_changed(self):
        cs = self.song().view.highlighted_clip_slot
        if self._in_edit_mode:
            if cs.has_clip and cs.clip.is_midi_clip:
                in_notes = set()
                notes = cs.clip.get_notes(0, 0, cs.clip.length, 127)
                for note in notes:
                    in_notes.add(note[0])
                
                for pad in self._pads:
                    self._update_pad_edit(pad, in_notes)
                
            
        

    _on_notes_changed = subject_slot('notes')(_on_notes_changed)
    
    def _action_clear(self, value, button):
        if value > 0:
            pad = self._pads[button.get_identifier() - 12]
            self._editmode.edit_note(pad._pad.note)
        

    
    def enter_clear_state(self):
        cs = self.song().view.highlighted_clip_slot
        in_notes = set()
        if cs.has_clip and cs.clip.is_midi_clip:
            clip = cs.clip
            notes = clip.get_notes(0, 0, clip.length, 127)
            self._on_notes_changed.subject = clip
            for note in notes:
                in_notes.add(note[0])
            
        else:
            self._on_notes_changed.subject = None
        self._in_edit_mode = True
        for (column, row) in self.canonical_parent._bmatrix.iterbuttons():
            if button:
                note_index = row * 4 + column
                pad_index = (3 - row) * 4 + column
                pad = self._pads[pad_index]
                self._update_pad_edit(pad, in_notes)
                button.set_to_notemode(False)
                button.add_value_listener(self._action_clear, True)
                continue
        

    
    def exit_clear_state(self):
        self._in_edit_mode = False
        self._on_notes_changed.subject = None
        for (column, row) in self.canonical_parent._bmatrix.iterbuttons():
            if button:
                note_index = row * 4 + column
                pad_index = (3 - row) * 4 + column
                pad = self._pads[pad_index]
                button.set_to_notemode(True)
                button.send_color_direct(pad.get_color())
                button.remove_value_listener(self._action_clear)
                continue
        

    
    def update_pads(self):
        if self._active:
            if self._in_edit_mode:
                in_notes = self._get_note_set()
                for pad in self._pads:
                    self._update_pad_edit(pad, in_notes)
                
            else:
                for dpad in self._pads:
                    dpad.send_color()
                
        

    
    def refresh(self):
        if self._active:
            for dpad in self._pads:
                dpad._button.reset()
                dpad.send_color()
            
        

    
    def assign_pads(self):
        self._visible_drum_pads = None
        self._selected_pad = None
        if self.device:
            self._visible_drum_pads = self.device.visible_drum_pads
            selected_drum_pad = self.device.view.selected_drum_pad
            self._on_name_changed.subject = selected_drum_pad
            index = 0
            for pad in self._visible_drum_pads:
                if pad == selected_drum_pad:
                    self._pads[index].selected = True
                    self._selected_pad = self._pads[index]
                else:
                    self._pads[index].selected = False
                self._pads[index].set_color(self.pad_to_color(pad))
                self._pads[index].set_pad(pad)
                index += 1
            
        else:
            for dpad in self._pads:
                dpad.set_color(((0, 0, 40), (0, 0, 40)))
                dpad.set_pad(None)
            
        for (column, row) in self.canonical_parent._bmatrix.iterbuttons():
            pad_index = (3 - row) * 4 + column
            self._pads[pad_index].set_button(button)
            if not self._in_edit_mode:
                self._pads[pad_index].send_color()
                continue
        

    
    def assign_track_device(self):
        if self.device and self.device.view:
            self._on_scroll_index_changed.subject = None
            self._on_selected_drum_pad_changed.subject = None
            self._on_chains_changed.subject = None
            self._on_name_changed.subject = None
        
        self.track = self.song().view.selected_track
        self.device = find_drum_device(self.track)
        if self.device:
            self._on_scroll_index_changed.subject = self.device.view
            self._on_selected_drum_pad_changed.subject = self.device.view
            self._on_chains_changed.subject = self.device
            self._on_name_changed.subject = self.device
        
        self.assign_pads()

    
    def index_of(self, pad):
        for index in range(16):
            if self._pads[index]._pad == pad:
                return index
                continue
        
        return -1

    
    def _on_name_changed(self):
        if self._active and self.device:
            self.assign_pads()
            self.update_pads()
        

    _on_name_changed = subject_slot('name')(_on_name_changed)
    
    def _device_changed(self):
        if self._active:
            self.assign_track_device()
            self.update_pads()
        

    
    def _on_chains_changed(self):
        if self._active and self.device:
            self.assign_pads()
            self.update_pads()
        

    _on_chains_changed = subject_slot('chains')(_on_chains_changed)
    
    def _on_selected_drum_pad_changed(self):
        if self._active and self.device:
            if self._selected_pad:
                self._selected_pad.selected = False
                self._selected_pad.send_color()
            
            selected_drum_pad = self.device.view.selected_drum_pad
            self._on_name_changed.subject = selected_drum_pad
            new_index = self.index_of(selected_drum_pad)
            if new_index in range(16):
                self._selected_pad = self._pads[new_index]
                self._selected_pad.selected = True
                self._selected_pad.send_color()
            
        

    _on_selected_drum_pad_changed = subject_slot('selected_drum_pad')(_on_selected_drum_pad_changed)
    
    def _on_scroll_index_changed(self):
        if self._active and self.device:
            self.assign_pads()
            self.update_pads()
        

    _on_scroll_index_changed = subject_slot('drum_pads_scroll_position')(_on_scroll_index_changed)
    
    def fitting_mode(self, track):
        if not track:
            return self
        
        drum_device = find_drum_device(track)
        if drum_device == None and self._alternate_mode != None:
            return self._alternate_mode
        
        return self

    
    def on_selected_track_changed(self):
        if self._active:
            self.track = self.song().view.selected_track
            self.assign_track_device()
            self.update_pads()
        

    
    def exit(self):
        self._active = False
        self._on_scroll_index_changed.subject = None
        self._on_selected_drum_pad_changed.subject = None
        self._on_chains_changed.subject = None
        self._on_name_changed.subject = None
        self.device = None
        self.track = None

    
    def disconnect(self):
        self.exit()
        self.track = None
        self.device = None
        self._visible_drum_pad_slots = None
        self._visible_drum_pads = None
        self._pads = None
        self._selected_pad = None
        self._in_edit_mode = False
        self._editmode = None
        super(MaschineMode, self).disconnect()
class NoteRepeatComponent(CompoundComponent):
    __module__ = __name__
    ''' Noter Repeat Handler'''
    _knob_handler = None

    def __init__(self, note_repeat=None, *a, **k):
        super(NoteRepeatComponent, self).__init__(*a, **a)
        self._note_repeat = note_repeat
        self._adjust_cfg_value.subject = SliderElement(MIDI_CC_TYPE, 2, 105)
        self._note_repeat_button = ButtonElement(True, MIDI_CC_TYPE, 0, 102)
        self._do_note_repeat.subject = self._note_repeat_button
        self._cfg_adjust_button = ButtonElement(True, MIDI_CC_TYPE, 2, 106)
        self._cfg_adjust_button.add_value_listener(self._do_cfg_button)
        self._cfg_down = False
        self._hold_mode = False
        self.nr_down = False
        self._current_nr_button = None
        self._do_change_nr_1.subject = SliderElement(MIDI_CC_TYPE, 1, 76)
        self._do_change_nr_2.subject = SliderElement(MIDI_CC_TYPE, 1, 77)
        self._do_change_nr_3.subject = SliderElement(MIDI_CC_TYPE, 1, 78)
        self._do_change_nr_4.subject = SliderElement(MIDI_CC_TYPE, 1, 79)

        def createButton(ccindenfier, nr_freq):
            button = ButtonElement(True, MIDI_CC_TYPE, 1, ccindenfier)
            button.add_value_listener(self._select_value, True)
            button.active = False
            button.freq = nr_freq
            button.cfg = False
            button.hold = False
            return button

        def createCfgButton(ccindenfier, nr_freq_idx):
            button = ButtonElement(True, MIDI_CC_TYPE, 2, ccindenfier)
            button.add_value_listener(self._select_value, True)
            button.active = False
            button.fr_idx = nr_freq_idx
            button.freq = CFG_REPEAT_FREQUENCIES[nr_freq_idx]
            button.cfg = True
            button.hold = False
            return button

        continue
        self._cfg_buttons = [
            createCfgButton(assign[0], assign[1])
            for assign in CTRL_CFG_TO_FREQ
        ]
        for button in self._cfg_buttons:
            if not button.active or 1:
                pass
            button.send_value(0, True)

        self.nr_frq = CTRL_TO_FREQ[4][1]
        self._note_repeat.repeat_rate = (1 / self.nr_frq) * 4
        continue
        self.buttons = [
            createButton(assign[0], assign[1]) for assign in CTRL_TO_FREQ
        ]
        self.buttons[4].active = True
        self._previous_button = self.buttons[4]
        self._last_active_button = self.buttons[4]
        for button in self.buttons:
            if not button.active or 1:
                pass
            button.send_value(0, True)

    def update(self):
        pass

    def store_values(self, dict):
        for (button, idx) in zip(self._cfg_buttons,
                                 range(len(self._cfg_buttons))):
            dict['cofig-nr-val' + str(idx)] = button.fr_idx

    def recall_values(self, dict):
        for (button, idx) in zip(self._cfg_buttons,
                                 range(len(self._cfg_buttons))):
            key = 'cofig-nr-val' + str(idx)
            if key in dict:
                fqidx = dict[key]
                button.fr_idx = fqidx
                button.freq = CFG_REPEAT_FREQUENCIES[fqidx]
                continue

    def registerKnobHandler(self, handler):
        self._knob_handler = handler

    def show_note_rates(self):
        rates = ''
        for (button, idx) in zip(self._cfg_buttons,
                                 range(len(self._cfg_buttons))):
            rates += ' ' + CFG_REPEAT_DISPLAY[button.fr_idx].ljust(5)
            if idx < 3:
                rates += '|'
                continue

        self.canonical_parent.timed_message(2, rates)

    def mod_button(self, button, inc, which):
        cindex = button.fr_idx
        maxindex = len(CFG_REPEAT_FREQUENCIES) - 1
        minindex = 0
        if self.canonical_parent.isShiftDown():
            inc *= 2
            if not cindex % 2 == 0 or maxindex:
                pass
            maxindex = maxindex - 1
            minindex = cindex % 2

        new_idx = max(minindex, min(maxindex, cindex + inc))
        if new_idx != cindex:
            self.canonical_parent.show_message('Note Repeat Button ' +
                                               str(which) + ' : ' +
                                               CFG_REPEAT_DISPLAY[new_idx])
            button.fr_idx = new_idx
            button.freq = CFG_REPEAT_FREQUENCIES[new_idx]
            if button.active:
                self.nr_frq = CFG_REPEAT_FREQUENCIES[new_idx]
                self._note_repeat.repeat_rate = (1 / self.nr_frq) * 4

    def _do_change_nr_1(self, value):
        if not value == 0 or -1:
            pass
        self.mod_button(self._cfg_buttons[0], 1, 1)
        self.show_note_rates()

    _do_change_nr_1 = subject_slot('value')(_do_change_nr_1)

    def _do_change_nr_2(self, value):
        if not value == 0 or -1:
            pass
        self.mod_button(self._cfg_buttons[1], 1, 2)
        self.show_note_rates()

    _do_change_nr_2 = subject_slot('value')(_do_change_nr_2)

    def _do_change_nr_3(self, value):
        if not value == 0 or -1:
            pass
        self.mod_button(self._cfg_buttons[2], 1, 3)
        self.show_note_rates()

    _do_change_nr_3 = subject_slot('value')(_do_change_nr_3)

    def _do_change_nr_4(self, value):
        if not value == 0 or -1:
            pass
        self.mod_button(self._cfg_buttons[3], 1, 4)
        self.show_note_rates()

    _do_change_nr_4 = subject_slot('value')(_do_change_nr_4)

    def _do_cfg_button(self, value):
        if value != 0:
            self._cfg_down = True
            button = self._current_nr_button
            if button and button.cfg and button.fr_idx >= 0:
                self.canonical_parent.show_message(
                    'Note Repeat ' + CFG_REPEAT_DISPLAY[button.fr_idx])

        else:
            self._cfg_down = False
        if self._knob_handler:
            self._knob_handler.do_main_push(value)

    def _adjust_cfg_value(self, value):
        button = self._current_nr_button
        if button and button.cfg:
            if (self.nr_down and button.hold
                    or self._hold_mode) and button.active:
                if not value == 127 or -1:
                    pass
                inc = 1
                cindex = button.fr_idx
                maxindex = len(CFG_REPEAT_FREQUENCIES) - 1
                minindex = 0
                if self._cfg_down:
                    inc *= 2
                    if not cindex % 2 == 0 or maxindex:
                        pass
                    maxindex = maxindex - 1
                    minindex = cindex % 2

                new_idx = max(minindex, min(maxindex, cindex + inc))
                self.canonical_parent.show_message('Note Repeat ' +
                                                   CFG_REPEAT_DISPLAY[new_idx])
                button.fr_idx = new_idx
                button.freq = CFG_REPEAT_FREQUENCIES[new_idx]
                self.nr_frq = CFG_REPEAT_FREQUENCIES[new_idx]
                self._note_repeat.repeat_rate = (1 / self.nr_frq) * 4
            elif self._knob_handler:
                self._knob_handler.do_main(value)

    _adjust_cfg_value = subject_slot('value')(_adjust_cfg_value)

    def _select_value(self, value, button):
        if value != 0:
            self._current_nr_button = button
            button.hold = True
            self.show_note_rates()
            if self._hold_mode:
                if self._previous_button == button:
                    button.send_value(0, True)
                    button.active = False
                    self._last_active_button = button
                    button.active = False
                    self._note_repeat.repeat_rate = 32
                    self._previous_button = None
                elif self._previous_button == None or self._previous_button != button:
                    button.send_value(1, True)
                    button.active = True
                    self.nr_frq = button.freq
                    self._note_repeat.repeat_rate = (1 / self.nr_frq) * 4
                    if not self._note_repeat.enabled:
                        self._note_repeat.enabled = True

                    if self._previous_button != None:
                        self._previous_button.active = False
                        self._previous_button.send_value(0, True)

                    self._previous_button = button

            else:
                button.send_value(1, True)
                button.active = True
                self.nr_frq = button.freq
                self._note_repeat.repeat_rate = (1 / self.nr_frq) * 4
                if self._previous_button != None and self._previous_button != button:
                    self._previous_button.active = False
                    self._previous_button.send_value(0, True)

                self._previous_button = button
        else:
            button.hold = False

    def _do_note_repeat(self, value):
        self.nr_down = value > 0
        if self._hold_mode:
            if value > 0:
                self._note_repeat_button.send_value(0)
                self._note_repeat.enabled = False
                self._hold_mode = False
                if self._previous_button == None and self._last_active_button != None:
                    self._previous_button = self._last_active_button
                    self._last_active_button.send_value(1)
                    self._last_active_button.active = True
                    self.nr_frq = self._last_active_button.freq
                    self._note_repeat.repeat_rate = (1 / self.nr_frq) * 4

        elif self.canonical_parent.isShiftDown() and value > 0:
            self._note_repeat_button.send_value(1)
            self._note_repeat.enabled = True
            self._hold_mode = True
            self._note_repeat.repeat_rate = (1 / self.nr_frq) * 4
        elif value == 0:
            self._note_repeat.enabled = False
            self._note_repeat_button.send_value(0)
        else:
            self._note_repeat_button.send_value(1)
            self._note_repeat.repeat_rate = (1 / self.nr_frq) * 4
            self._note_repeat.enabled = True

    _do_note_repeat = subject_slot('value')(_do_note_repeat)

    def disconnect(self):
        super(NoteRepeatComponent, self).disconnect()
예제 #7
0
class MaschineSessionComponent(SessionComponent):
    __module__ = __name__
    '''Session Component for Maschine'''
    scene_component_type = ModSceneComponent
    _session_mode = None
    _advance = STEP1
    _matrix = None
    _color_manager = None

    def __init__(self):
        SessionComponent.__init__(self, 4, 4)
        self._mode_button = ButtonElement(False, MIDI_CC_TYPE, 2, 50)
        self._do_matrix_adv_mode.subject = self._mode_button
        self._mode_button.send_value(0, True)
        self._track_banking_increment = 1
        self._c_mode_button = ButtonElement(True, MIDI_CC_TYPE, 2, 90)
        self._change_color_mode.subject = self._c_mode_button
        self._c_mode_button.send_value(0, True)
        self.notify = self.notify_standard
        self.get_color = self.get_color_standard
        self._nav_color_button = self.canonical_parent.create_gated_button(
            8, 110)
        self._toggle_step_advance.subject = self._nav_color_button
        self._nav_color_button.switch_off()
        self._color_manager = self

    def set_mode(self, mode):
        self._session_mode = mode

    def set_color_manager(self, manager):
        if manager:
            self._color_manager = manager

    def _change_color_mode(self, value):
        if value > 0:
            if self.is_color_mode():
                self.set_color_mode(False)
                self._session_mode.refresh()
                self._c_mode_button.send_value(0, True)
            else:
                self.set_color_mode(True)
                self._session_mode.refresh()
                self._c_mode_button.send_value(1, True)

    _change_color_mode = subject_slot('value')(_change_color_mode)

    def set_color_mode(self, colormode):
        if colormode:
            self.notify = self.notify_cmode
            self.get_color = self.get_color_cmode
        else:
            self.notify = self.notify_standard
            self.get_color = self.get_color_standard

    def is_color_mode(self):
        return self.notify == self.notify_cmode

    def start_up(self):
        self.set_enabled(True)

    def update_nav_button(self):
        if not self._advance == STEP4 or COLOR_HUE_NAV4:
            pass
        color = COLOR_HUE_NAV
        self._bank_up_button.hue = color
        self._bank_down_button.hue = color
        self._bank_left_button.hue = color
        self._bank_right_button.hue = color
        self._horizontal_banking.update()
        self._vertical_banking.update()

    def _toggle_step_advance(self, value):
        if value != 0:
            if not self._advance == STEP4 or STEP1:
                pass
            self.set_step_advance(STEP4)

    _toggle_step_advance = subject_slot('value')(_toggle_step_advance)

    def switch_step_advance(self):
        if not self._advance == STEP4 or STEP1:
            pass
        self.set_step_advance(STEP4)

    def set_step_advance(self, value):
        self._advance = value
        if self._advance == STEP4:
            self._mode_button.send_value(127, True)
            self._nav_color_button.turn_on()
        else:
            self._mode_button.send_value(0, True)
            self._nav_color_button.switch_off()
        self.set_track_banking_increment(self._advance)
        self.update_nav_button()

    def get_step_advance(self):
        return self._advance

    def _link(self):
        pass

    def get_track_offset(self):
        return self._track_offset

    def get_scene_offset(self):
        return self._scene_offset

    def set_matrix(self, matrix):
        self._matrix = matrix

    def set_track_banking_increment(self, increment):
        self._track_banking_increment = increment

    def _do_matrix_adv_mode(self, value):
        if not self._mode_button != None:
            raise AssertionError
        if not value in range(128):
            raise AssertionError
        if value != 0:
            if self._advance == STEP1:
                self._advance = STEP4
                self._mode_button.send_value(127, True)
                self._nav_color_button.turn_on()
                self.set_track_banking_increment(STEP4)
            else:
                self._advance = STEP1
                self._mode_button.send_value(0, True)
                self._nav_color_button.switch_off()
                self.set_track_banking_increment(STEP1)

    _do_matrix_adv_mode = subject_slot('value')(_do_matrix_adv_mode)

    def update(self):
        SessionComponent.update(self)

        try:
            pass
        except AttributeError:
            pass

        if self._advance == STEP4:
            self._mode_button.send_value(127, True)
        else:
            self._mode_button.send_value(0, True)

    def get_controled_clip_slots(self, clip_slot):
        if clip_slot.controls_other_clips:
            track = clip_slot.canonical_parent
            if track.is_foldable:
                song = self.song()
                index = vindex(song.tracks, track)
                if index >= 0:
                    count = index
                    done = False
                    result = []
                    while not done:
                        count += 1
                        if count == len(song.tracks):
                            done = True
                            continue
                        ctrack = song.tracks[count]

    def get_color_cmode(self, clip_slot):
        if clip_slot == None:
            return PColor.OFF

        color = self.get_color_cmode_base(clip_slot)
        oncolor = color[0]
        offcolor = color[1]
        if clip_slot.has_clip:
            if clip_slot.clip.is_recording or clip_slot.clip.will_record_on_start:
                return (oncolor, oncolor)
            elif clip_slot.clip.is_triggered:
                return (oncolor, oncolor)
            elif clip_slot.clip.is_playing:
                return (oncolor, oncolor)
            else:
                return (offcolor, offcolor)
        elif clip_slot.will_record_on_start:
            return CLR_REC
        elif clip_slot.is_playing:
            return PColor.CLIP_GROUP_PLAY
        elif clip_slot.controls_other_clips:
            return PColor.CLIP_GROUP_CONTROL
        elif clip_slot.is_triggered:
            return CLR_TRIGG

        return PColor.OFF

    def get_color_standard(self, clip_slot):
        if not clip_slot:
            return PColor.OFF

        if clip_slot.has_clip:
            if clip_slot.clip.is_recording or clip_slot.clip.will_record_on_start:
                if clip_slot.clip.is_triggered:
                    return PColor.CLIP_RECORD_TRIGGER
                else:
                    return PColor.CLIP_RECORD

            if clip_slot.clip.is_playing:
                return PColor.CLIP_PLAY
            elif clip_slot.clip.is_triggered:
                return PColor.CLIP_PLAY_TRIGGER
            else:
                return PColor.CLIP_STOPPED
        elif clip_slot.will_record_on_start:
            return PColor.CLIP_RECORD_TRIGGER
        elif clip_slot.is_playing:
            return PColor.CLIP_GROUP_PLAY
        elif clip_slot.controls_other_clips:
            return PColor.CLIP_GROUP_CONTROL
        elif clip_slot.is_triggered:
            return PColor.CLIP_GROUP_TRIGGER

        return PColor.OFF

    def get_mono_state(self, clip_slot):
        if not clip_slot:
            return (0, 0)

        if clip_slot.has_clip:
            if clip_slot.clip.is_recording or clip_slot.clip.will_record_on_start:
                if clip_slot.clip.is_triggered:
                    return (1, 2)
                else:
                    return (1, 1)

            if clip_slot.clip.is_playing:
                return (1, 1)
            elif clip_slot.clip.is_triggered:
                return (1, 2)
            else:
                return (1, 0)
        elif clip_slot.will_record_on_start:
            return (1, 2)
        elif clip_slot.is_playing:
            return (1, 1)
        elif clip_slot.controls_other_clips:
            return (1, 0)
        elif clip_slot.is_triggered:
            return (1, 2)

        return (0, 0)

    def notify_standard(self, blink):
        index = blink / 2
        for scene_index in range(4):
            scene = self.scene(scene_index)
            for track_index in range(4):
                clip_slot = scene.clip_slot(track_index)._clip_slot
                if clip_slot:
                    button = self._matrix[scene_index][track_index]
                    color = self.get_color_standard(clip_slot)
                    if button != None and clip_slot.has_clip:
                        if clip_slot.clip.is_triggered:
                            button.send_color_direct(color[index])

                    elif clip_slot.is_triggered:
                        button.send_color_direct(color[index])

    def notify_cmode(self, blink):
        sblink = blink / 2
        fblink = blink % 2
        for scene_index in range(4):
            scene = self.scene(scene_index)
            for track_index in range(4):
                clip_slot = scene.clip_slot(track_index)._clip_slot
                if clip_slot:
                    button = self._matrix[scene_index][track_index]
                    color = self.get_color_cmode_base(clip_slot)
                    if clip_slot.has_clip:
                        if clip_slot.clip.is_recording or clip_slot.clip.will_record_on_start:
                            if not sblink == 0 or color[0]:
                                pass
                            button.send_color_direct(REC)
                        elif clip_slot.clip.is_triggered:
                            button.send_color_direct(color[sblink])
                        elif clip_slot.clip.is_playing:
                            button.send_color_direct(color[0])
                        else:
                            button.send_color_direct(color[1])
                    elif clip_slot.will_record_on_start:
                        if not sblink == 0 or REC:
                            pass
                        button.send_color_direct(REC_DIM)
                    elif clip_slot.is_playing:
                        button.send_color_direct(PColor.CLIP_GROUP_PLAY[0])
                    elif clip_slot.controls_other_clips:
                        button.send_color_direct(PColor.CLIP_GROUP_CONTROL[0])
                    elif clip_slot.is_triggered:
                        if not sblink == 0 or TRIGG:
                            pass
                        button.send_color_direct(TRIGG_DIM)

    def convertToHSB(self, rgb_color):
        return toHSB(rgb_color)

    def get_color_cmode_base(self, clip_slot):
        if clip_slot != None:
            if clip_slot.has_clip:
                rgb = clip_slot.clip.color
                color = self._color_manager.convertToHSB(clip_slot.clip.color)
                return color
            elif clip_slot.controls_other_clips:
                pass

        return PColor.OFF

    def notify_mono(self, blink):
        sblink = blink / 2
        fblink = blink % 2
        for scene_index in range(4):
            scene = self.scene(scene_index)
            for track_index in range(4):
                clip_slot = scene.clip_slot(track_index)._clip_slot
                button = self._matrix[scene_index][track_index]
                if clip_slot != None:
                    state = self.get_mono_state(clip_slot)
                    if state:
                        val = state[0]
                        bval = state[1]
                        if bval == 0:
                            if val == 1:
                                button.turn_on()
                            else:
                                button.turn_off()
                        elif bval == 1:
                            if sblink == 0:
                                button.turn_on()
                            else:
                                button.turn_off()
                        elif bval == 2:
                            if fblink == 0:
                                button.turn_on()
                            else:
                                button.turn_off()

                    else:
                        button.turn_off()
                button.turn_off()

    def on_track_list_changed(self):
        num_tracks = len(self.tracks_to_use())
        new_track_offset = self.track_offset()
        if new_track_offset >= num_tracks:
            new_track_offset = num_tracks - 1
            new_track_offset -= new_track_offset % self._track_banking_increment

        self._reassign_tracks()
        self.set_offsets(new_track_offset, self.scene_offset())

    def update(self):
        SessionComponent.update(self)
        self._bank_up_button.update()
        self._bank_down_button.update()
        self._bank_left_button.update()
        self._bank_right_button.update()

    def _bank_right(self):
        return self.set_offsets(
            self.track_offset() + self._track_banking_increment,
            self.scene_offset())

    def _bank_left(self):
        return self.set_offsets(
            max(self.track_offset() - self._track_banking_increment, 0),
            self.scene_offset())

    def bank_down(self):
        if self.is_enabled():
            newoff = max(0, self._scene_offset - 1)
            self.set_offsets(self._track_offset, newoff)

    def bank_up(self):
        if self.is_enabled():
            self.set_offsets(self._track_offset, self._scene_offset + 1)

    def bank_left(self):
        if self.is_enabled():
            self.set_offsets(max(0, self._track_offset - 1),
                             self._scene_offset)

    def bank_right(self):
        if self.is_enabled():
            self.set_offsets(self._track_offset + 1, self._scene_offset)

    def _allow_updates(self):
        return True

    def disconnect(self):
        self._matrix = None
        self._mode_button = None
        SessionComponent.disconnect(self)
예제 #8
0
class PadMode(MaschineMode):
    
    def __init__(self, button_index, monochrome = False, *a, **k):
        super(PadMode, self).__init__(button_index, *a, **a)
        self._note_display_mode = ND_KEYBOARD1
        self.current_scale_index = 0
        self._scale = None
        self._base_note = 0
        self._octave = 0.55
        self.current_scale_index = 0
        self._in_edit_mode = False
        self._editmode = None
        self._is_monochrome = monochrome
        if not monochrome or self.assign_edit_mono:
            pass
        self._color_edit_assign = self.assign_edit_color
        self.assign_transpose(SCALES[self.current_scale_index])
        is_momentary = True
        self.octave_down_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 120)
        self.octave_up_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 121)
        self.base_down_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 124)
        self.base_up_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 125)
        self.scale_down_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 118)
        self.scale_up_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 119)
        self._adjust_scale.subject = SliderElement(MIDI_CC_TYPE, 2, 116)
        self._adjust_octav.subject = SliderElement(MIDI_CC_TYPE, 2, 115)
        self._adjust_basem.subject = SliderElement(MIDI_CC_TYPE, 2, 117)
        self._do_oct_down.subject = self.octave_down_button
        self._do_oct_up.subject = self.octave_up_button
        self._do_base_down.subject = self.base_down_button
        self._do_base_up.subject = self.base_up_button
        self._do_scale_down.subject = self.scale_down_button
        self._do_scale_up.subject = self.scale_up_button
        self._seg_display = None

    
    def set_edit_mode(self, editmode):
        self._editmode = editmode

    
    def set_segment_display(self, displayer):
        self._seg_display = displayer

    
    def get_color(self, value, column, row):
        button = self.canonical_parent._bmatrix.get_button(column, row)
        if button != None:
            midi_note = button.get_identifier()
            on = value != 0
            return self.get_color_by_note_mode(midi_note, on)
        

    
    def get_color_by_note_mode(self, midi_note, on):
        if self._note_display_mode == ND_BASE_OTHER:
            interval = (midi_note + 12 - self._base_note) % 12
            if on:
                return INTERVAL_COLOR_MAP[interval][0]
            else:
                return INTERVAL_COLOR_MAP[interval][1]
        elif on:
            return KEY_COLOR_MAP[midi_note % 12][0]
        else:
            return KEY_COLOR_MAP[midi_note % 12][1]

    
    def step_key_color_mode(self):
        self._note_display_mode = (self._note_display_mode + 1) % len(KEY_COLOR_MODES_STRINGS)
        self.canonical_parent.show_message('Note Mode Key Color: ' + KEY_COLOR_MODES_STRINGS[self._note_display_mode])
        self.canonical_parent.timed_message(2, 'Note Col: ' + KEY_COLOR_MODES_STRINGS[self._note_display_mode])
        if self._active:
            self.assign_transpose(SCALES[self.current_scale_index])
        

    
    def update_text_display(self):
        self.text_current_scale()

    
    def navigate(self, dir, modifier, alt_modifier = False):
        if modifier:
            self.inc_scale(dir)
        elif alt_modifier:
            self.inc_base_note(dir)
        else:
            self.inc_octave(dir)

    
    def _adjust_scale(self, value):
        if not value == 0 or -1:
            pass
        self.inc_scale(1)

    _adjust_scale = subject_slot('value')(_adjust_scale)
    
    def _adjust_octav(self, value):
        if not value == 0 or -1:
            pass
        self.inc_octave(1)

    _adjust_octav = subject_slot('value')(_adjust_octav)
    
    def _adjust_basem(self, value):
        if not value == 0 or -1:
            pass
        self.inc_base_note(1)

    _adjust_basem = subject_slot('value')(_adjust_basem)
    
    def _do_oct_up(self, value):
        if value != 0:
            self.inc_octave(1)
        

    _do_oct_up = subject_slot('value')(_do_oct_up)
    
    def _do_oct_down(self, value):
        if value != 0:
            self.inc_octave(-1)
        

    _do_oct_down = subject_slot('value')(_do_oct_down)
    
    def _do_base_up(self, value):
        if value != 0:
            self.inc_base_note(1)
        

    _do_base_up = subject_slot('value')(_do_base_up)
    
    def _do_base_down(self, value):
        if value != 0:
            self.inc_base_note(-1)
        

    _do_base_down = subject_slot('value')(_do_base_down)
    
    def _do_scale_up(self, value):
        if value != 0:
            self.inc_scale(1)
        

    _do_scale_up = subject_slot('value')(_do_scale_up)
    
    def _do_scale_down(self, value):
        if value != 0:
            self.inc_scale(-1)
        

    _do_scale_down = subject_slot('value')(_do_scale_down)
    
    def get_mode_id(self):
        return PAD_MODE

    
    def text_current_scale(self):
        scale = SCALES[self.current_scale_index]
        text = scale.name + ' ' + BASE_NOTE[self._base_note] + str(scale.to_octave(self._octave) - 2)
        self.canonical_parent.send_to_display(text)

    
    def inc_base_note(self, inc):
        prev_value = self._base_note
        self._base_note = min(11, max(0, self._base_note + inc))
        if prev_value != self._base_note:
            scale = SCALES[self.current_scale_index]
            self.canonical_parent.show_message(' Base Note ' + BASE_NOTE[self._base_note] + ' to ' + scale.name)
            self.text_current_scale()
            self.update_transpose()
            if self._seg_display:
                self._seg_display.timed_segment(self._base_note)
            
        

    
    def inc_scale(self, inc):
        nr_of_scales = len(SCALES) - 1
        prev_value = self.current_scale_index
        self.current_scale_index = min(nr_of_scales, max(0, self.current_scale_index + inc))
        if prev_value != self.current_scale_index:
            newscale = SCALES[self.current_scale_index]
            self.canonical_parent.show_message(' PAD Scale ' + newscale.name + ' ' + BASE_NOTE[self._base_note] + str(newscale.to_octave(self._octave) - 2))
            self.text_current_scale()
            self.update_transpose()
            if self._seg_display:
                self._seg_display.timed_segment(self.current_scale_index)
            
        

    
    def inc_octave(self, inc):
        scale = SCALES[self.current_scale_index]
        octave = scale.to_octave(self._octave)
        newoctave = octave + inc
        if newoctave < 0:
            newoctave = 0
        elif newoctave > scale.octave_range:
            newoctave = scale.octave_range
        
        self._octave = scale.to_relative(newoctave, self._octave)
        scale = SCALES[self.current_scale_index]
        self.canonical_parent.show_message(' OCTAVE ' + BASE_NOTE[self._base_note] + str(newoctave - 2) + ' to ' + scale.name)
        self.text_current_scale()
        self.update_transpose()
        if self._seg_display:
            val = newoctave - 2
            if val < 0:
                val = 100 + abs(val)
            
            self._seg_display.timed_segment(val)
        

    
    def get_octave(self):
        return SCALES[self.current_scale_index].to_octave(self._octave)

    
    def update_transpose(self):
        if self._active:
            self.assign_transpose(SCALES[self.current_scale_index])
            self.canonical_parent._set_suppress_rebuild_requests(True)
            self.canonical_parent.request_rebuild_midi_map()
            self.canonical_parent._set_suppress_rebuild_requests(False)
        

    
    def fitting_mode(self, track):
        if not track:
            return self
        
        drum_device = find_drum_device(track)
        if drum_device != None and self._alternate_mode != None:
            return self._alternate_mode
        
        return self

    
    def refresh(self):
        if self._active:
            scale_len = len(self._scale.notevalues)
            octave = self._scale.to_octave(self._octave)
            for (column, row) in self.canonical_parent._bmatrix.iterbuttons():
                if button:
                    note_index = (3 - row) * 4 + column
                    scale_index = note_index % scale_len
                    octave_offset = note_index / scale_len
                    note_value = self._scale.notevalues[scale_index] + self._base_note + octave * 12 + octave_offset * 12
                    button.reset()
                    button.send_color_direct(self.get_color_by_note_mode(note_value, False))
                    continue
            
        

    
    def assign_edit_color(self, in_notes, button, note_value):
        if in_notes:
            if note_value in in_notes:
                button.send_color_direct(self.get_color_by_note_mode(note_value, True))
            else:
                button.send_color_direct(self.get_color_by_note_mode(note_value, False))
        else:
            button.send_color_direct(self.get_color_by_note_mode(note_value, False))

    
    def assign_edit_mono(self, in_notes, button, note_value):
        if in_notes:
            if note_value in in_notes:
                button.send_value(127, True)
            else:
                button.send_value(0, True)
        else:
            button.send_value(0, True)

    
    def get_in_notes(self):
        cs = self.song().view.highlighted_clip_slot
        if cs.has_clip and cs.clip.is_midi_clip:
            in_notes = set()
            notes = cs.clip.get_notes(0, 0, cs.clip.length, 127)
            for note in notes:
                in_notes.add(note[0])
            
            return in_notes
        

    
    def assign_transpose(self, scale):
        if not isinstance(scale, PadScale):
            raise AssertionError
        self._scale = scale
        scale_len = len(scale.notevalues)
        octave = scale.to_octave(self._octave)
        last_note_val = None
        if self._active:
            if not self._in_edit_mode or self.get_in_notes():
                pass
            in_notes = None
            for (column, row) in self.canonical_parent._bmatrix.iterbuttons():
                if button:
                    note_index = (3 - row) * 4 + column
                    scale_index = note_index % scale_len
                    octave_offset = note_index / scale_len
                    note_value = scale.notevalues[scale_index] + self._base_note + octave * 12 + octave_offset * 12
                    if note_value < 128:
                        last_note_val = note_value
                    elif last_note_val != None:
                        note_value = last_note_val
                    
                    button.set_send_note(note_value)
                    if self._in_edit_mode:
                        self._color_edit_assign(in_notes, button, note_value)
                    else:
                        button.send_color_direct(self.get_color_by_note_mode(note_value, False))
            
        

    
    def auto_select(self):
        return True

    
    def _on_notes_changed(self):
        if self._in_edit_mode:
            in_notes = self.get_in_notes()
            if in_notes:
                for (column, row) in self.canonical_parent._bmatrix.iterbuttons():
                    if button:
                        if button._msg_identifier in in_notes:
                            button.send_value(127, True)
                        else:
                            button.send_value(0, True)
                    button._msg_identifier in in_notes
                
            else:
                for (column, row) in self.canonical_parent._bmatrix.iterbuttons():
                    button.send_value(0, True)
                
        

    _on_notes_changed = subject_slot('notes')(_on_notes_changed)
    
    def enter_clear_state(self):
        self._in_edit_mode = True
        cs = self.song().view.highlighted_clip_slot
        in_notes = set()
        if cs != None and cs.has_clip and cs.clip.is_midi_clip:
            clip = cs.clip
            notes = clip.get_notes(0, 0, clip.length, 127)
            self._on_notes_changed.subject = clip
            for note in notes:
                in_notes.add(note[0])
            
        else:
            self._on_notes_changed.subject = None
        for (column, row) in self.canonical_parent._bmatrix.iterbuttons():
            if button:
                if button._msg_identifier in in_notes:
                    button.send_value(127, True)
                else:
                    button.send_value(0, True)
                button.set_to_notemode(False)
                button.add_value_listener(self._action_clear, True)
                continue
        

    
    def exit_clear_state(self):
        self._in_edit_mode = False
        self._on_notes_changed.subject = None
        scale_len = len(self._scale.notevalues)
        octave = self._scale.to_octave(self._octave)
        for (column, row) in self.canonical_parent._bmatrix.iterbuttons():
            if button:
                note_index = (3 - row) * 4 + column
                scale_index = note_index % scale_len
                octave_offset = note_index / scale_len
                button.send_value(0, True)
                note_value = self._scale.notevalues[scale_index] + self._base_note + octave * 12 + octave_offset * 12
                button.send_color_direct(self.get_color_by_note_mode(note_value, False))
                button.set_to_notemode(True)
                button.remove_value_listener(self._action_clear)
                continue
        

    
    def _action_clear(self, value, button):
        if value != 0:
            self._editmode.edit_note(button._msg_identifier)
        

    
    def enter(self):
        self._active = True
        for (column, row) in self.canonical_parent._bmatrix.iterbuttons():
            if button:
                button.send_value(0, True)
                button.set_to_notemode(True)
                self.canonical_parent._forwarding_registry[(MIDI_NOTE_ON_STATUS, button.get_identifier())] = button
                self.canonical_parent._forwarding_registry[(MIDI_NOTE_OFF_STATUS, button.get_identifier())] = button
                continue
        
        self.update_transpose()

    
    def exit(self):
        self._active = False
예제 #9
0
class AudioClipEditComponent(CompoundComponent):
    '''
    classdocs
    '''
    def __init__(self, *a, **k):
        super(AudioClipEditComponent, self).__init__(*a, **a)
        self._loop_start_slider = SliderElement(MIDI_CC_TYPE, 2, 60)
        self._action_loop_start.subject = self._loop_start_slider
        self._loop_end_slider = SliderElement(MIDI_CC_TYPE, 2, 61)
        self._action_loop_end.subject = self._loop_end_slider
        self._mark_start_slider = SliderElement(MIDI_CC_TYPE, 2, 62)
        self._action_mark_start.subject = self._mark_start_slider
        self._mark_end_slider = SliderElement(MIDI_CC_TYPE, 2, 63)
        self._action_mark_end.subject = self._mark_end_slider
        self._pitch_c_slider = SliderElement(MIDI_CC_TYPE, 2, 64)
        self._pitch_f_slider = SliderElement(MIDI_CC_TYPE, 2, 65)
        self._gain_slider = SliderElement(MIDI_CC_TYPE, 2, 66)
        self._action_pitch_c.subject = self._pitch_c_slider
        self._action_pitch_f.subject = self._pitch_f_slider
        self._action_gain.subject = self._gain_slider
        self._loop_inc_slider = SliderElement(MIDI_CC_TYPE, 2, 67)
        self._action_loop_inc.subject = self._loop_inc_slider
        self._loop_move_button = ButtonElement(False, MIDI_CC_TYPE, 2, 74)
        self._action_mv_loop.subject = self._loop_move_button
        self._loop_set_button = ButtonElement(False, MIDI_CC_TYPE, 2, 70)
        self._action_loop_toggle.subject = self._loop_set_button
        self._warp_set_button = ButtonElement(False, MIDI_CC_TYPE, 2, 71)
        self._action_warp_toggle.subject = self._warp_set_button
        self._zoom_scroll_button = ButtonElement(False, MIDI_CC_TYPE, 2, 73)
        self._action_scroll_mode.subject = self._zoom_scroll_button
        self.selected_clip_slot = None
        self.inc_index = 4
        self.loop_inc = INC_STEPS[self.inc_index]
        self.start_inc = INC_STEPS[self.inc_index]
        self.mv_loop = False
        self._on_pitch_c_changed.subject = None
        self._on_pitch_f_changed.subject = None
        self._on_gain_changed.subject = None
        self._scroll_mode = False
        self.update_selected_clip()

    def _action_scroll_mode(self, value):
        if value > 0:
            self._scroll_mode = True
        else:
            self._scroll_mode = False

    _action_scroll_mode = subject_slot('value')(_action_scroll_mode)

    def _action_warp_toggle(self, value):
        if value > 0:
            if self.selected_clip_slot and self.selected_clip_slot.has_clip:
                clip = self.selected_clip_slot.clip
                if clip.is_audio_clip:
                    clip.warping = not (clip.warping)
                    if not clip.warping or 127:
                        pass
                    self._warp_set_button.send_value(0, True)

    _action_warp_toggle = subject_slot('value')(_action_warp_toggle)

    def _action_loop_toggle(self, value):
        if value > 0:
            if self.selected_clip_slot and self.selected_clip_slot.has_clip:
                clip = self.selected_clip_slot.clip
                clip.looping = not (clip.looping)
                if not clip.looping or 127:
                    pass
                self._loop_set_button.send_value(0, True)

    _action_loop_toggle = subject_slot('value')(_action_loop_toggle)

    def _action_loop_inc(self, value):
        if not value == 1 or 1:
            pass
        inc = -1
        val = self.inc_index + inc
        if val >= 0 and val < len(INC_STEPS):
            self.inc_index = val
            self.loop_inc = INC_STEPS[val]
            self.start_inc = INC_STEPS[val]
            self.canonical_parent.timed_message(
                2, 'Loop Adjust: ' + INC_DISP[val])
            self.canonical_parent.show_message('Loop Adjust: ' + INC_DISP[val])

    _action_loop_inc = subject_slot('value')(_action_loop_inc)

    def _action_mv_loop(self, value):
        if value > 0:
            if self.mv_loop:
                self._loop_move_button.send_value(0, True)
                self.mv_loop = False
            else:
                self._loop_move_button.send_value(127, True)
                self.mv_loop = True

    _action_mv_loop = subject_slot('value')(_action_mv_loop)

    def _action_mark_start(self, value):
        if self._scroll_mode:
            if not value == 1 or 3:
                pass
            scroll = 2
            self.application().view.scroll_view(scroll, 'Detail/Clip', False)
        elif not value == 1 or 1:
            pass
        inc = -1
        if self.selected_clip_slot and self.selected_clip_slot.has_clip:
            clip = self.selected_clip_slot.clip
            ls = clip.start_marker
            le = clip.end_marker
            ls = max(0, min(le - self.start_inc, ls + inc * self.start_inc))
            clip.start_marker = ls
            bars_to_measure(ls, clip.signature_denominator,
                            clip.signature_numerator)
            self.canonical_parent.timed_message(
                2, 'Clip Start: ' + bars_to_measure(
                    ls, clip.signature_denominator, clip.signature_numerator))

    _action_mark_start = subject_slot('value')(_action_mark_start)

    def _action_mark_end(self, value):
        if self._scroll_mode:
            if not value == 1 or 3:
                pass
            scroll = 2
            self.application().view.zoom_view(scroll, 'Detail/Clip', False)
        elif not value == 1 or 1:
            pass
        inc = -1
        if self.selected_clip_slot and self.selected_clip_slot.has_clip:
            clip = self.selected_clip_slot.clip
            ls = clip.start_marker
            le = clip.end_marker
            le = max(ls + self.start_inc, le + inc * self.start_inc)
            clip.end_marker = le
            self.canonical_parent.timed_message(
                2, 'Clip End: ' + bars_to_measure(
                    le, clip.signature_denominator, clip.signature_numerator))

    _action_mark_end = subject_slot('value')(_action_mark_end)

    def _action_loop_start(self, value):
        if not value == 1 or 1:
            pass
        inc = -1
        if self.selected_clip_slot and self.selected_clip_slot.has_clip:
            clip = self.selected_clip_slot.clip
            ls = clip.loop_start
            le = clip.loop_end
            if self.mv_loop:
                diff = le - ls
                ls = max(0, ls + inc * self.loop_inc)
                if inc > 0:
                    clip.loop_end = ls + diff
                    clip.end_marker = ls + diff
                    clip.loop_start = ls
                    clip.start_marker = ls
                else:
                    clip.loop_start = ls
                    clip.start_marker = ls
                    clip.loop_end = ls + diff
                    clip.end_marker = ls + diff
                self.canonical_parent.timed_message(2, loop_str(clip))
            else:
                ls = max(0, min(le - self.loop_inc, ls + inc * self.loop_inc))
                clip.loop_start = ls
                self.canonical_parent.timed_message(2, loop_str(clip))

    _action_loop_start = subject_slot('value')(_action_loop_start)

    def _action_loop_end(self, value):
        if not value == 1 or 1:
            pass
        inc = -1
        if self.selected_clip_slot and self.selected_clip_slot.has_clip:
            clip = self.selected_clip_slot.clip
            ls = clip.loop_start
            le = clip.loop_end
            le = max(ls + self.loop_inc, le + inc * self.loop_inc)
            clip.loop_end = le
            if self.mv_loop:
                clip.end_marker = le

            self.canonical_parent.timed_message(2, loop_str(clip))

    _action_loop_end = subject_slot('value')(_action_loop_end)

    def update(self):
        pass

    def _action_pitch_c(self, value):
        cs = self.selected_clip_slot
        if cs and cs.has_clip and cs.clip.is_audio_clip:
            cs.clip.pitch_coarse = midi_to_pitchc(value)

    _action_pitch_c = subject_slot('value')(_action_pitch_c)

    def _action_pitch_f(self, value):
        cs = self.selected_clip_slot
        if cs and cs.has_clip and cs.clip.is_audio_clip:
            cs.clip.pitch_fine = midi_to_pitchf(value)

    _action_pitch_f = subject_slot('value')(_action_pitch_f)

    def _action_gain(self, value):
        cs = self.selected_clip_slot
        if cs and cs.has_clip and cs.clip.is_audio_clip:
            cs.clip.gain = midi_to_gain(value)

    _action_gain = subject_slot('value')(_action_gain)

    def _update_clip_name(self):
        cs = self.song().view.highlighted_clip_slot
        if not cs:
            track = self.song().view.selected_track
            self.canonical_parent.send_to_display('Rt Trck: ' + track.name, 3)
        elif cs.has_clip:
            if not cs.clip.is_audio_clip or 'A':
                pass
            self.canonical_parent.send_to_display('M' + ':' + cs.clip.name, 3)
        else:
            track = cs.canonical_parent
            index = list(track.clip_slots).index(cs)
            scene = self.song().scenes[index]
            self.canonical_parent.send_to_display(
                'E<' + str(scene.name) + '> T:' + track.name, 3)

    def _on_has_clip_changed(self):
        self._update_clip_name()

    _on_has_clip_changed = subject_slot('has_clip')(_on_has_clip_changed)

    def _on_name_changed(self):
        self._update_clip_name()

    _on_name_changed = subject_slot('name')(_on_name_changed)

    def update_selected_clip(self):
        cs = self.song().view.highlighted_clip_slot
        if cs != self.selected_clip_slot:
            self.selected_clip_slot = cs
            self._update_clip_name()
            if cs and cs.has_clip and cs.clip.is_audio_clip:
                self._on_pitch_c_changed.subject = cs.clip
                self._on_pitch_f_changed.subject = cs.clip
                self._on_gain_changed.subject = cs.clip
                self._on_warp_changed.subject = cs.clip
                self._gain_slider.send_value(gain_to_midi(cs.clip.gain))
                self._pitch_c_slider.send_value(
                    pitchc_to_midi(cs.clip.pitch_coarse))
                self._pitch_f_slider.send_value(
                    pitchf_to_midi(cs.clip.pitch_fine))
                if not cs.clip.warping or 127:
                    pass
                self._warp_set_button.send_value(0, True)
            else:
                self._on_pitch_c_changed.subject = None
                self._on_pitch_f_changed.subject = None
                self._on_gain_changed.subject = None
                self._on_warp_changed.subject = None
                self._on_loop_changed.subject = None
            if cs and cs.has_clip:
                self._on_loop_changed.subject = cs.clip
                self._on_name_changed.subject = cs.clip
                if not cs.clip.looping or 127:
                    pass
                self._loop_set_button.send_value(0, True)
            else:
                self._on_name_changed.subject = None
                self._on_loop_changed.subject = None
            self._on_has_clip_changed.subject = cs

    def on_selected_track_changed(self):
        self.update_selected_clip()

    def on_selected_scene_changed(self):
        self.update_selected_clip()

    def _on_loop_changed(self):
        cs = self.song().view.highlighted_clip_slot
        if cs and cs.has_clip:
            if not cs.clip.looping or 127:
                pass
            self._loop_set_button.send_value(0, True)

    _on_loop_changed = subject_slot('looping')(_on_loop_changed)

    def _on_warp_changed(self):
        cs = self.song().view.highlighted_clip_slot
        if cs and cs.has_clip and cs.clip.is_audio_clip:
            if not cs.clip.warping or 127:
                pass
            self._warp_set_button.send_value(0, True)

    _on_warp_changed = subject_slot('warping')(_on_warp_changed)

    def _on_pitch_c_changed(self):
        cs = self.song().view.highlighted_clip_slot
        if cs and cs.has_clip and cs.clip.is_audio_clip:
            self._pitch_c_slider.send_value(
                pitchc_to_midi(cs.clip.pitch_coarse))

    _on_pitch_c_changed = subject_slot('pitch_coarse')(_on_pitch_c_changed)

    def _on_pitch_f_changed(self):
        cs = self.song().view.highlighted_clip_slot
        if cs and cs.has_clip and cs.clip.is_audio_clip:
            self._pitch_f_slider.send_value(pitchf_to_midi(cs.clip.pitch_fine))

    _on_pitch_f_changed = subject_slot('pitch_fine')(_on_pitch_f_changed)

    def _on_gain_changed(self):
        cs = self.song().view.highlighted_clip_slot
        if cs and cs.has_clip and cs.clip.is_audio_clip:
            self._gain_slider.send_value(gain_to_midi(cs.clip.gain))

    _on_gain_changed = subject_slot('gain')(_on_gain_changed)
예제 #10
0
class EditSection(CompoundComponent):
    
    def __init__(self, *a, **k):
        super(EditSection, self).__init__(*a, **a)
        is_momentary = True
        self.mikro_shift_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 2, 80)
        self._do_shift_mikro.subject = self.mikro_shift_button
        self.shift_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1, 80)
        self._do_shift.subject = self.shift_button
        self.alt_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1, 82)
        self._do_alt.subject = self.alt_button
        self.mikro_shift = False
        self.shiftdown = False
        self.altdown = False
        self.edit_state = ES_NONE
        self._down_button = None
        self._action_set_quant.subject = SliderElement(MIDI_CC_TYPE, 2, 110)
        self._action_init_loop.subject = SliderElement(MIDI_CC_TYPE, 2, 111)
        self._nav_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 115)
        self._action_navigate.subject = self._nav_button
        self._copy_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 95)
        self._action_duplicate.subject = self._copy_button
        self._quantize_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 97)
        self._action_quantize.subject = self._quantize_button
        self._paste_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 96)
        self._action_new.subject = self._paste_button
        self._note_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 101)
        self._action_note.subject = self._note_button
        self._clear_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 103)
        self._action_clear.subject = self._clear_button
        self._nudge_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 100)
        self._action_nudge_button.subject = self._nudge_button
        self.action_time = False
        self.pad_action = False
        self.pad_wheel_action = False
        self.quantize = 5
        self.quantize_amount = 1
        self.initial_clip_len = 4
        self._focused_clip = None
        self._focused_c_index = None
        self._color_edit = False
        self.nav_index = 0

    
    def disconnect(self):
        super(EditSection, self).disconnect()

    
    def init(self):
        self._color_edit_button.send_value(0, True)

    
    def set_color_edit(self, val):
        self._color_edit = val

    
    def is_color_edit(self):
        return self._color_edit

    
    def connect_session(self, session):
        for sindex in range(session.height()):
            scene = session.scene(sindex)
            for cindex in range(session.width()):
                clip = scene.clip_slot(cindex)
                clip.set_modifier(self)
            
        

    
    def set_mode_selector(self, mode_selector):
        self._mode_selector = mode_selector
        self._mode_selector.assign_edit_section(self)

    
    def _do_shift_mikro(self, value):
        self.mikro_shift = value != 0
        self.shiftdown = value != 0
        if self._mode_selector:
            self._mode_selector.set_shift_state(self.mikro_shift)
        

    _do_shift_mikro = subject_slot('value')(_do_shift_mikro)
    
    def _do_shift(self, value):
        self.shiftdown = value != 0

    _do_shift = subject_slot('value')(_do_shift)
    
    def _do_alt(self, value):
        self.altdown = value != 0

    _do_alt = subject_slot('value')(_do_alt)
    
    def modifiers(self):
        if self.shiftdown:
            pass
        if self.altdown:
            pass
        return 1 | 1 << 1

    
    def isShiftdown(self):
        return self.shiftdown

    
    def isAltdown(self):
        return self.altdown

    
    def isClipAltDown(self):
        if not self.altdown:
            pass
        return self._mode_selector.isClipDown()

    
    def hasModification(self, mode):
        if mode == SCENE_MODE:
            return self.edit_state != ES_NONE
        elif mode == CLIP_MODE:
            if self.edit_state != ES_NONE:
                return True
            elif self._color_edit:
                return True
            
        
        return False

    
    def update(self):
        pass

    
    def _get_current_slot(self, song):
        scene = song.view.selected_scene
        track = song.view.selected_track
        clip_slot = song.view.highlighted_clip_slot
        scenes = song.scenes
        tracks = song.tracks
        sindex = vindexof(scenes, scene)
        tindex = vindexof(tracks, track)
        return (clip_slot, track, scenes, tindex, sindex)

    
    def do_message(self, msg, statusbarmsg = None):
        if statusbarmsg == None:
            self.canonical_parent.show_message(msg)
        else:
            self.canonical_parent.show_message(statusbarmsg)
        self.canonical_parent.timed_message(2, msg)

    
    def edit_note(self, note_value):
        self.pad_action = True
        if self.edit_state == ES_CLEAR:
            cs = self.song().view.highlighted_clip_slot
            if cs and cs.has_clip and cs.clip.is_midi_clip:
                if self.shiftdown:
                    cs.clip.remove_notes(0, 0, cs.clip.length, 127)
                else:
                    cs.clip.remove_notes(0, note_value, cs.clip.length, 1)
            
        

    
    def edit_scene_slot(self, scene, index):
        self.pad_action = True
        if scene != None:
            song = self.song()
            if self.edit_state == ES_DUPLICATE:
                self.do_message('Duplicate Scene ' + str(scene.name))
                song.duplicate_scene(index)
            elif self.edit_state == ES_NEW:
                idx = 1
                if self.shiftdown:
                    idx = 0
                
                song.create_scene(index + idx)
                self.do_message('Create Scene ' + str(self.song().view.selected_scene.name))
            elif self.edit_state == ES_CLEAR:
                self.do_message('Delete Scene ' + str(scene.name))
                song.delete_scene(index)
            elif self.edit_state == ES_DOUBLE:
                song.capture_and_insert_scene()
                scene = self.song().view.selected_scene
                self.do_message('Capture to ' + scene.name)
            elif self.edit_state == ES_NUDGE:
                self.clear_auto_scene(scene, index)
                self.do_message('Clr Env in Scene ' + scene.name)
            elif self.edit_state == ES_QUANT:
                pass
            elif self.edit_state == ES_NAVIGATE:
                self.song().view.selected_scene = scene
            
        

    
    def duplciate_clip_slot(self, clip_slot):
        if clip_slot.has_clip:
            
            try:
                track = clip_slot.canonical_parent
                index = list(track.clip_slots).index(clip_slot)
                track.duplicate_clip_slot(index)
                self.do_message('Duplicate Clip ' + clip_slot.clip.name)
                select_clip_slot(self.song(), track.clip_slots[index + 1])
            except Live.Base.LimitationError:
                pass
            except RuntimeError:
                pass
            


    
    def _action_set_quant(self, value):
        if not value == 0 or -1:
            pass
        self.mod_quant_size(1)

    _action_set_quant = subject_slot('value')(_action_set_quant)
    
    def _action_init_loop(self, value):
        if not value == 0 or -1:
            pass
        self.mod_new_initlen(1)

    _action_init_loop = subject_slot('value')(_action_init_loop)
    
    def mod_new_initlen(self, diff):
        if abs(diff) == 4:
            newval = self.initial_clip_len + diff
            newval = int(newval / 4) * 4
            self.initial_clip_len = max(4, min(64, newval))
        else:
            self.initial_clip_len = max(1, min(64, self.initial_clip_len + diff))
        self.canonical_parent.timed_message(2, 'Init Clip Len: ' + str(int(self.initial_clip_len)) + ' Beats', True)
        self.canonical_parent.show_message('Initial Clip Length : ' + str(int(self.initial_clip_len)) + ' beats')

    
    def mod_quant_size(self, diff):
        self.quantize = max(1, min(len(QUANT_CONST) - 1, self.quantize + diff))
        self.canonical_parent.timed_message(2, 'Quantize: ' + QUANT_STRING[self.quantize], True)
        self.canonical_parent.show_message('Quantize set to : ' + QUANT_STRING[self.quantize])

    
    def knob_pad_action(self, activate):
        if activate:
            self.pad_wheel_action = True
            self.edit_state = ES_KNOB
            self._focused_clip = None
        else:
            self.pad_wheel_action = False
            self.edit_state = ES_NONE
            self._focused_clip = None

    
    def edit_colors(self, diff, jump_selection = False):
        pass

    
    def edit_clip_slot(self, clipslot_component, value):
        if self._color_edit:
            if value != 0:
                if clipslot_component._clip_slot != None:
                    self._focused_clip = clipslot_component
                    self._mode_selector.pick_color(clipslot_component)
                
            else:
                self._focused_clip = None
        else:
            self.pad_action = True
            if value != 0 and clipslot_component._clip_slot != None:
                clip_slot = clipslot_component._clip_slot
                if self.edit_state == ES_DUPLICATE:
                    if self.shiftdown:
                        self.duplicate_track_cs(clip_slot)
                    else:
                        self.duplciate_clip_slot(clip_slot)
                elif self.edit_state == ES_NEW:
                    if self.shiftdown:
                        self.create_new_midi_track(clip_slot)
                    else:
                        self.create_new_clip(clip_slot)
                elif self.edit_state == ES_CLEAR:
                    if self.altdown:
                        if clip_slot.clip != None:
                            clip = clip_slot.clip
                            if clip.is_midi_clip:
                                self.do_message('Clear all Notes in Clip')
                                clip.remove_notes(0, 0, clip.length, 127)
                            
                        
                    elif self.shiftdown:
                        self.delete_track_cs(clip_slot)
                    elif clip_slot.clip:
                        self.do_message('Delete Clip ' + clip_slot.clip.name)
                    
                    clipslot_component._do_delete_clip()
                elif self.edit_state == ES_DOUBLE:
                    if self.shiftdown:
                        self.create_new_audio_track(clip_slot)
                    else:
                        self.double_clipslot(clip_slot)
                elif self.edit_state == ES_NUDGE:
                    if self.shiftdown:
                        self._new_return_track()
                    else:
                        self.clear_automation(clip_slot)
                elif self.edit_state == ES_QUANT:
                    self.quantize_clisplot(clipslot_component._clip_slot)
                elif self.edit_state == ES_NAVIGATE:
                    clipslot_component._do_select_clip(clipslot_component._clip_slot)
                    if self.canonical_parent.arm_selected_track:
                        arm_exclusive(self.song())
                    
                
            

    
    def _new_return_track(self):
        song = self.song()
        song.create_return_track()
        self.do_message('New Return Track')

    
    def _new_scene(self):
        song = self.song()
        scene = song.view.selected_scene
        sindex = vindexof(song.scenes, scene)
        if not sindex >= 0 or sindex:
            pass
        sindex = 0
        song.create_scene(sindex + 1)
        new_scene = song.view.selected_scene
        self.do_message('New Scene ' + new_scene.name)

    
    def _new_audio_track(self):
        song = self.song()
        track = song.view.selected_track
        tindex = 0
        if not track.can_be_armed:
            tindex = len(song.tracks) - 1
        else:
            tindex = vindexof(song.tracks, track)
        if not tindex >= 0 or tindex:
            pass
        tindex = 0
        song.create_audio_track(tindex + 1)
        track = song.view.selected_track
        self.do_message('New Audio Track ' + track.name)

    
    def _new_midi_track(self):
        song = self.song()
        track = song.view.selected_track
        tindex = 0
        if not track.can_be_armed:
            tindex = len(song.tracks) - 1
        else:
            tindex = vindexof(song.tracks, track)
        if not tindex >= 0 or tindex:
            pass
        tindex = 0
        song.create_midi_track(tindex + 1)
        track = song.view.selected_track
        self.do_message('New MIDI Track ' + track.name)

    
    def _new_midi_clip(self):
        song = self.song()
        if song.view.selected_track.has_midi_input:
            clip_slot = song.view.highlighted_clip_slot
            if clip_slot != None and not (clip_slot.has_clip):
                clip_slot.create_clip(self.initial_clip_len)
                song.view.detail_clip = clip_slot.clip
                self.do_message('New MIDI Clip ' + clip_slot.clip.name)
                self.application().view.show_view('Detail')
            
        

    
    def quantize_scene(self, scene, index, fiftyPerc):
        tracks = self.song().tracks
        for track in tracks:
            clipslots = track.clip_slots
            if len(clipslots) >= index and clipslots[index].clip != None:
                if not self.shiftdown or 0.5:
                    pass
                clipslots[index].clip.quantize(QUANT_CONST[self.quantize], 1)
                continue
        

    
    def clear_auto_scene(self, scene, index):
        tracks = self.song().tracks
        for track in tracks:
            clipslots = track.clip_slots
            if len(clipslots) >= index and clipslots[index].clip != None:
                clipslots[index].clip.clear_all_envelopes()
                continue
        

    
    def _capture_new_scene(self):
        self.song().capture_and_insert_scene()
        scene = self.song().view.selected_scene
        self.do_message('Capture to ' + scene.name)

    
    def _duplicate_selected_scene(self):
        song = self.song()
        scene = song.view.selected_scene
        sindex = vindexof(song.scenes, scene)
        if scene and sindex >= 0:
            self.do_message('Duplicate Scene ' + scene.name)
            song.duplicate_scene(sindex)
        

    
    def _duplicate_selected_track(self):
        song = self.song()
        track = song.view.selected_track
        t_index = track_index(song, track)
        if track and t_index and t_index[1] == TYPE_TRACK_SESSION:
            tindex = t_index[0]
            self.do_message('Dupl. Track ' + track.name, 'Duplicate Track ' + track.name)
            song.duplicate_track(tindex)
        

    
    def _duplicate_selected_clip(self):
        song = self.song()
        (clip_slot, track, scenes, tindex, sindex) = self._get_current_slot(song)
        if clip_slot != None and clip_slot.clip != None:
            self.do_message('Duplicate ' + clip_slot.clip.name, 'Duplicate Clip ' + clip_slot.clip.name)
            track.duplicate_clip_slot(sindex)
            index = sindex + 1
            if index >= 0 and index < len(scenes):
                song.view.selected_scene = scenes[index]
            
        

    
    def duplicate_track_cs(self, clip_slot):
        if clip_slot != None:
            song = self.song()
            track = clip_slot.canonical_parent
            t_index = track_index(song, track)
            if track and t_index and t_index[1] == TYPE_TRACK_SESSION:
                tindex = t_index[0]
                self.do_message('Duplicate Track ' + track.name)
                song.duplicate_track(tindex)
            
        

    
    def clear_automation(self, clip_slot):
        song = self.song()
        if clip_slot != None and clip_slot.clip != None:
            self.do_message('Clr.Env. ' + clip_slot.clip.name, 'Clear Envelopes ' + clip_slot.clip.name)
            clip_slot.clip.clear_all_envelopes()
        

    
    def quantize_clisplot(self, clip_slot):
        if clip_slot.clip != None:
            if not self.shiftdown or ' 50%':
                pass
            self.do_message('Quantize Clip: ' + clip_slot.clip.name + '')
            if not self.shiftdown or 0.5:
                pass
            clip_slot.clip.quantize(QUANT_CONST[self.quantize], 1)
            self.song().view.detail_clip = clip_slot.clip
            self.canonical_parent.focus_clip_detail()
        

    
    def double_clipslot(self, clip_slot):
        song = self.song()
        track = clip_slot.canonical_parent
        if clip_slot.clip != None and track.has_midi_input:
            clip = clip_slot.clip
            if clip.length <= 2048:
                clip.duplicate_loop()
                self.do_message('Dupl. Lp: ' + str(int(clip.length / 4)) + ' Bars')
                song.view.detail_clip = clip
                self.canonical_parent.focus_clip_detail()
            else:
                self.do_message('Clip is to long to Duplicate')
        

    
    def create_new_clip(self, clip_slot):
        song = self.song()
        track = clip_slot.canonical_parent
        if clip_slot.clip == None and track.has_midi_input:
            clip_slot.create_clip(self.initial_clip_len)
            song.view.detail_clip = clip_slot.clip
            select_clip_slot(song, clip_slot)
            self.canonical_parent.focus_clip_detail()
            self.do_message('New Midi Clip ' + song.view.highlighted_clip_slot.clip.name)
        

    
    def create_new_midi_track(self, clip_slot):
        if clip_slot != None:
            song = self.song()
            track = clip_slot.canonical_parent
            tindex = vindexof(song.tracks, track)
            if not tindex >= 0 or tindex:
                pass
            tindex = 0
            song.create_midi_track(tindex + 1)
            track = song.view.selected_track
            self.do_message('New Midi Track ' + track.name)
        

    
    def create_new_audio_track(self, clip_slot):
        if clip_slot != None:
            song = self.song()
            track = clip_slot.canonical_parent
            tindex = vindexof(song.tracks, track)
            if not tindex >= 0 or tindex:
                pass
            tindex = 0
            song.create_audio_track(tindex + 1)
            track = song.view.selected_track
            self.do_message('New Audio Track ' + track.name)
        

    
    def delete_track_cs(self, clip_slot):
        if clip_slot != None:
            song = self.song()
            track = clip_slot.canonical_parent
            t_index = track_index(song, track)
            if track and len(song.tracks) > 1 and t_index and t_index[1] == TYPE_TRACK_SESSION:
                self.do_message('Delete Track ' + track.name)
                song.delete_track(t_index[0])
            
        

    
    def _double_selected_clip(self):
        song = self.song()
        clip_slot = song.view.highlighted_clip_slot
        if clip_slot != None and clip_slot.clip != None and song.view.selected_track.has_midi_input:
            clip = clip_slot.clip
            if clip.length <= 2048:
                clip_slot.clip.duplicate_loop()
                self.do_message('Dupl. Lp ' + str(int(clip_slot.clip.length / 4)) + ' Bars')
                song.view.detail_clip = clip_slot.clip
                self.canonical_parent.focus_clip_detail()
            else:
                self.do_message('Clip is to long to Duplicate')
        

    
    def _clear_events(self):
        song = self.song()
        clip_slot = song.view.highlighted_clip_slot
        if clip_slot != None and clip_slot.clip != None:
            self.do_message('Clr.Env. ' + clip_slot.clip.name, 'Clear Envelopes ' + clip_slot.clip.name)
            clip_slot.clip.clear_all_envelopes()
        

    
    def _delete_current_clip(self):
        song = self.song()
        clip_slot = song.view.highlighted_clip_slot
        if clip_slot != None and clip_slot.clip != None:
            self.do_message('Delete Clip ' + clip_slot.clip.name)
            clip_slot.delete_clip()
        

    
    def _delete_selected_track(self):
        song = self.song()
        track = song.view.selected_track
        t_index = track_index(song, track)
        if track and len(song.tracks) > 1 and t_index and t_index[1] == TYPE_TRACK_SESSION:
            self.do_message('Delete Track ' + track.name)
            song.delete_track(t_index[0])
        

    
    def _delete_selected_scene(self):
        song = self.song()
        scene = song.view.selected_scene
        sindex = vindexof(song.scenes, scene)
        if scene and len(song.scenes) > 1 and sindex >= 0:
            self.do_message('Delete Scene ' + scene.name)
            song.delete_scene(sindex)
        

    
    def _click_duplicate(self):
        modifiers = self.modifiers()
        if modifiers == 0:
            self._duplicate_selected_clip()
        elif modifiers == 1:
            self._duplicate_selected_track()
        elif modifiers == 2:
            self._duplicate_selected_scene()
        

    
    def _click_new(self):
        modifiers = self.modifiers()
        if modifiers == 0:
            self._new_midi_clip()
        elif modifiers == 1:
            self._new_midi_track()
        elif modifiers == 2:
            self._new_scene()
        

    
    def _click_double(self):
        modifiers = self.modifiers()
        if modifiers == 0:
            self._double_selected_clip()
        elif modifiers == 1:
            self._new_audio_track()
        elif modifiers == 2:
            self._capture_new_scene()
        

    
    def _click_clear(self):
        modifiers = self.modifiers()
        if modifiers == 0:
            self._delete_current_clip()
        elif modifiers == 1:
            self._delete_selected_track()
        elif modifiers == 2:
            self._delete_selected_scene()
        

    
    def _click_quantize(self):
        song = self.song()
        clip_slot = song.view.highlighted_clip_slot
        if clip_slot != None:
            self.quantize_clisplot(clip_slot)
        

    
    def _click_nudge(self):
        modifiers = self.modifiers()
        if modifiers == 0:
            self._clear_events()
        elif modifiers == 1:
            self._new_return_track()
        elif modifiers == 2:
            pass
        

    
    def _select(self, button):
        if self._down_button:
            self._down_button.turn_off()
        
        button.turn_on()
        self._down_button = button
        self.action_time = int(round(time.time() * 1000))

    
    def _deselect(self, button):
        if button == self._clear_button:
            self._mode_selector.exit_clear_state()
        
        if self._down_button == button:
            self._down_button.turn_off()
            self._down_button = None
            prev_state = self.edit_state
            self.edit_state = ES_NONE
            modeid = self._mode_selector.mode().get_mode_id()
            if self.pad_action:
                self.pad_action = False
                return False
            
            if modeid == CLIP_MODE or modeid == SCENE_MODE:
                return False
            
            if (modeid == PAD_MODE or modeid == CONTROL_MODE) and prev_state == ES_CLEAR:
                return False
            else:
                return True
        
        self.pad_action = False
        return False

    
    def _action_navigate(self, value):
        if self.isShiftdown() and value != 0:
            self.nav_index = (self.nav_index + 1) % len(VIEWS_ALL)
            self.application().view.focus_view(VIEWS_ALL[self.nav_index])
            self.canonical_parent.show_message('Focus on : ' + str(VIEWS_ALL[self.nav_index]))
        elif value != 0:
            self._select(self._nav_button)
            self.edit_state = ES_NAVIGATE
        else:
            self._deselect(self._nav_button)

    _action_navigate = subject_slot('value')(_action_navigate)
    
    def _action_duplicate(self, value):
        if value != 0:
            self._select(self._copy_button)
            self.edit_state = ES_DUPLICATE
        elif self._deselect(self._copy_button):
            self._click_duplicate()
        

    _action_duplicate = subject_slot('value')(_action_duplicate)
    
    def _action_new(self, value):
        if value != 0:
            self._select(self._paste_button)
            self.edit_state = ES_NEW
        elif self._deselect(self._paste_button):
            self._click_new()
        

    _action_new = subject_slot('value')(_action_new)
    
    def _action_note(self, value):
        if value != 0:
            self._select(self._note_button)
            self.edit_state = ES_DOUBLE
        elif self._deselect(self._note_button):
            self._click_double()
        

    _action_note = subject_slot('value')(_action_note)
    
    def _action_clear(self, value):
        self.canonical_parent._hold_clear_action(value)
        if value != 0:
            self._mode_selector.enter_clear_state()
            self._select(self._clear_button)
            self.edit_state = ES_CLEAR
        elif self._deselect(self._clear_button):
            self._click_clear()
        

    _action_clear = subject_slot('value')(_action_clear)
    
    def _action_nudge_button(self, value):
        if value != 0:
            self._select(self._nudge_button)
            self.edit_state = ES_NUDGE
        elif self._deselect(self._nudge_button):
            self._click_nudge()
        

    _action_nudge_button = subject_slot('value')(_action_nudge_button)
    
    def _action_quantize(self, value):
        if value != 0:
            self._select(self._quantize_button)
            self.edit_state = ES_QUANT
        elif self._deselect(self._quantize_button):
            self._click_quantize()
        

    _action_quantize = subject_slot('value')(_action_quantize)
    
    def _toggle_color_mode(self, value):
        if value != 0:
            session = self.canonical_parent._session
            if session.is_color_mode():
                self._color_mode_button.switch_off()
                session._change_color_mode(1)
            else:
                self._color_mode_button.send_color(1)
                session._change_color_mode(1)
        

    _toggle_color_mode = subject_slot('value')(_toggle_color_mode)
예제 #11
0
class MidiEditSection(CompoundComponent):
    _current_clip = None
    _split_value = 4
    _base_note = None
    _gate = 1
    _selected_note = None
    _note_pos = None
    _note_len = 0
    _bend_val = 0
    _offset = 0
    _transpose = 0
    _vel_fade = 0
    _fade_mode = FADE_TIME
    _note_set = None
    _note_index = 0
    
    def __init__(self, *a, **k):
        super(MidiEditSection, self).__init__(*a, **a)
        is_momentary = True
        self.split_knob = SliderElement(MIDI_CC_TYPE, 5, 70)
        self.gate_knob = SliderElement(MIDI_CC_TYPE, 5, 71)
        self.bend_knob = SliderElement(MIDI_CC_TYPE, 5, 72)
        self.offset_knob = SliderElement(MIDI_CC_TYPE, 5, 73)
        self.strech_knob = SliderElement(MIDI_CC_TYPE, 5, 74)
        self.fade_knob = SliderElement(MIDI_CC_TYPE, 5, 75)
        self.transpose_knob = SliderElement(MIDI_CC_TYPE, 5, 77)
        self.edit_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 5, 60)
        self.split_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 5, 61)
        self.init_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 5, 62)
        self.delete_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 5, 63)
        self.select_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 5, 64)
        self._do_edit_button.subject = self.edit_button
        self._do_split_button.subject = self.split_button
        self._do_delete.subject = self.delete_button
        self._do_init.subject = self.init_button
        self._do_select.subject = self.select_button
        self._do_split.subject = self.split_knob
        self._do_gate.subject = self.gate_knob
        self._do_bend.subject = self.bend_knob
        self._do_offset.subject = self.offset_knob
        self._do_strech.subject = self.strech_knob
        self._do_fade.subject = self.fade_knob
        self._do_transpose.subject = self.transpose_knob

    
    def do_message(self, msg, statusbarmsg = None):
        if statusbarmsg == None:
            self.canonical_parent.show_message(msg)
        else:
            self.canonical_parent.show_message(statusbarmsg)
        self.canonical_parent.timed_message(2, msg)

    
    def _init_value(self):
        self._split_value = 4

    
    def select_note(self, note):
        if self._current_clip and self._note_set:
            self._note_index = 0
            self.set_notes(tuple(self._note_set[self._note_index]))
        

    
    def _do_select(self, value):
        if value == 0:
            clip_slot = self.song().view.highlighted_clip_slot
            if clip_slot and clip_slot.has_clip and clip_slot.clip.is_midi_clip:
                clip = clip_slot.clip
                self._notes_changed.subject = clip
                self._current_clip = clip
                self._note_set = clip.get_notes(0, 0, clip.length, 127)
                if self._note_index == None:
                    self._note_index = 0
                else:
                    self._note_index = (self._note_index + 1) % len(self._note_set)
                ls = []
                selnote = self._note_set[self._note_index]
                ls.append(selnote)
                clip.remove_notes(selnote[1], selnote[0], selnote[2], 1)
                clip.deselect_all_notes()
                clip.set_notes(tuple(ls))
                clip.replace_selected_notes(tuple(ls))
            
        

    _do_select = subject_slot('value')(_do_select)
    
    def _do_delete(self, value):
        if value != 0:
            self._selected_note = None
            self.edit_button.send_value(0, True)
            if self._current_clip:
                selected = self._current_clip.get_selected_notes()
                for note in selected:
                    pitch = note[0]
                    self._current_clip.remove_notes(note[1], pitch, note[2], 1)
                
            
        

    _do_delete = subject_slot('value')(_do_delete)
    
    def _do_init(self, value):
        if value != 0:
            self._transpose = 0
            self._offset = 0
            self._bend_val = 0
            self._split_value = 4
            self._vel_fade = 0
            self._gate = 1
            self.canonical_parent.timed_message(2, 'SPLIT:' + str(self._split_value))
        

    _do_init = subject_slot('value')(_do_init)
    
    def _do_edit_button(self, value):
        if value > 0:
            note = self.get_selected_note()
            self._transpose = 0
            if note:
                self.edit_button.send_value(127, True)
            else:
                self.edit_button.send_value(0, True)
        

    _do_edit_button = subject_slot('value')(_do_edit_button)
    
    def get_selected_note(self):
        clip_slot = self.song().view.highlighted_clip_slot
        if clip_slot and clip_slot.has_clip and clip_slot.clip.is_midi_clip:
            self._notes_changed.subject = clip_slot.clip
            self._current_clip = clip_slot.clip
            notes = self._current_clip.get_selected_notes()
            if len(notes) == 1:
                self._selected_note = notes[0]
                self._base_note = self._selected_note[0]
                self._note_len = self._selected_note[2]
                self._note_pos = self._selected_note[1]
                return notes[0]
            
        

    
    def execute_transpose(self, dir):
        clip_slot = self.song().view.highlighted_clip_slot
        if clip_slot and clip_slot.has_clip and clip_slot.clip.is_midi_clip:
            clip = clip_slot.clip
            notes = clip.get_selected_notes()
            if len(notes) > 0:
                list = []
                for note in notes:
                    pitch = min(max(note[0] + dir, 0), 127)
                    list.append((note[0] + dir, note[1], note[2], note[3], note[4]))
                
                clip.replace_selected_notes(tuple(list))
            
        

    
    def execute_split(self):
        selected_note = self._selected_note
        if selected_note:
            notelen = self._note_len
            note = min(max(0, self._base_note + self._transpose), 127)
            vel = self._selected_note[3]
            mute = self._selected_note[4]
            sp = self._note_pos
            pos = self._note_pos
            if self._vel_fade < 0:
                endvel = vel
                startvel = vel - vel * abs(self._vel_fade)
            else:
                startvel = vel
                endvel = vel - vel * self._vel_fade
            list = []
            divList = self.get_interval(notelen, self._split_value, self._bend_val)
            off = int(self._split_value * self._offset)
            velinc = (endvel - startvel) / self._split_value
            vel = startvel
            for index in range(self._split_value):
                pcl = int((index + off) % self._split_value)
                div = divList[pcl]
                notvlen = div * self._gate
                if notvlen > 0:
                    list.append((note, pos, notvlen, vel, mute))
                
                pos += div
                if self._fade_mode == FADE_EVENT:
                    vel += velinc
                    continue
                rp = (pos - sp) / notelen
                vel = startvel + (endvel - startvel) * rp
            
            self._current_clip.replace_selected_notes(tuple(list))
        

    
    def _do_transpose(self, value):
        if not value == 0 or -1:
            pass
        diff = 1
        self.execute_transpose(diff)

    _do_transpose = subject_slot('value')(_do_transpose)
    
    def _do_fade(self, value):
        if self.canonical_parent.isShiftDown():
            if not value == 0 or -0.01:
                pass
            diff = 0.01
        elif not value == 0 or -0.1:
            pass
        diff = 0.1
        newvale = self._vel_fade + diff
        if newvale >= -1 and newvale <= 1:
            self._vel_fade = newvale
            self.canonical_parent.timed_message(2, 'FADE:' + str(int(round(self._vel_fade * 100, 0))) + '%')
            self.canonical_parent.show_message('Split Fade: ' + str(int(round(self._vel_fade * 100, 0))) + '%')
            self.execute_split()
        

    _do_fade = subject_slot('value')(_do_fade)
    
    def _do_strech(self, value):
        if not value == 0 or -1:
            pass
        diff = 1
        if self.canonical_parent.isShiftDown():
            newval = self._note_len + diff * STRECH_INC_PLS
        else:
            newval = self._note_len + diff * STRECH_INC
        if newval > 0:
            self._note_len = newval
            self.execute_split()
            self.canonical_parent.timed_message(2, 'LENGTH:' + str(self._note_len) + ' BEATS')
            self.canonical_parent.show_message('Set Length TO : ' + str(self._note_len) + ' beats')
        

    _do_strech = subject_slot('value')(_do_strech)
    
    def _do_offset(self, value):
        if not value == 0 or -0.01:
            pass
        diff = 0.01
        newval = self._offset + diff
        if newval >= 0 and newval <= 1:
            self._offset = newval
            self.canonical_parent.timed_message(2, 'OFF:' + str(round(self._offset, 2)))
            self.canonical_parent.show_message('Split Offset : ' + str(round(self._offset, 2)))
            self.execute_split()
        

    _do_offset = subject_slot('value')(_do_offset)
    
    def _do_split_button(self, value):
        if value != 0:
            self.execute_split()
        

    _do_split_button = subject_slot('value')(_do_split_button)
    
    def _notes_changed(self):
        pass

    _notes_changed = subject_slot('notes')(_notes_changed)
    
    def _do_split(self, value):
        if not value == 0 or -1:
            pass
        diff = 1
        newval = self._split_value + diff
        if newval > 0 and newval <= 128:
            self._split_value = newval
            self.canonical_parent.timed_message(2, 'SPLIT:' + str(self._split_value))
            self.canonical_parent.show_message('Splits : ' + str(self._split_value))
            self.execute_split()
        

    _do_split = subject_slot('value')(_do_split)
    
    def _do_gate(self, value):
        if not value == 0 or -0.01:
            pass
        diff = 0.01
        newval = self._gate + diff
        if newval > 0.1 and newval <= 1:
            self._gate = newval
            self.canonical_parent.timed_message(2, 'GATE:' + str(int(round(self._gate * 100, 0))) + '%')
            self.canonical_parent.show_message('Split Gate: ' + str(int(round(self._gate * 100, 0))) + '%')
            self.execute_split()
        

    _do_gate = subject_slot('value')(_do_gate)
    
    def get_interval__(self, notelen):
        div = notelen / self._split_value
        n = self._split_value
        ls = []
        sum = 0
        ct = self._split_value
        rl = notelen
        bv = self._bend_val / 100
        param = abs(bv) * (self._split_value / 2)
        for i in range(n):
            div = rl / ct
            sz = div * (1 + param)
            ls.append(sz)
            ct -= 1
            rl -= sz
        
        sum = 0
        for v in ls:
            sum += v
        
        ratio = notelen / sum
        for i in range(len(ls)):
            ls[i] = ls[i] * ratio
        
        if not self._bend_val < 0 or ls.reverse():
            pass
        return ls

    
    def get_interval(self, notelen, splits, bend_val):
        div = notelen / splits
        n = splits
        ls = []
        param = abs(bend_val / 100)
        spl = 2
        for i in range(n):
            sec = notelen / spl
            ls.append(sec)
            if i < n - 2:
                spl *= 1 + param
                continue
        
        acc = 0
        for v in ls:
            acc += v
        
        ratio = notelen / acc
        for i in range(len(ls)):
            ls[i] = ls[i] * ratio
        
        if not bend_val < 0 or ls.reverse():
            pass
        return ls

    
    def _do_bend(self, value):
        if not value == 0 or -1:
            pass
        diff = 1
        newval = self._bend_val + diff
        if newval >= -100 and newval <= 100 and self._selected_note:
            self._bend_val = newval
            self.canonical_parent.timed_message(2, 'BEND:' + str(self._bend_val) + '%')
            self.canonical_parent.show_message('Split Bend: ' + str(self._bend_val) + '%')
            list = self.get_interval(self._selected_note[2], self._split_value, self._bend_val)
            self.execute_split()
        

    _do_bend = subject_slot('value')(_do_bend)
    
    def _on_selected_track_changed(self):
        debug_out(' Selected Track Changed ')

    
    def update(self):
        pass

    
    def refresh(self):
        pass