def send_value(self, value, force_send=False ):
   if value in self.blink_colors: 
     self.blinking = value
   else:
     self.blinking = False
   if value is not None:
     ButtonElement.send_value(self, value, force_send)
示例#2
0
class CustomEncoderElement(RingedEncoderElement):
    """ CustomEncoderElement for use with LI Code that handles updating LED ring types
    depending on the type of parameter being controlled. """

    def __init__(self, msg_type, channel, identifier, map_mode, name='', *a, **k):
        self._ring_mode_button = ButtonElement(False, 1, 15, identifier + 32, name=name +
                                               ' Ring_Mode_Button')
        super(CustomEncoderElement, self).__init__(msg_type, channel, identifier,
                                                   map_mode, name=name, *a, **k)

    def disconnect(self):
        self._ring_mode_button = None
        super(CustomEncoderElement, self).disconnect()

    def set_ring_mode(self, mode):
        if mode in SKIP_MODES:
            self._ring_mode_button.send_value(FILL_VALUE, True)
        else:
            self._ring_mode_button.send_value(self._get_ring_value(mode), True)

    def _get_ring_value(self, mode):
        param = self.mapped_parameter()
        parent = ('MixerDevice' if type(param.canonical_parent) ==
                  Live.MixerDevice.MixerDevice else param.canonical_parent.class_name)
        if parent in PARAM_DICT and param.original_name in PARAM_DICT[parent]:
            return PARAM_DICT[parent][param.original_name]
        if mode == MAP_BIPOLAR:
            return EQ_VALUE
        elif mode == MAP_QUANTIZED:
            return WALK_VALUE
        return FILL_VALUE
 def send_value(self, value, force_send=False ):
   self.current_color = value
   if value > 0 and value is not self.off_color:
     self.blinking = True
   else:
     self.blinking = False
   if value is not None:
     #super(FlashingButtonElement, self).send_value(value, force_send)
     ButtonElement.send_value(self, value, force_send)
示例#4
0
class Maschine(ControlSurface):
    """Basic Control Script for All Maschine Modell Mikro, Mikro Mk2, Mk1, Mk2, Studio"""
    __module__ = __name__

    def __init__(self, c_instance):
        super(Maschine, self).__init__(c_instance)
        with self.component_guard():
            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()

    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.0
        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
        self.set_sel_arm_button.send_value(
            self.arm_selected_track and 127 or 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):
        from pickle import loads, dumps
        from encodings import ascii
        nop(ascii)
        preferences = self._c_instance.preferences(self.preferences_name())
        self._pref_dict = {}
        try:
            self._pref_dict = loads(str(preferences))
        except Exception:
            pass

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

    def preferences_name(self):
        return 'Maschine'

    def _pre_serialize(self):
        from pickle import dumps
        from encodings import ascii
        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])
        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 button, (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)

        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.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

    @subject_slot('appointed_device')
    def _on_appointed_device_changed(self):
        self._modeselect._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

    @subject_slot('devices')
    def _on_devices_changed(self):
        pass

    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)

        return

    def update_display(self):
        with self.component_guard():
            with self._is_sending_scheduled_messages():
                self._task_group.update(0.1)
            self._modeselect.notify(self.blink_state)
            self.blink_state = (self.blink_state + 1) % 4
            self.display_task.tick()
            self.update_undo_redo(False)

    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
            self._undo_button.send_value(self.undo_state == 1 and 127 or 0)
        if self.song().can_redo != self.redo_state:
            self.redo_state = self.song().can_redo
            self._redo_button.send_value(self.redo_state == 1 and 127 or 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

    @subject_slot('value')
    def _do_fire_button(self, value):
        assert self._fire_button != None
        assert value in range(128)
        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()
        return

    @subject_slot('value')
    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'))

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

    @subject_slot('value')
    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)

    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)

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

    @subject_slot('value')
    def _do_key_color(self, value):
        assert value in range(128)
        if value != 0:
            self._modeselect._pad_mode.step_key_color_mode()

    @subject_slot('value')
    def _do_tap_tempo(self, value):
        assert value in range(128)
        if value != 0:
            self.song().tap_tempo()

    @subject_slot('value')
    def _do_toggle_cue(self, value):
        assert value in range(128)
        if value != 0:
            self.song().set_or_delete_cue()

    @subject_slot('value')
    def _do_toggle_prev_cue(self, value):
        assert value in range(128)
        if value != 0:
            self.song().jump_to_prev_cue()

    @subject_slot('value')
    def _do_toggle_next_cue(self, value):
        assert value in range(128)
        if value != 0:
            self.song().jump_to_next_cue()

    @subject_slot('value')
    def _do_toggle_send(self, value):
        assert value in range(128)
        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
            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))

        return

    @subject_slot('value')
    def _a_trk_left(self, value):
        assert value in range(128)
        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)

    @subject_slot('value')
    def _a_trk_right(self, value):
        assert value in range(128)
        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)

    @subject_slot('value')
    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)

    @subject_slot('value')
    def _nav_value_left(self, value):
        assert self._device_nav_button_left != None
        assert value in range(128)
        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)
        return

    @subject_slot('value')
    def _nav_value_right(self, value):
        assert self._device_nav_button_right != None
        assert value in range(128)
        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)
        return

    @subject_slot('value')
    def _do_focus_navigate(self, value):
        assert self._navigate_button != None
        assert value in range(128)
        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]))
        return

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

    @subject_slot('follow_song')
    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)

    @subject_slot('value')
    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)

    @subject_slot('value')
    def _hold_duplicate_action(self, value):
        if value != 0:
            pass

    @subject_slot('value')
    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()

    @subject_slot('value')
    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')

    @subject_slot('value')
    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')

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

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

    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
                        d1 += name[:6] + (i < 3 and '|' or '')
                    else:
                        d1 += '      ' + (i < 3 and '|' or '')

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

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

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

    def send_to_display(self, text, grid=0):
        if USE_DISPLAY == False:
            return
        if self._diplay_cache[grid] == text:
            return
        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 button, (track_index, scene_index) in self._bmatrix.iterbuttons():
            if button:
                button.send_color_direct(PColor.OFF[0])

        time.sleep(0.2)
        self._active = False
        self._suppress_send_midi = True
        super(Maschine, self).disconnect()
        return
示例#5
0
class KnobSection(CompoundComponent):
    _wheel_overide = None
    _mode = KSM_SCROLL
    _push_down = False
    scrub_mode = True
    alt_mode = False

    def __init__(self, modeselector, editsection, *a, **k):
        super(KnobSection, self).__init__(*a, **k)
        self._modesel = modeselector
        self._editsection = editsection
        self._modesel.connect_main_knob(self)
        is_momentary = True
        self.main_knob = SliderElement(MIDI_CC_TYPE, 1, 85)
        self.push_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 1, 87)
        self.volume_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 110)
        self.swing_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 111)
        self.tempo_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 112)
        self.xfade_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 116)
        self._mode_button = self.canonical_parent.create_gated_button(80, KSM_HUES[0])
        self._color_edit_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 113)
        self._set_inicliplen_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 122)
        self._set_quantize_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 3, 126)
        self.do_main.subject = self.main_knob
        self.do_main_push.subject = self.push_button
        self._do_volume.subject = self.volume_button
        self._do_swing.subject = self.swing_button
        self._do_tempo.subject = self.tempo_button
        self._do_xfade.subject = self.xfade_button
        self._do_toggle_mode.subject = self._mode_button
        self._do_color_button.subject = self._color_edit_button
        self._do_mikr_cliplen.subject = self._set_inicliplen_button
        self._do_mikr_quantize.subject = self._set_quantize_button
        self._do_dedicated_rec_quantize.subject = SliderElement(MIDI_CC_TYPE, 2, 112)
        self._do_dedicated_clip_quantize.subject = SliderElement(MIDI_CC_TYPE, 2, 113)
        self._radio_buttons = (
         self.volume_button, self.swing_button, self.tempo_button, self.xfade_button, self._color_edit_button)
        self._do_button_left.subject = ButtonElement(is_momentary, MIDI_CC_TYPE, 2, 120)
        self._do_button_right.subject = ButtonElement(is_momentary, MIDI_CC_TYPE, 2, 121)
        self.volume_button.send_value(0, True)
        self._mode_button.set_color(KSM_HUES[0])
        self.knob_action = self._scroll_action
        self._prev_mode = None
        self._prev_action = None
        return

    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)
        return

    def use_scrub_mode(self):
        return self.scrub_mode

    def set_scrub_mode(self, value):
        self.scrub_mode = value
        self.scrub_mode_button.send_value(value and 127 or 0)

    def set_override(self, overide_callback):
        if self._wheel_overide != overide_callback:
            self._wheel_overide = overide_callback
            self.volume_button.send_value(0, True)
            self.swing_button.send_value(0, True)
            self.tempo_button.send_value(0, True)
            self._mode_button.switch_off()
            self._mode = None
        return

    def reset_overide(self):
        if self._wheel_overide:
            self._wheel_overide = None
        return

    def _scroll_action(self, value):
        inc = value == 1 and 1 or -1
        self._modesel.navigate(inc, self._push_down, self._editsection.isShiftdown())

    def _do_channel_slider(self, value):
        song = self.song()
        if self._editsection.isShiftdown():
            dir = value == 127 and Live.Application.Application.View.NavDirection.left or Live.Application.Application.View.NavDirection.right
            self.application().view.scroll_view(dir, 'Detail/DeviceChain', True)
        else:
            if self._push_down:
                dir = value == 127 and -1 or 1
                scenes = song.scenes
                scene = song.view.selected_scene
                sindex = list(scenes).index(scene)
                sel_scene = sindex + dir
                if sel_scene >= 0 and sel_scene < len(scenes):
                    song.view.selected_scene = scenes[sel_scene]
            else:
                direction = value == 127 and Live.Application.Application.View.NavDirection.left or Live.Application.Application.View.NavDirection.right
                self.application().view.scroll_view(direction, 'Session', True)
                if self.canonical_parent.arm_selected_track:
                    arm_exclusive(song)

    def _do_transport(self, value):
        diff = value == 127 and -1 or 1
        jump = 4.0
        if self._push_down:
            if self._editsection.isShiftdown():
                jump = 0.25
            else:
                jump = 1.0
        else:
            if self._editsection.isShiftdown():
                jump = 0.5
        if self.scrub_mode:
            self.song().scrub_by(jump * diff)
        else:
            self.song().jump_by(jump * diff)

    @subject_slot('value')
    def do_main(self, value):
        if self._wheel_overide:
            self._wheel_overide(value == 1 and 1 or -1, self._editsection.isShiftdown(), self._push_down)
        else:
            if self.knob_action:
                self.knob_action(value)

    def _disable_radio_button(self):
        for button in self._radio_buttons:
            button.send_value(0, True)

    def enter_toggle_mode(self, mode=None):
        self.reset_overide()
        self.switch_pad_wheel_edit(False)
        self.alt_mode = False
        if self._mode < KSM_SCROLL or mode != None:
            if mode == None:
                self.switch_pad_wheel_edit(False)
                self._mode = KSM_SCROLL
            else:
                self._mode = mode
            self._disable_radio_button()
        else:
            modeval = self._mode + 1
            if modeval > KSM_TRANSPORT:
                modeval = KSM_SCROLL
            self._mode = modeval
        if self._mode == KSM_SCROLL:
            self.knob_action = self._scroll_action
            self.do_message('Main Knob -> Navigate')
        else:
            if self._mode == KSM_SELECT:
                self.knob_action = self._do_channel_slider
                self.do_message('Main Knob -> Select')
            else:
                if self._mode == KSM_TRANSPORT:
                    self.knob_action = self._do_transport
                    self.do_message('Main Knob -> Transport')
        self._mode_button.set_color(KSM_HUES[self._mode - KSM_SCROLL])
        return

    @subject_slot('value')
    def _do_toggle_mode(self, value):
        if value > 0:
            if self._editsection.isShiftdown():
                self.canonical_parent.toggle_nav_mode()
            else:
                self.enter_toggle_mode()

    def _scroll_xfade(self, value):
        diff = value == 127 and -1 or 1
        if self._wheel_overide:
            self._wheel_overide(diff, self._editsection.isShiftdown(), self._push_down)
        else:
            self.chg_xfade(diff)

    def _scroll_volume(self, value):
        diff = value == 127 and -1 or 1
        if self._wheel_overide:
            self._wheel_overide(diff, self._editsection.isShiftdown(), self._push_down)
        else:
            if self._editsection.isShiftdown():
                self.chg_cue(diff)
            else:
                self.chg_volume(diff)

    def _scroll_tempo(self, value):
        diff = value == 127 and -1 or 1
        if self._wheel_overide:
            self._wheel_overide(diff, self._editsection.isShiftdown(), self._push_down)
        else:
            if self._push_down:
                self.chg_tempo(diff * 0.1)
            else:
                if self._editsection.isShiftdown():
                    self.chg_tempo(diff * 0.01)
                else:
                    self.chg_tempo(diff)

    def _scroll_req_quantize(self, value):
        diff = value == 127 and -1 or 1
        if self._wheel_overide:
            self._wheel_overide(diff, self._editsection.isShiftdown(), self._push_down)
        else:
            song = self.song()
            if self._editsection.isShiftdown():
                quant = song.clip_trigger_quantization
                song.clip_trigger_quantization = max(0, min(13, quant + diff))
                self.do_message('Clip Quantize ' + CLIQ_DESCR[song.clip_trigger_quantization])
            else:
                rec_quant = song.midi_recording_quantization
                index = QUANT_CONST.index(rec_quant) + diff
                if index >= 0 and index < len(QUANT_CONST):
                    song.midi_recording_quantization = QUANT_CONST[index]
                    self.do_message(QUANT_DESCR[index])

    @subject_slot('value')
    def do_main_push(self, value):
        if value != 0:
            self.alt_mode = not self.alt_mode
        self._push_down = value != 0
        self._modesel.handle_push(value != 0)

    def switch_pad_wheel_edit(self, activate):
        if activate:
            self._color_edit_button.send_value(1, True)
            self._editsection.set_color_edit(True)
        else:
            self._color_edit_button.send_value(0, True)
            self._editsection.set_color_edit(False)

    def invoke_color_mode(self, active):
        if active and self._mode != KSM_EDIT:
            self._prev_mode = self._mode
            self._to_mode(KSM_EDIT)
        else:
            if not active and self._prev_mode != None:
                self.switch_pad_wheel_edit(False)
                self._to_mode(self._prev_mode)
                self._prev_mode = None
        return

    @subject_slot('value')
    def _do_color_button(self, value, force=False):
        if value > 0:
            if self._mode != KSM_EDIT:
                self._prev_mode = self._mode
                self.reset_overide()
                self._to_mode(KSM_EDIT)
            elif self._prev_mode != None:
                self.switch_pad_wheel_edit(False)
                self._to_mode(self._prev_mode)
                self._prev_mode = None
        return

    def _to_mode(self, mode):
        button = None
        if mode == KSM_VOLUME:
            button = self.volume_button
            self.knob_action = self._scroll_volume
            self.switch_pad_wheel_edit(False)
        else:
            if mode == KSM_SWING:
                button = self.swing_button
                self.knob_action = self._scroll_req_quantize
                self.switch_pad_wheel_edit(False)
            else:
                if mode == KSM_TEMPO:
                    button = self.tempo_button
                    self.knob_action = self._scroll_tempo
                    self.switch_pad_wheel_edit(False)
                else:
                    if mode == KSM_XFADE:
                        button = self.xfade_button
                        self.knob_action = self._scroll_xfade
                        self.switch_pad_wheel_edit(False)
                    else:
                        if mode == KSM_EDIT:
                            self._editsection.set_color_edit(True)
                        else:
                            self.enter_toggle_mode(mode)
        self._mode = mode
        for rbutton in self._radio_buttons:
            if rbutton != button:
                rbutton.send_value(0)

        if button:
            self._mode_button.switch_off()
            button.send_value(127, True)
        return

    def _edit_color(self, value):
        diff = value == 127 and -1 or 1
        if self._wheel_overide:
            self._wheel_overide(diff, self._editsection.isShiftdown(), self._push_down)
        else:
            self._editsection.edit_colors(diff)

    @subject_slot('value')
    def _do_button_left(self, value):
        if value != 0:
            self._modesel.navigate(-1, self._editsection.isShiftdown(), False)

    @subject_slot('value')
    def _do_button_right(self, value):
        if value != 0:
            self._modesel.navigate(1, self._editsection.isShiftdown(), False)

    @subject_slot('value')
    def _do_mikr_cliplen(self, value):
        if value == 0:
            self.knob_action = self._prev_action
        else:
            self._prev_action = self.knob_action
            self.knob_action = self._modify_init_cliplen

    @subject_slot('value')
    def _do_mikr_quantize(self, value):
        if value == 0:
            self.knob_action = self._prev_action
        else:
            self._prev_action = self.knob_action
            self.knob_action = self._modify_quant_grid

    def _modify_init_cliplen(self, value):
        if self._push_down:
            self._editsection.mod_new_initlen(value == 1 and 1 or -1)
        else:
            self._editsection.mod_new_initlen(value == 1 and 4 or -4)

    def _modify_quant_grid(self, value):
        self._editsection.mod_quant_size(value == 1 and 1 or -1)

    @subject_slot('value')
    def _do_xfade(self, value):
        if value > 0 and self._mode != KSM_XFADE:
            self.reset_overide()
            self._to_mode(KSM_XFADE)

    @subject_slot('value')
    def _do_volume(self, value):
        if value > 0 and self._mode != KSM_VOLUME:
            self.reset_overide()
            self._to_mode(KSM_VOLUME)

    @subject_slot('value')
    def _do_swing(self, value):
        if value > 0 and self._mode != KSM_SWING:
            self.reset_overide()
            self._to_mode(KSM_SWING)

    @subject_slot('value')
    def _do_tempo(self, value):
        if value > 0 and self._mode != KSM_TEMPO:
            self.reset_overide()
            self._to_mode(KSM_TEMPO)

    @subject_slot('value')
    def _do_dedicated_clip_quantize(self, value):
        diff = value == 127 and -1 or 1
        song = self.song()
        quant = song.clip_trigger_quantization
        song.clip_trigger_quantization = max(0, min(13, quant + diff))
        self.do_message('Clip Quantize ' + CLIQ_DESCR[song.clip_trigger_quantization])

    @subject_slot('value')
    def _do_dedicated_rec_quantize(self, value):
        diff = value == 127 and -1 or 1
        song = self.song()
        rec_quant = song.midi_recording_quantization
        index = QUANT_CONST.index(rec_quant) + diff
        if index >= 0 and index < len(QUANT_CONST):
            song.midi_recording_quantization = QUANT_CONST[index]
            self.do_message('Rec Quantize: ' + QUANT_STRING[index])

    def chg_tempo(self, diff):
        self.song().tempo = max(20, min(999, self.song().tempo + diff))
        self.canonical_parent.timed_message(2, 'Tempo: ' + str(round(self.song().tempo, 2)))

    def chg_volume(self, diff):
        if self._push_down:
            self.song().master_track.mixer_device.volume.value = calc_new_parm(self.song().master_track.mixer_device.volume, diff)
        else:
            repeat(self.song().master_track.mixer_device.volume, diff)

    def chg_xfade(self, diff):
        if self._push_down:
            self.song().master_track.mixer_device.crossfader.value = calc_new_parm(self.song().master_track.mixer_device.crossfader, diff)
        else:
            repeat(self.song().master_track.mixer_device.crossfader, diff)

    def chg_cue(self, diff):
        if self._push_down:
            self.song().master_track.mixer_device.cue_volume.value = calc_new_parm(self.song().master_track.mixer_device.cue_volume, diff)
        else:
            repeat(self.song().master_track.mixer_device.cue_volume, diff)

    def update(self):
        pass

    def refresh(self):
        pass
class AudioClipEditComponent(CompoundComponent):
    """
    classdocs
    """

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

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

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

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

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

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

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

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

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

    @subject_slot("value")
    def _action_loop_end(self, value):
        if not (value == 1 and 1):
            inc = -1
            if self.selected_clip_slot and self.selected_clip_slot.has_clip:
                clip = self.selected_clip_slot.clip
                ls = clip.loop_start
                le = clip.loop_end
                le = max(ls + self.loop_inc, le + inc * self.loop_inc)
                clip.loop_end = le
                clip.end_marker = self.mv_loop and le
            self.canonical_parent.timed_message(2, loop_str(clip))

    def update(self):
        pass

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

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

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

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

    @subject_slot("has_clip")
    def _on_has_clip_changed(self):
        self._update_clip_name()

    @subject_slot("name")
    def _on_name_changed(self):
        self._update_clip_name()

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

    def on_selected_track_changed(self):
        self.update_selected_clip()

    def on_selected_scene_changed(self):
        self.update_selected_clip()

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

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

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

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

    @subject_slot("gain")
    def _on_gain_changed(self):
        cs = self.song().view.highlighted_clip_slot
        if cs and cs.has_clip and cs.clip.is_audio_clip:
            self._gain_slider.send_value(gain_to_midi(cs.clip.gain))
class Launchpad(ControlSurface):
    """ Script for Novation's Launchpad Controller """

    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
            self._suppress_send_midi = True
            self._suppress_session_highlight = True
            is_momentary = True
            self._suggested_input_port = 'Launchpad'
            self._suggested_output_port = 'Launchpad'
            self._control_is_with_automap = False
            self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)
            self._user_byte_write_button.name = 'User_Byte_Button'
            self._user_byte_write_button.send_value(1)
            self._user_byte_write_button.add_value_listener(self._user_byte_value)
            self._wrote_user_byte = False
            self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143
            matrix = ButtonMatrixElement()
            matrix.name = 'Button_Matrix'
            for row in range(8):
                button_row = []
                for column in range(8):
                    button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, row * 16 + column)
                    button.name = str(column) + '_Clip_' + str(row) + '_Button'
                    button_row.append(button)

                matrix.add_row(tuple(button_row))

            self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0, optimized_send_midi=False)
            self._config_button.add_value_listener(self._config_value)
            top_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0, 104 + index) for index in range(8) ]
            side_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index]) for index in range(8) ]
            top_buttons[0].name = 'Bank_Select_Up_Button'
            top_buttons[1].name = 'Bank_Select_Down_Button'
            top_buttons[2].name = 'Bank_Select_Left_Button'
            top_buttons[3].name = 'Bank_Select_Right_Button'
            top_buttons[4].name = 'Session_Button'
            top_buttons[5].name = 'User1_Button'
            top_buttons[6].name = 'User2_Button'
            top_buttons[7].name = 'Mixer_Button'
            side_buttons[0].name = 'Vol_Button'
            side_buttons[1].name = 'Pan_Button'
            side_buttons[2].name = 'SndA_Button'
            side_buttons[3].name = 'SndB_Button'
            side_buttons[4].name = 'Stop_Button'
            side_buttons[5].name = 'Trk_On_Button'
            side_buttons[6].name = 'Solo_Button'
            side_buttons[7].name = 'Arm_Button'
            self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button)
            self._selector.name = 'Main_Modes'
            for control in self.controls:
                if isinstance(control, ConfigurableButtonElement):
                    control.add_value_listener(self._button_value)

            self.set_highlighting_session_component(self._selector.session_component())
            self._suppress_session_highlight = False

    def disconnect(self):
        self._suppress_send_midi = True
        for control in self.controls:
            if isinstance(control, ConfigurableButtonElement):
                control.remove_value_listener(self._button_value)

        self._selector = None
        self._user_byte_write_button.remove_value_listener(self._user_byte_value)
        self._config_button.remove_value_listener(self._config_value)
        ControlSurface.disconnect(self)
        self._suppress_send_midi = False
        self._config_button.send_value(32)
        self._config_button.send_value(0)
        self._config_button = None
        self._user_byte_write_button.send_value(0)
        self._user_byte_write_button = None

    def refresh_state(self):
        ControlSurface.refresh_state(self)
        self.schedule_message(5, self._update_hardware)

    def handle_sysex(self, midi_bytes):
        if len(midi_bytes) == 8:
            if midi_bytes[1:5] == (0, 32, 41, 6):
                response = long(midi_bytes[5])
                response += long(midi_bytes[6]) << 8
                if response == Live.Application.encrypt_challenge2(self._challenge):
                    self._on_handshake_successful()

    def _on_handshake_successful(self):
        self._suppress_send_midi = False
        self.set_enabled(True)

    def build_midi_map(self, midi_map_handle):
        ControlSurface.build_midi_map(self, midi_map_handle)
        if self._selector.mode_index == 1:
            new_channel = self._selector.channel_for_current_mode()
            for note in DRUM_NOTES:
                self._translate_message(MIDI_NOTE_TYPE, note, 0, note, new_channel)

    def _send_midi(self, midi_bytes, optimized = None):
        sent_successfully = False
        if not self._suppress_send_midi:
            sent_successfully = ControlSurface._send_midi(self, midi_bytes, optimized=optimized)
        return sent_successfully

    def _update_hardware(self):
        self._suppress_send_midi = False
        self._wrote_user_byte = True
        self._user_byte_write_button.send_value(1)
        self._suppress_send_midi = True
        self.set_enabled(False)
        self._suppress_send_midi = False
        self._send_challenge()

    def _send_challenge(self):
        for index in range(4):
            challenge_byte = self._challenge >> 8 * index & 127
            self._send_midi((176, 17 + index, challenge_byte))

    def _user_byte_value(self, value):
        if not value in range(128):
            raise AssertionError
            enabled = self._wrote_user_byte or value == 1
            self._control_is_with_automap = not enabled
            self._suppress_send_midi = self._control_is_with_automap
            if not self._control_is_with_automap:
                for control in self.controls:
                    if isinstance(control, ConfigurableButtonElement):
                        control.set_force_next_value()

            self._selector.set_mode(0)
            self.set_enabled(enabled)
            self._suppress_send_midi = False
        else:
            self._wrote_user_byte = False

    def _button_value(self, value):
        raise value in range(128) or AssertionError

    def _config_value(self, value):
        raise value in range(128) or AssertionError

    def _set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks):
        if not self._suppress_session_highlight:
            ControlSurface._set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks)
class AxiomPro(ControlSurface):
    """ Script for the M-Audio Axiom Pro """

    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
            is_momentary = True
            self._device_selection_follows_track_selection = True
            self.set_pad_translations(PAD_TRANSLATIONS)
            self._suggested_input_port = 'HyperControl'
            self._suggested_output_port = 'HyperControl'
            self._display_on_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, 15, 79)
            self._waiting_for_first_response = True
            mixer1 = DisplayingMixerComponent(0)
            mixer1.set_select_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 111), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 110))
            mixer1.set_mute_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 12))
            mixer1.set_solo_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 13))
            mixer2 = NotifyingMixerComponent(8)
            mixer2.set_bank_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 15), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 14))
            mixer2.master_strip().set_volume_control(SliderElement(MIDI_CC_TYPE, 15, 41))
            for index in range(8):
                mixer2.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, 15, 33 + index))

            device = PageableDeviceComponent()
            self.set_device_component(device)
            ffwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 115)
            rwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 114)
            loop_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 113)
            transport = TransportComponent()
            transport.set_stop_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 116))
            transport.set_play_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 117))
            transport.set_record_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 118))
            session = SessionComponent(0, 0)
            transport_view_modes = TransportViewModeSelector(transport, session, ffwd_button, rwd_button, loop_button)
            select_button_modes = SelectButtonModeSelector(mixer2, tuple([ ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 49 + offset) for offset in range(8) ]))
            select_button_modes.set_mode_toggle(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 57))
            self._mixer_encoder_modes = EncoderMixerModeSelector(mixer2)
            encoders = []
            for offset in range(8):
                encoders.append(PeekableEncoderElement(MIDI_CC_TYPE, 15, 17 + offset, Live.MidiMap.MapMode.relative_smooth_two_compliment))
                encoders[-1].set_feedback_delay(-1)

            mixer_or_device = MixerOrDeviceModeSelector(self._mixer_encoder_modes, device, tuple(encoders), tuple([ ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 74 + offset) for offset in range(4) ]))
            mixer_or_device.set_mode_toggle(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 109))
            mixer_or_device.set_peek_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 78))
            self._track_display = PhysicalDisplayElement(8, 1)
            self._track_display.set_clear_all_message(SYSEX_START + (16, 247))
            self._track_display.set_message_parts(SYSEX_START + (17, 1, 0, 0), (247,))
            self._track_display.segment(0).set_data_source(mixer1.selected_strip().track_name_data_source())
            device_display = PhysicalDisplayElement(8, 1)
            device_display.set_message_parts(SYSEX_START + (17, 1, 0, 10), (247,))
            parameter_display = PhysicalDisplayElement(16, 1)
            parameter_display.set_message_parts(SYSEX_START + (17, 2, 0, 0), (247,))
            select_button_modes.set_mode_display(parameter_display)
            mixer1.set_display(parameter_display)
            mixer2.set_bank_display(parameter_display)
            page_displays = []
            for index in range(4):
                page_displays.append(PhysicalDisplayElement(5, 1))
                page_displays[-1].set_message_parts(SYSEX_START + (17,
                 4,
                 index,
                 0), (247,))

            encoder_display = PhysicalDisplayElement(80, 8)
            encoder_display.set_message_parts(SYSEX_START + (17, 3), (247,))
            for index in range(8):
                pos_id = tuple()
                if index != 0:
                    pos_id += (0,)
                if index > 3:
                    pos_id += (index % 4, 13)
                else:
                    pos_id += (index % 4, 0)
                encoder_display.segment(index).set_position_identifier(pos_id)

            mixer_or_device.set_displays(encoder_display, parameter_display, device_display, tuple(page_displays))
            for component in self.components:
                component.set_enabled(False)

    def refresh_state(self):
        ControlSurface.refresh_state(self)
        self._waiting_for_first_response = True
        self.schedule_message(10, self._send_midi, SYSEX_START + (32, 46, 247))

    def handle_sysex(self, midi_bytes):
        if midi_bytes[0:-2] == SYSEX_START + (32,):
            msg_id_byte = midi_bytes[-2]
            is_setup_response = msg_id_byte in (46, 38)
            has_sliders = msg_id_byte == 46
            if is_setup_response:
                if self._waiting_for_first_response:
                    self._waiting_for_first_response = False
                    self._display_on_button.send_value(0)
                    for component in self.components:
                        component.set_enabled(True)

                    self._display_on_button.send_value(127)
                    self._send_midi(SYSEX_START + (16, 247))
                    self._send_midi(SYSEX_START + (17, 3, 0, 1, 65, 98, 108, 101, 116, 111, 110, 32, 76, 105, 118, 101, 32, 67, 111, 110, 116, 114, 111, 108, 32, 0, 1, 4, 83, 117, 114, 102, 97, 99, 101, 32, 118, 49, 46, 48, 46, 48, 46, 247))
                self._mixer_encoder_modes.set_show_volume_page(not has_sliders)
                for display in self._displays:
                    display.set_block_messages(False)

                self.schedule_message(25, self._refresh_displays)
            elif msg_id_byte == 43:
                self._send_midi(SYSEX_START + (16, 247))
                for display in self._displays:
                    if display is self._track_display:
                        display.update()
                    else:
                        display.set_block_messages(True)

    def disconnect(self):
        ControlSurface.disconnect(self)
        self._send_midi(SYSEX_START + (32, 0, 247))
        self._send_midi(SYSEX_START + (16, 247))
        self._send_midi(SYSEX_START + (17, 3, 0, 4, 65, 98, 108, 101, 116, 111, 110, 32, 76, 105, 118, 101, 32, 67, 111, 110, 116, 114, 111, 108, 32, 0, 1, 4, 83, 117, 114, 102, 97, 99, 101, 32, 67, 108, 111, 115, 101, 100, 46, 247))
示例#9
0
class MidiEditSection(CompoundComponent):
    _current_clip = None
    _split_value = 4
    _base_note = None
    _gate = 1.0
    _selected_note = None
    _note_pos = None
    _note_len = 0.0
    _bend_val = 0
    _offset = 0.0
    _transpose = 0
    _vel_fade = 0
    _fade_mode = FADE_TIME
    _note_set = None
    _note_index = 0

    def __init__(self, *a, **k):
        super(MidiEditSection, self).__init__(*a, **k)
        is_momentary = True
        self.split_knob = SliderElement(MIDI_CC_TYPE, 5, 70)
        self.gate_knob = SliderElement(MIDI_CC_TYPE, 5, 71)
        self.bend_knob = SliderElement(MIDI_CC_TYPE, 5, 72)
        self.offset_knob = SliderElement(MIDI_CC_TYPE, 5, 73)
        self.strech_knob = SliderElement(MIDI_CC_TYPE, 5, 74)
        self.fade_knob = SliderElement(MIDI_CC_TYPE, 5, 75)
        self.transpose_knob = SliderElement(MIDI_CC_TYPE, 5, 77)
        self.edit_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 5, 60)
        self.split_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 5, 61)
        self.init_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 5, 62)
        self.delete_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 5, 63)
        self.select_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 5, 64)
        self._do_edit_button.subject = self.edit_button
        self._do_split_button.subject = self.split_button
        self._do_delete.subject = self.delete_button
        self._do_init.subject = self.init_button
        self._do_select.subject = self.select_button
        self._do_split.subject = self.split_knob
        self._do_gate.subject = self.gate_knob
        self._do_bend.subject = self.bend_knob
        self._do_offset.subject = self.offset_knob
        self._do_strech.subject = self.strech_knob
        self._do_fade.subject = self.fade_knob
        self._do_transpose.subject = self.transpose_knob

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

    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]))

    @subject_slot('value')
    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, 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))
        return

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

        return

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

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

    def get_selected_note(self):
        clip_slot = self.song().view.highlighted_clip_slot
        if clip_slot 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]
        return

    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.0:
                    list.append((note, pos, notvlen, vel, mute))
                pos += div
                if self._fade_mode == FADE_EVENT:
                    vel += velinc
                else:
                    rp = (pos - sp) / notelen
                    vel = startvel + (endvel - startvel) * rp

            self._current_clip.replace_selected_notes(tuple(list))

    @subject_slot('value')
    def _do_transpose(self, value):
        diff = value == REL_KNOB_DOWN and -1 or 1
        self.execute_transpose(diff)

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

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

    @subject_slot('value')
    def _do_offset(self, value):
        diff = value == REL_KNOB_DOWN and -0.01 or 0.01
        newval = self._offset + diff
        if newval >= 0.0 and newval <= 1.0:
            self._offset = newval
            self.canonical_parent.timed_message(2, 'OFF:' + str(round(self._offset, 2)))
            self.canonical_parent.show_message('Split Offset : ' + str(round(self._offset, 2)))
            self.execute_split()

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

    @subject_slot('notes')
    def _notes_changed(self):
        pass

    @subject_slot('value')
    def _do_split(self, value):
        diff = value == REL_KNOB_DOWN and -1 or 1
        newval = self._split_value + diff
        if newval > 0 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()

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

    def get_interval__(self, notelen):
        div = notelen / self._split_value
        n = self._split_value
        ls = []
        sum = 0
        ct = self._split_value
        rl = notelen
        bv = self._bend_val / 100.0
        param = abs(bv) * (self._split_value / 2)
        for i in range(n):
            div = rl / ct
            sz = div * (1.0 + param)
            ls.append(sz)
            ct -= 1
            rl -= sz

        sum = 0
        for v in ls:
            sum += v

        ratio = notelen / sum
        for i in range(len(ls)):
            ls[i] = ls[i] * ratio

        return self._bend_val < 0 and ls.reverse() or ls

    def get_interval(self, notelen, splits, bend_val):
        div = notelen / splits
        n = splits
        ls = []
        param = abs(bend_val / 100.0)
        spl = 2
        for i in range(n):
            sec = notelen / spl
            ls.append(sec)
            if i < n - 2:
                spl *= 1.0 + param

        acc = 0
        for v in ls:
            acc += v

        ratio = notelen / acc
        for i in range(len(ls)):
            ls[i] = ls[i] * ratio

        return bend_val < 0.0 and ls.reverse() or ls

    @subject_slot('value')
    def _do_bend(self, value):
        diff = value == REL_KNOB_DOWN and -1 or 1
        newval = self._bend_val + diff
        if newval >= -100 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()

    def _on_selected_track_changed(self):
        debug_out(' Selected Track Changed ')

    def update(self):
        pass

    def refresh(self):
        pass
示例#10
0
class MonoNavSection(CompoundComponent):

    def __init__(self, mode_selector, *a, **k):
        super(MonoNavSection, self).__init__(*a, **k)
        is_momentary = True
        self._modesel = mode_selector
        self._device_bank_registry = DeviceBankRegistry()
        self.volume_knob = SliderElement(MIDI_CC_TYPE, 0, 40)
        self.tempo_knob = SliderElement(MIDI_CC_TYPE, 0, 41)
        self.swing_knob = SliderElement(MIDI_CC_TYPE, 0, 42)
        self.mode_button = ButtonElement(True, MIDI_CC_TYPE, 2, 86)
        self.alt_button = ButtonElement(True, MIDI_CC_TYPE, 2, 81)
        self._do_left_knob.subject = self.volume_knob
        self._do_center_knob.subject = self.tempo_knob
        self._do_right_knob.subject = self.swing_knob
        self._do_mode_button.subject = self.mode_button
        self._do_alt_button.subject = self.alt_button
        self._mode = MODE_ADJUST
        self._alt_down = False

    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)

    @subject_slot('value')
    def _do_left_knob(self, value):
        if not (value == 0 and -1):
            diff = 1
            if self._mode == MODE_ADJUST:
                self.canonical_parent.isShiftDown() and self.chg_cue(diff)
            else:
                self.chg_volume(diff)
        else:
            self._do_channel_selection(diff)

    @subject_slot('value')
    def _do_center_knob(self, value):
        if not (value == 0 and -1):
            diff = 1
            if self._mode == MODE_ADJUST:
                self.canonical_parent.isShiftDown() and self.chg_tempo(diff * 0.1)
            else:
                self.chg_tempo(diff)
        else:
            self._modesel.navigate(diff, False, self.canonical_parent.isShiftDown())

    def chg_tempo(self, diff):
        self.song().tempo = max(20, min(999, self.song().tempo + diff))
        self.canonical_parent.timed_message(2, 'Tempo: ' + str(round(self.song().tempo, 2)))

    def chg_volume(self, diff):
        if self._alt_down:
            self.song().master_track.mixer_device.volume.value = calc_new_parm(self.song().master_track.mixer_device.volume, diff)
        else:
            repeat(self.song().master_track.mixer_device.volume, diff)

    def chg_cue(self, diff):
        if self._alt_down:
            self.song().master_track.mixer_device.cue_volume.value = calc_new_parm(self.song().master_track.mixer_device.cue_volume, diff)
        else:
            repeat(self.song().master_track.mixer_device.cue_volume, diff)

    def _do_channel_selection(self, dir):
        song = self.song()
        if self._alt_down:
            if self.canonical_parent.isShiftDown():
                if dir == 1:
                    self.canonical_parent._device._bank_up_value(1)
                else:
                    self.canonical_parent._device._bank_down_value(1)
            else:
                ndir = dir == -1 and Live.Application.Application.View.NavDirection.left or Live.Application.Application.View.NavDirection.right
                self.application().view.scroll_view(ndir, 'Detail/DeviceChain', True)
        elif self.canonical_parent.isShiftDown():
            scenes = song.scenes
            scene = song.view.selected_scene
            sindex = list(scenes).index(scene)
            sel_scene = sindex + dir
            if sel_scene >= 0 and sel_scene < len(scenes):
                song.view.selected_scene = scenes[sel_scene]
        elif not (dir == -1 and Live.Application.Application.View.NavDirection.left):
            direction = Live.Application.Application.View.NavDirection.right
            self.application().view.scroll_view(direction, 'Session', True)
            self.canonical_parent.arm_selected_track and arm_exclusive(song)

    @subject_slot('value')
    def _do_right_knob(self, value):
        diff = value == 0 and -1 or 1
        if self._mode == MODE_ADJUST:
            song = self.song()
            if self.canonical_parent.isShiftDown():
                quant = song.clip_trigger_quantization
                song.clip_trigger_quantization = max(0, min(13, quant + diff))
                self.do_message('Clip Quantize ' + CLIQ_DESCR[song.clip_trigger_quantization])
            else:
                rec_quant = song.midi_recording_quantization
                index = QUANT_CONST.index(rec_quant) + diff
                if index >= 0 and index < len(QUANT_CONST):
                    song.midi_recording_quantization = QUANT_CONST[index]
                    self.do_message(QUANT_DESCR[index])
        else:
            self._modesel.navigate(diff, True, self.canonical_parent.isShiftDown())

    @subject_slot('value')
    def _do_mode_button(self, value):
        if value != 0:
            if self.canonical_parent.isShiftDown():
                self.canonical_parent.toggle_nav_mode()
            elif self._alt_down:
                self.canonical_parent._do_focus_navigate(1)
            elif self._mode == MODE_ADJUST:
                self._mode = MODE_NAV
                self.do_message('Master Knobs control navigation')
                self.mode_button.send_value(1, True)
            elif self._mode == MODE_NAV:
                self._mode = MODE_ADJUST
                self.do_message('Master Knobs control Volume | Tempo | Quantization')
                self.mode_button.send_value(0, True)

    @subject_slot('value')
    def _do_alt_button(self, value):
        self._alt_down = value > 0

    def refresh(self):
        pass

    def update(self):
        pass

    def disconnect(self):
        super(MonoNavSection, self).disconnect()
class NoteRepeatComponent(CompoundComponent):
    __module__ = __name__
    __doc__ = ' Noter Repeat Handler'
    _knob_handler = None

    def __init__(self, note_repeat = None, *a, **k):
        super(NoteRepeatComponent, self).__init__(*a, **k)
        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

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

        self.nr_frq = CTRL_TO_FREQ[4][1]
        self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0
        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:
            button.send_value(button.active and 1 or 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]

    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 += '|'

        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 and maxindex):
                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]
                self.nr_frq = button.active and CFG_REPEAT_FREQUENCIES[new_idx]
                self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0

    @subject_slot('value')
    def _do_change_nr_1(self, value):
        self.mod_button(self._cfg_buttons[0], value == 0 and -1 or 1, 1)
        self.show_note_rates()

    @subject_slot('value')
    def _do_change_nr_2(self, value):
        self.mod_button(self._cfg_buttons[1], value == 0 and -1 or 1, 2)
        self.show_note_rates()

    @subject_slot('value')
    def _do_change_nr_3(self, value):
        self.mod_button(self._cfg_buttons[2], value == 0 and -1 or 1, 3)
        self.show_note_rates()

    @subject_slot('value')
    def _do_change_nr_4(self, value):
        self.mod_button(self._cfg_buttons[3], value == 0 and -1 or 1, 4)
        self.show_note_rates()

    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)

    @subject_slot('value')
    def _adjust_cfg_value(self, value):
        button = self._current_nr_button
        if button and button.cfg and (self.nr_down or button.hold or self._hold_mode and button.active):
            if not (value == 127 and -1):
                inc = 1
                cindex = button.fr_idx
                maxindex = len(CFG_REPEAT_FREQUENCIES) - 1
                minindex = 0
                self._cfg_down and inc *= 2
                maxindex = cindex % 2 == 0 and maxindex or 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.0 / self.nr_frq * 4.0
        elif self._knob_handler:
            self._knob_handler.do_main(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.0
                    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.0 / self.nr_frq * 4.0
                    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.0 / self.nr_frq * 4.0
                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

    @subject_slot('value')
    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.0 / self.nr_frq * 4.0
        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.0 / self.nr_frq * 4.0
        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.0 / self.nr_frq * 4.0
            self._note_repeat.enabled = True

    def disconnect(self):
        super(NoteRepeatComponent, self).disconnect()
class F1ColorButtonElement(ButtonElement):
    ' SPECIAL BUTTON CLASS THAT INTERNALLY HOLDS 3 BUTTONS FOR HANDLING RGB / HSV AND ONE BUTTON THAT HANDLES INCOMING MIDI'
    __module__ = __name__
    """ MAIN CONSTRUCTOR """
    def __init__(self, is_momentary, msg_type, identifier, hsvChannels,
                 controlChannel, rgbColor, name):
        log(True, __name__)
        ButtonElement.__init__(self, is_momentary, msg_type, controlChannel,
                               identifier)
        self.name = name + " Control"
        # create 3 buttons for HSV
        self.hueButton = ButtonElement(is_momentary, msg_type, hsvChannels[0],
                                       identifier)
        self.satButton = ButtonElement(is_momentary, msg_type, hsvChannels[1],
                                       identifier)
        self.valButton = ButtonElement(is_momentary, msg_type, hsvChannels[2],
                                       identifier)
        self.id = identifier
        # color
        self.hsv_fader = None
        rgbColor = _liveOsTools.colorsys.hex2rgb(rgbColor)
        hsvColor = _liveOsTools.colorsys.rgb_to_hsv(rgbColor[0] / 255.0,
                                                    rgbColor[1] / 255.0,
                                                    rgbColor[2] / 255.0)
        self.hsv_fader = HSVFader(hsvColor[0], hsvColor[1], hsvColor[2])
        self.send_current_color()
        log(False, __name__)

    """ DISCONNECT """

    def disconnect(self):
        log(__name__, "disconnect")
        self.hueButton = None
        self.hsvColor = None
        self.satButton = None
        self.hsv_fader = None

    """ FADE ONCE TO THAT VALUE """

    def fade_to(self, hue, sat, val, time):
        #log(__name__, "fade_to: hue("+str(hue)+"), sat("+str(sat)+"), val("+str(val)+"), time("+str(time)+")")
        self.hsv_fader.add_fade(hue, sat, val, time)

    """ UPDATE FRAME TIME BASED """

    def process(self, time_in_samples):
        #log(__name__, "update")
        #self.hsv_fader.process(time_in_samples)
        self.send_current_color()

    """ SEND COLOR """

    def send_current_color(self):
        # send color values to buttons
        #log("sending: on CC: "+ str(self.id)+ " -- val: "+ str([int(self.hsv_fader.current_color[INDEX_HUE] * MIDI_RANGE),int(self.hsv_fader.current_color[INDEX_SAT] * MIDI_RANGE),int(self.hsv_fader.current_color[INDEX_VAL] * MIDI_RANGE)]))
        self.hueButton.send_value(
            int(self.hsv_fader.current_color[INDEX_HUE] * MIDI_RANGE), True)
        self.satButton.send_value(
            int(self.hsv_fader.current_color[INDEX_SAT] * MIDI_RANGE), True)
        self.valButton.send_value(
            int(self.hsv_fader.current_color[INDEX_VAL] * MIDI_RANGE), True)

    """ SEND BASE COLOR """

    def send_base_color(self):
        self.hueButton.send_value(
            int(self.hsv_fader.get_base_color()[INDEX_HUE] * MIDI_RANGE), True)
        self.satButton.send_value(
            int(self.hsv_fader.get_base_color()[INDEX_SAT] * MIDI_RANGE), True)
        self.valButton.send_value(
            int(self.hsv_fader.get_base_color()[INDEX_VAL] * MIDI_RANGE), True)

    """ SET THE MAIN COLOR """

    def set_base_color(self, liveRGBcolor):
        rgbColor = _liveOsTools.colorsys.hex2rgb(liveRGBcolor)
        hsvColor = _liveOsTools.colorsys.rgb_to_hsv(rgbColor[0] / 255.0,
                                                    rgbColor[1] / 255.0,
                                                    rgbColor[2] / 255.0)
        log(__name__,
            "new base color: rgb=" + str(rgbColor) + ", hsv=" + str(hsvColor))
        self.hsv_fader.set_base_color(hsvColor[0], hsvColor[1], hsvColor[2])
        self.send_base_color()
示例#13
0
class APCmini(ControlSurface):

	""" Script for Novation's Launchpad Controller """

	def __init__(self, c_instance):
		live = Live.Application.get_application()
		self._live_major_version = live.get_major_version()
		self._live_minor_version = live.get_minor_version()
		self._live_bugfix_version = live.get_bugfix_version()
		ControlSurface.__init__(self, c_instance)
		#self._device_selection_follows_track_selection = True
		with self.component_guard():
			self._suppress_send_midi = True
			self._suppress_session_highlight = True

			is_momentary = True
			self._suggested_input_port = 'Launchpad'
			self._suggested_output_port = 'Launchpad'
			self._control_is_with_automap = False
			self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)		# Apparently this CC is used to enable feedback, ie lighting up buttons that you pressed
			self._user_byte_write_button.name = 'User_Byte_Button'
			self._user_byte_write_button.send_value(1)
			self._user_byte_write_button.add_value_listener(self._user_byte_value)
			self._wrote_user_byte = False
			self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143
			matrix = ButtonMatrixElement()
			matrix.name = 'Button_Matrix'
			for row in range(8):
				button_row = []
				for column in range(8):
					button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, (7-row) * 8 + column)	# APCmini rows are in reverse order from Launchpad
					button.name = str(column) + '_Clip_' + str(row) + '_Button'
					button_row.append(button)

				matrix.add_row(tuple(button_row))

			self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0, optimized_send_midi=False)	# Control goes through here on LP, no real equivalent in APCmini (I don't think)
			self._config_button.add_value_listener(self._config_value)
			top_buttons = [ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 64 + index) for index in range(8)]
			side_buttons = [ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index]) for index in range(8)]
			top_buttons[0].name = 'Bank_Select_Up_Button'
			top_buttons[1].name = 'Bank_Select_Down_Button'
			top_buttons[2].name = 'Bank_Select_Left_Button'
			top_buttons[3].name = 'Bank_Select_Right_Button'
			top_buttons[4].name = 'Session_Button'
			top_buttons[5].name = 'User1_Button'
			top_buttons[6].name = 'User2_Button'
			top_buttons[7].name = 'Mixer_Button'
			side_buttons[0].name = 'Vol_Button'
			side_buttons[1].name = 'Pan_Button'
			side_buttons[2].name = 'SndA_Button'
			side_buttons[3].name = 'SndB_Button'
			side_buttons[4].name = 'Stop_Button'
			side_buttons[5].name = 'Trk_On_Button'
			side_buttons[6].name = 'Solo_Button'
			side_buttons[7].name = 'Arm_Button'
			self._osd = M4LInterface()
			self._osd.name = "OSD"
			self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button, self._osd, self)
			self._selector.name = 'Main_Modes'
			self._do_combine()
			for control in self.controls:
				if isinstance(control, ConfigurableButtonElement):
					control.add_value_listener(self._button_value)

			self.set_highlighting_session_component(self._selector.session_component())
			self._suppress_session_highlight = False

			self.log_message("LaunchPad95 Loaded !")

	def disconnect(self):
		self._suppress_send_midi = True
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.remove_value_listener(self._button_value)
		self._do_uncombine()
		self._selector = None
		self._user_byte_write_button.remove_value_listener(self._user_byte_value)
		self._config_button.remove_value_listener(self._config_value)
		ControlSurface.disconnect(self)
		self._suppress_send_midi = False
		self._config_button.send_value(32)
		self._config_button.send_value(0)
		self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None

	_active_instances = []

	#def highlighting_session_component(self):
	#	" Return the session component showing the ring in Live session "
	#	return self._selector.session_component()

	def _combine_active_instances():
		support_devices = False
		for instance in APCmini._active_instances:
			support_devices |= (instance._device_component != None)
		offset = 0
		for instance in APCmini._active_instances:
			instance._activate_combination_mode(offset, support_devices)
			offset += instance._selector._session.width()

	_combine_active_instances = staticmethod(_combine_active_instances)

	def _activate_combination_mode(self, track_offset, support_devices):
		if(Settings.STEPSEQ__LINK_WITH_SESSION):
			self._selector._stepseq.link_with_step_offset(track_offset)
		if(Settings.SESSION__LINK):
			self._selector._session.link_with_track_offset(track_offset)

	def _do_combine(self):
		if (DO_COMBINE and (self not in APCmini._active_instances)):
			APCmini._active_instances.append(self)
			APCmini._combine_active_instances()

	def _do_uncombine(self):
		if self in APCmini._active_instances:
			APCmini._active_instances.remove(self)
			if(Settings.SESSION__LINK):
				self._selector._session.unlink()
			if(Settings.STEPSEQ__LINK_WITH_SESSION):
				self._selector._stepseq.unlink()
			APCmini._combine_active_instances()

	def refresh_state(self):
		ControlSurface.refresh_state(self)
		self.schedule_message(5, self._update_hardware)

	def handle_sysex(self, midi_bytes):
		# if len(midi_bytes) == 8:
		# if midi_bytes[1:5] == (0, 32, 41, 6):
		# response = long(midi_bytes[5])
		# response += long(midi_bytes[6]) << 8
		# if response == Live.Application.encrypt_challenge2(self._challenge):
		self._suppress_send_midi = False
		self.set_enabled(True)

	def build_midi_map(self, midi_map_handle):
		ControlSurface.build_midi_map(self, midi_map_handle)
		if self._selector.mode_index == 1:
			if self._selector._sub_mode_index[self._selector._mode_index] > 0:  # disable midi map rebuild for instrument mode to prevent light feedback errors
				new_channel = self._selector.channel_for_current_mode()
				# self.log_message(str(new_channel))
				# for note in DRUM_NOTES:
				#	self._translate_message(MIDI_NOTE_TYPE, note, 0, note, new_channel)

	def _send_midi(self, midi_bytes, optimized=None):
		sent_successfully = False
		if not self._suppress_send_midi:
			sent_successfully = ControlSurface._send_midi(self, midi_bytes, optimized=optimized)
		return sent_successfully

	def _update_hardware(self):
		self._suppress_send_midi = False
		self._wrote_user_byte = True
		self._user_byte_write_button.send_value(1)
		self._suppress_send_midi = True
		self.set_enabled(False)
		self._suppress_send_midi = False
		# self._send_challenge()
		self.set_enabled(True)			# Enable anyways, without checking

	def _send_challenge(self):
		for index in range(4):
			challenge_byte = self._challenge >> 8 * index & 127
			self._send_midi((176, 17 + index, challenge_byte))

	def _user_byte_value(self, value):
		assert (value in range(128))
		if not self._wrote_user_byte:
			enabled = (value == 1)
			self._control_is_with_automap = not enabled
			self._suppress_send_midi = self._control_is_with_automap
			if not self._control_is_with_automap:
				for control in self.controls:
					if isinstance(control, ConfigurableButtonElement):
						control.set_force_next_value()

			self._selector.set_mode(0)
			self.set_enabled(enabled)
			self._suppress_send_midi = False
		else:
			self._wrote_user_byte = False

	def _button_value(self, value):
		assert value in range(128)

	def _config_value(self, value):
		assert value in range(128)

	def _set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks):
		if not self._suppress_session_highlight:
			ControlSurface._set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks)
示例#14
0
class NanoKontrolLP95(ControlSurface):
    __module__ = __name__
    __doc__ = " NanoKontrolLP95 controller script "

    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        #self._suppress_session_highlight = True
        self._suppress_send_midi = True  # Turn off rebuild MIDI map until after we're done setting up
        Live.Base.log(time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) + "--------------= NanoKontrolLP95 log opened =--------------") # Writes message into Live's main log file. This is a ControlSurface method.
        with self.component_guard():
            # OBJECTS
            self._session = None #session object
            self._mixer = None #mixer object
            self._transport = None #transport object
            self._last_button_time = time.time()
            self._io_list_index = 0
            
            self._setup_controls()

            self._setup_session_control()  # Setup the session object
            self._setup_mixer_control() # Setup the mixer object
            self._session.set_mixer(self._mixer) # Bind mixer to session
            self._setup_transport_control() # Setup transport object

            self._set_mode_button()
            self._set_normal_mode()
            self._track = self.song().view.selected_track
            
            self.set_highlighting_session_component(self._session)

            self._flash_counter = 0
            self._flash_on = True
            
            for component in self.components:
                component.set_enabled(True)

        self._suppress_send_midi = True # Turn rebuild back on, once we're done setting up
        Live.Base.log("NanoKontrolLP95 Loaded !")

    def disconnect(self):
        """clean things up on disconnect"""
        if self._cycle_button != None:
            self._cycle_button.remove_value_listener(self._cycle_button_value)
        self._clear_controls()
        self._transport.set_stop_button(None)
        self._transport.set_play_button(None)
        self._transport.set_rec_button(None)

        self._solo_buttons = None 
        self._mute_buttons = None 
        self._arm_buttons = None 
        self._knobs = None 
        self._faders = None 

        self._ff_button = None
        self._rwd_button = None
        self._play_button = None
        self._stop_button = None
        self._rec_button = None
        
        self._track_left_button = None
        self._track_right_button = None
        self._cycle_button = None
        
        self._set_button = None    
        self._mrk_left_button = None
        self._mrk_right_button = None
        
        self._session = None
        self._mixer = None
        self._transport = None

        ControlSurface.disconnect(self)
    
    def _setup_controls(self):
        self._track_left_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, track_left_btn)
        self._track_right_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, track_right_btn)    
        self._cycle_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, cycle_btn)
        self._cycle_button_active = False             
        
        self._set_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, set_btn)        
        self._mrk_left_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, mrk_left_btn)
        self._mrk_right_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, mrk_right_btn)

        self._ff_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, ff_btn)
        self._rwd_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, rwd_btn)        
        self._play_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, play_btn)
        self._stop_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, stop_btn)
        self._rec_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, rec_btn)
        
        self._solo_buttons = [ButtonElement(True, MIDI_CC_TYPE, CHANNEL, track_solo_cc[index]) for index in range(num_tracks)] 
        self._mute_buttons = [ButtonElement(True, MIDI_CC_TYPE, CHANNEL, track_mute_cc[index]) for index in range(num_tracks)] 
        self._arm_buttons = [ButtonElement(True, MIDI_CC_TYPE, CHANNEL, track_arm_cc[index]) for index in range(num_tracks)] 
        self._knobs = [SliderElement(MIDI_CC_TYPE, CHANNEL, mixer_knob_cc[index]) for index in range(num_tracks)] 
        self._faders = [SliderElement(MIDI_CC_TYPE, CHANNEL, mixer_fader_cc[index]) for index in range(num_tracks)] 
    
    
    def _setup_session_control(self):
        # CREATE SESSION, SET OFFSETS, BUTTONS NAVIGATION AND BUTTON MATRIX
        self._session = SpecialSessionComponent(num_tracks, num_scenes) #(num_tracks, num_scenes)
        self._session.set_offsets(0, 0)

    def _setup_mixer_control(self):
        #CREATE MIXER, SET OFFSET (SPECIALMIXERCOMPONENT USES SPECIALCHANNELSTRIP THAT ALLOWS US TO UNFOLD TRACKS WITH TRACK SELECT BUTTON)
        self._mixer = SpecialMixerComponent(self, num_tracks, 0, False, False) # 8 tracks, 2 returns, no EQ, no filters
        self._mixer.name = 'Mixer'
        self._mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left)
        self._mixer.set_select_buttons(self._track_right_button,self._track_left_button)
        self._mixer.set_knobs(self._knobs)
    def _setup_transport_control(self):
        # CREATE TRANSPORT DEVICE
        self._transport = SpecialTransportComponent(self)
        self._transport.set_stop_button(self._stop_button)
        self._transport.set_play_button(self._play_button)
        self._transport.set_rec_button(self._rec_button)
        
    def connect_script_instances(self, instanciated_scripts):
        #Live.Base.log("connect_script_instances - Start")
        #Live.Base.log("connect_script_instances - self._control_surfaces()=" + str(self._control_surfaces()))
        if(linked):
            for control_surface in self._control_surfaces():
                control_surface_type = str(control_surface)
                for sync_master in SYNC_TO_LIST:
                    if(control_surface_type.count(sync_master)>0):
                        control_surface_session = control_surface.highlighting_session_component()
                        if control_surface_session:
                            self._session.sync_to(control_surface_session)
                            self._on_track_list_changed()
                            break


    def _clear_controls(self):
            
        if (self._ff_button != None):
            self._ff_button.remove_value_listener(self._out_value)
            self._ff_button.turn_off()
    
        if (self._rwd_button != None):
            self._rwd_button.remove_value_listener(self._in_value)
            self._rwd_button.turn_off()           
            
        if (self._set_button != None):
            self._set_button.remove_value_listener(self._monitor_value)
            self._set_button.remove_value_listener(self._dup_track_value)           
            
        if (self._mrk_left_button != None):
            self._mrk_left_button.remove_value_listener(self._sub_in_value)
            self._mrk_left_button.remove_value_listener(self._new_midi_value)            
            
        if (self._mrk_right_button != None):
            self._mrk_right_button.remove_value_listener(self._sub_out_value)
            self._mrk_right_button.remove_value_listener(self._new_audio_value)            

        # SESSION
        resetsend_controls = []
        self._mixer.send_controls = []
        self._session.set_stop_track_clip_buttons(None)

        # MIXER
        self._mixer._set_send_nav(None, None)
        for track_index in range(num_tracks):
            strip = self._mixer.channel_strip(track_index)
            strip.set_solo_button(None)
            strip.set_mute_button(None)
            strip.set_arm_button(None)
            resetsend_controls.append(None)
            strip.set_select_button(None)
            for i in range(12):
                self._mixer.send_controls.append(None)
            strip.set_send_controls(tuple(self._mixer.send_controls))
        self._mixer.set_resetsend_buttons(tuple(resetsend_controls))
        self.log_message("Controls Cleared")

    def _set_mode_button(self):
        if self._cycle_button != None:
            self._cycle_button.remove_value_listener(self._cycle_button_value)
            self._cycle_button.add_value_listener(self._cycle_button_value)
            self._cycle_button.set_light(self._cycle_button_active)

    def _cycle_button_value(self, value):
        assert (value in range(128))        
        if self._cycle_button != None:
            if value is not 0:
                self._cycle_button_active = not self._cycle_button_active
                self._clear_controls()
                if self._cycle_button_active:
                    self._set_alt_mode()
                else:
                    self._set_normal_mode()
                self.update()   
            
    def _set_normal_mode(self):
        for index in range(num_tracks):
            strip = self._mixer.channel_strip(index)
            strip.set_solo_button(self._solo_buttons[index])
            strip.set_mute_button(self._mute_buttons[index])
            strip.set_arm_button(self._arm_buttons[index])
            strip.set_pan_control(self._knobs[index])
            strip.set_volume_control(self._faders[index])
        self._set_in_out_nav_listeners()    
        self.show_message("IN/OUT SETUP - MUTE SOLO ARM")
                        
    def _set_alt_mode(self):
        self._mixer._set_send_nav(self._ff_button, self._rwd_button)
        stop_track_controls = []
        resetsend_controls = []
        # SET SESSION TRACKSTOP, TRACK SELECT, RESET SEND KNOB
        for index in range(num_tracks):
            strip = self._mixer.channel_strip(index)
            strip.set_select_button(self._solo_buttons[index])
            stop_track_controls.append(self._arm_buttons[index])
            resetsend_controls.append(self._mute_buttons[index])
        self._session.set_stop_track_clip_buttons(tuple(stop_track_controls))
        self._mixer.set_resetsend_buttons(tuple(resetsend_controls))
        self._mixer._update_send_index()
        self._set_create_track_listeners()
        self.show_message("TRACK CREATE DEL DUPE - SEL STOP RESET SEND")
        
    def _set_in_out_nav_listeners(self):
        if (self._ff_button != None):
            self._ff_button.add_value_listener(self._out_value)
    
        if (self._rwd_button != None):
            self._rwd_button.add_value_listener(self._in_value)
            
        if (self._set_button != None):
            self._set_button.add_value_listener(self._monitor_value)
            
        if (self._mrk_left_button != None):
            self._mrk_left_button.add_value_listener(self._sub_in_value)
            
        if (self._mrk_right_button != None):
            self._mrk_right_button.add_value_listener(self._sub_out_value)                                                
        self.update()
           
    def _monitor_value(self, value):
        now = time.time()
        if(value is not 0):
            self._last_button_time = now
        else:
            song = self.song()
            if self._track in song.tracks:
                if now - self._last_button_time < LONG_PRESS:            
                    if not self._track.is_foldable:
                        self._track.current_monitoring_state = (self._track.current_monitoring_state + 1) % 3
                else:  
                    self._set_default_io()            

    def _set_default_io(self):
        if self._track.has_midi_input:
                self._track.input_routing_type = list(self._track.available_input_routing_types)[0]
                if self._track.has_audio_output:
                    if self._track.is_grouped:
                        self._track.output_routing_type = list(self._track.available_output_routing_types)[2]       
                    else:
                        self._track.output_routing_type = list(self._track.available_output_routing_types)[1]
                else:
                    self._track.output_routing_type = list(self._track.available_output_routing_types)[-1]
        else:
                self._track.input_routing_type = list(self._track.available_input_routing_types)[-1]
                if self._track.is_grouped:
                    self._track.output_routing_type = list(self._track.available_output_routing_types)[2]       
                else:
                    self._track.output_routing_type = list(self._track.available_output_routing_types)[1]
                    
        self._track.input_routing_channel = list(self._track.available_input_routing_channels)[0]            
        self._track.output_routing_channel = list(self._track.available_output_routing_channels)[0]  
        self.show_message("TRACK: " + str(self._track.name) + ' INPUT - OUTPUT RESET ')                             
                                     
    def _in_value(self, value):
        if(value is not 0):
            routings = list(self._track.available_input_routing_types)
            current_routing = self._track.input_routing_type
            if current_routing in routings:
                new_index = (routings.index(current_routing) + 1) % len(routings)
                self._track.input_routing_type = routings[new_index]
                route = ' INPUT: ' +  str(self._track.input_routing_type.display_name)
                self.show_message("TRACK: " + str(self._track.name) + route)
            self.update()
            
    def _out_value(self, value):
        if(value is not 0):
            routings = list(self._track.available_output_routing_types)
            current_routing = self._track.output_routing_type
            if current_routing in routings:
                new_index = (routings.index(current_routing) + 1) % len(routings)
                self._track.output_routing_type = routings[new_index]
                route = ' OUTPUT: ' +  str(self._track.output_routing_type.display_name)
                self.show_message("TRACK: " + str(self._track.name) + route)
        self.update()

    def _sub_in_value(self, value):
        if(value is not 0):
            routings = list(self._track.available_input_routing_channels)
            current_routing = self._track.input_routing_channel
            if current_routing in routings:
                new_index = (routings.index(current_routing) + 1) % len(routings)
                self._track.input_routing_channel = routings[new_index]
                route = ' SUB_INPUT: ' +  str(self._track.input_routing_channel.display_name)
                self.show_message("TRACK: " + str(self._track.name) + route)
            self.update()
     
    def _sub_out_value(self, value):
        if(value is not 0):
            routings = list(self._track.available_output_routing_channels)
            current_routing = self._track.output_routing_channel
            if current_routing in routings:
                new_index = (routings.index(current_routing) + 1) % len(routings)
                self._track.output_routing_channel = routings[new_index]
                route = ' SUB_OUTPUT: ' +  str(self._track.output_routing_channel.display_name)
                self.show_message("TRACK: " + str(self._track.name) + route)                       
            self.update()


    def _on_selected_track_changed(self):
        # ALLOWS TO GRAB THE FIRST DEVICE OF A SELECTED TRACK IF THERE'S ANY
        ControlSurface._on_selected_track_changed(self)
        self._track = self.song().view.selected_track
              
    def update(self):
        ControlSurface.update(self)
        self._cycle_button.set_light(self._cycle_button_active)
        
        
    def _set_create_track_listeners(self):
        if (self._set_button != None):
            self._set_button.add_value_listener(self._dup_track_value)
            
        if (self._mrk_left_button != None):
            self._mrk_left_button.add_value_listener(self._new_midi_value)
            
        if (self._mrk_right_button != None):
            self._mrk_right_button.add_value_listener(self._new_audio_value)                                                
        self.update()            
        
    def _dup_track_value(self, value):
        now = time.time()
        if(value is not 0):
            self._last_button_time = now
        else:
            song = self.song()
            if self._track in song.tracks:
                if now - self._last_button_time < LONG_PRESS:            
                    song.duplicate_track(list(song.tracks).index(self._track))
                else:  
                    song.delete_track(list(song.tracks).index(self._track))

    def _new_audio_value(self, value):
        if(value is not 0):
            self._add_track(self.song().create_audio_track)
            
    def _new_midi_value(self, value):
        if(value is not 0):
            self._add_track(self.song().create_midi_track)
            
    def _add_track(self, func):
        song = self.song()
        index = list(song.tracks).index(self._track) + 1
        if index < len(song.tracks) and index >0:
            track = song.tracks[index]
            if track.is_foldable or track.is_grouped:
                while index < len(song.tracks) and song.tracks[index].is_grouped:
                    index += 1
        func(index)
        
    @profile
    def update_display(self):
        super(NanoKontrolLP95, self).update_display()
        self._flash_counter = self._flash_counter + 1
        if self._cycle_button_active  == True:
            if(self._flash_counter % 2  == 0):
                if (self._flash_on == True):
                    self._cycle_button.send_value(127) 
                else:
                    self._cycle_button.send_value(0) 
                self._flash_on = not self._flash_on
                self._flash_counter = self._flash_counter % 4                                                  
示例#15
0
class Launchpad(ControlSurface):
	" SCRIPT FOR NOVATION'S LAUNCHPAD CONTROLLER "

	" INITALIZE "
	def __init__(self, c_instance):
		ControlSurface.__init__(self, c_instance)
		with self.component_guard():
			#self.set_suppress_rebuild_requests(True)
			self._suppress_send_midi = True
			self._suppress_session_highlight = True
			is_momentary = True
			self._suggested_input_port = "Launchpad"
			self._suggested_output_port = "Launchpad"
			self._control_is_with_automap = False
			self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16) 
			self._user_byte_write_button.name = "User_Byte_Button"
			self._user_byte_write_button.send_value(1)
			self._user_byte_write_button.add_value_listener(self._user_byte_value)
			self._wrote_user_byte = False
			self._challenge = (Live.Application.get_random_int(0, 400000000) & 2139062143)
			matrix = ButtonMatrixElement()
			matrix.name = "Button_Matrix"
			
			""" TRACKFINDER TEST 
			track_index = 0
			for track in self.song().tracks:
				if track_index < 8:
					button_row = []			
					if track.is_foldable:
						for column in range(8):	
							log("right one: " + str(track_index))		
							button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, ((track_index * 16) + column)) #@UndefinedVariable
							button.name = (((str(column) + "_Clip_") + str(track_index)) + "_Button")
							button_row.append(button)
						track_index = track_index + 1
					else:
						for column in range(8):
							log("wrong one: " + str(track_index))
							button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 99, True) #@UndefinedVariable
							button.name = (str(column) + "_Clip_Button-DUMMY")
							button_row.append(button)
					matrix.add_row(tuple(button_row))
			log("done")"""
			
			""" ORIGINAL CODE """
			for row in range(8):
				button_row = []
				for column in range(8):
					button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, ((row * 16) + column)) 
					button.name = (((str(column) + "_Clip_") + str(row)) + "_Button")
					button_row.append(button)
				matrix.add_row(tuple(button_row))
				
			self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0, optimized_send_midi=False)
			self._config_button.add_value_listener(self._config_value)
			top_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0, (104 + index)) for index in range(8) ] 
			side_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index]) for index in range(8) ] 
			top_buttons[0].name = "Bank_Select_Up_Button"
			top_buttons[1].name = "Bank_Select_Down_Button"
			top_buttons[2].name = "Bank_Select_Left_Button"
			top_buttons[3].name = "Bank_Select_Right_Button"
			top_buttons[4].name = "Session_Button"
			top_buttons[5].name = "User1_Button"
			top_buttons[6].name = "User2_Button"
			top_buttons[7].name = "Mixer_Button"
			side_buttons[0].name = "Vol_Button"
			side_buttons[1].name = "Pan_Button"
			side_buttons[2].name = "SndA_Button"
			side_buttons[3].name = "SndB_Button"
			side_buttons[4].name = "Stop_Button"
			side_buttons[5].name = "Trk_On_Button"
			side_buttons[6].name = "Solo_Button"
			side_buttons[7].name = "Arm_Button"
			self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button)
			self._selector.name = "Main_Modes"
			for control in self.controls:
				if isinstance(control, ConfigurableButtonElement):
					control.add_value_listener(self._button_value)
			self.set_highlighting_session_component(self._selector.session_component())
			self._suppress_session_highlight = False
			#self.set_suppress_rebuild_requests(False)

	" DISCONNECTOR "
	def disconnect(self):
		self._suppress_send_midi = True
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.remove_value_listener(self._button_value)
		self._selector = None
		self._user_byte_write_button.remove_value_listener(self._user_byte_value)
		self._config_button.remove_value_listener(self._config_value)
		ControlSurface.disconnect(self)
		self._suppress_send_midi = False
		self._config_button.send_value(32)
		self._config_button.send_value(0)
		self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None

	" RETURN THE SESSION COMPONENT SHOWING THE RING IN LIVE SESSION "
	def highlighting_session_component(self):		
		return self._selector.session_component()

	" REFRESH "
	def refresh_state(self):
		ControlSurface.refresh_state(self)
		self.schedule_message(5, self._update_hardware)

	" SYSEX HANDLING "
	def handle_sysex(self, midi_bytes):
		if (len(midi_bytes) == 8):
			if (midi_bytes[1:5] == (0, 32, 41, 6)):
				response = long(midi_bytes[5])
				response += (long(midi_bytes[6]) << 8)
				if (response == Live.Application.encrypt_challenge2(self._challenge)):
					self._suppress_send_midi = False
					self.set_enabled(True)

	" MIDI MAP "
	def build_midi_map(self, midi_map_handle):
		ControlSurface.build_midi_map(self, midi_map_handle)
		if (self._selector.mode_index == 1):
			new_channel = self._selector.channel_for_current_mode()
			for note in DRUM_NOTES:
				self._translate_message(MIDI_NOTE_TYPE, note, 0, note, new_channel) 

	" SEND THE MIDI STUFF "
	def _send_midi(self, midi_bytes, optimized = None):
		sent_successfully = False
		if (not self._suppress_send_midi):
			sent_successfully = ControlSurface._send_midi(self, midi_bytes, optimized=optimized)
		return sent_successfully

	" UPDATE THE HARDWARE "
	def _update_hardware(self):
		self._suppress_send_midi = False
		self._wrote_user_byte = True
		self._user_byte_write_button.send_value(1)
		self._suppress_send_midi = True
		self.set_enabled(False)
		self._suppress_send_midi = False
		self._send_challenge()

	" CHALLANGE SEND "
	def _send_challenge(self):
		for index in range(4):
			challenge_byte = ((self._challenge >> (8 * index)) & 127)
			self._send_midi((176, (17 + index),	 challenge_byte))

	" USER BYTE STUFF "
	def _user_byte_value(self, value):
		if not value in range(128):
			raise AssertionError
			enabled = self._wrote_user_byte or value == 1
			self._control_is_with_automap = not enabled
			self._suppress_send_midi = self._control_is_with_automap
			if not self._control_is_with_automap:
				for control in self.controls:
					if isinstance(control, ConfigurableButtonElement):
						control.set_force_next_value()
			self._selector.set_mode(0)
			self.set_enabled(enabled)
			self._suppress_send_midi = False
		else:
			self._wrote_user_byte = False

	" BUTTON VALUE "
	def _button_value(self, value):		
		assert (value in range(128))
		
	" CONFIG VALUE "
	def _config_value(self, value):
		assert (value in range(128))

	" SET THE SESSION HIGHLIGHT "
	def _set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks):
		if (not self._suppress_session_highlight):
			ControlSurface._set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks)
示例#16
0
class LaunchMod(ControlSurface):
	__module__ = __name__
	__doc__ = " Script for Novation's Launchpad Controller "

	def __init__(self, c_instance):
		ControlSurface.__init__(self, c_instance)
		self._monomod_version = 'b994'
		self._host_name = 'LaunchMod'
		self._color_type = 'Launchpad'
		self.hosts = []
		self._timer = 0
		self.set_suppress_rebuild_requests(True)
		self._suppress_send_midi = True
		self._suppress_session_highlight = True
		is_momentary = True
		self._suggested_input_port = 'Launchpad'
		self._suggested_output_port = 'Launchpad'
		self._wrote_user_byte = False
		self._control_is_with_automap = False
		self._challenge = (Live.Application.get_random_int(0, 400000000) & 2139062143)
		matrix = ButtonMatrixElement()
		matrix.name = 'ButtonMatrix'
		for row in range(8):
			#button_row = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, ((row * 16) + column)) for column in range(8) ]
			button_row = [ FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, ((row * 16) + column), 'Button_'+str(row)+'_'+str(column), self) for column in range(8) ]
			matrix.add_row(tuple(button_row))
		self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0)
		self._config_button.add_value_listener(self._config_value)
		top_buttons = [ FlashingButtonElement(is_momentary, MIDI_CC_TYPE, 0, (104 + index), 'Top_Button'+str(index), self) for index in range(8) ]
		side_buttons = [ FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index], 'Side_Button'+str(index), self) for index in range(8) ]
		self._setup_monobridge()
		self._setup_monomod()
		self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button, self)
		self._suppress_session_highlight = False
		self._suppress_send_midi = False
		self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)
		self._user_byte_write_button.send_value(1)
		self._user_byte_write_button.add_value_listener(self._user_byte_value)
		self._suppress_send_midi = True
		self.set_suppress_rebuild_requests(False)
		self.log_message("--------------= LaunchMod log opened =--------------") #Create entry in log file
		self.refresh_state()

	def _setup_monobridge(self):
		self._monobridge = MonoBridgeElement(self)
		self._monobridge.name = 'MonoBridge'
	

	def _setup_monomod(self):
		self._host = MonomodComponent(self)
		self._host.name = 'Monomod_Host'
		self.hosts = [self._host]
	

	def disconnect(self):
		self._suppress_send_midi = True
		self._selector = None
		self._user_byte_write_button.remove_value_listener(self._user_byte_value)
		self._config_button.remove_value_listener(self._config_value)
		ControlSurface.disconnect(self)
		self._suppress_send_midi = False
		self._config_button.send_value(32)
		self._config_button.send_value(0)
		self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None
		self.log_message("--------------= LaunchMod log closed =--------------") #Create entry in log file


	def refresh_state(self):
		ControlSurface.refresh_state(self)
		self.schedule_message(5, self._update_hardware)



	def handle_sysex(self, midi_bytes):
		if (len(midi_bytes) == 8):
			if (midi_bytes[1:5] == (0,
			 32,
			 41,
			 6)):
				response = long(midi_bytes[5])
				response += (long(midi_bytes[6]) << 8)
				if (response == Live.Application.encrypt_challenge2(self._challenge)):
					self._suppress_send_midi = False
					self.set_enabled(True)
					#self.refresh_state()



	def _send_midi(self, midi_bytes):
		if (not self._suppress_send_midi):
			ControlSurface._send_midi(self, midi_bytes)



	def _update_hardware(self):
		self._suppress_send_midi = False
		self._config_button.send_value(40)
		self._wrote_user_byte = True
		self._user_byte_write_button.send_value(1)
		self._suppress_send_midi = True
		self.set_enabled(False)
		self._suppress_send_midi = False
		self._send_challenge()



	def _send_challenge(self):
		for index in range(4):
			challenge_byte = ((self._challenge >> (8 * index)) & 127)
			self._send_midi((176,
			 (17 + index),
			 challenge_byte))




	def _user_byte_value(self, value):
		assert (value in range(128))
		enabled = (value == 1)
		if enabled:
			self._config_button.send_value(40)
		self._control_is_with_automap = (not enabled)
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.set_force_next_value()

		if (not self._wrote_user_byte):
			self._selector.set_mode(0)
			self.set_enabled(enabled)
		else:
			self._wrote_user_byte = False
		self.request_rebuild_midi_map()



	def _config_value(self, value):
		assert (value in range(128))



	def _set_session_highlight(self, track_offset, scene_offset, width, height, include_returns = False):
		if (not self._suppress_session_highlight):
			ControlSurface._set_session_highlight(self, track_offset, scene_offset, width, height, include_returns)



	def _install_forwarding(self, control):
		result = False
		if ((not self._control_is_with_automap) or (control == self._user_byte_write_button)):
			result = ControlSurface._install_forwarding(self, control)
		return result



	def _translate_message(self, type, from_identifier, from_channel, to_identifier, to_channel):
		if (not self._control_is_with_automap):
			ControlSurface._translate_message(self, type, from_identifier, from_channel, to_identifier, to_channel)


	def update_display(self):
		""" Live -> Script
		Aka on_timer. Called every 100 ms and should be used to update display relevant
		parts of the controller
		"""
		for message in self._scheduled_messages:
			message['Delay'] -= 1
			if (message['Delay'] == 0):
				if (message['Parameter'] != None):
					message['Message'](message['Parameter'])
				else:
					message['Message']()
					del self._scheduled_messages[self._scheduled_messages.index(message)]

		for callback in self._timer_callbacks:
			callback()
		self._timer = (self._timer + 1) % 256
		self.flash()
	

	def flash(self):
		#if(self.flash_status > 0):
		for row in range(8):
			if(self._selector._side_buttons[row]._flash_state > 0):
				self._selector._side_buttons[row].flash(self._timer)
			for column in range(8):
				button = self._selector._matrix.get_button(column, row)
				if(button._flash_state > 0):
					button.flash(self._timer)
		for index in range(4):
			if(self._selector._nav_buttons[index]._flash_state > 0):
				self._selector._nav_buttons[index].flash(self._timer)
			if(self._selector._modes_buttons[index]._flash_state > 0):
				self._selector._modes_buttons[index].flash(self._timer)
	

	def allow_updates(self, allow_updates):
		for component in self.components:
			component.set_allow_update(int(allow_updates!=0))
示例#17
0
class BlockPad(ControlSurface):
	__module__ = __name__
	__doc__ = " Script for Novation's Launchpad Controller adapted to Livid's Block controller and Monomodular by amounra "

	def __init__(self, c_instance):
		ControlSurface.__init__(self, c_instance)
		self._monomod_version = 'b994'
		self.hosts = []
		self._host_name = 'BlockPad'
		self._color_type = 'Monochrome'
		self._timer = 0
		is_momentary = True
		self._suggested_input_port = 'block (Controls)'
		self._suggested_output_port = 'block (Controls)'
		self._wrote_user_byte = False
		matrix = ButtonMatrixElement()
		for row in range(8):
			button_row = [ FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, ((column * 8) + row), 'Button_'+str(column)+'_'+str(row), self) for column in range(8) ]
			matrix.add_row(tuple(button_row))
		knobs = [ EncoderElement(MIDI_CC_TYPE, 0, KNOB_CC[index], Live.MidiMap.MapMode.absolute) for index in range(8) ]
		sliders = [ EncoderElement(MIDI_CC_TYPE, 0, SLIDER_CC[index], Live.MidiMap.MapMode.absolute) for index in range(2) ]
		self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0)
		self._config_button.add_value_listener(self._config_value)
		top_buttons = [ FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, TOP_NOTES[index], 'Top_Button'+str(index), self) for index in range(8) ]
		side_buttons = [ FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index], 'Side_Button'+str(index), self) for index in range(8) ]
		self._setup_monobridge()
		self._setup_monomod()
		self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button, tuple(knobs), tuple(sliders), self)
		self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)
		self._user_byte_value(1)
		self._user_byte_write_button.add_value_listener(self._user_byte_value)
		self.set_enabled(True)
		self.log_message("--------------= BlockPad log opened =--------------") #Create entry in log file
		self.refresh_state()

	def _setup_monobridge(self):
		self._monobridge = MonoBridgeElement(self)
		self._monobridge.name = 'MonoBridge'
	

	def _setup_monomod(self):
		self._host = MonomodComponent(self)
		self._host.name = 'Monomod_Host'
		self.hosts = [self._host]
	

	def disconnect(self):
		self._suppress_send_midi = True
		self._selector = None
		self._user_byte_write_button.remove_value_listener(self._user_byte_value)
		self._config_button.remove_value_listener(self._config_value)
		ControlSurface.disconnect(self)
		self._suppress_send_midi = False
		self._config_button.send_value(32)
		self._config_button.send_value(0)
		self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None
		self.log_message("--------------= BlockPad log closed =--------------") #Create entry in log file


	def _user_byte_value(self, value):
		assert (value in range(128))
		enabled = (value == 1)
		if enabled:
			self._config_button.send_value(40)
		self._control_is_with_automap = (not enabled)
		for control in self.controls:
			if isinstance(control, FlashingButtonElement):
				control.set_force_next_value()

		if (not self._wrote_user_byte):
			self._selector.set_mode(0)
			self.set_enabled(enabled)
		else:
			self._wrote_user_byte = False
		self.request_rebuild_midi_map()



	def _config_value(self, value):
		assert (value in range(128))

	def update_display(self):
		""" Live -> Script
		Aka on_timer. Called every 100 ms and should be used to update display relevant
		parts of the controller
		"""
		for message in self._scheduled_messages:
			message['Delay'] -= 1
			if (message['Delay'] == 0):
				if (message['Parameter'] != None):
					message['Message'](message['Parameter'])
				else:
					message['Message']()
					del self._scheduled_messages[self._scheduled_messages.index(message)]

		for callback in self._timer_callbacks:
			callback()
		self._timer = (self._timer + 1) % 256
		if(self._timer == 0):
			self._selector._shift_pressed_timer = -12
		self.flash()
	

	def flash(self):
		for row in range(8):
			for column in range(8):
				button = self._selector._matrix.get_button(column, row)
				if(button._flash_state > 0):
					button.flash(self._timer)
示例#18
0
class AudioClipEditComponent(CompoundComponent):
    """
    classdocs
    """

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

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

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

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

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

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

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

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

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

    @subject_slot('value')
    def _action_loop_end(self, value):
        inc = value == 1 and 1 or -1
        if self.selected_clip_slot and self.selected_clip_slot.has_clip:
            clip = self.selected_clip_slot.clip
            ls = clip.loop_start
            le = clip.loop_end
            le = max(ls + self.loop_inc, le + inc * self.loop_inc)
            clip.loop_end = le
            if self.mv_loop:
                clip.end_marker = le
            self.canonical_parent.timed_message(2, loop_str(clip))

    def update(self):
        pass

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

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

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

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

    @subject_slot('has_clip')
    def _on_has_clip_changed(self):
        self._update_clip_name()

    @subject_slot('name')
    def _on_name_changed(self):
        self._update_clip_name()

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

    def on_selected_track_changed(self):
        self.update_selected_clip()

    def on_selected_scene_changed(self):
        self.update_selected_clip()

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

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

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

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

    @subject_slot('gain')
    def _on_gain_changed(self):
        cs = self.song().view.highlighted_clip_slot
        if cs and cs.has_clip and cs.clip.is_audio_clip:
            self._gain_slider.send_value(gain_to_midi(cs.clip.gain))
class F1ColorButtonElement(ButtonElement): 
    ' SPECIAL BUTTON CLASS THAT INTERNALLY HOLDS 3 BUTTONS FOR HANDLING RGB / HSV AND ONE BUTTON THAT HANDLES INCOMING MIDI'
    __module__ = __name__
    
    """ MAIN CONSTRUCTOR """
    def __init__(self, is_momentary, msg_type, identifier, hsvChannels, controlChannel, rgbColor, name):
        log(True, __name__)                
        ButtonElement.__init__(self, is_momentary, msg_type, controlChannel, identifier) 
        self.name = name + " Control"
        # create 3 buttons for HSV
        self.hueButton = ButtonElement(is_momentary, msg_type, hsvChannels[0], identifier)
        self.satButton = ButtonElement(is_momentary, msg_type, hsvChannels[1], identifier)
        self.valButton = ButtonElement(is_momentary, msg_type, hsvChannels[2], identifier)
        self.id = identifier
        # color
        self.hsv_fader = None
        rgbColor = _liveOsTools.colorsys.hex2rgb(rgbColor)
        hsvColor = _liveOsTools.colorsys.rgb_to_hsv(rgbColor[0] / 255.0, rgbColor[1] / 255.0, rgbColor[2] / 255.0)
        self.hsv_fader = HSVFader(hsvColor[0], hsvColor[1], hsvColor[2])
        self.send_current_color()
        log(False, __name__)

    """ DISCONNECT """
    def disconnect(self):
        log(__name__, "disconnect")
        self.hueButton = None
        self.hsvColor = None
        self.satButton = None
        self.hsv_fader = None     
              
    """ FADE ONCE TO THAT VALUE """
    def fade_to(self, hue, sat, val, time):
        #log(__name__, "fade_to: hue("+str(hue)+"), sat("+str(sat)+"), val("+str(val)+"), time("+str(time)+")")
        self.hsv_fader.add_fade(hue, sat, val, time)
        
    """ UPDATE FRAME TIME BASED """
    def process(self, time_in_samples):  
        #log(__name__, "update")      
        #self.hsv_fader.process(time_in_samples)
        self.send_current_color()          
                  
    """ SEND COLOR """
    def send_current_color(self):
        # send color values to buttons  
        #log("sending: on CC: "+ str(self.id)+ " -- val: "+ str([int(self.hsv_fader.current_color[INDEX_HUE] * MIDI_RANGE),int(self.hsv_fader.current_color[INDEX_SAT] * MIDI_RANGE),int(self.hsv_fader.current_color[INDEX_VAL] * MIDI_RANGE)]))
        self.hueButton.send_value(int(self.hsv_fader.current_color[INDEX_HUE] * MIDI_RANGE), True)
        self.satButton.send_value(int(self.hsv_fader.current_color[INDEX_SAT] * MIDI_RANGE), True)
        self.valButton.send_value(int(self.hsv_fader.current_color[INDEX_VAL] * MIDI_RANGE), True)  

    """ SEND BASE COLOR """
    def send_base_color(self):
        self.hueButton.send_value(int(self.hsv_fader.get_base_color()[INDEX_HUE] * MIDI_RANGE), True)
        self.satButton.send_value(int(self.hsv_fader.get_base_color()[INDEX_SAT] * MIDI_RANGE), True)
        self.valButton.send_value(int(self.hsv_fader.get_base_color()[INDEX_VAL] * MIDI_RANGE), True)  

    """ SET THE MAIN COLOR """
    def set_base_color(self, liveRGBcolor):
        rgbColor = _liveOsTools.colorsys.hex2rgb(liveRGBcolor)
        hsvColor = _liveOsTools.colorsys.rgb_to_hsv(rgbColor[0] / 255.0, rgbColor[1] / 255.0, rgbColor[2] / 255.0)
        log(__name__, "new base color: rgb=" + str(rgbColor) + ", hsv=" + str(hsvColor))
        self.hsv_fader.set_base_color(hsvColor[0], hsvColor[1], hsvColor[2])
        self.send_base_color()
        
        
示例#20
0
class LaunchMod(ControlSurface):
    """ Script for Novation's Launchpad Controller """
    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
            self._monomod_version = 'b995'
            self._host_name = 'LaunchMod'
            self._color_type = 'Launchpad'
            self.hosts = []
            self._timer = 0
            self._suppress_send_midi = True
            self._suppress_session_highlight = True
            self._suppress_highlight = False
            is_momentary = True
            self._suggested_input_port = 'Launchpad'
            self._suggested_output_port = 'Launchpad'
            self._control_is_with_automap = False
            self._user_byte_write_button = ButtonElement(
                is_momentary, MIDI_CC_TYPE, 0, 16)
            self._user_byte_write_button.name = 'User_Byte_Button'
            self._user_byte_write_button.send_value(1)
            self._user_byte_write_button.add_value_listener(
                self._user_byte_value)
            self._wrote_user_byte = False
            self._challenge = Live.Application.get_random_int(
                0, 400000000) & 2139062143
            matrix = ButtonMatrixElement()
            matrix.name = 'Button_Matrix'
            for row in range(8):
                button_row = [
                    ConfigurableButtonElement(
                        is_momentary, MIDI_NOTE_TYPE, 0, ((row * 16) + column),
                        str(column) + '_Clip_' + str(row) + '_Button', self)
                    for column in range(8)
                ]
                matrix.add_row(tuple(button_row))
            self._config_button = ButtonElement(is_momentary,
                                                MIDI_CC_TYPE,
                                                0,
                                                0,
                                                optimized_send_midi=False)
            self._config_button.add_value_listener(self._config_value)
            top_button_names = [
                'Bank_Select_Up_Button', 'Bank_Select_Down_Button',
                'Bank_Select_Left_Button', 'Bank_Select_Right_Button',
                'Session_Button', 'User1_Button', 'User2_Button',
                'Mixer_Button'
            ]
            side_button_names = [
                'Vol_Button', 'Pan_Button', 'SndA_Button', 'SndB_Button',
                'Stop_Button', 'Trk_On_Button', 'Solo_Button', 'Arm_Button'
            ]
            top_buttons = [
                ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0,
                                          (104 + index),
                                          top_button_names[index], self)
                for index in range(8)
            ]
            side_buttons = [
                ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0,
                                          SIDE_NOTES[index],
                                          side_button_names[index], self)
                for index in range(8)
            ]
            self._setup_monobridge()
            self._setup_monomod()
            self._selector = MainSelectorComponent(matrix, tuple(top_buttons),
                                                   tuple(side_buttons),
                                                   self._config_button, self)
            self._selector.name = 'Main_Modes'
            for control in self.controls:
                if isinstance(control, MonoButtonElement):
                    control.add_value_listener(self._button_value)
            self.set_highlighting_session_component(
                self._selector.session_component())
            self._suppress_session_highlight = False
        self.log_message(
            "--------------= " + str(self._monomod_version) +
            " log opened =--------------")  #Create entry in log file

    def allow_updates(self, allow_updates):
        for component in self.components:
            component.set_allow_update(int(allow_updates != 0))

    def disconnect(self):
        self._suppress_send_midi = True
        for control in self.controls:
            if isinstance(control, ConfigurableButtonElement):
                control.remove_value_listener(self._button_value)

        self._selector = None
        self._user_byte_write_button.remove_value_listener(
            self._user_byte_value)
        self._config_button.remove_value_listener(self._config_value)
        ControlSurface.disconnect(self)
        self._suppress_send_midi = False
        self._config_button.send_value(32)
        self._config_button.send_value(0)
        self._config_button = None
        self._user_byte_write_button.send_value(0)
        self._user_byte_write_button = None

    def refresh_state(self):
        ControlSurface.refresh_state(self)
        self.schedule_message(5, self._update_hardware)

    def handle_sysex(self, midi_bytes):
        if len(midi_bytes) == 8:
            if midi_bytes[1:5] == (0, 32, 41, 6):
                response = long(midi_bytes[5])
                response += long(midi_bytes[6]) << 8
                if response == Live.Application.encrypt_challenge2(
                        self._challenge):
                    self._suppress_send_midi = False
                    self.set_enabled(True)

    def build_midi_map(self, midi_map_handle):
        ControlSurface.build_midi_map(self, midi_map_handle)
        if self._selector.mode_index == 1:
            new_channel = self._selector.channel_for_current_mode()
            for note in DRUM_NOTES:
                self._translate_message(MIDI_NOTE_TYPE, note, 0, note,
                                        new_channel)

    def _send_midi(self, midi_bytes, optimized=None):
        sent_successfully = False
        if not self._suppress_send_midi:
            sent_successfully = ControlSurface._send_midi(self,
                                                          midi_bytes,
                                                          optimized=optimized)
        return sent_successfully

    def _update_hardware(self):
        self._suppress_send_midi = False
        self._wrote_user_byte = True
        self._user_byte_write_button.send_value(1)
        self._suppress_send_midi = True
        self.set_enabled(False)
        self._suppress_send_midi = False
        self._send_challenge()

    def _send_challenge(self):
        for index in range(4):
            challenge_byte = self._challenge >> 8 * index & 127
            self._send_midi((176, 17 + index, challenge_byte))

    def _user_byte_value(self, value):
        assert value in range(128)
        enabled = self._wrote_user_byte or value == 1
        self._control_is_with_automap = not enabled
        self._suppress_send_midi = self._control_is_with_automap
        if not self._control_is_with_automap:
            for control in self.controls:
                if isinstance(control, MonoButtonElement):
                    control.set_force_next_value()

        self._selector.set_mode(0)
        self.set_enabled(enabled)
        self._suppress_send_midi = False

    def _button_value(self, value):
        assert value in range(128)

    def _config_value(self, value):
        assert value in range(128)

    def _set_session_highlight(self, track_offset, scene_offset, width, height,
                               include_return_tracks):
        if not self._suppress_session_highlight:
            ControlSurface._set_session_highlight(self, track_offset,
                                                  scene_offset, width, height,
                                                  include_return_tracks)

    def _setup_m4l_interface(self):
        self._m4l_interface = M4LInterfaceComponent(
            controls=self.controls, component_guard=self.component_guard)
        self.get_control_names = self._m4l_interface.get_control_names
        self.get_control = self._m4l_interface.get_control
        self.grab_control = self._m4l_interface.grab_control
        self.release_control = self._m4l_interface.release_control

    """Mono overrides and additions"""

    def _setup_monobridge(self):
        self._monobridge = MonoBridgeElement(self)
        self._monobridge.name = 'MonoBridge'

    def _setup_monomod(self):
        self._host = MonomodComponent(self)
        self._host.name = 'Monomod_Host'
        self.hosts = [self._host]

    def update_display(self):
        ControlSurface.update_display(self)
        self._timer = (self._timer + 1) % 256
        self.flash()

    def flash(self):
        if self._host.is_enabled():
            for control in self.controls:
                if isinstance(control, MonoButtonElement):
                    control.flash(self._timer)
示例#21
0
class Launchpad(ControlSurface):
    """ Script for Novation's Launchpad Controller """
    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        self.set_suppress_rebuild_requests(True)
        self._suppress_send_midi = True
        self._suppress_session_highlight = True
        is_momentary = True
        self._suggested_input_port = 'Launchpad'
        self._suggested_output_port = 'Launchpad'
        self._control_is_with_automap = False
        self._user_byte_write_button = ButtonElement(is_momentary,
                                                     MIDI_CC_TYPE, 0, 16)
        self._user_byte_write_button.name = 'User_Byte_Button'
        self._user_byte_write_button.send_value(1)
        self._user_byte_write_button.add_value_listener(self._user_byte_value)
        self._wrote_user_byte = False
        self._challenge = Live.Application.get_random_int(
            0, 400000000) & 2139062143
        matrix = ButtonMatrixElement()
        matrix.name = 'Button_Matrix'
        for row in range(8):
            button_row = []
            for column in range(8):
                button = ConfigurableButtonElement(is_momentary,
                                                   MIDI_NOTE_TYPE, 0,
                                                   row * 16 + column)
                button.name = str(column) + '_Clip_' + str(row) + '_Button'
                button_row.append(button)

            matrix.add_row(tuple(button_row))

        self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0)
        self._config_button.add_value_listener(self._config_value)
        top_buttons = [
            ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0,
                                      104 + index) for index in range(8)
        ]
        side_buttons = [
            ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0,
                                      SIDE_NOTES[index]) for index in range(8)
        ]
        top_buttons[0].name = 'Bank_Select_Up_Button'
        top_buttons[1].name = 'Bank_Select_Down_Button'
        top_buttons[2].name = 'Bank_Select_Left_Button'
        top_buttons[3].name = 'Bank_Select_Right_Button'
        top_buttons[4].name = 'Session_Button'
        top_buttons[5].name = 'User1_Button'
        top_buttons[6].name = 'User2_Button'
        top_buttons[7].name = 'Mixer_Button'
        side_buttons[0].name = 'Vol_Button'
        side_buttons[1].name = 'Pan_Button'
        side_buttons[2].name = 'SndA_Button'
        side_buttons[3].name = 'SndB_Button'
        side_buttons[4].name = 'Stop_Button'
        side_buttons[5].name = 'Trk_On_Button'
        side_buttons[6].name = 'Solo_Button'
        side_buttons[7].name = 'Arm_Button'
        self._selector = MainSelectorComponent(matrix, tuple(top_buttons),
                                               tuple(side_buttons),
                                               self._config_button, self)
        self._selector.name = 'Main_Modes'
        self._do_combine()
        for control in self.controls:
            if isinstance(control, ConfigurableButtonElement):
                control.add_value_listener(self._button_value)

        self._suppress_session_highlight = False
        self.set_suppress_rebuild_requests(False)

        self.log_message("LaunchPad85 Loaded !")

    def disconnect(self):
        self._suppress_send_midi = True
        for control in self.controls:
            if isinstance(control, ConfigurableButtonElement):
                control.remove_value_listener(self._button_value)
        self._do_uncombine()
        self._selector = None
        self._user_byte_write_button.remove_value_listener(
            self._user_byte_value)
        self._config_button.remove_value_listener(self._config_value)
        ControlSurface.disconnect(self)
        self._suppress_send_midi = False
        self._config_button.send_value(32)
        self._config_button.send_value(0)
        self._config_button = None
        self._user_byte_write_button.send_value(0)
        self._user_byte_write_button = None

    _active_instances = []

    def highlighting_session_component(self):
        " Return the session component showing the ring in Live session "
        return self._selector.session_component()

    def _combine_active_instances():
        support_devices = False
        for instance in Launchpad._active_instances:
            support_devices |= (instance._device_component != None)
        offset = 0
        for instance in Launchpad._active_instances:
            instance._activate_combination_mode(offset, support_devices)
            offset += instance._selector._session.width()

    _combine_active_instances = staticmethod(_combine_active_instances)

    def _activate_combination_mode(self, track_offset, support_devices):
        if (LINK_STEPSEQ):
            self._selector._stepseq.link_with_step_offset(track_offset)
        if (LINK_SESSION):
            self._selector._session.link_with_track_offset(track_offset)

    def _do_combine(self):
        if (DO_COMBINE and (self not in Launchpad._active_instances)):
            Launchpad._active_instances.append(self)
            Launchpad._combine_active_instances()

    def _do_uncombine(self):
        if self in Launchpad._active_instances:
            Launchpad._active_instances.remove(self)
            if (LINK_SESSION):
                self._selector._session.unlink()
            if (LINK_STEPSEQ):
                self._selector._stepseq.unlink()
            Launchpad._combine_active_instances()

    def refresh_state(self):
        ControlSurface.refresh_state(self)
        self.schedule_message(5, self._update_hardware)

    def handle_sysex(self, midi_bytes):
        if len(midi_bytes) == 8:
            if midi_bytes[1:5] == (0, 32, 41, 6):
                response = long(midi_bytes[5])
                response += long(midi_bytes[6]) << 8
                if response == Live.Application.encrypt_challenge2(
                        self._challenge):
                    self._suppress_send_midi = False
                    self.set_enabled(True)

    def build_midi_map(self, midi_map_handle):
        ControlSurface.build_midi_map(self, midi_map_handle)
        if self._selector.mode_index == 1:
            new_channel = self._selector.channel_for_current_mode()
            for note in DRUM_NOTES:
                self._translate_message(MIDI_NOTE_TYPE, note, 0, note,
                                        new_channel)

    def _send_midi(self, midi_bytes):
        sent_successfully = False
        if not self._suppress_send_midi:
            sent_successfully = ControlSurface._send_midi(self, midi_bytes)
        return sent_successfully

    def _update_hardware(self):
        self._suppress_send_midi = False
        self._wrote_user_byte = True
        self._user_byte_write_button.send_value(1)
        self._suppress_send_midi = True
        self.set_enabled(False)
        self._suppress_send_midi = False
        self._send_challenge()

    def _send_challenge(self):
        for index in range(4):
            challenge_byte = self._challenge >> 8 * index & 127
            self._send_midi((176, 17 + index, challenge_byte))

    def _user_byte_value(self, value):
        assert (value in range(128))
        if (not self._wrote_user_byte):
            enabled = (value == 1)
            self._control_is_with_automap = (not enabled)
            self._suppress_send_midi = self._control_is_with_automap
            if not self._control_is_with_automap:
                for control in self.controls:
                    if isinstance(control, ConfigurableButtonElement):
                        control.set_force_next_value()

            self._selector.set_mode(0)
            self.set_enabled(enabled)
            self._suppress_send_midi = False
        else:
            self._wrote_user_byte = False

    def _button_value(self, value):
        assert (value in range(128))

    def _config_value(self, value):
        assert (value in range(128))

    def _set_session_highlight(self, track_offset, scene_offset, width, height,
                               include_return_tracks):
        if not self._suppress_session_highlight:
            ControlSurface._set_session_highlight(self, track_offset,
                                                  scene_offset, width, height,
                                                  include_return_tracks)
示例#22
0
class Launchpad(ControlSurface):
    u""" Script for Novation's Launchpad Controller """
    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
            self._suppress_send_midi = True
            self._suppress_session_highlight = True
            is_momentary = True
            self._suggested_input_port = 'Launchpad'
            self._suggested_output_port = 'Launchpad'
            self._control_is_with_automap = False
            self._user_byte_write_button = ButtonElement(
                is_momentary, MIDI_CC_TYPE, 0, 16)
            self._user_byte_write_button.name = 'User_Byte_Button'
            self._user_byte_write_button.send_value(1)
            self._user_byte_write_button.add_value_listener(
                self._user_byte_value)
            self._wrote_user_byte = False
            self._challenge = Live.Application.get_random_int(
                0, 400000000) & 2139062143
            matrix = ButtonMatrixElement()
            matrix.name = 'Button_Matrix'
            for row in range(8):
                button_row = []
                for column in range(8):
                    button = ConfigurableButtonElement(is_momentary,
                                                       MIDI_NOTE_TYPE, 0,
                                                       row * 16 + column)
                    button.name = str(column) + '_Clip_' + str(row) + '_Button'
                    button_row.append(button)

                matrix.add_row(tuple(button_row))

            self._config_button = ButtonElement(is_momentary,
                                                MIDI_CC_TYPE,
                                                0,
                                                0,
                                                optimized_send_midi=False)
            self._config_button.add_value_listener(self._config_value)
            top_buttons = [
                ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0,
                                          104 + index) for index in range(8)
            ]
            side_buttons = [
                ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0,
                                          SIDE_NOTES[index])
                for index in range(8)
            ]
            top_buttons[0].name = 'Bank_Select_Up_Button'
            top_buttons[1].name = 'Bank_Select_Down_Button'
            top_buttons[2].name = 'Bank_Select_Left_Button'
            top_buttons[3].name = 'Bank_Select_Right_Button'
            top_buttons[4].name = 'Session_Button'
            top_buttons[5].name = 'User1_Button'
            top_buttons[6].name = 'User2_Button'
            top_buttons[7].name = 'Mixer_Button'
            side_buttons[0].name = 'Vol_Button'
            side_buttons[1].name = 'Pan_Button'
            side_buttons[2].name = 'SndA_Button'
            side_buttons[3].name = 'SndB_Button'
            side_buttons[4].name = 'Stop_Button'
            side_buttons[5].name = 'Trk_On_Button'
            side_buttons[6].name = 'Solo_Button'
            side_buttons[7].name = 'Arm_Button'
            self._selector = MainSelectorComponent(matrix, tuple(top_buttons),
                                                   tuple(side_buttons),
                                                   self._config_button)
            self._selector.name = 'Main_Modes'
            for control in self.controls:
                if isinstance(control, ConfigurableButtonElement):
                    control.add_value_listener(self._button_value)

            self.set_highlighting_session_component(
                self._selector.session_component())
            self._suppress_session_highlight = False

    def disconnect(self):
        self._suppress_send_midi = True
        for control in self.controls:
            if isinstance(control, ConfigurableButtonElement):
                control.remove_value_listener(self._button_value)

        self._selector = None
        self._user_byte_write_button.remove_value_listener(
            self._user_byte_value)
        self._config_button.remove_value_listener(self._config_value)
        ControlSurface.disconnect(self)
        self._suppress_send_midi = False
        self._config_button.send_value(32)
        self._config_button.send_value(0)
        self._config_button = None
        self._user_byte_write_button.send_value(0)
        self._user_byte_write_button = None
        return

    def refresh_state(self):
        ControlSurface.refresh_state(self)
        self.schedule_message(5, self._update_hardware)

    def handle_sysex(self, midi_bytes):
        if len(midi_bytes) == 8:
            if midi_bytes[1:5] == (0, 32, 41, 6):
                response = long(midi_bytes[5])
                response += long(midi_bytes[6]) << 8
                if response == Live.Application.encrypt_challenge2(
                        self._challenge):
                    self._on_handshake_successful()

    def _on_handshake_successful(self):
        self._suppress_send_midi = False
        self.set_enabled(True)

    def build_midi_map(self, midi_map_handle):
        ControlSurface.build_midi_map(self, midi_map_handle)
        if self._selector.mode_index == 1:
            new_channel = self._selector.channel_for_current_mode()
            for note in DRUM_NOTES:
                self._translate_message(MIDI_NOTE_TYPE, note, 0, note,
                                        new_channel)

    def _send_midi(self, midi_bytes, optimized=None):
        sent_successfully = False
        if not self._suppress_send_midi:
            sent_successfully = ControlSurface._send_midi(self,
                                                          midi_bytes,
                                                          optimized=optimized)
        return sent_successfully

    def _update_hardware(self):
        self._suppress_send_midi = False
        self._wrote_user_byte = True
        self._user_byte_write_button.send_value(1)
        self._suppress_send_midi = True
        self.set_enabled(False)
        self._suppress_send_midi = False
        self._send_challenge()

    def _send_challenge(self):
        for index in range(4):
            challenge_byte = self._challenge >> 8 * index & 127
            self._send_midi((176, 17 + index, challenge_byte))

    def _user_byte_value(self, value):
        assert value in range(128)
        if not self._wrote_user_byte:
            enabled = value == 1
            self._control_is_with_automap = not enabled
            self._suppress_send_midi = self._control_is_with_automap
            if not self._control_is_with_automap:
                for control in self.controls:
                    if isinstance(control, ConfigurableButtonElement):
                        control.set_force_next_value()

            self._selector.set_mode(0)
            self.set_enabled(enabled)
            self._suppress_send_midi = False
        else:
            self._wrote_user_byte = False

    def _button_value(self, value):
        assert value in range(128)

    def _config_value(self, value):
        assert value in range(128)

    def _set_session_highlight(self, track_offset, scene_offset, width, height,
                               include_return_tracks):
        if not self._suppress_session_highlight:
            ControlSurface._set_session_highlight(self, track_offset,
                                                  scene_offset, width, height,
                                                  include_return_tracks)
class Maschine(ControlSurface):
    __module__ = __name__
    __doc__ = 'Basic Control Script for All Maschine Modell Mikro, Mikro Mk2, Mk1, Mk2, Studio'

    def __init__(self, c_instance):
        super(Maschine, self).__init__(c_instance)
        with self.component_guard():
            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()

    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.0
        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
        self.set_sel_arm_button.send_value(self.arm_selected_track and 127 or 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):
        from pickle import loads, dumps
        from encodings import ascii
        nop(ascii)
        preferences = self._c_instance.preferences(self.preferences_name())
        self._pref_dict = {}
        try:
            self._pref_dict = loads(str(preferences))
        except Exception:
            pass

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

    def preferences_name(self):
        return 'Maschine'

    def _pre_serialize(self):
        from pickle import dumps
        from encodings import ascii
        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])
        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 button, (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)

        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

    @subject_slot('appointed_device')
    def _on_appointed_device_changed(self):
        self._modeselect._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

    @subject_slot('devices')
    def _on_devices_changed(self):
        pass

    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):
        with self.component_guard():
            with self._is_sending_scheduled_messages():
                self._task_group.update(0.1)
            self._modeselect.notify(self.blink_state)
            self.blink_state = (self.blink_state + 1) % 4
            self.display_task.tick()
            self.update_undo_redo(False)

    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
            self._undo_button.send_value(self.undo_state == 1 and 127 or 0)
        if self.song().can_redo != self.redo_state:
            self.redo_state = self.song().can_redo
            self._redo_button.send_value(self.redo_state == 1 and 127 or 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

    @subject_slot('value')
    def _do_fire_button(self, value):
        raise self._fire_button != None or AssertionError
        raise value in range(128) or 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()

    @subject_slot('value')
    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'))

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

    @subject_slot('value')
    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)

    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)

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

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

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

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

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

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

    @subject_slot('value')
    def _do_toggle_send(self, value):
        if not value in range(128):
            raise AssertionError
            if self.isShiftDown():
                value != 0 and 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
            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))

    @subject_slot('value')
    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)
                    self.arm_selected_track and track.can_be_armed and arm_exclusive(self.song(), track)

    @subject_slot('value')
    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)
                    self.arm_selected_track and track.can_be_armed and arm_exclusive(self.song(), track)

    @subject_slot('value')
    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)

    @subject_slot('value')
    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
                value != 0 and (not self.application().view.is_view_visible('Detail') or not self.application().view.is_view_visible('Detail/DeviceChain')) and 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)

    @subject_slot('value')
    def _nav_value_right(self, value):
        if not self._device_nav_button_right != None:
            raise AssertionError
            if not value in range(128):
                raise AssertionError
                modifier_pressed = value != 0 and True
                (not self.application().view.is_view_visible('Detail') or not self.application().view.is_view_visible('Detail/DeviceChain')) and 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)

    @subject_slot('value')
    def _do_focus_navigate(self, value):
        if not self._navigate_button != None:
            raise AssertionError
            raise value in range(128) or AssertionError
            self.nav_index = value != 0 and (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]))

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

    @subject_slot('follow_song')
    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)

    @subject_slot('value')
    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)

    @subject_slot('value')
    def _hold_duplicate_action(self, value):
        if value != 0:
            pass

    @subject_slot('value')
    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()

    @subject_slot('value')
    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')

    @subject_slot('value')
    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')

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

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

    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
                        d1 += name[:6] + (i < 3 and '|' or '')
                    else:
                        d1 += '      ' + (i < 3 and '|' or '')

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

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

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

    def send_to_display(self, text, grid = 0):
        if USE_DISPLAY == False:
            return
        if self._diplay_cache[grid] == text:
            return
        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 button, (track_index, scene_index) in self._bmatrix.iterbuttons():
            if button:
                button.send_color_direct(PColor.OFF[0])

        time.sleep(0.2)
        self._active = False
        self._suppress_send_midi = True
        super(Maschine, self).disconnect()
示例#24
0
class Launchpad(ControlSurface):

	""" Script for Novation's Launchpad Controller """

	def __init__(self, c_instance):
		live = Live.Application.get_application()
		self._live_major_version = live.get_major_version()
		self._live_minor_version = live.get_minor_version()
		self._live_bugfix_version = live.get_bugfix_version()
		self._mk2 = Settings.DEVICE == 'Launchpad mk2'
		if self._mk2:
			self._skin = Skin('Launchpad mk2')
			self._side_notes = (89, 79, 69, 59, 49, 39, 29, 19)
			self._drum_notes = (20, 30, 31, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126)
		else:
			self._skin = Skin('Launchpad')
			self._side_notes = (8, 24, 40, 56, 72, 88, 104, 120)
			self._drum_notes = (41, 42, 43, 44, 45, 46, 47, 57, 58, 59, 60, 61, 62, 63, 73, 74, 75, 76, 77, 78, 79, 89, 90, 91, 92, 93, 94, 95, 105, 106, 107)
			
			
		ControlSurface.__init__(self, c_instance)
	
	
		with self.component_guard():
			self._suppress_send_midi = True
			self._suppress_session_highlight = True

			is_momentary = True
			if self._mk2:
				self._suggested_input_port = 'Launchpad'
				self._suggested_output_port = 'Launchpad'
			else:
				self._suggested_input_port = 'Launchpad MK2'
				self._suggested_output_port = 'Launchpad MK2'
				
			self._control_is_with_automap = False
			self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)
			self._user_byte_write_button.name = 'User_Byte_Button'
			self._user_byte_write_button.send_value(1)
			self._user_byte_write_button.add_value_listener(self._user_byte_value)
			self._wrote_user_byte = False
			self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143
			matrix = ButtonMatrixElement()
			matrix.name = 'Button_Matrix'
			for row in range(8):
				button_row = []
				for column in range(8):
					if self._mk2:
						# for mk2 buttons are assigned "top to bottom"
 						midi_note = (81 - (10 * row)) + column
					else:
						midi_note = row * 16 + column
					button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, midi_note, self._skin.off)
					button.name = str(column) + '_Clip_' + str(row) + '_Button'
					button_row.append(button)

				matrix.add_row(tuple(button_row))

			self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0, optimized_send_midi=False)
			self._config_button.add_value_listener(self._config_value)
			top_buttons = [ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0, 104 + index, self._skin.off) for index in range(8)]
			side_buttons = [ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, self._side_notes[index], self._skin.off) for index in range(8)]
			top_buttons[0].name = 'Bank_Select_Up_Button'
			top_buttons[1].name = 'Bank_Select_Down_Button'
			top_buttons[2].name = 'Bank_Select_Left_Button'
			top_buttons[3].name = 'Bank_Select_Right_Button'
			top_buttons[4].name = 'Session_Button'
			top_buttons[5].name = 'User1_Button'
			top_buttons[6].name = 'User2_Button'
			top_buttons[7].name = 'Mixer_Button'
			side_buttons[0].name = 'Vol_Button'
			side_buttons[1].name = 'Pan_Button'
			side_buttons[2].name = 'SndA_Button'
			side_buttons[3].name = 'SndB_Button'
			side_buttons[4].name = 'Stop_Button'
			side_buttons[5].name = 'Trk_On_Button'
			side_buttons[6].name = 'Solo_Button'
			side_buttons[7].name = 'Arm_Button'
			self._osd = M4LInterface()
			self._osd.name = "OSD"
			self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button, self._osd, self, self._skin)
			self._selector.name = 'Main_Modes'
			self._do_combine()
			for control in self.controls:
				if isinstance(control, ConfigurableButtonElement):
					control.add_value_listener(self._button_value)

			self.set_highlighting_session_component(self._selector.session_component())
			self._suppress_session_highlight = False

			self.log_message("LaunchPad95 Loaded !")

	def disconnect(self):
		self._suppress_send_midi = True
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.remove_value_listener(self._button_value)
		self._do_uncombine()
		self._selector = None
		self._user_byte_write_button.remove_value_listener(self._user_byte_value)
		self._config_button.remove_value_listener(self._config_value)
		ControlSurface.disconnect(self)
		self._suppress_send_midi = False
		if self._mk2:
			self._send_midi((240, 0, 32, 41, 2, 24, 64, 247))
			# launchpad mk2 needs disconnect string sent			
		self._config_button.send_value(32)
		self._config_button.send_value(0)
		self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None

	_active_instances = []

	#def highlighting_session_component(self):
	#	" Return the session component showing the ring in Live session "
	#	return self._selector.session_component()

	def _combine_active_instances():
		support_devices = False
		for instance in Launchpad._active_instances:
			support_devices |= (instance._device_component != None)
		offset = 0
		for instance in Launchpad._active_instances:
			instance._activate_combination_mode(offset, support_devices)
			offset += instance._selector._session.width()

	_combine_active_instances = staticmethod(_combine_active_instances)

	def _activate_combination_mode(self, track_offset, support_devices):
		if(Settings.STEPSEQ__LINK_WITH_SESSION):
			self._selector._stepseq.link_with_step_offset(track_offset)
		if(Settings.SESSION__LINK):
			self._selector._session.link_with_track_offset(track_offset)

	def _do_combine(self):
		if (DO_COMBINE and (self not in Launchpad._active_instances)):
			Launchpad._active_instances.append(self)
			Launchpad._combine_active_instances()

	def _do_uncombine(self):
		if self in Launchpad._active_instances:
			Launchpad._active_instances.remove(self)
			if(Settings.SESSION__LINK):
				self._selector._session.unlink()
			if(Settings.STEPSEQ__LINK_WITH_SESSION):
				self._selector._stepseq.unlink()
			Launchpad._combine_active_instances()

	def refresh_state(self):
		ControlSurface.refresh_state(self)
		self.schedule_message(5, self._update_hardware)

	def handle_sysex(self, midi_bytes):
		if self._mk2:
			# mk2 has different challenge and params
			if len(midi_bytes) == 10:
				if midi_bytes[:7] == (240, 0, 32, 41, 2, 24, 64):
					response = long(midi_bytes[7])
					response += long(midi_bytes[8]) << 8
					if response == Live.Application.encrypt_challenge2(self._challenge):
						# self.log_message("Challenge Response ok")
						self._suppress_send_midi = False
						self.set_enabled(True)
		else:
			if len(midi_bytes) == 8:
				if midi_bytes[1:5] == (0, 32, 41, 6):
					response = long(midi_bytes[5])
					response += long(midi_bytes[6]) << 8
					if response == Live.Application.encrypt_challenge2(self._challenge):
						self._suppress_send_midi = False
						self.set_enabled(True)

	def build_midi_map(self, midi_map_handle):
		ControlSurface.build_midi_map(self, midi_map_handle)
		if self._selector.mode_index == 1:
			if self._selector._sub_mode_index[self._selector._mode_index] > 0:  # disable midi map rebuild for instrument mode to prevent light feedback errors
				new_channel = self._selector.channel_for_current_mode()
				# self.log_message(str(new_channel))
				for note in self.drum_notes:
					self._translate_message(MIDI_NOTE_TYPE, note, 0, note, new_channel)

	def _send_midi(self, midi_bytes, optimized=None):
		sent_successfully = False
		if not self._suppress_send_midi:
			sent_successfully = ControlSurface._send_midi(self, midi_bytes, optimized=optimized)
		return sent_successfully

	def _update_hardware(self):
		self._suppress_send_midi = False
		self._wrote_user_byte = True
		self._user_byte_write_button.send_value(1)
		self._suppress_send_midi = True
		self.set_enabled(False)
		self._suppress_send_midi = False
		self._send_challenge()

	def _send_challenge(self):
		if self._mk2:
			challenge_bytes = tuple([ self._challenge >> 8 * index & 127 for index in xrange(4) ])
			self._send_midi((240, 0, 32, 41, 2, 24, 64) + challenge_bytes + (247,))
		else:
			for index in range(4):
				challenge_byte = self._challenge >> 8 * index & 127
				self._send_midi((176, 17 + index, challenge_byte))
		

	def _user_byte_value(self, value):
		assert (value in range(128))
		if not self._wrote_user_byte:
			enabled = (value == 1)
			self._control_is_with_automap = not enabled
			self._suppress_send_midi = self._control_is_with_automap
			if not self._control_is_with_automap:
				for control in self.controls:
					if isinstance(control, ConfigurableButtonElement):
						control.set_force_next_value()

			self._selector.set_mode(0)
			self.set_enabled(enabled)
			self._suppress_send_midi = False
		else:
			self._wrote_user_byte = False

	def _button_value(self, value):
		assert value in range(128)

	def _config_value(self, value):
		assert value in range(128)

	def _set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks):
		if not self._suppress_session_highlight:
			ControlSurface._set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks)
示例#25
0
文件: Axiom_OJI.py 项目: cybass/m4m7
class Axiom_OJI(AxiomPro):
    """ Script for the M-Audio Axiom Pro OJI version """

    _browser_mode_enabled = False

    def __init__(self, *a, **k):
        #super(Axiom_OJI, self).__init__(*a, **k)
        ControlSurface.__init__(self, *a, **k)
        with self.component_guard():
            is_momentary = True
            #self.set_pad_translations(PAD_TRANSLATIONS)
            self._suggested_input_port = u'HyperControl'
            self._suggested_output_port = u'HyperControl'
            self._display_on_button = ButtonElement(not is_momentary,
                                                    MIDI_CC_TYPE, 15, 79)
            self._waiting_for_first_response = True
            self._mixer1 = DisplayingMixerComponent(0)
            self._mixer1.set_select_buttons(
                ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 111),
                ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 110))
            self._mixer1.set_mute_button(
                ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 12))
            self._mixer1.set_solo_button(
                ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 13))
            self._mixer2 = NotifyingMixerComponent(8)
            self._mixer2.set_bank_buttons(
                ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 15),
                ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 14))
            self._mixer2.master_strip().set_volume_control(
                SliderElement(MIDI_CC_TYPE, 15, 41))
            for index in range(8):
                self._mixer2.channel_strip(index).set_volume_control(
                    SliderElement(MIDI_CC_TYPE, 15, 33 + index))

            self._device = PageableDeviceComponent(
                device_selection_follows_track_selection=True)
            self.set_device_component(self._device)
            self._ffwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15,
                                              115)
            self._rwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15,
                                             114)
            self._loop_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15,
                                              113)
            self._transport = TransportComponent()
            self._transport.set_stop_button(
                ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 116))
            self._transport.set_play_button(
                ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 117))
            self._transport.set_record_button(
                ButtonElement(is_momentary,
                              MIDI_CC_TYPE,
                              15,
                              118,
                              name='RecordButton'))
            self._session = SessionComponent(0, 0)
            self._transport_view_modes = TransportViewModeSelector(
                self._transport, self._session, self._ffwd_button,
                self._rwd_button, self._loop_button)
            self._select_button_modes = SelectButtonModeSelector(
                self._mixer2,
                tuple([
                    ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 49 + offset)
                    for offset in range(8)
                ]))
            self._select_button_modes.set_mode_toggle(
                ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 57))
            self._mixer_encoder_modes = EncoderMixerModeSelector(self._mixer2)
            self._encoders = []
            for offset in range(8):
                self._encoders.append(
                    PeekableEncoderElement(
                        MIDI_CC_TYPE, 15, 17 + offset,
                        Live.MidiMap.MapMode.relative_smooth_two_compliment))
                self._encoders[-1].set_feedback_delay(-1)

            self._mixer_or_device = MixerOrDeviceModeSelector(
                self._mixer_encoder_modes, self._device, tuple(self._encoders),
                tuple([
                    ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 74 + offset)
                    for offset in range(4)
                ]))
            self._mixer_or_device.set_mode_toggle(
                ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 109))
            self._mixer_or_device.set_peek_button(
                ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 78))
            self._track_display = PhysicalDisplayElement(8, 1)
            self._track_display.set_clear_all_message(SYSEX_START + (16, 247))
            self._track_display.set_message_parts(SYSEX_START + (17, 1, 0, 0),
                                                  (247, ))
            #self._track_display.segment(0).set_data_source(mixer1.selected_strip().track_name_data_source())
            self._device_display = PhysicalDisplayElement(8, 1)
            self._device_display.set_message_parts(
                SYSEX_START + (17, 1, 0, 10), (247, ))
            self._parameter_display = PhysicalDisplayElement(16, 1)
            self._parameter_display.set_message_parts(
                SYSEX_START + (17, 2, 0, 0), (247, ))
            #self._select_button_modes.set_mode_display(parameter_display)
            #self._mixer1.set_display(parameter_display)
            #self._mixer2.set_bank_display(parameter_display)
            self._page_displays = []
            for index in range(4):
                self._page_displays.append(PhysicalDisplayElement(5, 1))
                self._page_displays[-1].set_message_parts(
                    SYSEX_START + (17, 4, index, 0), (247, ))

            self._encoder_display = PhysicalDisplayElement(80, 8)
            self._encoder_display.set_message_parts(SYSEX_START + (17, 3),
                                                    (247, ))
            for index in range(8):
                pos_id = tuple()
                if index != 0:
                    pos_id += (0, )
                if index > 3:
                    pos_id += (index % 4, 13)
                else:
                    pos_id += (index % 4, 0)
                self._encoder_display.segment(index).set_position_identifier(
                    pos_id)

            self._data_sources = [
                DisplayDataSource('                           ')
                for index in range(7)
            ]
            top_display = PhysicalDisplayElement(20, 1)
            top_display.set_message_parts(SYSEX_START + (17, 1, 0, 0), (247, ))
            top_display.set_clear_all_message(SYSEX_START + (16, 247))
            self._header_display = top_display
            self._display1 = top_display.segment(0)
            long_display = PhysicalDisplayElement(80, 4)
            long_display.set_message_parts(SYSEX_START + (
                17,
                3,
            ), (247, ))
            self._display2 = long_display.segment(0)
            pos_id = tuple()
            pos_id += (0, 0)
            self._display2.set_position_identifier(pos_id)
            self._display3 = long_display.segment(1)
            pos_id = tuple()
            pos_id += (0, 1, 0)
            self._display3.set_position_identifier(pos_id)
            self._display4 = long_display.segment(2)
            pos_id = tuple()
            pos_id += (0, 2, 0)
            self._display4.set_position_identifier(pos_id)
            self._display5 = long_display.segment(3)
            pos_id = tuple()
            pos_id += (0, 3, 0)
            self._display5.set_position_identifier(pos_id)
            middle_display = PhysicalDisplayElement(20, 1)
            middle_display.set_message_parts(SYSEX_START + (17, 2, 0, 0),
                                             (247, ))
            self._display6 = middle_display.segment(0)
            bottom_display = PhysicalDisplayElement(20, 1)
            bottom_display.set_message_parts(SYSEX_START + (17, 4, 0, 0),
                                             (247, ))
            self._display7 = bottom_display.segment(0)

            self._browser_displays = [
                self._display1, self._display2, self._display3, self._display4,
                self._display5, self._display6, self._display7
            ]
            self._drumpads = [
                ButtonElement(True,
                              MIDI_NOTE_TYPE,
                              15,
                              81 + index,
                              name='Pad_' + str(index)) for index in range(8)
            ]
            self._setup_m4l_interface()

        self.log_message('Axiom_OJI script installed')

    """
	def __init__(self, *a, **k):
		super(Axiom_OJI, self).__init__(*a, **k)
		with self.component_guard():
			#self._data_sources = (DisplayDataSource('TEST') for index in range(7))
			self._display1 = PhysicalDisplayElement(16, 1)
			self._display1.set_message_parts(SYSEX_START + (17, 1, 0, 0), (247,))
			self._header_display = self._display1
			self._header_display.set_clear_all_message(SYSEX_START + (16, 247))
			self._display2 = PhysicalDisplayElement(16, 1)
			self._display2.set_message_parts(SYSEX_START + (17, 3, 0, 0), (247,))
			self._display3 = PhysicalDisplayElement(16, 1)
			self._display3.set_message_parts(SYSEX_START + (17, 3, 1, 0), (247,))
			self._display4 = PhysicalDisplayElement(16, 1)
			self._display4.set_message_parts(SYSEX_START + (17, 3, 2, 0), (247,))
			self._display5 = PhysicalDisplayElement(16, 1)
			self._display5.set_message_parts(SYSEX_START + (17, 3, 3, 0), (247,))
			self._display6 = PhysicalDisplayElement(16, 1)
			self._display6.set_message_parts(SYSEX_START + (17, 2, 0, 0), (247,))
			self._display7 = PhysicalDisplayElement(16, 1)
			self._display7 .set_message_parts(SYSEX_START + (17, 4, 0, 0), (247,))
			self._browser_displays = [self._display1, self._display2, self._display3, self._display4, self._display5, self._display6, self._display7]
	"""

    def _setup_m4l_interface(self):
        self._m4l_interface = M4LInterfaceComponent(
            controls=self.controls,
            component_guard=self.component_guard,
            priority=10)
        self._m4l_interface.name = "M4LInterface"
        self.get_control_names = self._m4l_interface.get_control_names
        self.get_control = self._m4l_interface.get_control
        self.grab_control = self._m4l_interface.grab_control
        self.release_control = self._m4l_interface.release_control

    def handle_sysex(self, midi_bytes):
        if midi_bytes[0:-2] == SYSEX_START + (32, ):
            msg_id_byte = midi_bytes[-2]
            is_setup_response = msg_id_byte in (46, 38)
            has_sliders = msg_id_byte == 46
            if is_setup_response:
                if self._waiting_for_first_response:
                    self._waiting_for_first_response = False
                    self._display_on_button.send_value(0)
                    if not self._browser_mode_enabled:
                        for component in self.components:
                            component.set_enabled(True)

                    self._display_on_button.send_value(127)
                    self._send_midi(SYSEX_START + (16, 247))
                    self._send_midi(SYSEX_START +
                                    (17, 3, 0, 1, 65, 98, 108, 101, 116, 111,
                                     110, 32, 76, 105, 118, 101, 32, 67, 111,
                                     110, 116, 114, 111, 108, 32, 0, 1, 4, 83,
                                     117, 114, 102, 97, 99, 101, 32, 118, 49,
                                     46, 48, 46, 48, 46, 247))
                self._mixer_encoder_modes.set_show_volume_page(not has_sliders)
                #if not self._browser_mode_enabled:
                for display in self._displays:
                    display.set_block_messages(False)

                self.schedule_message(25, self._refresh_displays)
                #self.schedule_message(30, self._enable_browser)
            elif msg_id_byte == 43:
                self._send_midi(SYSEX_START + (16, 247))
                #if not self._browser_mode_enabled:
                for display in self._displays:
                    if display is self._track_display:
                        display.update()
                    else:
                        display.set_block_messages(True)

    def _enable_browser(self):
        self.enable_browser_mode(True)

    def enable_browser_mode(self, enable):
        self._browser_mode_enabled = enable > 0
        debug('enable_browser_mode:' + str(enable))
        if enable:
            for component in self.components:
                component.set_enabled(False)
            self._header_display.reset()
            self._track_display.segment(0).set_data_source(None)
            for index in range(7):
                debug('index: ' + str(index))
                self._browser_displays[index].set_data_source(
                    self._data_sources[index])
        else:
            self._header_display.reset()
            for index in range(7):
                debug('index: ' + str(index))
                self._browser_displays[index].set_data_source(None)
            for component in self.components:
                component.set_enabled(True)

    def _enable_browser_mode(self, enable):
        self._browser_mode_enabled = enable > 0
        #debug('enable_browser_mode', enable)
        if enable:
            #debug('here 1')
            for component in self.components:
                component.set_enabled(False)
            self._header_display.reset()
            #debug('here 2')
            #for index, display in enumerate(self._browser_displays):
            #debug('index:', index, 'display:', display)
            #self._data_sources[index].clear()
            #display.set_data_source(self._data_sources[index])
        else:
            for component in self.components:
                component.set_enabled(True)

    def write_to_lcd(self, display, message):
        if self._browser_mode_enabled and display in range(7):
            self._data_sources[display].set_display_string(message)

    def test_browser(self):
        debug('test_browser')
        browser = self.application.browser
        debug('browser is:', browser)
        user_folders = browser.user_folders
        debug('user_folders are:', user_folders)
        for item in user_folders:
            #debug('item is:', item, item.name)
            if item.name == 'defaultPresets':
                inneritems = item.iter_children
                for inneritem in inneritems:
                    debug('inneritem:', inneritem)
                    if inneritem.name == 'Default.aupreset':
                        browser.load_item(inneritem)
                        break

    def load_preset(self,
                    target=None,
                    folder=None,
                    directory='defaultPresets'):
        debug('load_preset()', target, folder, directory)
        if not target is None:
            browser = Live.Application.get_application(
            ).browser  ##if not self.application.view.browse_mode else self.application.browser.hotswap_target
            user_folders = browser.user_folders
            for item in user_folders:
                if item.name == directory:
                    if not folder is None:
                        folder_target = None
                        item_iterator = item.iter_children
                        inneritems = [inneritem for inneritem in item_iterator]
                        for inneritem in inneritems:
                            if inneritem.name == folder:
                                folder_target = inneritem
                                break
                        if folder_target:
                            item_iterator = folder_target.iter_children
                            inneritems = [
                                inneritem for inneritem in item_iterator
                            ]
                            for inneritem in inneritems:
                                if isinstance(target, int):
                                    if target < len(inneritems):
                                        if inneritems[target].is_loadable:
                                            browser.load_item(
                                                inneritems[target])
                                            break
                                        elif inneritems[target].is_folder:
                                            debug(inneritems[target],
                                                  '.is_folder')
                                            innertarget = inneritems[target]
                                            innertarget_iterator = innertarget.iter_children
                                            innertargetitems = [
                                                innertargetitem
                                                for innertargetitem in
                                                innertarget_iterator
                                            ]
                                            #debug('innertargetitems:', innertargetitems)
                                            if len(innertargetitems
                                                   ) > 0 and innertargetitems[
                                                       0].is_loadable:
                                                browser.load_item(
                                                    innertargetitems[0])
                                                break
                                            else:
                                                debug(innertargetitems[0],
                                                      'item isnt loadable 0')
                                                break
                                        else:
                                            debug(inneritems[target],
                                                  'item isnt loadable 1')
                                            break
                                else:
                                    if inneritem.name == target:
                                        if inneritem.is_loadable:
                                            browser.load_item(inneritem)
                                        else:
                                            debug(inneritem,
                                                  'item isnt loadable 2')
                                        break
                    else:
                        item_iterator = item.iter_children
                        inneritems = [inneritem for inneritem in item_iterator]
                        for inneritem in inneritems:
                            if isinstance(target, int):
                                if target < len(inneritems):
                                    if inneritems[target].is_loadable:
                                        browser.load_item(inneritems[target])
                                        break
                                    else:
                                        debug(inneritems[target],
                                              'item isnt loadable 3')
                                        break
                            else:
                                if inneritem.name == target:
                                    if inneritem.is_loadable:
                                        browser.load_item(inneritem)
                                        break
                                    else:
                                        debug(inneritem,
                                              'item isnt loadable 4')
                                        break

    def get_preset_names(self, folder=None, directory='defaultPresets'):
        #debug('get_preset_names', folder, directory)
        preset_names = [
            'no target', 'no target', 'no target', 'no target', 'no target',
            'no target', 'no target', 'no target'
        ]
        browser = Live.Application.get_application(
        ).browser  ##if not self.application.view.browse_mode else self.application.browser.hotswap_target
        user_folders = browser.user_folders
        for item in user_folders:
            if item.name == directory:
                if not folder is None:
                    folder_target = None
                    item_iterator = item.iter_children
                    inneritems = [inneritem for inneritem in item_iterator]
                    for inneritem in inneritems:
                        if inneritem.name == folder:
                            folder_target = inneritem
                            break
                    if folder_target:
                        item_iterator = folder_target.iter_children
                        preset_names = [
                            inneritem.name for inneritem in item_iterator
                        ]
                else:
                    item_iterator = item.iter_children
                    preset_names = [
                        inneritem.name for inneritem in item_iterator
                    ]
        #debug('names:', preset_names)
        return preset_names

    def write_presets_to_lcd(self, folder=None, directory='defaultPresets'):
        #debug('write_presets_to_lcd')
        preset_names = self.get_preset_names(folder, directory)
        #debug('names:', preset_names)
        for i, name in enumerate(preset_names):
            if i < 7:
                #debug('name:', i, name)
                self.write_to_lcd(i, name[:20])
示例#26
0
class Launchpad(ControlSurface):
	""" Script for Novation's Launchpad Controller """

	def __init__(self, c_instance):
		ControlSurface.__init__(self, c_instance)
		self.set_suppress_rebuild_requests(True)
		self._suppress_send_midi = True
		self._suppress_session_highlight = True
		is_momentary = True
		self._suggested_input_port = 'Launchpad'
		self._suggested_output_port = 'Launchpad'
		self._control_is_with_automap = False
		self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)
		self._user_byte_write_button.name = 'User_Byte_Button'
		self._user_byte_write_button.send_value(1)
		self._user_byte_write_button.add_value_listener(self._user_byte_value)
		self._wrote_user_byte = False
		self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143
		matrix = ButtonMatrixElement()
		matrix.name = 'Button_Matrix'
		for row in range(8):
			button_row = []
			for column in range(8):
				button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, row * 16 + column)
				button.name = str(column) + '_Clip_' + str(row) + '_Button'
				button_row.append(button)

			matrix.add_row(tuple(button_row))

		self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0)
		self._config_button.add_value_listener(self._config_value)
		top_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0, 104 + index) for index in range(8) ]
		side_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index]) for index in range(8) ]
		top_buttons[0].name = 'Bank_Select_Up_Button'
		top_buttons[1].name = 'Bank_Select_Down_Button'
		top_buttons[2].name = 'Bank_Select_Left_Button'
		top_buttons[3].name = 'Bank_Select_Right_Button'
		top_buttons[4].name = 'Session_Button'
		top_buttons[5].name = 'User1_Button'
		top_buttons[6].name = 'User2_Button'
		top_buttons[7].name = 'Mixer_Button'
		side_buttons[0].name = 'Vol_Button'
		side_buttons[1].name = 'Pan_Button'
		side_buttons[2].name = 'SndA_Button'
		side_buttons[3].name = 'SndB_Button'
		side_buttons[4].name = 'Stop_Button'
		side_buttons[5].name = 'Trk_On_Button'
		side_buttons[6].name = 'Solo_Button'
		side_buttons[7].name = 'Arm_Button'
		self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button, self)
		self._selector.name = 'Main_Modes'
		self._do_combine()
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.add_value_listener(self._button_value)

		self._suppress_session_highlight = False
		self.set_suppress_rebuild_requests(False)

		self.log_message("LaunchPad85 Loaded !")

	def disconnect(self):
		self._suppress_send_midi = True
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.remove_value_listener(self._button_value)
		self._do_uncombine()
		self._selector = None
		self._user_byte_write_button.remove_value_listener(self._user_byte_value)
		self._config_button.remove_value_listener(self._config_value)
		ControlSurface.disconnect(self)
		self._suppress_send_midi = False
		self._config_button.send_value(32)
		self._config_button.send_value(0)
		self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None

	_active_instances = []

	def highlighting_session_component(self):
		" Return the session component showing the ring in Live session "
		return self._selector.session_component()

	def _combine_active_instances():
		support_devices = False
		for instance in Launchpad._active_instances:
			support_devices |= (instance._device_component != None)
		offset = 0
		for instance in Launchpad._active_instances:
			instance._activate_combination_mode(offset, support_devices)
			offset += instance._selector._session.width()

	_combine_active_instances = staticmethod(_combine_active_instances)

	def _activate_combination_mode(self, track_offset, support_devices):
		if(LINK_STEPSEQ):
			self._selector._stepseq.link_with_step_offset(track_offset)
		if(LINK_SESSION):
			self._selector._session.link_with_track_offset(track_offset)
		

	def _do_combine(self):
		if (DO_COMBINE and (self not in Launchpad._active_instances)):
			Launchpad._active_instances.append(self)
			Launchpad._combine_active_instances()
	
	def _do_uncombine(self):
		if self in Launchpad._active_instances:
			Launchpad._active_instances.remove(self)
			if(LINK_SESSION):
				self._selector._session.unlink()
			if(LINK_STEPSEQ):
				self._selector._stepseq.unlink()
			Launchpad._combine_active_instances()


	def refresh_state(self):
		ControlSurface.refresh_state(self)
		self.schedule_message(5, self._update_hardware)

	def handle_sysex(self, midi_bytes):
		if len(midi_bytes) == 8:
			if midi_bytes[1:5] == (0, 32, 41, 6):
				response = long(midi_bytes[5])
				response += long(midi_bytes[6]) << 8
				if response == Live.Application.encrypt_challenge2(self._challenge):
					self._suppress_send_midi = False
					self.set_enabled(True)

	def build_midi_map(self, midi_map_handle):
		ControlSurface.build_midi_map(self, midi_map_handle)
		if self._selector.mode_index == 1:
			new_channel = self._selector.channel_for_current_mode()
			for note in DRUM_NOTES:
				self._translate_message(MIDI_NOTE_TYPE, note, 0, note, new_channel)

	def _send_midi(self, midi_bytes):
		sent_successfully = False
		if not self._suppress_send_midi:
			sent_successfully = ControlSurface._send_midi(self, midi_bytes)
		return sent_successfully

	def _update_hardware(self):
		self._suppress_send_midi = False
		self._wrote_user_byte = True
		self._user_byte_write_button.send_value(1)
		self._suppress_send_midi = True
		self.set_enabled(False)
		self._suppress_send_midi = False
		self._send_challenge()

	def _send_challenge(self):
		for index in range(4):
			challenge_byte = self._challenge >> 8 * index & 127
			self._send_midi((176, 17 + index, challenge_byte))

	def _user_byte_value(self, value):
		assert (value in range(128))
		if (not self._wrote_user_byte):
			enabled = (value == 1)
			self._control_is_with_automap = (not enabled)
			self._suppress_send_midi = self._control_is_with_automap
			if not self._control_is_with_automap:
				for control in self.controls:
					if isinstance(control, ConfigurableButtonElement):
						control.set_force_next_value()

			self._selector.set_mode(0)
			self.set_enabled(enabled)
			self._suppress_send_midi = False
		else:
			self._wrote_user_byte = False

	def _button_value(self, value):
		assert (value in range(128))

	def _config_value(self, value):
		assert (value in range(128))

	def _set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks):
		if not self._suppress_session_highlight:
			ControlSurface._set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks)
示例#27
0
class LaunchMod(ControlSurface):
	""" Script for Novation's Launchpad Controller """

	def __init__(self, c_instance):
		ControlSurface.__init__(self, c_instance)
		with self.component_guard():
			self._monomod_version = 'b995'
			self._host_name = 'LaunchMod'
			self._color_type = 'Launchpad'
			self.hosts = []
			self._timer = 0
			self._suppress_send_midi = True
			self._suppress_session_highlight = True
			self._suppress_highlight = False
			is_momentary = True
			self._suggested_input_port = 'Launchpad'
			self._suggested_output_port = 'Launchpad'
			self._control_is_with_automap = False
			self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)
			self._user_byte_write_button.name = 'User_Byte_Button'
			self._user_byte_write_button.send_value(1)
			self._user_byte_write_button.add_value_listener(self._user_byte_value)
			self._wrote_user_byte = False
			self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143
			matrix = ButtonMatrixElement()
			matrix.name = 'Button_Matrix'
			for row in range(8):
				button_row = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, ((row * 16) + column), str(column) + '_Clip_' + str(row) + '_Button', self) for column in range(8) ]
				matrix.add_row(tuple(button_row))
			self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0, optimized_send_midi=False)
			self._config_button.add_value_listener(self._config_value)
			top_button_names = ['Bank_Select_Up_Button', 'Bank_Select_Down_Button', 'Bank_Select_Left_Button', 'Bank_Select_Right_Button', 'Session_Button', 'User1_Button', 'User2_Button', 'Mixer_Button']
			side_button_names = ['Vol_Button', 'Pan_Button', 'SndA_Button',  'SndB_Button', 'Stop_Button', 'Trk_On_Button', 'Solo_Button', 'Arm_Button']
			top_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0, (104 + index), top_button_names[index], self) for index in range(8) ]
			side_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index], side_button_names[index], self) for index in range(8) ]
			self._setup_monobridge()
			self._setup_monomod()
			self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button, self)
			self._selector.name = 'Main_Modes'
			for control in self.controls:
				if isinstance(control, MonoButtonElement):
					control.add_value_listener(self._button_value)
			self.set_highlighting_session_component(self._selector.session_component())
			self._suppress_session_highlight = False
		self.log_message("--------------= " + str(self._monomod_version) + " log opened =--------------") #Create entry in log file


	

	def allow_updates(self, allow_updates):
		for component in self.components:
			component.set_allow_update(int(allow_updates!=0))

	def disconnect(self):
		self._suppress_send_midi = True
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.remove_value_listener(self._button_value)

		self._selector = None
		self._user_byte_write_button.remove_value_listener(self._user_byte_value)
		self._config_button.remove_value_listener(self._config_value)
		ControlSurface.disconnect(self)
		self._suppress_send_midi = False
		self._config_button.send_value(32)
		self._config_button.send_value(0)
		self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None

	def refresh_state(self):
		ControlSurface.refresh_state(self)
		self.schedule_message(5, self._update_hardware)

	def handle_sysex(self, midi_bytes):
		if len(midi_bytes) == 8:
			if midi_bytes[1:5] == (0, 32, 41, 6):
				response = long(midi_bytes[5])
				response += long(midi_bytes[6]) << 8
				if response == Live.Application.encrypt_challenge2(self._challenge):
					self._suppress_send_midi = False
					self.set_enabled(True)

	def build_midi_map(self, midi_map_handle):
		ControlSurface.build_midi_map(self, midi_map_handle)
		if self._selector.mode_index == 1:
			new_channel = self._selector.channel_for_current_mode()
			for note in DRUM_NOTES:
				self._translate_message(MIDI_NOTE_TYPE, note, 0, note, new_channel)

	def _send_midi(self, midi_bytes, optimized = None):
		sent_successfully = False
		if not self._suppress_send_midi:
			sent_successfully = ControlSurface._send_midi(self, midi_bytes, optimized=optimized)
		return sent_successfully

	def _update_hardware(self):
		self._suppress_send_midi = False
		self._wrote_user_byte = True
		self._user_byte_write_button.send_value(1)
		self._suppress_send_midi = True
		self.set_enabled(False)
		self._suppress_send_midi = False
		self._send_challenge()


	def _send_challenge(self):
		for index in range(4):
			challenge_byte = self._challenge >> 8 * index & 127
			self._send_midi((176, 17 + index, challenge_byte))

	def _user_byte_value(self, value):
		assert value in range(128)
		enabled = self._wrote_user_byte or value == 1
		self._control_is_with_automap = not enabled
		self._suppress_send_midi = self._control_is_with_automap
		if not self._control_is_with_automap:
			for control in self.controls:
				if isinstance(control, MonoButtonElement):
					control.set_force_next_value()

		self._selector.set_mode(0)
		self.set_enabled(enabled)
		self._suppress_send_midi = False

	def _button_value(self, value):
		assert value in range(128)

	def _config_value(self, value):
		assert value in range(128)

	def _set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks):
		if not self._suppress_session_highlight:
			ControlSurface._set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks)
	

	def _setup_m4l_interface(self):
		self._m4l_interface = M4LInterfaceComponent(controls=self.controls, component_guard=self.component_guard)
		self.get_control_names = self._m4l_interface.get_control_names
		self.get_control = self._m4l_interface.get_control
		self.grab_control = self._m4l_interface.grab_control
		self.release_control = self._m4l_interface.release_control
	

	"""Mono overrides and additions"""
	def _setup_monobridge(self):
		self._monobridge = MonoBridgeElement(self)
		self._monobridge.name = 'MonoBridge'
	

	def _setup_monomod(self):
		self._host = MonomodComponent(self)
		self._host.name = 'Monomod_Host'
		self.hosts = [self._host]
	

	def update_display(self):
		ControlSurface.update_display(self)
		self._timer = (self._timer + 1) % 256
		self.flash()
	

	def flash(self):
		if self._host.is_enabled():
			for control in self.controls:
				if isinstance(control, MonoButtonElement):
					control.flash(self._timer)
示例#28
0
class Launchpad(ControlSurface):

	_active_instances = []
	
	def __init__(self, c_instance):
		ControlSurface.__init__(self, c_instance)
		live = Live.Application.get_application()
		self._live_major_version = live.get_major_version()
		self._live_minor_version = live.get_minor_version()
		self._live_bugfix_version = live.get_bugfix_version()
		self._selector = None #needed because update hardware is called.
		self._mk2_rgb = False
		with self.component_guard():
			self._suppress_send_midi = True
			self._suppress_session_highlight = True
			self._suggested_input_port = ("Launchpad", "Launchpad Mini", "Launchpad S", "Launchpad MK2")
			self._suggested_output_port = ("Launchpad", "Launchpad Mini", "Launchpad S", "Launchpad MK2")				
			self._control_is_with_automap = False
			self._user_byte_write_button = None
			self._config_button = None
			self._wrote_user_byte = False
			self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143
			self._init_done = False
		# caller will send challenge and we will continue as challenge is received.
		
			
	def init(self):
		#skip init if already done.
		if self._init_done:
			return
		self._init_done = True
		
		# second part of the __init__ after model has been identified using its challenge response
		if self._mk2_rgb:
			from SkinMK2 import make_skin
			self._skin = make_skin()
			self._side_notes = (89, 79, 69, 59, 49, 39, 29, 19)
			#self._drum_notes = (20, 30, 31, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126)
			self._drum_notes = (20, 30, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126)
		else:
			from SkinMK1 import make_skin
			self._skin = make_skin()
			self._side_notes = (8, 24, 40, 56, 72, 88, 104, 120)
			self._drum_notes = (41, 42, 43, 44, 45, 46, 47, 57, 58, 59, 60, 61, 62, 63, 73, 74, 75, 76, 77, 78, 79, 89, 90, 91, 92, 93, 94, 95, 105, 106, 107)
		
		with self.component_guard():
			is_momentary = True
			self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0, optimized_send_midi=False)
			self._config_button.add_value_listener(self._config_value)
			self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)
			self._user_byte_write_button.name = 'User_Byte_Button'
			self._user_byte_write_button.send_value(1)
			self._user_byte_write_button.add_value_listener(self._user_byte_value)
			matrix = ButtonMatrixElement()
			matrix.name = 'Button_Matrix'
			for row in range(8):
				button_row = []
				for column in range(8):
					if self._mk2_rgb:
						# for mk2 buttons are assigned "top to bottom"
						midi_note = (81 - (10 * row)) + column
					else:
						midi_note = row * 16 + column
					button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, midi_note, skin = self._skin, control_surface = self)
					button.name = str(column) + '_Clip_' + str(row) + '_Button'
					button_row.append(button)
				matrix.add_row(tuple(button_row))

			top_buttons = [ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0, 104 + index, skin = self._skin) for index in range(8)]
			side_buttons = [ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, self._side_notes[index], skin = self._skin) for index in range(8)]
			top_buttons[0].name = 'Bank_Select_Up_Button'
			top_buttons[1].name = 'Bank_Select_Down_Button'
			top_buttons[2].name = 'Bank_Select_Left_Button'
			top_buttons[3].name = 'Bank_Select_Right_Button'
			top_buttons[4].name = 'Session_Button'
			top_buttons[5].name = 'User1_Button'
			top_buttons[6].name = 'User2_Button'
			top_buttons[7].name = 'Mixer_Button'
			side_buttons[0].name = 'Vol_Button'
			side_buttons[1].name = 'Pan_Button'
			side_buttons[2].name = 'SndA_Button'
			side_buttons[3].name = 'SndB_Button'
			side_buttons[4].name = 'Stop_Button'
			side_buttons[5].name = 'Trk_On_Button'
			side_buttons[6].name = 'Solo_Button'
			side_buttons[7].name = 'Arm_Button'
			self._osd = M4LInterface()
			self._osd.name = "OSD"
			self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button, self._osd, self)
			self._selector.name = 'Main_Modes'
			self._do_combine()
			for control in self.controls:
				if isinstance(control, ConfigurableButtonElement):
					control.add_value_listener(self._button_value)

			self.set_highlighting_session_component(self._selector.session_component())
			self._suppress_session_highlight = False
			# due to our 2 stage init, we need to rebuild midi map 
			self.request_rebuild_midi_map()
			# and request update 
			self._selector.update()
			if self._mk2_rgb:
				self.log_message("LaunchPad95 (mk2) Loaded !")
			else:
				self.log_message("LaunchPad95 Loaded !")
				
	def disconnect(self):
		self._suppress_send_midi = True
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.remove_value_listener(self._button_value)
		self._do_uncombine()
		if self._selector != None:
			self._user_byte_write_button.remove_value_listener(self._user_byte_value)
			self._config_button.remove_value_listener(self._config_value)
		ControlSurface.disconnect(self)
		self._suppress_send_midi = False
		if self._mk2_rgb:
			# launchpad mk2 needs disconnect string sent
			self._send_midi((240, 0, 32, 41, 2, 24, 64, 247))
		if self._config_button != None:
			self._config_button.send_value(32)
			self._config_button.send_value(0)
			self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None

	def _combine_active_instances():
		support_devices = False
		for instance in Launchpad._active_instances:
			support_devices |= (instance._device_component != None)
		offset = 0
		for instance in Launchpad._active_instances:
			instance._activate_combination_mode(offset, support_devices)
			offset += instance._selector._session.width()

	_combine_active_instances = staticmethod(_combine_active_instances)

	def _activate_combination_mode(self, track_offset, support_devices):
		if(Settings.STEPSEQ__LINK_WITH_SESSION):
			self._selector._stepseq.link_with_step_offset(track_offset)
		if(Settings.SESSION__LINK):
			self._selector._session.link_with_track_offset(track_offset)

	def _do_combine(self):
		if (DO_COMBINE and (self not in Launchpad._active_instances)):
			Launchpad._active_instances.append(self)
			Launchpad._combine_active_instances()

	def _do_uncombine(self):
		if self in Launchpad._active_instances:
			Launchpad._active_instances.remove(self)
			if(Settings.SESSION__LINK):
				self._selector._session.unlink()
			if(Settings.STEPSEQ__LINK_WITH_SESSION):
				self._selector._stepseq.unlink()
			Launchpad._combine_active_instances()

	def refresh_state(self):
		ControlSurface.refresh_state(self)
		self.schedule_message(5, self._update_hardware)

	def handle_sysex(self, midi_bytes):
		# MK2 has different challenge and params
		if len(midi_bytes) == 10 and midi_bytes[:7] == (240, 0, 32, 41, 2, 24, 64):
					response = long(midi_bytes[7])
					response += long(midi_bytes[8]) << 8
					if response == Live.Application.encrypt_challenge2(self._challenge):
						self._mk2_rgb = True
						self.log_message("Challenge Response ok (mk2)")
						
						self._suppress_send_midi = False
						self.set_enabled(True)
						self.init()
		#MK1 Challenge
		elif len(midi_bytes) == 8 and midi_bytes[1:5] == (0, 32, 41, 6):
					response = long(midi_bytes[5])
					response += long(midi_bytes[6]) << 8
					if response == Live.Application.encrypt_challenge2(self._challenge):
						self.log_message("Challenge Response ok (mk1)")
						self._mk2_rgb = False
						self.init()
						self._suppress_send_midi = False
						self.set_enabled(True)
		else:
			ControlSurface.handle_sysex(self,midi_bytes)
		

	def build_midi_map(self, midi_map_handle):
		ControlSurface.build_midi_map(self, midi_map_handle)
		if self._selector!=None:
			if self._selector._main_mode_index==2 or self._selector._main_mode_index==1:
				mode = Settings.USER_MODES[ (self._selector._main_mode_index-1) * 3 + self._selector._sub_mode_index[self._selector._main_mode_index] ] 
				#self._selector.mode_index == 1:
				#if self._selector._sub_mode_index[self._selector._mode_index] > 0:  # disable midi map rebuild for instrument mode to prevent light feedback errors
				if mode != "instrument":
					new_channel = self._selector.channel_for_current_mode()
					for note in self._drum_notes:
						self._translate_message(MIDI_NOTE_TYPE, note, 0, note, new_channel)

	def _send_midi(self, midi_bytes, optimized=None):
		sent_successfully = False
		if not self._suppress_send_midi:
			sent_successfully = ControlSurface._send_midi(self, midi_bytes, optimized=optimized)
		return sent_successfully

	def _update_hardware(self):
		self._suppress_send_midi = False
		if self._user_byte_write_button != None:
			self._user_byte_write_button.send_value(1)
			self._wrote_user_byte = True
		self._suppress_send_midi = True
		self.set_enabled(False)
		self._suppress_send_midi = False
		self._send_challenge()

	def _send_challenge(self):
		# send challenge for all models to allow to detect which one is actually plugged
		# mk2
		challenge_bytes = tuple([ self._challenge >> 8 * index & 127 for index in xrange(4) ])
		self._send_midi((240, 0, 32, 41, 2, 24, 64) + challenge_bytes + (247,))
		# mk1's
		for index in range(4):
			challenge_byte = self._challenge >> 8 * index & 127
			self._send_midi((176, 17 + index, challenge_byte))

	def _user_byte_value(self, value):
		assert (value in range(128))
		if not self._wrote_user_byte:
			enabled = (value == 1)
			self._control_is_with_automap = not enabled
			self._suppress_send_midi = self._control_is_with_automap
			if not self._control_is_with_automap:
				for control in self.controls:
					if isinstance(control, ConfigurableButtonElement):
						control.force_next_send()

			self._selector.set_mode(0)
			self.set_enabled(enabled)
			self._suppress_send_midi = False
		else:
			self._wrote_user_byte = False

	def _button_value(self, value):
		assert value in range(128)

	def _config_value(self, value):
		assert value in range(128)

	def _set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks):
		if not self._suppress_session_highlight:
			ControlSurface._set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks)
示例#29
0
class Launchpad(ControlSurface):
    " SCRIPT FOR NOVATION'S LAUNCHPAD CONTROLLER "

    " INITALIZE "

    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
            #self.set_suppress_rebuild_requests(True)
            self._suppress_send_midi = True
            self._suppress_session_highlight = True
            is_momentary = True
            self._suggested_input_port = "Launchpad"
            self._suggested_output_port = "Launchpad"
            self._control_is_with_automap = False
            self._user_byte_write_button = ButtonElement(
                is_momentary, MIDI_CC_TYPE, 0, 16)
            self._user_byte_write_button.name = "User_Byte_Button"
            self._user_byte_write_button.send_value(1)
            self._user_byte_write_button.add_value_listener(
                self._user_byte_value)
            self._wrote_user_byte = False
            self._challenge = (Live.Application.get_random_int(0, 400000000)
                               & 2139062143)
            matrix = ButtonMatrixElement()
            matrix.name = "Button_Matrix"
            """ TRACKFINDER TEST 
			track_index = 0
			for track in self.song().tracks:
				if track_index < 8:
					button_row = []			
					if track.is_foldable:
						for column in range(8):	
							log("right one: " + str(track_index))		
							button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, ((track_index * 16) + column)) #@UndefinedVariable
							button.name = (((str(column) + "_Clip_") + str(track_index)) + "_Button")
							button_row.append(button)
						track_index = track_index + 1
					else:
						for column in range(8):
							log("wrong one: " + str(track_index))
							button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 99, True) #@UndefinedVariable
							button.name = (str(column) + "_Clip_Button-DUMMY")
							button_row.append(button)
					matrix.add_row(tuple(button_row))
			log("done")"""
            """ ORIGINAL CODE """
            for row in range(8):
                button_row = []
                for column in range(8):
                    button = ConfigurableButtonElement(is_momentary,
                                                       MIDI_NOTE_TYPE, 0,
                                                       ((row * 16) + column))
                    button.name = (((str(column) + "_Clip_") + str(row)) +
                                   "_Button")
                    button_row.append(button)
                matrix.add_row(tuple(button_row))

            self._config_button = ButtonElement(is_momentary,
                                                MIDI_CC_TYPE,
                                                0,
                                                0,
                                                optimized_send_midi=False)
            self._config_button.add_value_listener(self._config_value)
            top_buttons = [
                ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0,
                                          (104 + index)) for index in range(8)
            ]
            side_buttons = [
                ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0,
                                          SIDE_NOTES[index])
                for index in range(8)
            ]
            top_buttons[0].name = "Bank_Select_Up_Button"
            top_buttons[1].name = "Bank_Select_Down_Button"
            top_buttons[2].name = "Bank_Select_Left_Button"
            top_buttons[3].name = "Bank_Select_Right_Button"
            top_buttons[4].name = "Session_Button"
            top_buttons[5].name = "User1_Button"
            top_buttons[6].name = "User2_Button"
            top_buttons[7].name = "Mixer_Button"
            side_buttons[0].name = "Vol_Button"
            side_buttons[1].name = "Pan_Button"
            side_buttons[2].name = "SndA_Button"
            side_buttons[3].name = "SndB_Button"
            side_buttons[4].name = "Stop_Button"
            side_buttons[5].name = "Trk_On_Button"
            side_buttons[6].name = "Solo_Button"
            side_buttons[7].name = "Arm_Button"
            self._selector = MainSelectorComponent(matrix, tuple(top_buttons),
                                                   tuple(side_buttons),
                                                   self._config_button)
            self._selector.name = "Main_Modes"
            for control in self.controls:
                if isinstance(control, ConfigurableButtonElement):
                    control.add_value_listener(self._button_value)
            self.set_highlighting_session_component(
                self._selector.session_component())
            self._suppress_session_highlight = False
            #self.set_suppress_rebuild_requests(False)

    " DISCONNECTOR "

    def disconnect(self):
        self._suppress_send_midi = True
        for control in self.controls:
            if isinstance(control, ConfigurableButtonElement):
                control.remove_value_listener(self._button_value)
        self._selector = None
        self._user_byte_write_button.remove_value_listener(
            self._user_byte_value)
        self._config_button.remove_value_listener(self._config_value)
        ControlSurface.disconnect(self)
        self._suppress_send_midi = False
        self._config_button.send_value(32)
        self._config_button.send_value(0)
        self._config_button = None
        self._user_byte_write_button.send_value(0)
        self._user_byte_write_button = None

    " RETURN THE SESSION COMPONENT SHOWING THE RING IN LIVE SESSION "

    def highlighting_session_component(self):
        return self._selector.session_component()

    " REFRESH "

    def refresh_state(self):
        ControlSurface.refresh_state(self)
        self.schedule_message(5, self._update_hardware)

    " SYSEX HANDLING "

    def handle_sysex(self, midi_bytes):
        if (len(midi_bytes) == 8):
            if (midi_bytes[1:5] == (0, 32, 41, 6)):
                response = long(midi_bytes[5])
                response += (long(midi_bytes[6]) << 8)
                if (response == Live.Application.encrypt_challenge2(
                        self._challenge)):
                    self._suppress_send_midi = False
                    self.set_enabled(True)

    " MIDI MAP "

    def build_midi_map(self, midi_map_handle):
        ControlSurface.build_midi_map(self, midi_map_handle)
        if (self._selector.mode_index == 1):
            new_channel = self._selector.channel_for_current_mode()
            for note in DRUM_NOTES:
                self._translate_message(MIDI_NOTE_TYPE, note, 0, note,
                                        new_channel)

    " SEND THE MIDI STUFF "

    def _send_midi(self, midi_bytes, optimized=None):
        sent_successfully = False
        if (not self._suppress_send_midi):
            sent_successfully = ControlSurface._send_midi(self,
                                                          midi_bytes,
                                                          optimized=optimized)
        return sent_successfully

    " UPDATE THE HARDWARE "

    def _update_hardware(self):
        self._suppress_send_midi = False
        self._wrote_user_byte = True
        self._user_byte_write_button.send_value(1)
        self._suppress_send_midi = True
        self.set_enabled(False)
        self._suppress_send_midi = False
        self._send_challenge()

    " CHALLANGE SEND "

    def _send_challenge(self):
        for index in range(4):
            challenge_byte = ((self._challenge >> (8 * index)) & 127)
            self._send_midi((176, (17 + index), challenge_byte))

    " USER BYTE STUFF "

    def _user_byte_value(self, value):
        if not value in range(128):
            raise AssertionError
            enabled = self._wrote_user_byte or value == 1
            self._control_is_with_automap = not enabled
            self._suppress_send_midi = self._control_is_with_automap
            if not self._control_is_with_automap:
                for control in self.controls:
                    if isinstance(control, ConfigurableButtonElement):
                        control.set_force_next_value()
            self._selector.set_mode(0)
            self.set_enabled(enabled)
            self._suppress_send_midi = False
        else:
            self._wrote_user_byte = False

    " BUTTON VALUE "

    def _button_value(self, value):
        assert (value in range(128))

    " CONFIG VALUE "

    def _config_value(self, value):
        assert (value in range(128))

    " SET THE SESSION HIGHLIGHT "

    def _set_session_highlight(self, track_offset, scene_offset, width, height,
                               include_return_tracks):
        if (not self._suppress_session_highlight):
            ControlSurface._set_session_highlight(self, track_offset,
                                                  scene_offset, width, height,
                                                  include_return_tracks)
示例#30
0
class AxiomPro(ControlSurface):
    """ Script for the M-Audio Axiom Pro """

    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
            is_momentary = True
            self.set_pad_translations(PAD_TRANSLATIONS)
            self._suggested_input_port = 'HyperControl'
            self._suggested_output_port = 'HyperControl'
            self._display_on_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, 15, 79)
            self._waiting_for_first_response = True
            mixer1 = DisplayingMixerComponent(0)
            mixer1.set_select_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 111), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 110))
            mixer1.set_mute_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 12))
            mixer1.set_solo_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 13))
            mixer2 = NotifyingMixerComponent(8)
            mixer2.set_bank_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 15), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 14))
            mixer2.master_strip().set_volume_control(SliderElement(MIDI_CC_TYPE, 15, 41))
            for index in range(8):
                mixer2.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, 15, 33 + index))

            device = PageableDeviceComponent(device_selection_follows_track_selection=True)
            self.set_device_component(device)
            ffwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 115)
            rwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 114)
            loop_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 113)
            transport = TransportComponent()
            transport.set_stop_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 116))
            transport.set_play_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 117))
            transport.set_record_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 118))
            session = SessionComponent(0, 0)
            transport_view_modes = TransportViewModeSelector(transport, session, ffwd_button, rwd_button, loop_button)
            select_button_modes = SelectButtonModeSelector(mixer2, tuple([ ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 49 + offset) for offset in range(8) ]))
            select_button_modes.set_mode_toggle(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 57))
            self._mixer_encoder_modes = EncoderMixerModeSelector(mixer2)
            encoders = []
            for offset in range(8):
                encoders.append(PeekableEncoderElement(MIDI_CC_TYPE, 15, 17 + offset, Live.MidiMap.MapMode.relative_smooth_two_compliment))
                encoders[-1].set_feedback_delay(-1)

            mixer_or_device = MixerOrDeviceModeSelector(self._mixer_encoder_modes, device, tuple(encoders), tuple([ ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 74 + offset) for offset in range(4) ]))
            mixer_or_device.set_mode_toggle(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 109))
            mixer_or_device.set_peek_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 78))
            self._track_display = PhysicalDisplayElement(8, 1)
            self._track_display.set_clear_all_message(SYSEX_START + (16, 247))
            self._track_display.set_message_parts(SYSEX_START + (17, 1, 0, 0), (247,))
            self._track_display.segment(0).set_data_source(mixer1.selected_strip().track_name_data_source())
            device_display = PhysicalDisplayElement(8, 1)
            device_display.set_message_parts(SYSEX_START + (17, 1, 0, 10), (247,))
            parameter_display = PhysicalDisplayElement(16, 1)
            parameter_display.set_message_parts(SYSEX_START + (17, 2, 0, 0), (247,))
            select_button_modes.set_mode_display(parameter_display)
            mixer1.set_display(parameter_display)
            mixer2.set_bank_display(parameter_display)
            page_displays = []
            for index in range(4):
                page_displays.append(PhysicalDisplayElement(5, 1))
                page_displays[-1].set_message_parts(SYSEX_START + (17,
                 4,
                 index,
                 0), (247,))

            encoder_display = PhysicalDisplayElement(80, 8)
            encoder_display.set_message_parts(SYSEX_START + (17, 3), (247,))
            for index in range(8):
                pos_id = tuple()
                if index != 0:
                    pos_id += (0,)
                if index > 3:
                    pos_id += (index % 4, 13)
                else:
                    pos_id += (index % 4, 0)
                encoder_display.segment(index).set_position_identifier(pos_id)

            mixer_or_device.set_displays(encoder_display, parameter_display, device_display, tuple(page_displays))
            for component in self.components:
                component.set_enabled(False)

    def refresh_state(self):
        ControlSurface.refresh_state(self)
        self._waiting_for_first_response = True
        self.schedule_message(10, self._send_midi, SYSEX_START + (32, 46, 247))

    def handle_sysex(self, midi_bytes):
        if midi_bytes[0:-2] == SYSEX_START + (32,):
            msg_id_byte = midi_bytes[-2]
            is_setup_response = msg_id_byte in (46, 38)
            has_sliders = msg_id_byte == 46
            if is_setup_response:
                if self._waiting_for_first_response:
                    self._waiting_for_first_response = False
                    self._display_on_button.send_value(0)
                    for component in self.components:
                        component.set_enabled(True)

                    self._display_on_button.send_value(127)
                    self._send_midi(SYSEX_START + (16, 247))
                    self._send_midi(SYSEX_START + (17, 3, 0, 1, 65, 98, 108, 101, 116, 111, 110, 32, 76, 105, 118, 101, 32, 67, 111, 110, 116, 114, 111, 108, 32, 0, 1, 4, 83, 117, 114, 102, 97, 99, 101, 32, 118, 49, 46, 48, 46, 48, 46, 247))
                self._mixer_encoder_modes.set_show_volume_page(not has_sliders)
                for display in self._displays:
                    display.set_block_messages(False)

                self.schedule_message(25, self._refresh_displays)
            elif msg_id_byte == 43:
                self._send_midi(SYSEX_START + (16, 247))
                for display in self._displays:
                    if display is self._track_display:
                        display.update()
                    else:
                        display.set_block_messages(True)

    def disconnect(self):
        ControlSurface.disconnect(self)
        self._send_midi(SYSEX_START + (32, 0, 247))
        self._send_midi(SYSEX_START + (16, 247))
        self._send_midi(SYSEX_START + (17, 3, 0, 4, 65, 98, 108, 101, 116, 111, 110, 32, 76, 105, 118, 101, 32, 67, 111, 110, 116, 114, 111, 108, 32, 0, 1, 4, 83, 117, 114, 102, 97, 99, 101, 32, 67, 108, 111, 115, 101, 100, 46, 247))
示例#31
0
class LaunchMod(ControlSurface):
    __module__ = __name__
    __doc__ = " Script for Novation's Launchpad Controller "

    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        self._monomod_version = 'b994'
        self._host_name = 'LaunchMod'
        self._color_type = 'Launchpad'
        self.hosts = []
        self._timer = 0
        self.set_suppress_rebuild_requests(True)
        self._suppress_send_midi = True
        self._suppress_session_highlight = True
        is_momentary = True
        self._suggested_input_port = 'Launchpad'
        self._suggested_output_port = 'Launchpad'
        self._wrote_user_byte = False
        self._control_is_with_automap = False
        self._challenge = (Live.Application.get_random_int(0, 400000000)
                           & 2139062143)
        matrix = ButtonMatrixElement()
        matrix.name = 'ButtonMatrix'
        for row in range(8):
            #button_row = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, ((row * 16) + column)) for column in range(8) ]
            button_row = [
                FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, 0,
                                      ((row * 16) + column),
                                      'Button_' + str(row) + '_' + str(column),
                                      self) for column in range(8)
            ]
            matrix.add_row(tuple(button_row))
        self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0)
        self._config_button.add_value_listener(self._config_value)
        top_buttons = [
            FlashingButtonElement(is_momentary, MIDI_CC_TYPE, 0, (104 + index),
                                  'Top_Button' + str(index), self)
            for index in range(8)
        ]
        side_buttons = [
            FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, 0,
                                  SIDE_NOTES[index],
                                  'Side_Button' + str(index), self)
            for index in range(8)
        ]
        self._setup_monobridge()
        self._setup_monomod()
        self._selector = MainSelectorComponent(matrix, tuple(top_buttons),
                                               tuple(side_buttons),
                                               self._config_button, self)
        self._suppress_session_highlight = False
        self._suppress_send_midi = False
        self._user_byte_write_button = ButtonElement(is_momentary,
                                                     MIDI_CC_TYPE, 0, 16)
        self._user_byte_write_button.send_value(1)
        self._user_byte_write_button.add_value_listener(self._user_byte_value)
        self._suppress_send_midi = True
        self.set_suppress_rebuild_requests(False)
        self.log_message("--------------= LaunchMod log opened =--------------"
                         )  #Create entry in log file
        self.refresh_state()

    def _setup_monobridge(self):
        self._monobridge = MonoBridgeElement(self)
        self._monobridge.name = 'MonoBridge'

    def _setup_monomod(self):
        self._host = MonomodComponent(self)
        self._host.name = 'Monomod_Host'
        self.hosts = [self._host]

    def disconnect(self):
        self._suppress_send_midi = True
        self._selector = None
        self._user_byte_write_button.remove_value_listener(
            self._user_byte_value)
        self._config_button.remove_value_listener(self._config_value)
        ControlSurface.disconnect(self)
        self._suppress_send_midi = False
        self._config_button.send_value(32)
        self._config_button.send_value(0)
        self._config_button = None
        self._user_byte_write_button.send_value(0)
        self._user_byte_write_button = None
        self.log_message("--------------= LaunchMod log closed =--------------"
                         )  #Create entry in log file

    def refresh_state(self):
        ControlSurface.refresh_state(self)
        self.schedule_message(5, self._update_hardware)

    def handle_sysex(self, midi_bytes):
        if (len(midi_bytes) == 8):
            if (midi_bytes[1:5] == (0, 32, 41, 6)):
                response = long(midi_bytes[5])
                response += (long(midi_bytes[6]) << 8)
                if (response == Live.Application.encrypt_challenge2(
                        self._challenge)):
                    self._suppress_send_midi = False
                    self.set_enabled(True)
                    #self.refresh_state()

    def _send_midi(self, midi_bytes):
        if (not self._suppress_send_midi):
            ControlSurface._send_midi(self, midi_bytes)

    def _update_hardware(self):
        self._suppress_send_midi = False
        self._config_button.send_value(40)
        self._wrote_user_byte = True
        self._user_byte_write_button.send_value(1)
        self._suppress_send_midi = True
        self.set_enabled(False)
        self._suppress_send_midi = False
        self._send_challenge()

    def _send_challenge(self):
        for index in range(4):
            challenge_byte = ((self._challenge >> (8 * index)) & 127)
            self._send_midi((176, (17 + index), challenge_byte))

    def _user_byte_value(self, value):
        assert (value in range(128))
        enabled = (value == 1)
        if enabled:
            self._config_button.send_value(40)
        self._control_is_with_automap = (not enabled)
        for control in self.controls:
            if isinstance(control, ConfigurableButtonElement):
                control.set_force_next_value()

        if (not self._wrote_user_byte):
            self._selector.set_mode(0)
            self.set_enabled(enabled)
        else:
            self._wrote_user_byte = False
        self.request_rebuild_midi_map()

    def _config_value(self, value):
        assert (value in range(128))

    def _set_session_highlight(self,
                               track_offset,
                               scene_offset,
                               width,
                               height,
                               include_returns=False):
        if (not self._suppress_session_highlight):
            ControlSurface._set_session_highlight(self, track_offset,
                                                  scene_offset, width, height,
                                                  include_returns)

    def _install_forwarding(self, control):
        result = False
        if ((not self._control_is_with_automap)
                or (control == self._user_byte_write_button)):
            result = ControlSurface._install_forwarding(self, control)
        return result

    def _translate_message(self, type, from_identifier, from_channel,
                           to_identifier, to_channel):
        if (not self._control_is_with_automap):
            ControlSurface._translate_message(self, type, from_identifier,
                                              from_channel, to_identifier,
                                              to_channel)

    def update_display(self):
        """ Live -> Script
		Aka on_timer. Called every 100 ms and should be used to update display relevant
		parts of the controller
		"""
        for message in self._scheduled_messages:
            message['Delay'] -= 1
            if (message['Delay'] == 0):
                if (message['Parameter'] != None):
                    message['Message'](message['Parameter'])
                else:
                    message['Message']()
                    del self._scheduled_messages[
                        self._scheduled_messages.index(message)]

        for callback in self._timer_callbacks:
            callback()
        self._timer = (self._timer + 1) % 256
        self.flash()

    def flash(self):
        #if(self.flash_status > 0):
        for row in range(8):
            if (self._selector._side_buttons[row]._flash_state > 0):
                self._selector._side_buttons[row].flash(self._timer)
            for column in range(8):
                button = self._selector._matrix.get_button(column, row)
                if (button._flash_state > 0):
                    button.flash(self._timer)
        for index in range(4):
            if (self._selector._nav_buttons[index]._flash_state > 0):
                self._selector._nav_buttons[index].flash(self._timer)
            if (self._selector._modes_buttons[index]._flash_state > 0):
                self._selector._modes_buttons[index].flash(self._timer)

    def allow_updates(self, allow_updates):
        for component in self.components:
            component.set_allow_update(int(allow_updates != 0))
示例#32
0
class NoteRepeatComponent(CompoundComponent):
    """ Noter Repeat Handler"""
    __module__ = __name__
    _knob_handler = None

    def __init__(self, note_repeat=None, *a, **k):
        super(NoteRepeatComponent, self).__init__(*a, **k)
        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

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

        self.nr_frq = CTRL_TO_FREQ[4][1]
        self._note_repeat.repeat_rate = 1.0 / self.nr_frq * 4.0
        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:
            button.send_value(button.active and 1 or 0, True)

        return

    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]

    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 += '|'

        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
            maxindex = cindex % 2 == 0 and maxindex or 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.0 / self.nr_frq * 4.0

    @subject_slot('value')
    def _do_change_nr_1(self, value):
        self.mod_button(self._cfg_buttons[0], value == REL_KNOB_DOWN and -1
                        or 1, 1)
        self.show_note_rates()

    @subject_slot('value')
    def _do_change_nr_2(self, value):
        self.mod_button(self._cfg_buttons[1], value == REL_KNOB_DOWN and -1
                        or 1, 2)
        self.show_note_rates()

    @subject_slot('value')
    def _do_change_nr_3(self, value):
        self.mod_button(self._cfg_buttons[2], value == REL_KNOB_DOWN and -1
                        or 1, 3)
        self.show_note_rates()

    @subject_slot('value')
    def _do_change_nr_4(self, value):
        self.mod_button(self._cfg_buttons[3], value == REL_KNOB_DOWN and -1
                        or 1, 4)
        self.show_note_rates()

    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)

    @subject_slot('value')
    def _adjust_cfg_value(self, value):
        button = self._current_nr_button
        if button and button.cfg and (self.nr_down or button.hold
                                      or self._hold_mode and button.active):
            inc = value == 127 and -1 or 1
            cindex = button.fr_idx
            maxindex = len(CFG_REPEAT_FREQUENCIES) - 1
            minindex = 0
            if self._cfg_down:
                inc *= 2
                maxindex = cindex % 2 == 0 and maxindex or 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.0 / self.nr_frq * 4.0
        else:
            if self._knob_handler:
                self._knob_handler.do_main(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.0
                    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.0 / self.nr_frq * 4.0
                    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.0 / self.nr_frq * 4.0
                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
        return

    @subject_slot('value')
    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.0 / self.nr_frq * 4.0
        else:
            if 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.0 / self.nr_frq * 4.0
            else:
                if 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.0 / self.nr_frq * 4.0
                    self._note_repeat.enabled = True
        return

    def disconnect(self):
        super(NoteRepeatComponent, self).disconnect()
示例#33
0
class Launchpad(ControlSurface):
	" Script for Novation's Launchpad Controller "

	def __init__(self, c_instance):
		ControlSurface.__init__(self, c_instance)
		self.set_suppress_rebuild_requests(True)
		self._suppress_send_midi = True
		self._suppress_session_highlight = True
		is_momentary = True
		self._suggested_input_port = "Launchpad"
		self._suggested_output_port = "Launchpad"
		self._control_is_with_automap = False
		self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)
		self._user_byte_write_button.name = "User_Byte_Button"
		self._user_byte_write_button.send_value(1)
		self._user_byte_write_button.add_value_listener(self._user_byte_value)
		self._wrote_user_byte = False
		self._challenge = (Live.Application.get_random_int(0, 400000000) & 2139062143)
		matrix = ButtonMatrixElement()
		matrix.name = "Button_Matrix"
		for row in range(8):
			button_row = []
			for column in range(8):
				button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, ((row * 16) + column))
				button.name = (((str(column) + "_Clip_") + str(row)) + "_Button")
				button_row.append(button)

			matrix.add_row(tuple(button_row))

		self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0)
		self._config_button.add_value_listener(self._config_value)
		top_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0, (104 + index)) for index in range(8) ]
		side_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index]) for index in range(8) ]
		top_buttons[0].name = "Bank_Select_Up_Button"
		top_buttons[1].name = "Bank_Select_Down_Button"
		top_buttons[2].name = "Bank_Select_Left_Button"
		top_buttons[3].name = "Bank_Select_Right_Button"
		top_buttons[4].name = "Session_Button"
		top_buttons[5].name = "User1_Button"
		top_buttons[6].name = "User2_Button"
		top_buttons[7].name = "Mixer_Button"
		side_buttons[0].name = "Vol_Button"
		side_buttons[1].name = "Pan_Button"
		side_buttons[2].name = "SndA_Button"
		side_buttons[3].name = "SndB_Button"
		side_buttons[4].name = "Stop_Button"
		side_buttons[5].name = "Trk_On_Button"
		side_buttons[6].name = "Solo_Button"
		side_buttons[7].name = "Arm_Button"
		self._selector = MainSelectorComponent(matrix, tuple(top_buttons), tuple(side_buttons), self._config_button, self)
		self._selector.name = "Main_Modes"
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.add_value_listener(self._button_value)

		self._suppress_session_highlight = False
		self.set_suppress_rebuild_requests(False)

		self.log_message("LaunchPad85 Loaded !")

	def disconnect(self):
		self._suppress_send_midi = True
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.remove_value_listener(self._button_value)

		self._selector = None
		self._user_byte_write_button.remove_value_listener(self._user_byte_value)
		self._config_button.remove_value_listener(self._config_value)
		ControlSurface.disconnect(self)
		self._suppress_send_midi = False
		self._config_button.send_value(32)
		self._config_button.send_value(0)
		self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None



	def highlighting_session_component(self):
		" Return the session component showing the ring in Live session "
		return self._selector.session_component()



	def refresh_state(self):
		ControlSurface.refresh_state(self)
		self.schedule_message(5, self._update_hardware)



	def handle_sysex(self, midi_bytes):
		if (len(midi_bytes) == 8):
			if (midi_bytes[1:5] == (0, 32, 41, 6)):
				response = long(midi_bytes[5])
				response += (long(midi_bytes[6]) << 8)
				if (response == Live.Application.encrypt_challenge2(self._challenge)):
					self._suppress_send_midi = False
					self.set_enabled(True)



	def build_midi_map(self, midi_map_handle):
		ControlSurface.build_midi_map(self, midi_map_handle)
		if (self._selector.mode_index == 1):
			new_channel = self._selector.channel_for_current_mode()
			for note in DRUM_NOTES:
				self._translate_message(MIDI_NOTE_TYPE, note, 0, note, new_channel)




	def _send_midi(self, midi_bytes):
		sent_successfully = False
		if (not self._suppress_send_midi):
			sent_successfully = ControlSurface._send_midi(self, midi_bytes)
		return sent_successfully



	def _update_hardware(self):
		self._suppress_send_midi = False
		self._wrote_user_byte = True
		self._user_byte_write_button.send_value(1)
		self._suppress_send_midi = True
		self.set_enabled(False)
		self._suppress_send_midi = False
		self._send_challenge()



	def _send_challenge(self):
		for index in range(4):
			challenge_byte = ((self._challenge >> (8 * index)) & 127)
			self._send_midi((176,
			 (17 + index),
			 challenge_byte))




	def _user_byte_value(self, value):
		assert (value in range(128))
		if (not self._wrote_user_byte):
			enabled = (value == 1)
			self._control_is_with_automap = (not enabled)
			self._suppress_send_midi = self._control_is_with_automap
			if (not self._control_is_with_automap):
				for control in self.controls:
					if isinstance(control, ConfigurableButtonElement):
						control.set_force_next_value()

			self._selector.set_mode(0)
			self.set_enabled(enabled)
			self._suppress_send_midi = False
		else:
			self._wrote_user_byte = False



	def _button_value(self, value):
		assert (value in range(128))



	def _config_value(self, value):
		assert (value in range(128))



	def _set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks):
		if (not self._suppress_session_highlight):
			ControlSurface._set_session_highlight(self, track_offset, scene_offset, width, height, include_return_tracks)