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)
class Novation_Impulse(ControlSurface): """ Script for Novation's Impulse keyboards """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self.set_pad_translations(PAD_TRANSLATIONS) self._device_selection_follows_track_selection = True self._suggested_input_port = 'Impulse' self._suggested_output_port = 'Impulse' self._has_sliders = True self._current_midi_map = None self._display_reset_delay = -1 self._shift_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 39) self._preview_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 41) self._master_slider = SliderElement(MIDI_CC_TYPE, 0, 8) self._shift_button.name = 'Shift_Button' self._master_slider.name = 'Master_Volume_Control' self._master_slider.add_value_listener(self._slider_value, identify_sender=True) self._preview_button.add_value_listener(self._preview_value) self._setup_mixer() self._setup_session() self._setup_transport() self._setup_device() self._setup_name_display() device_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 1, 10) mixer_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 1, 9) device_button.name = 'Encoder_Device_Mode' mixer_button.name = 'Encoder_Mixer_Mode' self._encoder_modes = EncoderModeSelector(self._device_component, self._mixer, self._next_bank_button, self._prev_bank_button, self._encoders) self._encoder_modes.set_device_mixer_buttons(device_button, mixer_button) self._string_to_display = None for component in self.components: component.set_enabled(False) def refresh_state(self): ControlSurface.refresh_state(self) self.schedule_message(3, self._send_midi, SYSEX_START + (6, 1, 1, 1, 247)) def handle_sysex(self, midi_bytes): if midi_bytes[0:-2] == SYSEX_START + (7,) and midi_bytes[-2] != 0: self._has_sliders = midi_bytes[-2] != 25 self.schedule_message(1, self._show_startup_message) for control in self.controls: if isinstance(control, InputControlElement): control.clear_send_cache() for component in self.components: component.set_enabled(True) if self._has_sliders: self._mixer.master_strip().set_volume_control(self._master_slider) self._mixer.update() else: self._mixer.master_strip().set_volume_control(None) self._mixer.selected_strip().set_volume_control(self._master_slider) for index in range(len(self._sliders)): self._mixer.channel_strip(index).set_volume_control(None) slider = self._sliders[index] slider.release_parameter() if slider.value_has_listener(self._slider_value): slider.remove_value_listener(self._slider_value) self._encoder_modes.set_provide_volume_mode(not self._has_sliders) self.request_rebuild_midi_map() def disconnect(self): self._name_display_data_source.set_display_string(' ') for encoder in self._encoders: encoder.remove_value_listener(self._encoder_value) self._master_slider.remove_value_listener(self._slider_value) if self._has_sliders: for slider in tuple(self._sliders): slider.remove_value_listener(self._slider_value) for button in self._strip_buttons: button.remove_value_listener(self._mixer_button_value) self._preview_button.remove_value_listener(self._preview_value) ControlSurface.disconnect(self) self._encoders = None self._sliders = None self._strip_buttons = None self._master_slider = None self._current_midi_map = None self._shift_button = None self._name_display = None self._prev_bank_button = None self._next_bank_button = None self._encoder_modes = None self._transport_view_modes = None self._send_midi(SYSEX_START + (6, 0, 0, 0, 247)) def build_midi_map(self, midi_map_handle): self._current_midi_map = midi_map_handle ControlSurface.build_midi_map(self, midi_map_handle) def update_display(self): ControlSurface.update_display(self) if self._string_to_display != None: self._name_display_data_source.set_display_string(self._string_to_display) self._string_to_display = None if self._display_reset_delay >= 0: self._display_reset_delay -= 1 if self._display_reset_delay == -1: self._show_current_track_name() def _setup_mixer(self): mute_solo_flip_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 34) self._next_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 37) self._prev_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 38) self._strip_buttons = [] mute_solo_flip_button.name = 'Mute_Solo_Flip_Button' self._next_nav_button.name = 'Next_Track_Button' self._prev_nav_button.name = 'Prev_Track_Button' self._mixer = SpecialMixerComponent(8) self._mixer.name = 'Mixer' self._mixer.set_select_buttons(self._next_nav_button, self._prev_nav_button) self._mixer.selected_strip().name = 'Selected_Channel_Strip' self._mixer.master_strip().name = 'Master_Channel_Strip' self._mixer.master_strip().set_volume_control(self._master_slider) self._sliders = [] for index in range(8): strip = self._mixer.channel_strip(index) strip.name = 'Channel_Strip_' + str(index) strip.set_invert_mute_feedback(True) self._sliders.append(SliderElement(MIDI_CC_TYPE, 0, index)) self._sliders[-1].name = str(index) + '_Volume_Control' self._sliders[-1].set_feedback_delay(-1) self._sliders[-1].add_value_listener(self._slider_value, identify_sender=True) strip.set_volume_control(self._sliders[-1]) self._strip_buttons.append(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 9 + index)) self._strip_buttons[-1].name = str(index) + '_Mute_Button' self._strip_buttons[-1].add_value_listener(self._mixer_button_value, identify_sender=True) self._mixer.master_strip().set_mute_button(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 17)) self._mixer.set_strip_mute_solo_buttons(tuple(self._strip_buttons), mute_solo_flip_button) def _setup_session(self): num_pads = len(PAD_TRANSLATIONS) self._track_left_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 36) self._track_right_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 35) self._session = SessionComponent(8, 0) self._session.name = 'Session_Control' self._session.selected_scene().name = 'Selected_Scene' self._session.set_mixer(self._mixer) self._session.set_page_left_button(self._track_left_button) self._session.set_page_right_button(self._track_right_button) pads = [] for index in range(num_pads): pads.append(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 60 + index)) pads[-1].name = 'Pad_' + str(index) clip_slot = self._session.selected_scene().clip_slot(index) clip_slot.set_triggered_to_play_value(GREEN_BLINK) clip_slot.set_triggered_to_record_value(RED_BLINK) clip_slot.set_stopped_value(AMBER_FULL) clip_slot.set_started_value(GREEN_FULL) clip_slot.set_recording_value(RED_FULL) clip_slot.set_launch_button(pads[-1]) clip_slot.name = str(index) + '_Selected_Clip_Slot' def _setup_transport(self): rwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 27) ffwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 28) stop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 29) play_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 30) loop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 31) rec_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 32) ffwd_button.name = 'FFwd_Button' rwd_button.name = 'Rwd_Button' loop_button.name = 'Loop_Button' play_button.name = 'Play_Button' stop_button.name = 'Stop_Button' rec_button.name = 'Record_Button' transport = ShiftableTransportComponent() transport.name = 'Transport' transport.set_stop_button(stop_button) transport.set_play_button(play_button) transport.set_record_button(rec_button) transport.set_shift_button(self._shift_button) self._transport_view_modes = TransportViewModeSelector(transport, self._session, ffwd_button, rwd_button, loop_button) self._transport_view_modes.name = 'Transport_View_Modes' def _setup_device(self): encoders = [] for index in range(8): encoders.append(PeekableEncoderElement(MIDI_CC_TYPE, 1, index, Live.MidiMap.MapMode.relative_binary_offset)) encoders[-1].set_feedback_delay(-1) encoders[-1].add_value_listener(self._encoder_value, identify_sender=True) encoders[-1].name = 'Device_Control_' + str(index) self._encoders = tuple(encoders) self._prev_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 12) self._next_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 11) self._prev_bank_button.name = 'Device_Bank_Down_Button' self._next_bank_button.name = 'Device_Bank_Up_Button' device = DeviceComponent() device.name = 'Device_Component' self.set_device_component(device) device.set_parameter_controls(self._encoders) device.set_bank_nav_buttons(self._prev_bank_button, self._next_bank_button) def _setup_name_display(self): self._name_display = PhysicalDisplayElement(16, 1) self._name_display.name = 'Display' self._name_display.set_message_parts(SYSEX_START + (8,), (247,)) self._name_display_data_source = DisplayDataSource() self._name_display.segment(0).set_data_source(self._name_display_data_source) def _encoder_value(self, value, sender): if not sender in self._encoders: raise AssertionError if not value in range(128): raise AssertionError display_string = self._device_component.is_enabled() and ' - ' display_string = sender.mapped_parameter() != None and sender.mapped_parameter().name self._set_string_to_display(display_string) def _slider_value(self, value, sender): if not sender in tuple(self._sliders) + (self._master_slider,): raise AssertionError if not value in range(128): raise AssertionError if self._mixer.is_enabled(): display_string = ' - ' if sender.mapped_parameter() != None: master = self.song().master_track tracks = self.song().tracks returns = self.song().return_tracks track = None if sender == self._master_slider: track = self._has_sliders and master else: track = self.song().view.selected_track else: track = self._mixer.channel_strip(self._sliders.index(sender))._track display_string = track == master and 'Master' elif track in tracks: display_string = str(list(tracks).index(track) + 1) elif track in returns: display_string = str(chr(ord('A') + list(returns).index(track))) else: raise False or AssertionError display_string += ' Volume' self._set_string_to_display(display_string) def _mixer_button_value(self, value, sender): if not value in range(128): raise AssertionError if self._mixer.is_enabled() and value > 0: strip = self._mixer.channel_strip(self._strip_buttons.index(sender)) self._string_to_display = strip != None and None self._name_display.segment(0).set_data_source(strip.track_name_data_source()) self._name_display.update() self._display_reset_delay = STANDARD_DISPLAY_DELAY else: self._set_string_to_display(' - ') def _preview_value(self, value): raise value in range(128) or AssertionError for encoder in self._encoders: encoder.set_peek_mode(value > 0) def _show_current_track_name(self): if self._name_display != None and self._mixer != None: self._string_to_display = None self._name_display.segment(0).set_data_source(self._mixer.selected_strip().track_name_data_source()) self._name_display.update() def _show_startup_message(self): self._name_display.display_message('LIVE') self._display_reset_delay = INITIAL_DISPLAY_DELAY def _set_string_to_display(self, string_to_display): raise isinstance(string_to_display, (str, unicode)) or AssertionError self._name_display.segment(0).set_data_source(self._name_display_data_source) self._string_to_display = string_to_display self._display_reset_delay = STANDARD_DISPLAY_DELAY def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(self) self._show_current_track_name() all_tracks = self._has_sliders or self._session.tracks_to_use() selected_track = self.song().view.selected_track num_strips = self._session.width() if selected_track in all_tracks: track_index = list(all_tracks).index(selected_track) new_offset = track_index - track_index % num_strips if not new_offset / num_strips == int(new_offset / num_strips): raise AssertionError self._session.set_offsets(new_offset, self._session.scene_offset())
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)
class Oxygen_3rd_Gen(ControlSurface): """ Script for the 3rd generation of M-Audio's Oxygen controllers """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): is_momentary = True self._suggested_input_port = 'Oxygen' self._suggested_output_port = 'Oxygen' self._has_slider_section = True self._device_selection_follows_track_selection = True self._shift_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 57) self._shift_button.add_value_listener(self._shift_value) self._mixer = SpecialMixerComponent(NUM_TRACKS) self._mute_solo_buttons = [] self._track_up_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 111) self._track_down_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 110) self._master_slider = SliderElement(MIDI_CC_TYPE, GLOBAL_CHANNEL, 41) for index in range(NUM_TRACKS): self._mute_solo_buttons.append( ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 49 + index)) self._mixer.channel_strip(index).set_volume_control( SliderElement(MIDI_CC_TYPE, GLOBAL_CHANNEL, 33 + index)) self._shift_value(0) self._mixer.master_strip().set_volume_control(self._master_slider) self._mixer.selected_strip().set_volume_control(None) device = DeviceComponent() device.set_parameter_controls( tuple([ EncoderElement(MIDI_CC_TYPE, GLOBAL_CHANNEL, 17 + index, Live.MidiMap.MapMode.absolute) for index in range(8) ])) self.set_device_component(device) ffwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 115) rwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 114) loop_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 113) transport = TransportComponent() transport.set_stop_button( ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 116)) transport.set_play_button( ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 117)) transport.set_record_button( ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 118)) session = SessionComponent(0, 0) transport_view_modes = TransportViewModeSelector( transport, session, ffwd_button, rwd_button, loop_button) def disconnect(self): self._shift_button.remove_value_listener(self._shift_value) self._shift_button = None ControlSurface.disconnect(self) def refresh_state(self): ControlSurface.refresh_state(self) self.schedule_message(5, self._send_midi, IDENTITY_REQUEST) def handle_sysex(self, midi_bytes): if midi_bytes[0:5] == IDENTITY_RESPONSE: if midi_bytes[10] == 38: self._mixer.master_strip().set_volume_control(None) self._mixer.selected_strip().set_volume_control( self._master_slider) def _shift_value(self, value): raise value in range(128) or AssertionError for index in range(NUM_TRACKS): if value == 0: self._mixer.channel_strip(index).set_solo_button(None) self._mixer.channel_strip(index).set_mute_button( self._mute_solo_buttons[index]) self._mixer.set_bank_buttons(None, None) self._mixer.set_select_buttons(self._track_up_button, self._track_down_button) else: self._mixer.channel_strip(index).set_mute_button(None) self._mixer.channel_strip(index).set_solo_button( self._mute_solo_buttons[index]) self._mixer.set_select_buttons(None, None) self._mixer.set_bank_buttons(self._track_up_button, self._track_down_button)
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 Novation_Impulse(ControlSurface): """ Script for Novation's Impulse keyboards """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self.set_pad_translations(PAD_TRANSLATIONS) self._suggested_input_port = b'Impulse' self._suggested_output_port = b'Impulse' self._has_sliders = True self._current_midi_map = None self._display_reset_delay = -1 self._shift_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 39) self._preview_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 41) self._master_slider = SliderElement(MIDI_CC_TYPE, 0, 8) self._shift_button.name = b'Shift_Button' self._master_slider.name = b'Master_Volume_Control' self._master_slider.add_value_listener(self._slider_value, identify_sender=True) self._preview_button.add_value_listener(self._preview_value) self._setup_mixer() self._setup_session() self._setup_transport() self._setup_device() self._setup_name_display() device_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 1, 10) mixer_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 1, 9) device_button.name = b'Encoder_Device_Mode' mixer_button.name = b'Encoder_Mixer_Mode' self._encoder_modes = EncoderModeSelector(self._device_component, self._mixer, self._next_bank_button, self._prev_bank_button, self._encoders) self._encoder_modes.set_device_mixer_buttons( device_button, mixer_button) self._string_to_display = None for component in self.components: component.set_enabled(False) return def refresh_state(self): ControlSurface.refresh_state(self) self.schedule_message(3, self._send_midi, SYSEX_START + (6, 1, 1, 1, 247)) def handle_sysex(self, midi_bytes): if midi_bytes[0:-2] == SYSEX_START + (7, ) and midi_bytes[(-2)] != 0: self._has_sliders = midi_bytes[(-2)] != 25 self.schedule_message(1, self._show_startup_message) for control in self.controls: if isinstance(control, InputControlElement): control.clear_send_cache() for component in self.components: component.set_enabled(True) if self._has_sliders: self._mixer.master_strip().set_volume_control( self._master_slider) self._mixer.update() else: self._mixer.master_strip().set_volume_control(None) self._mixer.selected_strip().set_volume_control( self._master_slider) for index in range(len(self._sliders)): self._mixer.channel_strip(index).set_volume_control(None) slider = self._sliders[index] slider.release_parameter() if slider.value_has_listener(self._slider_value): slider.remove_value_listener(self._slider_value) self._encoder_modes.set_provide_volume_mode(not self._has_sliders) self.request_rebuild_midi_map() return def disconnect(self): self._name_display_data_source.set_display_string(b' ') for encoder in self._encoders: encoder.remove_value_listener(self._encoder_value) self._master_slider.remove_value_listener(self._slider_value) if self._has_sliders: for slider in tuple(self._sliders): slider.remove_value_listener(self._slider_value) for button in self._strip_buttons: button.remove_value_listener(self._mixer_button_value) self._preview_button.remove_value_listener(self._preview_value) ControlSurface.disconnect(self) self._encoders = None self._sliders = None self._strip_buttons = None self._master_slider = None self._current_midi_map = None self._shift_button = None self._name_display = None self._prev_bank_button = None self._next_bank_button = None self._encoder_modes = None self._transport_view_modes = None self._send_midi(SYSEX_START + (6, 0, 0, 0, 247)) return def build_midi_map(self, midi_map_handle): self._current_midi_map = midi_map_handle ControlSurface.build_midi_map(self, midi_map_handle) def update_display(self): ControlSurface.update_display(self) if self._string_to_display != None: self._name_display_data_source.set_display_string( self._string_to_display) self._string_to_display = None if self._display_reset_delay >= 0: self._display_reset_delay -= 1 if self._display_reset_delay == -1: self._show_current_track_name() return def _setup_mixer(self): mute_solo_flip_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 34) self._next_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 37) self._prev_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 38) self._strip_buttons = [] mute_solo_flip_button.name = b'Mute_Solo_Flip_Button' self._next_nav_button.name = b'Next_Track_Button' self._prev_nav_button.name = b'Prev_Track_Button' self._mixer = SpecialMixerComponent(8) self._mixer.name = b'Mixer' self._mixer.set_select_buttons(self._next_nav_button, self._prev_nav_button) self._mixer.selected_strip().name = b'Selected_Channel_Strip' self._mixer.master_strip().name = b'Master_Channel_Strip' self._mixer.master_strip().set_volume_control(self._master_slider) self._sliders = [] for index in range(8): strip = self._mixer.channel_strip(index) strip.name = b'Channel_Strip_' + str(index) strip.set_invert_mute_feedback(True) self._sliders.append(SliderElement(MIDI_CC_TYPE, 0, index)) self._sliders[(-1)].name = str(index) + b'_Volume_Control' self._sliders[(-1)].set_feedback_delay(-1) self._sliders[(-1)].add_value_listener(self._slider_value, identify_sender=True) strip.set_volume_control(self._sliders[(-1)]) self._strip_buttons.append( ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 9 + index)) self._strip_buttons[(-1)].name = str(index) + b'_Mute_Button' self._strip_buttons[(-1)].add_value_listener( self._mixer_button_value, identify_sender=True) self._mixer.master_strip().set_mute_button( ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 17)) self._mixer.set_strip_mute_solo_buttons(tuple(self._strip_buttons), mute_solo_flip_button) def _setup_session(self): num_pads = len(PAD_TRANSLATIONS) self._track_left_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 36) self._track_right_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 35) self._session = SessionComponent(8, 0) self._session.name = b'Session_Control' self._session.selected_scene().name = b'Selected_Scene' self._session.set_mixer(self._mixer) self._session.set_page_left_button(self._track_left_button) self._session.set_page_right_button(self._track_right_button) pads = [] for index in range(num_pads): pads.append( ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 60 + index)) pads[(-1)].name = b'Pad_' + str(index) clip_slot = self._session.selected_scene().clip_slot(index) clip_slot.set_triggered_to_play_value(GREEN_BLINK) clip_slot.set_triggered_to_record_value(RED_BLINK) clip_slot.set_stopped_value(AMBER_FULL) clip_slot.set_started_value(GREEN_FULL) clip_slot.set_recording_value(RED_FULL) clip_slot.set_launch_button(pads[(-1)]) clip_slot.name = str(index) + b'_Selected_Clip_Slot' def _setup_transport(self): rwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 27) ffwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 28) stop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 29) play_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 30) loop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 31) rec_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 32) ffwd_button.name = b'FFwd_Button' rwd_button.name = b'Rwd_Button' loop_button.name = b'Loop_Button' play_button.name = b'Play_Button' stop_button.name = b'Stop_Button' rec_button.name = b'Record_Button' transport = ShiftableTransportComponent() transport.name = b'Transport' transport.set_stop_button(stop_button) transport.set_play_button(play_button) transport.set_record_button(rec_button) transport.set_shift_button(self._shift_button) self._transport_view_modes = TransportViewModeSelector( transport, self._session, ffwd_button, rwd_button, loop_button) self._transport_view_modes.name = b'Transport_View_Modes' def _setup_device(self): encoders = [] for index in range(8): encoders.append( PeekableEncoderElement( MIDI_CC_TYPE, 1, index, Live.MidiMap.MapMode.relative_binary_offset)) encoders[(-1)].set_feedback_delay(-1) encoders[(-1)].add_value_listener(self._encoder_value, identify_sender=True) encoders[(-1)].name = b'Device_Control_' + str(index) self._encoders = tuple(encoders) self._prev_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 12) self._next_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 11) self._prev_bank_button.name = b'Device_Bank_Down_Button' self._next_bank_button.name = b'Device_Bank_Up_Button' device = DeviceComponent(device_selection_follows_track_selection=True) device.name = b'Device_Component' self.set_device_component(device) device.set_parameter_controls(self._encoders) device.set_bank_nav_buttons(self._prev_bank_button, self._next_bank_button) def _setup_name_display(self): self._name_display = PhysicalDisplayElement(16, 1) self._name_display.name = b'Display' self._name_display.set_message_parts(SYSEX_START + (8, ), (247, )) self._name_display_data_source = DisplayDataSource() self._name_display.segment(0).set_data_source( self._name_display_data_source) def _encoder_value(self, value, sender): assert sender in self._encoders assert value in range(128) if self._device_component.is_enabled(): display_string = b' - ' if sender.mapped_parameter() != None: display_string = sender.mapped_parameter().name self._set_string_to_display(display_string) return def _slider_value(self, value, sender): assert sender in tuple(self._sliders) + (self._master_slider, ) assert value in range(128) if self._mixer.is_enabled(): display_string = b' - ' if sender.mapped_parameter() != None: master = self.song().master_track tracks = self.song().tracks returns = self.song().return_tracks track = None if sender == self._master_slider: if self._has_sliders: track = master else: track = self.song().view.selected_track else: track = self._mixer.channel_strip( self._sliders.index(sender))._track if track == master: display_string = b'Master' elif track in tracks: display_string = str(list(tracks).index(track) + 1) elif track in returns: display_string = str( chr(ord(b'A') + list(returns).index(track))) else: assert False display_string += b' Volume' self._set_string_to_display(display_string) return def _mixer_button_value(self, value, sender): assert value in range(128) if self._mixer.is_enabled() and value > 0: strip = self._mixer.channel_strip( self._strip_buttons.index(sender)) if strip != None: self._string_to_display = None self._name_display.segment(0).set_data_source( strip.track_name_data_source()) self._name_display.update() self._display_reset_delay = STANDARD_DISPLAY_DELAY else: self._set_string_to_display(b' - ') return def _preview_value(self, value): assert value in range(128) for encoder in self._encoders: encoder.set_peek_mode(value > 0) def _show_current_track_name(self): if self._name_display != None and self._mixer != None: self._string_to_display = None self._name_display.segment(0).set_data_source( self._mixer.selected_strip().track_name_data_source()) self._name_display.update() return def _show_startup_message(self): self._name_display.display_message(b'LIVE') self._display_reset_delay = INITIAL_DISPLAY_DELAY def _set_string_to_display(self, string_to_display): assert isinstance(string_to_display, (str, unicode)) self._name_display.segment(0).set_data_source( self._name_display_data_source) self._string_to_display = string_to_display self._display_reset_delay = STANDARD_DISPLAY_DELAY def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(self) self._show_current_track_name() all_tracks = self._has_sliders or self._session.tracks_to_use() selected_track = self.song().view.selected_track num_strips = self._session.width() if selected_track in all_tracks: track_index = list(all_tracks).index(selected_track) new_offset = track_index - track_index % num_strips if not new_offset / num_strips == int(new_offset / num_strips): raise AssertionError self._session.set_offsets(new_offset, self._session.scene_offset())
class MaschineChannelStripComponent(ChannelStripComponent): def __init__(self): ChannelStripComponent.__init__(self) self.deleted = {} self.clear_mode = False self.touch_mode = False self.send_control = None self.clear_vol_button = None self.clear_pan_button = None self.clear_send_button = None return def set_touch_mode(self, touchchannel): self.touch_mode = True id_vol = self._volume_control.message_identifier() id_pan = self._pan_control.message_identifier() id_send = None for send in self._send_controls: if send: id_send = send.message_identifier() self.clear_vol_button = ButtonElement(False, MIDI_CC_TYPE, touchchannel, id_vol) self.clear_vol_button.add_value_listener(self._do_clear_vol) self.clear_pan_button = ButtonElement(False, MIDI_CC_TYPE, touchchannel, id_pan) self.clear_pan_button.add_value_listener(self._do_clear_pan) self.clear_send_button = ButtonElement(False, MIDI_CC_TYPE, touchchannel, id_send) self.clear_send_button.add_value_listener(self._do_clear_send) for send in self._send_controls: if send: self.send_control = send return def enter_clear(self): self.clear_mode = True self.deleted = {} if not self.touch_mode: self.set_enabled(False) self._volume_control.add_value_listener(self._do_clear_vol) self._pan_control.add_value_listener(self._do_clear_pan) for send in self._send_controls: if send: self.send_control = send send.add_value_listener(self._do_clear_send) def exit_clear(self): self.clear_mode = False if not self.touch_mode: self._volume_control.remove_value_listener(self._do_clear_vol) self._pan_control.remove_value_listener(self._do_clear_pan) for send in self._send_controls: if send: send.remove_value_listener(self._do_clear_send) self.set_enabled(True) def _do_clear_vol(self, value): key = self._volume_control.message_identifier() if self.clear_mode and key not in self.deleted: self.deleted[key] = True playing_clip = self._get_playing_clip() if playing_clip: playing_clip.clear_envelope(self._track.mixer_device.volume) def _do_clear_pan(self, value): key = self._pan_control.message_identifier() if self.clear_mode and key not in self.deleted: self.deleted[key] = True playing_clip = self._get_playing_clip() if playing_clip: playing_clip.clear_envelope(self._track.mixer_device.panning) def _do_clear_send(self, value): key = self.send_control.message_identifier() if self.clear_mode and key not in self.deleted: send_index = len(self._send_controls) - 1 self.deleted[key] = True playing_clip = self._get_playing_clip() if playing_clip and send_index in range(len(self._track.mixer_device.sends)): playing_clip.clear_envelope(self._track.mixer_device.sends[send_index]) def _mute_value(self, value): super(MaschineChannelStripComponent, self)._mute_value(value) key = self._mute_button.message_identifier() if self.clear_mode and key not in self.deleted: self.deleted[key] = True playing_clip = self._get_playing_clip() if playing_clip: playing_clip.clear_envelope(self._track.mixer_device.track_activator) def _get_playing_clip(self): if self._track == None: return clips_slots = self._track.clip_slots for cs in clips_slots: if cs.has_clip and cs.is_playing: return cs.clip return def disconnect(self): self.clear_pan_button = None self.clear_send_button = None if self.clear_vol_button != None: self.clear_vol_button.remove_value_listener(self._do_clear_vol) self.clear_vol_button = None if self.clear_pan_button != None: self.clear_pan_button.remove_value_listener(self._do_clear_pan) self.clear_pan_button = None if self.clear_send_button != None: self.clear_send_button.remove_value_listener(self._do_clear_send) self.clear_send_button = None if not self.touch_mode and self.clear_mode: if self.send_control != None: self.send_control.remove_value_listener(self._do_clear_send) self.send_control = None if self._volume_control != None: self._volume_control.remove_value_listener(self._do_clear_vol) self._volume_control = None if self._pan_control != None: self._pan_control.remove_value_listener(self._do_clear_pan) self._pan_control = None super(MaschineChannelStripComponent, self).disconnect() return
class OP1ModeSelectorComponent(ModeSelectorComponent): __doc__ = ' SelectorComponent that assigns buttons to functions based on the shift button ' def __init__(self, parent, transport, mixer, session): ModeSelectorComponent.__init__(self) self._current_mode = -1 self._mode_index = 0 self._parent = parent self._transport = transport self._mixer = mixer self._session = session self._shift_active = False; # creating buttons for the arrows keys self._left_arrow_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_LEFT_ARROW) self._right_arrow_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_RIGHT_ARROW) # creating button for the shift key self._shift_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SHIFT_BUTTON) self._shift_button.add_value_listener(self.shift_pressed) # creating buttons for the note shifted keys self.note_keys_shifted_buttons = [] self.note_keys_shifted_ccs = [77, 79, 81, 83, 84, 86, 88, 89, 91, 93, 95, 96, 98] # creating a list of shifted note keys buttons for i in range(len(self.note_keys_shifted_ccs)): self.note_keys_shifted_buttons.append(ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, self.note_keys_shifted_ccs[i])) # creating buttons for the note keys self.note_keys_buttons = [] self.note_keys_ccs = [53, 55, 57, 59, 60, 62, 64, 65, 67, 69, 71, 72, 74, 76] # creating a list of note keys buttons for i in range(len(self.note_keys_ccs)): self.note_keys_buttons.append(ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, self.note_keys_ccs[i])) def disconnect(self): ModeSelectorComponent.disconnect(self) self._transport = None return None def number_of_modes(self): return NUM_MODES def shift_pressed(self, value): # handling shift pressed (only for transport mode) if (self._current_mode==OP1_MODE_TRANSPORT): if (value==127): self._transport.set_seek_buttons(None, None) self._left_arrow_button.add_value_listener(self.shifted_left_arrow_pressed) self._right_arrow_button.add_value_listener(self.shifted_right_arrow_pressed) else: self._left_arrow_button.remove_value_listener(self.shifted_left_arrow_pressed) self._right_arrow_button.remove_value_listener(self.shifted_right_arrow_pressed) self._transport.set_seek_buttons(self._right_arrow_button, self._left_arrow_button) def shifted_left_arrow_pressed(self, value): # handling negative loop offset behavior if (value==127): if (self._parent.song().loop_start>0): self._parent.song().loop_start -= 1 def shifted_right_arrow_pressed(self, value): # handling positive loop offset behavior if (value==127): self._parent.song().loop_start += 1 def set_loop(self, index, set_loop_start): # handling set loop self._parent.song().loop = 1 if (set_loop_start): self._parent.song().loop_start = round(self._parent.song().current_song_time) if (index==0): self._parent.song().loop_length = 1 elif (index==1): self._parent.song().loop_length = 2 elif (index==2): self._parent.song().loop_length = 4 elif (index==3): self._parent.song().loop_length = 8 elif (index==4): self._parent.song().loop_length = 16 elif (index==5): self._parent.song().loop_length = 32 elif (index==6): self._parent.song().loop_length = 64 elif (index==7): self._parent.song().loop_length = 128 elif (index==8): self._parent.song().loop_length = 256 elif (index==9): self._parent.song().loop_length = 512 elif (index==10): self._parent.song().loop_length = 1024 elif (index==11): self._parent.song().loop_length = 2048 elif (index==12): self._parent.song().loop_length = 4096 def note_key_pressed(self, value, sender): # determining index of note key button in list index = self.note_keys_buttons.index(sender) if (self._current_mode==OP1_MODE_MIXER): # if on mixer mode, use not key to select a track all_tracks = ((self.song().visible_tracks + self.song().return_tracks)) + (self.song().master_track,) #modified if (index < len(all_tracks)): self.song().view.selected_track = all_tracks[index] elif (self._current_mode==OP1_MODE_TRANSPORT): # if on transport mode, use key to set loop self.set_loop(index, False) def note_key_shifted_pressed(self, value, sender): # determining index of note key button in list index = self.note_keys_shifted_buttons.index(sender) if (self._current_mode==OP1_MODE_TRANSPORT): # if on transport mode, use key to set loop with loop start change self.set_loop(index, True) def clip_color_changed(self): self._parent.log("clip color changed") def has_clip_listener(self): self._parent.log("slot has clip") def update(self): # handle current mode change if self.is_enabled(): # clearing last mappings self.clear() # updating current mode index self._current_mode = self._mode_index # based on current mode, perform necessay re mappings if (self._mode_index == OP1_MODE_PERFORM): # nothing is done for perform mode self._parent.log("PERFORM MODE") elif (self._mode_index == OP1_MODE_TRANSPORT): self._parent.log("TRANSPORT MODE") # settings arrows as seek buttons self._transport.set_seek_buttons(self._right_arrow_button, self._left_arrow_button) # adding value listeners for note keys and note shifted keys for i in range(NUM_TRACKS): self.note_keys_buttons[i].add_value_listener(self.note_key_pressed, True) for i in range(NUM_TRACKS): self.note_keys_shifted_buttons[i].add_value_listener(self.note_key_shifted_pressed, True) elif (self._mode_index == OP1_MODE_MIXER): self._parent.log("MIXER MODE") # setting arrow butons as track select buttons self._mixer.set_select_buttons(self._right_arrow_button, self._left_arrow_button) # adding value listeners for note keys for i in range(NUM_TRACKS): self.note_keys_buttons[i].add_value_listener(self.note_key_pressed, True) elif (self._mode_index == OP1_MODE_CLIP): self._parent.log("CLIP MODE") # setting arrows as track bank buttons self._session.set_track_bank_buttons(self._right_arrow_button, self._left_arrow_button) # setting last key note as stop all clip button self._session.set_stop_all_clips_button(ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, 100)) # setting track stop clip buttons self._session.set_stop_track_clip_buttons(tuple(self.note_keys_shifted_buttons)) # setting track individual clip launch button for i in range(NUM_TRACKS): self._session.scene(0).clip_slot(i).set_launch_button(self.note_keys_buttons[i]) # setting scene launch button self._session.scene(0).set_launch_button(self.note_keys_buttons[NUM_TRACKS]) return None def clear(self): if (self._current_mode == OP1_MODE_PERFORM): self._parent.log("CLEARING PERFORM MODE") elif (self._current_mode == OP1_MODE_TRANSPORT): self._parent.log("CLEARING TRANSPORT MODE") # removing value listeners for note keys for i in range(NUM_TRACKS): self.note_keys_buttons[i].remove_value_listener(self.note_key_pressed) # removing value listeners for shifted note keys for i in range(NUM_TRACKS): self.note_keys_shifted_buttons[i].remove_value_listener(self.note_key_shifted_pressed) # clearing transport seek buttons self._transport.set_seek_buttons(None, None) elif (self._current_mode == OP1_MODE_MIXER): self._parent.log("CLEARING MIXER MODE") # removing value listeners for note key press for i in range(NUM_TRACKS): self.note_keys_buttons[i].remove_value_listener(self.note_key_pressed) self._parent.clear_tracks_assigments() # clearing mixer track select buttons self._mixer.set_select_buttons(None, None) elif (self._current_mode == OP1_MODE_CLIP): self._parent.log("CLEARING CLIP MODE") # clearing session track bank buttons self._session.set_track_bank_buttons(None,None) # clearing session stop all clips button self._session.set_stop_all_clips_button(None) # clearing session track stop clip buttons self._session.set_stop_track_clip_buttons(None) # clearing individual clip launch button for i in range(NUM_TRACKS): self._session.scene(0).clip_slot(i).set_launch_button(None) # clearing session launch button self._session.scene(0).set_launch_button(None)
class OP1ModeSelectorComponent(ModeSelectorComponent): __doc__ = ' SelectorComponent that assigns buttons to functions based on the shift button ' def __init__(self, parent, transport, mixer, session): ModeSelectorComponent.__init__(self) self._current_mode = -1 self._mode_index = 0 self._parent = parent self._transport = transport self._mixer = mixer self._session = session self._shift_active = False # creating buttons for the arrows keys self._left_arrow_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_LEFT_ARROW) self._right_arrow_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_RIGHT_ARROW) # creating button for the shift key self._shift_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SHIFT_BUTTON) self._shift_button.add_value_listener(self.shift_pressed) # creating buttons for the note shifted keys self.note_keys_shifted_buttons = [] self.note_keys_shifted_ccs = [ 77, 79, 81, 83, 84, 86, 88, 89, 91, 93, 95, 96, 98 ] # creating a list of shifted note keys buttons for i in range(len(self.note_keys_shifted_ccs)): self.note_keys_shifted_buttons.append( ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, self.note_keys_shifted_ccs[i])) # creating buttons for the note keys self.note_keys_buttons = [] self.note_keys_ccs = [ 53, 55, 57, 59, 60, 62, 64, 65, 67, 69, 71, 72, 74, 76 ] # creating a list of note keys buttons for i in range(len(self.note_keys_ccs)): self.note_keys_buttons.append( ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, self.note_keys_ccs[i])) def disconnect(self): ModeSelectorComponent.disconnect(self) self._transport = None return None def number_of_modes(self): return NUM_MODES def shift_pressed(self, value): # handling shift pressed (only for transport mode) if (self._current_mode == OP1_MODE_TRANSPORT): if (value == 127): self._transport.set_seek_buttons(None, None) self._left_arrow_button.add_value_listener( self.shifted_left_arrow_pressed) self._right_arrow_button.add_value_listener( self.shifted_right_arrow_pressed) else: self._left_arrow_button.remove_value_listener( self.shifted_left_arrow_pressed) self._right_arrow_button.remove_value_listener( self.shifted_right_arrow_pressed) self._transport.set_seek_buttons(self._right_arrow_button, self._left_arrow_button) def shifted_left_arrow_pressed(self, value): # handling negative loop offset behavior if (value == 127): if (self._parent.song().loop_start > 0): self._parent.song().loop_start -= 1 def shifted_right_arrow_pressed(self, value): # handling positive loop offset behavior if (value == 127): self._parent.song().loop_start += 1 def set_loop(self, index, set_loop_start): # handling set loop self._parent.song().loop = 1 if (set_loop_start): self._parent.song().loop_start = round( self._parent.song().current_song_time) if (index == 0): self._parent.song().loop_length = 1 elif (index == 1): self._parent.song().loop_length = 2 elif (index == 2): self._parent.song().loop_length = 4 elif (index == 3): self._parent.song().loop_length = 8 elif (index == 4): self._parent.song().loop_length = 16 elif (index == 5): self._parent.song().loop_length = 32 elif (index == 6): self._parent.song().loop_length = 64 elif (index == 7): self._parent.song().loop_length = 128 elif (index == 8): self._parent.song().loop_length = 256 elif (index == 9): self._parent.song().loop_length = 512 elif (index == 10): self._parent.song().loop_length = 1024 elif (index == 11): self._parent.song().loop_length = 2048 elif (index == 12): self._parent.song().loop_length = 4096 def note_key_pressed(self, value, sender): # determining index of note key button in list index = self.note_keys_buttons.index(sender) if (self._current_mode == OP1_MODE_MIXER): # if on mixer mode, use not key to select a track all_tracks = ( (self.song().visible_tracks + self.song().return_tracks)) + ( self.song().master_track, ) #modified if (index < len(all_tracks)): self.song().view.selected_track = all_tracks[index] elif (self._current_mode == OP1_MODE_TRANSPORT): # if on transport mode, use key to set loop self.set_loop(index, False) def note_key_shifted_pressed(self, value, sender): # determining index of note key button in list index = self.note_keys_shifted_buttons.index(sender) if (self._current_mode == OP1_MODE_TRANSPORT): # if on transport mode, use key to set loop with loop start change self.set_loop(index, True) def clip_color_changed(self): self._parent.log("clip color changed") def has_clip_listener(self): self._parent.log("slot has clip") def update(self): # handle current mode change if self.is_enabled(): # clearing last mappings self.clear() # updating current mode index self._current_mode = self._mode_index # based on current mode, perform necessay re mappings if (self._mode_index == OP1_MODE_PERFORM): # nothing is done for perform mode self._parent.log("PERFORM MODE") elif (self._mode_index == OP1_MODE_TRANSPORT): self._parent.log("TRANSPORT MODE") # settings arrows as seek buttons self._transport.set_seek_buttons(self._right_arrow_button, self._left_arrow_button) # adding value listeners for note keys and note shifted keys for i in range(NUM_TRACKS): self.note_keys_buttons[i].add_value_listener( self.note_key_pressed, True) for i in range(NUM_TRACKS): self.note_keys_shifted_buttons[i].add_value_listener( self.note_key_shifted_pressed, True) elif (self._mode_index == OP1_MODE_MIXER): self._parent.log("MIXER MODE") # setting arrow butons as track select buttons self._mixer.set_select_buttons(self._right_arrow_button, self._left_arrow_button) # adding value listeners for note keys for i in range(NUM_TRACKS): self.note_keys_buttons[i].add_value_listener( self.note_key_pressed, True) elif (self._mode_index == OP1_MODE_CLIP): self._parent.log("CLIP MODE") # setting arrows as track bank buttons self._session.set_track_bank_buttons(self._right_arrow_button, self._left_arrow_button) # setting last key note as stop all clip button self._session.set_stop_all_clips_button( ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, 100)) # setting track stop clip buttons self._session.set_stop_track_clip_buttons( tuple(self.note_keys_shifted_buttons)) # setting track individual clip launch button for i in range(NUM_TRACKS): self._session.scene(0).clip_slot(i).set_launch_button( self.note_keys_buttons[i]) # setting scene launch button self._session.scene(0).set_launch_button( self.note_keys_buttons[NUM_TRACKS]) return None def clear(self): if (self._current_mode == OP1_MODE_PERFORM): self._parent.log("CLEARING PERFORM MODE") elif (self._current_mode == OP1_MODE_TRANSPORT): self._parent.log("CLEARING TRANSPORT MODE") # removing value listeners for note keys for i in range(NUM_TRACKS): self.note_keys_buttons[i].remove_value_listener( self.note_key_pressed) # removing value listeners for shifted note keys for i in range(NUM_TRACKS): self.note_keys_shifted_buttons[i].remove_value_listener( self.note_key_shifted_pressed) # clearing transport seek buttons self._transport.set_seek_buttons(None, None) elif (self._current_mode == OP1_MODE_MIXER): self._parent.log("CLEARING MIXER MODE") # removing value listeners for note key press for i in range(NUM_TRACKS): self.note_keys_buttons[i].remove_value_listener( self.note_key_pressed) self._parent.clear_tracks_assigments() # clearing mixer track select buttons self._mixer.set_select_buttons(None, None) elif (self._current_mode == OP1_MODE_CLIP): self._parent.log("CLEARING CLIP MODE") # clearing session track bank buttons self._session.set_track_bank_buttons(None, None) # clearing session stop all clips button self._session.set_stop_all_clips_button(None) # clearing session track stop clip buttons self._session.set_stop_track_clip_buttons(None) # clearing individual clip launch button for i in range(NUM_TRACKS): self._session.scene(0).clip_slot(i).set_launch_button(None) # clearing session launch button self._session.scene(0).set_launch_button(None)
class Novation_Impulse2(ControlSurface): """ Script for Novation's Impulse keyboards """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) self.c_instance = c_instance with self.component_guard(): self.set_pad_translations(PAD_TRANSLATIONS) self._device_selection_follows_track_selection = True self._suggested_input_port = 'Impulse' self._suggested_output_port = 'Impulse' self._has_sliders = True self._current_midi_map = None self._display_reset_delay = -1 self._string_to_display = None self.shift_pressed = False # special alternative buttons mode. for now only mixer buttons become record buttons. later we will add something more self.alternative_buttons_mode = False self._shift_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 39) self._preview_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 41) self._master_slider = SliderElement(MIDI_CC_TYPE, 0, 8) self._shift_button.name = 'Shift_Button' self._master_slider.name = 'Master_Volume_Control' self._master_slider.add_value_listener(self._slider_value, identify_sender=True) self._preview_button.add_value_listener(self._preview_value) self._setup_mixer() self._setup_session() self._setup_transport() self._setup_device() self._setup_name_display() device_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 1, 10) mixer_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 1, 9) device_button.name = 'Encoder_Device_Mode' mixer_button.name = 'Encoder_Mixer_Mode' self._encoder_modes = EncoderModeSelector(self._device_component, self._mixer, self._next_bank_button, self._prev_bank_button, self._encoders) self._encoder_modes.set_device_mixer_buttons( device_button, mixer_button) self._shift_button.add_value_listener(self._shift_button_handler) for component in self.components: component.set_enabled(False) # attributes def alternative_buttons_mode(self): return self.alternative_buttons_mode def alternative_buttons_mode(self, value): self.log('alternative_buttons_mode_value ' + str(value)) self.alternative_buttons_mode = value def shift_pressed(self): return self.shift_pressed def shift_pressed(self, value): self.log('shift_pressed value ' + str(value)) self.shift_pressed = value def refresh_state(self): ControlSurface.refresh_state(self) self.schedule_message(3, self._send_midi, SYSEX_START + (6, 1, 1, 1, 247)) def handle_sysex(self, midi_bytes): if midi_bytes[0:-2] == SYSEX_START + (7, ) and midi_bytes[-2] != 0: self._has_sliders = midi_bytes[-2] != 25 self.schedule_message(1, self._show_startup_message) for control in self.controls: if isinstance(control, InputControlElement): control.clear_send_cache() for component in self.components: component.set_enabled(True) if self._has_sliders: self._mixer.master_strip().set_volume_control( self._master_slider) self._mixer.update() else: self._mixer.master_strip().set_volume_control(None) self._mixer.selected_strip().set_volume_control( self._master_slider) for index in range(len(self._sliders)): self._mixer.channel_strip(index).set_volume_control(None) slider = self._sliders[index] slider.release_parameter() if slider.value_has_listener(self._slider_value): slider.remove_value_listener(self._slider_value) self._encoder_modes.set_provide_volume_mode(not self._has_sliders) self.request_rebuild_midi_map() def disconnect(self): self.log('starting disconnect 1') self._name_display_data_source.set_display_string(' ') for encoder in self._encoders: encoder.remove_value_listener(self._encoder_value) self._master_slider.remove_value_listener(self._slider_value) if self._has_sliders: for slider in tuple(self._sliders): slider.remove_value_listener(self._slider_value) for button in self._strip_buttons: button.remove_value_listener(self._mixer_button_value) self._preview_button.remove_value_listener(self._preview_value) self.log('starting disconnect 3') ControlSurface.disconnect(self) self.log('starting disconnect 3') self._encoders = None self._sliders = None self._strip_buttons = None self._master_slider = None self._current_midi_map = None self._name_display = None self._prev_bank_button = None self._next_bank_button = None self._encoder_modes = None self._transport_view_modes = None self.log('starting disconnect 4') self._send_midi(SYSEX_START + (6, 0, 0, 0, 247)) self.log('starting disconnect 5') if self._shift_button != None: self._shift_button.remove_value_listener( self._shift_button_handler) self._shift_button = None self.log('starting disconnect 6') def build_midi_map(self, midi_map_handle): self._current_midi_map = midi_map_handle ControlSurface.build_midi_map(self, midi_map_handle) def update_display(self): ControlSurface.update_display(self) if self._string_to_display != None: self._name_display_data_source.set_display_string( self._string_to_display) self._string_to_display = None if self._display_reset_delay >= 0: self._display_reset_delay -= 1 if self._display_reset_delay == -1: self._show_current_track_name() def _setup_mixer(self): self.log('setup mixer') mute_solo_flip_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 34) self._next_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 37) self._prev_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 38) self._strip_buttons = [] mute_solo_flip_button.name = 'Mute_Solo_Flip_Button' self._next_nav_button.name = 'Next_Track_Button' self._prev_nav_button.name = 'Prev_Track_Button' self._mixer = SpecialMixerComponent(self, 8, self.c_instance) self._mixer.name = 'Mixer' self._mixer.set_select_buttons(self._next_nav_button, self._prev_nav_button) self._mixer.selected_strip().name = 'Selected_Channel_Strip' self._mixer.master_strip().name = 'Master_Channel_Strip' self._mixer.master_strip().set_volume_control(self._master_slider) self._sliders = [] for index in range(8): strip = self._mixer.channel_strip(index) strip.name = 'Channel_Strip_' + str(index) strip.set_invert_mute_feedback(True) self._sliders.append(SliderElement(MIDI_CC_TYPE, 0, index)) self._sliders[-1].name = str(index) + '_Volume_Control' self._sliders[-1].set_feedback_delay(-1) self._sliders[-1].add_value_listener(self._slider_value, identify_sender=True) strip.set_volume_control(self._sliders[-1]) self._strip_buttons.append( ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 9 + index)) self._strip_buttons[-1].name = str(index) + '_Mute_Button' self._strip_buttons[-1].add_value_listener( self._mixer_button_value, identify_sender=True) self._mixer.master_strip().set_mute_button( ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 17)) self._mixer.set_strip_mute_solo_buttons(tuple(self._strip_buttons), mute_solo_flip_button) #self._mixer.set_shift_button(self._shift_button) self._mixer.updateMixerButtons() self._button9 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 9 + 8) def _setup_session(self): num_pads = len(PAD_TRANSLATIONS) self._session = SessionComponent(8, 0) self._session.name = 'Session_Control' self._session.selected_scene().name = 'Selected_Scene' self._session.set_mixer(self._mixer) # for ableton 9.1.1 and lower #self._session.set_track_banking_increment(num_pads) #self._session.set_track_bank_buttons(ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 35), ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 36)) # for ableton 9.1.1 and higher self._track_left_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 36) self._track_right_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 35) self._session.set_page_left_button(self._track_left_button) self._session.set_page_right_button(self._track_right_button) pads = [] for index in range(num_pads): pads.append( ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 60 + index)) pads[-1].name = 'Pad_' + str(index) clip_slot = self._session.selected_scene().clip_slot(index) clip_slot.set_triggered_to_play_value(GREEN_BLINK) clip_slot.set_triggered_to_record_value(RED_BLINK) clip_slot.set_stopped_value(AMBER_FULL) clip_slot.set_started_value(GREEN_FULL) clip_slot.set_recording_value(RED_FULL) clip_slot.set_launch_button(pads[-1]) clip_slot.name = str(index) + '_Selected_Clip_Slot' def _setup_transport(self): rwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 27) ffwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 28) stop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 29) play_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 30) loop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 31) rec_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 32) ffwd_button.name = 'FFwd_Button' rwd_button.name = 'Rwd_Button' loop_button.name = 'Loop_Button' play_button.name = 'Play_Button' stop_button.name = 'Stop_Button' rec_button.name = 'Record_Button' self._transport = ShiftableTransportComponent(self.c_instance, self._session, self, ffwd_button, rwd_button) self._transport.name = 'Transport' self._transport.set_stop_buttonOnInit(stop_button) self._transport.set_play_button(play_button) self._transport.set_record_buttonOnInit(rec_button) # self._transport.set_shift_button(self._shift_button) self._transport.set_mixer9_button(self._button9) self._transport_view_modes = TransportViewModeSelector( self, self.c_instance, self._transport, self._session, ffwd_button, rwd_button, loop_button) self._transport_view_modes.name = 'Transport_View_Modes' def _setup_device(self): encoders = [] for index in range(8): encoders.append( PeekableEncoderElement( MIDI_CC_TYPE, 1, index, Live.MidiMap.MapMode.relative_binary_offset)) encoders[-1].set_feedback_delay(-1) encoders[-1].add_value_listener(self._encoder_value, identify_sender=True) encoders[-1].name = 'Device_Control_' + str(index) self._encoders = tuple(encoders) self._prev_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 12) self._next_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 11) self._prev_bank_button.name = 'Device_Bank_Down_Button' self._next_bank_button.name = 'Device_Bank_Up_Button' device = DeviceComponent() device.name = 'Device_Component' self.set_device_component(device) device.set_parameter_controls(self._encoders) device.set_bank_nav_buttons(self._prev_bank_button, self._next_bank_button) def _setup_name_display(self): self._name_display = PhysicalDisplayElement(16, 1) self._name_display.name = 'Display' self._name_display.set_message_parts(SYSEX_START + (8, ), (247, )) self._name_display_data_source = DisplayDataSource() self._name_display.segment(0).set_data_source( self._name_display_data_source) def _encoder_value(self, value, sender): if not sender in self._encoders: raise AssertionError if not value in range(128): raise AssertionError # display_string = self._device_component.is_enabled() and ' - ' # display_string = sender.mapped_parameter() != None and sender.mapped_parameter().name display_string = '' if self._device_component.is_enabled(): # display_string = sender.name # track = self.song().view.selected_track # display_string = str(list(tracks).index(track) + 1) pass if (sender.mapped_parameter() != None): # display_string = display_string + '-' display_string = display_string + sender.mapped_parameter().name self._set_string_to_display(display_string) def _slider_value(self, value, sender): self.log('_slider_value ' + str(value) + ' ' + str(sender)) if not sender in tuple(self._sliders) + (self._master_slider, ): raise AssertionError if not value in range(128): raise AssertionError if self._mixer.is_enabled(): display_string = ' - ' master = self.song().master_track tracks = self.song().tracks returns = self.song().return_tracks track = None if sender.mapped_parameter() != None: self.log('1') if sender == self._master_slider: self.log('2') # track = self._has_sliders and master if self._has_sliders: track = master else: self.log('2.1') track = self.song().view.selected_track else: self.log('3') track = self._mixer.channel_strip( self._sliders.index(sender))._track else: self.log('4') track = self.song().view.selected_track self.log('track=' + str(track)) if track == master: display_string = 'Master' elif track in tracks: display_string = str(list(tracks).index(track) + 1) elif track in returns: display_string = str( chr(ord('A') + list(returns).index(track))) else: # raise False or AssertionError raise AssertionError display_string += ' Volume' self._set_string_to_display(display_string) def _mixer_button_value(self, value, sender): self.log('__mixer_button_value ' + str(value) + ' ' + str(sender)) if not value in range(128): raise AssertionError #if self._mixer.is_enabled() and value > 0: if self._mixer.is_enabled(): strip = self._mixer.channel_strip( self._strip_buttons.index(sender)) #self._string_to_display = strip != None and None self._name_display.segment(0).set_data_source( strip.track_name_data_source()) self._name_display.update() self._display_reset_delay = STANDARD_DISPLAY_DELAY else: self._set_string_to_display(' - ') # if shift_pressed XOR alternative_mode if self.shift_pressed <> self.alternative_buttons_mode: self.log("_mixer_button_value") self.log(str(value)) if (value == 0): self.select_armed_track_if_only_one() def select_armed_track_if_only_one(self): self.log("select_armed_track_if_only_one") song = self.song() armed_tracks = [] tracks = song.tracks self.log("select_armed_track_if_only_one 2") for track in tracks: if track.can_be_armed and track.arm: armed_tracks.append(track) self.log(str(len(armed_tracks))) if (len(armed_tracks) == 1): self.log("selecting the track") sel_track = armed_tracks[0] self.song().view.selected_track = sel_track self._mixer._selected_tracks = [] self._mixer._selected_tracks.append(sel_track) self._mixer.on_selected_track_changed() def _preview_value(self, value): if not value in range(128): raise AssertionError for encoder in self._encoders: encoder.set_peek_mode(value > 0) def _show_current_track_name(self): if self._name_display != None and self._mixer != None: self._string_to_display = None self._name_display.segment(0).set_data_source( self._mixer.selected_strip().track_name_data_source()) self._name_display.update() def _show_startup_message(self): self._name_display.display_message('LIVE') self._display_reset_delay = INITIAL_DISPLAY_DELAY def _set_string_to_display(self, string_to_display): if not isinstance(string_to_display, (str, unicode)): raise AssertionError self._name_display.segment(0).set_data_source( self._name_display_data_source) self._string_to_display = string_to_display self._display_reset_delay = STANDARD_DISPLAY_DELAY def _on_selected_track_changed(self): self.log('_on_selected_track_changed') ControlSurface._on_selected_track_changed(self) self._show_current_track_name() #all_tracks = self._has_sliders or self._session.tracks_to_use() all_tracks2 = self._session.tracks_to_use() selected_track = self.song().view.selected_track num_strips = self._session.width() if selected_track in all_tracks2: track_index = list(all_tracks2).index(selected_track) self.log('track_index ' + str(track_index)) new_offset = track_index - track_index % num_strips self.log('new_offset ' + str(new_offset)) if not new_offset / num_strips == int(new_offset / num_strips): raise AssertionError self._session.set_offsets(new_offset, self._session.scene_offset()) def _shift_button_handler(self, value): self.log("root shift handler : " + str(value)) if not self._shift_button != None: raise AssertionError if not value in range(128): raise AssertionError self.log("root shift handler 2") self.shift_pressed = value > 0 # calling other handlers self._mixer._shift_button_handler(value) self._transport._shift_button_handler(value) self._transport_view_modes._shift_button_handler(value) #clip stop self.log("root shift handler 3") num_pads = len(PAD_TRANSLATIONS) pads = [] for index in range(num_pads): pads.append( ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 60 + index)) pads[-1].name = 'Pad_' + str(index) clip_slot = self._session.selected_scene().clip_slot(index) if self.shift_pressed: clip_slot.set_launch_button(None) else: clip_slot.set_launch_button(pads[index]) if self.shift_pressed: self._session.set_stop_track_clip_buttons(tuple(pads)) else: self._session.set_stop_track_clip_buttons(None) self.log("root shift handler 4") def flipAlternativeButtonMode(self): self.alternative_buttons_mode = not self.alternative_buttons_mode self.updateAlternativeButtonMode() def updateAlternativeButtonMode(self): self._mixer.updateMixerButtons() self._transport_view_modes.update() def log(self, message): pass
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)
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
class Novation_Impulse2(ControlSurface): """ Script for Novation's Impulse keyboards """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) self.c_instance = c_instance with self.component_guard(): self.set_pad_translations(PAD_TRANSLATIONS) self._device_selection_follows_track_selection = True self._suggested_input_port = 'Impulse' self._suggested_output_port = 'Impulse' self._has_sliders = True self._current_midi_map = None self._display_reset_delay = -1 self._string_to_display = None self.shift_pressed = False # special alternative buttons mode. for now only mixer buttons become record buttons. later we will add something more self.alternative_buttons_mode = False self._shift_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 39) self._preview_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 41) self._master_slider = SliderElement(MIDI_CC_TYPE, 0, 8) self._shift_button.name = 'Shift_Button' self._master_slider.name = 'Master_Volume_Control' self._master_slider.add_value_listener(self._slider_value, identify_sender=True) self._preview_button.add_value_listener(self._preview_value) self._setup_mixer() self._setup_session() self._setup_transport() self._setup_device() self._setup_name_display() device_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 1, 10) mixer_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 1, 9) device_button.name = 'Encoder_Device_Mode' mixer_button.name = 'Encoder_Mixer_Mode' self._encoder_modes = EncoderModeSelector(self._device_component, self._mixer, self._next_bank_button, self._prev_bank_button, self._encoders) self._encoder_modes.set_device_mixer_buttons(device_button, mixer_button) self._shift_button.add_value_listener(self._shift_button_handler) for component in self.components: component.set_enabled(False) # attributes def alternative_buttons_mode(self): return self.alternative_buttons_mode def alternative_buttons_mode(self,value): self.log ('alternative_buttons_mode_value ' + str(value)) self.alternative_buttons_mode = value def shift_pressed(self): return self.shift_pressed def shift_pressed(self,value): self.log ('shift_pressed value ' + str(value)) self.shift_pressed = value def refresh_state(self): ControlSurface.refresh_state(self) self.schedule_message(3, self._send_midi, SYSEX_START + (6, 1, 1, 1, 247)) def handle_sysex(self, midi_bytes): if midi_bytes[0:-2] == SYSEX_START + (7,) and midi_bytes[-2] != 0: self._has_sliders = midi_bytes[-2] != 25 self.schedule_message(1, self._show_startup_message) for control in self.controls: if isinstance(control, InputControlElement): control.clear_send_cache() for component in self.components: component.set_enabled(True) if self._has_sliders: self._mixer.master_strip().set_volume_control(self._master_slider) self._mixer.update() else: self._mixer.master_strip().set_volume_control(None) self._mixer.selected_strip().set_volume_control(self._master_slider) for index in range(len(self._sliders)): self._mixer.channel_strip(index).set_volume_control(None) slider = self._sliders[index] slider.release_parameter() if slider.value_has_listener(self._slider_value): slider.remove_value_listener(self._slider_value) self._encoder_modes.set_provide_volume_mode(not self._has_sliders) self.request_rebuild_midi_map() def disconnect(self): self.log('starting disconnect 1') self._name_display_data_source.set_display_string(' ') for encoder in self._encoders: encoder.remove_value_listener(self._encoder_value) self._master_slider.remove_value_listener(self._slider_value) if self._has_sliders: for slider in tuple(self._sliders): slider.remove_value_listener(self._slider_value) for button in self._strip_buttons: button.remove_value_listener(self._mixer_button_value) self._preview_button.remove_value_listener(self._preview_value) self.log('starting disconnect 3') ControlSurface.disconnect(self) self.log('starting disconnect 3') self._encoders = None self._sliders = None self._strip_buttons = None self._master_slider = None self._current_midi_map = None self._name_display = None self._prev_bank_button = None self._next_bank_button = None self._encoder_modes = None self._transport_view_modes = None self.log('starting disconnect 4') self._send_midi(SYSEX_START + (6, 0, 0, 0, 247)) self.log('starting disconnect 5') if self._shift_button != None: self._shift_button.remove_value_listener(self._shift_button_handler) self._shift_button = None self.log('starting disconnect 6') def build_midi_map(self, midi_map_handle): self._current_midi_map = midi_map_handle ControlSurface.build_midi_map(self, midi_map_handle) def update_display(self): ControlSurface.update_display(self) if self._string_to_display != None: self._name_display_data_source.set_display_string(self._string_to_display) self._string_to_display = None if self._display_reset_delay >= 0: self._display_reset_delay -= 1 if self._display_reset_delay == -1: self._show_current_track_name() def _setup_mixer(self): self.log('setup mixer') mute_solo_flip_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 34) self._next_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 37) self._prev_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 38) self._strip_buttons = [] mute_solo_flip_button.name = 'Mute_Solo_Flip_Button' self._next_nav_button.name = 'Next_Track_Button' self._prev_nav_button.name = 'Prev_Track_Button' self._mixer = SpecialMixerComponent(self, 8, self.c_instance) self._mixer.name = 'Mixer' self._mixer.set_select_buttons(self._next_nav_button, self._prev_nav_button) self._mixer.selected_strip().name = 'Selected_Channel_Strip' self._mixer.master_strip().name = 'Master_Channel_Strip' self._mixer.master_strip().set_volume_control(self._master_slider) self._sliders = [] for index in range(8): strip = self._mixer.channel_strip(index) strip.name = 'Channel_Strip_' + str(index) strip.set_invert_mute_feedback(True) self._sliders.append(SliderElement(MIDI_CC_TYPE, 0, index)) self._sliders[-1].name = str(index) + '_Volume_Control' self._sliders[-1].set_feedback_delay(-1) self._sliders[-1].add_value_listener(self._slider_value, identify_sender=True) strip.set_volume_control(self._sliders[-1]) self._strip_buttons.append(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 9 + index)) self._strip_buttons[-1].name = str(index) + '_Mute_Button' self._strip_buttons[-1].add_value_listener(self._mixer_button_value, identify_sender=True) self._mixer.master_strip().set_mute_button(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 17)) self._mixer.set_strip_mute_solo_buttons(tuple(self._strip_buttons), mute_solo_flip_button) #self._mixer.set_shift_button(self._shift_button) self._mixer.updateMixerButtons() self._button9 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 9 + 8) def _setup_session(self): num_pads = len(PAD_TRANSLATIONS) self._session = SessionComponent(8, 0) self._session.name = 'Session_Control' self._session.selected_scene().name = 'Selected_Scene' self._session.set_mixer(self._mixer) # for ableton 9.1.1 and lower #self._session.set_track_banking_increment(num_pads) #self._session.set_track_bank_buttons(ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 35), ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 36)) # for ableton 9.1.1 and higher self._track_left_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 36) self._track_right_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 35) self._session.set_page_left_button(self._track_left_button) self._session.set_page_right_button(self._track_right_button) pads = [] for index in range(num_pads): pads.append(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 60 + index)) pads[-1].name = 'Pad_' + str(index) clip_slot = self._session.selected_scene().clip_slot(index) clip_slot.set_triggered_to_play_value(GREEN_BLINK) clip_slot.set_triggered_to_record_value(RED_BLINK) clip_slot.set_stopped_value(AMBER_FULL) clip_slot.set_started_value(GREEN_FULL) clip_slot.set_recording_value(RED_FULL) clip_slot.set_launch_button(pads[-1]) clip_slot.name = str(index) + '_Selected_Clip_Slot' def _setup_transport(self): rwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 27) ffwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 28) stop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 29) play_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 30) loop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 31) rec_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 32) ffwd_button.name = 'FFwd_Button' rwd_button.name = 'Rwd_Button' loop_button.name = 'Loop_Button' play_button.name = 'Play_Button' stop_button.name = 'Stop_Button' rec_button.name = 'Record_Button' self._transport = ShiftableTransportComponent(self.c_instance,self._session, self, ffwd_button, rwd_button) self._transport.name = 'Transport' self._transport.set_stop_buttonOnInit(stop_button) self._transport.set_play_button(play_button) self._transport.set_record_buttonOnInit(rec_button) # self._transport.set_shift_button(self._shift_button) self._transport.set_mixer9_button(self._button9) self._transport_view_modes = TransportViewModeSelector(self,self.c_instance,self._transport, self._session, ffwd_button, rwd_button, loop_button) self._transport_view_modes.name = 'Transport_View_Modes' def _setup_device(self): encoders = [] for index in range(8): encoders.append(PeekableEncoderElement(MIDI_CC_TYPE, 1, index, Live.MidiMap.MapMode.relative_binary_offset)) encoders[-1].set_feedback_delay(-1) encoders[-1].add_value_listener(self._encoder_value, identify_sender=True) encoders[-1].name = 'Device_Control_' + str(index) self._encoders = tuple(encoders) self._prev_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 12) self._next_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 11) self._prev_bank_button.name = 'Device_Bank_Down_Button' self._next_bank_button.name = 'Device_Bank_Up_Button' device = DeviceComponent() device.name = 'Device_Component' self.set_device_component(device) device.set_parameter_controls(self._encoders) device.set_bank_nav_buttons(self._prev_bank_button, self._next_bank_button) def _setup_name_display(self): self._name_display = PhysicalDisplayElement(16, 1) self._name_display.name = 'Display' self._name_display.set_message_parts(SYSEX_START + (8,), (247,)) self._name_display_data_source = DisplayDataSource() self._name_display.segment(0).set_data_source(self._name_display_data_source) def _encoder_value(self, value, sender): if not sender in self._encoders: raise AssertionError if not value in range(128): raise AssertionError # display_string = self._device_component.is_enabled() and ' - ' # display_string = sender.mapped_parameter() != None and sender.mapped_parameter().name display_string = '' if self._device_component.is_enabled(): # display_string = sender.name # track = self.song().view.selected_track # display_string = str(list(tracks).index(track) + 1) pass if (sender.mapped_parameter() != None): # display_string = display_string + '-' display_string = display_string + sender.mapped_parameter().name self._set_string_to_display(display_string) def _slider_value(self, value, sender): self.log ('_slider_value ' + str(value) + ' ' +str(sender)) if not sender in tuple(self._sliders) + (self._master_slider,): raise AssertionError if not value in range(128): raise AssertionError if self._mixer.is_enabled(): display_string = ' - ' master = self.song().master_track tracks = self.song().tracks returns = self.song().return_tracks track = None if sender.mapped_parameter() != None: self.log ('1') if sender == self._master_slider: self.log ('2') # track = self._has_sliders and master if self._has_sliders: track = master else: self.log ('2.1') track = self.song().view.selected_track else: self.log ('3') track = self._mixer.channel_strip(self._sliders.index(sender))._track else: self.log ('4') track = self.song().view.selected_track self.log('track='+str(track)) if track == master: display_string = 'Master' elif track in tracks: display_string = str(list(tracks).index(track) + 1) elif track in returns: display_string = str(chr(ord('A') + list(returns).index(track))) else: # raise False or AssertionError raise AssertionError display_string += ' Volume' self._set_string_to_display(display_string) def _mixer_button_value(self, value, sender): self.log ('__mixer_button_value ' + str(value) + ' ' +str(sender)) if not value in range(128): raise AssertionError #if self._mixer.is_enabled() and value > 0: if self._mixer.is_enabled(): strip = self._mixer.channel_strip(self._strip_buttons.index(sender)) #self._string_to_display = strip != None and None self._name_display.segment(0).set_data_source(strip.track_name_data_source()) self._name_display.update() self._display_reset_delay = STANDARD_DISPLAY_DELAY else: self._set_string_to_display(' - ') # if shift_pressed XOR alternative_mode if self.shift_pressed <> self.alternative_buttons_mode: self.log("_mixer_button_value") self.log(str(value)) if (value == 0): self.select_armed_track_if_only_one() def select_armed_track_if_only_one(self): self.log("select_armed_track_if_only_one") song = self.song() armed_tracks = [] tracks = song.tracks self.log("select_armed_track_if_only_one 2") for track in tracks: if track.can_be_armed and track.arm: armed_tracks.append(track) self.log(str(len(armed_tracks))) if (len(armed_tracks) == 1): self.log("selecting the track") sel_track = armed_tracks[0] self.song().view.selected_track = sel_track self._mixer._selected_tracks = [] self._mixer._selected_tracks.append(sel_track) self._mixer.on_selected_track_changed() def _preview_value(self, value): if not value in range(128): raise AssertionError for encoder in self._encoders: encoder.set_peek_mode(value > 0) def _show_current_track_name(self): if self._name_display != None and self._mixer != None: self._string_to_display = None self._name_display.segment(0).set_data_source(self._mixer.selected_strip().track_name_data_source()) self._name_display.update() def _show_startup_message(self): self._name_display.display_message('LIVE') self._display_reset_delay = INITIAL_DISPLAY_DELAY def _set_string_to_display(self, string_to_display): if not isinstance(string_to_display, (str, unicode)): raise AssertionError self._name_display.segment(0).set_data_source(self._name_display_data_source) self._string_to_display = string_to_display self._display_reset_delay = STANDARD_DISPLAY_DELAY def _on_selected_track_changed(self): self.log('_on_selected_track_changed') ControlSurface._on_selected_track_changed(self) self._show_current_track_name() #all_tracks = self._has_sliders or self._session.tracks_to_use() all_tracks2 = self._session.tracks_to_use() selected_track = self.song().view.selected_track num_strips = self._session.width() if selected_track in all_tracks2: track_index = list(all_tracks2).index(selected_track) self.log('track_index '+ str(track_index)) new_offset = track_index - track_index % num_strips self.log('new_offset '+ str(new_offset)) if not new_offset / num_strips == int(new_offset / num_strips): raise AssertionError self._session.set_offsets(new_offset, self._session.scene_offset()) def _shift_button_handler(self, value): self.log("root shift handler : "+ str(value)) if not self._shift_button != None: raise AssertionError if not value in range(128): raise AssertionError self.log("root shift handler 2") self.shift_pressed = value > 0 # calling other handlers self._mixer._shift_button_handler(value) self._transport._shift_button_handler(value) self._transport_view_modes._shift_button_handler(value) #clip stop self.log("root shift handler 3") num_pads = len(PAD_TRANSLATIONS) pads = [] for index in range(num_pads): pads.append(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 60 + index)) pads[-1].name = 'Pad_' + str(index) clip_slot = self._session.selected_scene().clip_slot(index) if self.shift_pressed: clip_slot.set_launch_button(None) else: clip_slot.set_launch_button(pads[index]) if self.shift_pressed: self._session.set_stop_track_clip_buttons(tuple(pads)) else: self._session.set_stop_track_clip_buttons(None) self.log("root shift handler 4") def flipAlternativeButtonMode(self): self.alternative_buttons_mode = not self.alternative_buttons_mode self.updateAlternativeButtonMode() def updateAlternativeButtonMode(self): self._mixer.updateMixerButtons() self._transport_view_modes.update() def log(self, message): pass
class midi_twister_110(ControlSurface): def __init__(self, c_instance): super(midi_twister_110, self).__init__(c_instance) with self.component_guard(): global active_mode active_mode = "_mode1" self._set_active_mode() self.show_message("Modified by XXPW") def _mode1(self): self.show_message("_mode1 is active") # mixer global mixer num_tracks = 32 num_returns = 7 self.mixer = MixerComponent(num_tracks, num_returns) self.mixer.set_track_offset(0) self.song().view.selected_track = self.mixer.channel_strip(0)._track # sends send0_controls = ( SliderElement(MIDI_CC_TYPE, 0, 32), SliderElement(MIDI_CC_TYPE, 0, 36), SliderElement(MIDI_CC_TYPE, 0, 40), None, None, None, None, None, ) self.mixer.channel_strip(0).set_send_controls(tuple(send0_controls)) self.mixer.channel_strip(0).set_volume_control( SliderElement(MIDI_CC_TYPE, 0, 44)) send1_controls = ( SliderElement(MIDI_CC_TYPE, 0, 33), SliderElement(MIDI_CC_TYPE, 0, 37), SliderElement(MIDI_CC_TYPE, 0, 41), None, None, None, None, None, ) self.mixer.channel_strip(1).set_send_controls(tuple(send1_controls)) self.mixer.channel_strip(1).set_volume_control( SliderElement(MIDI_CC_TYPE, 0, 45)) send2_controls = ( SliderElement(MIDI_CC_TYPE, 0, 34), SliderElement(MIDI_CC_TYPE, 0, 38), SliderElement(MIDI_CC_TYPE, 0, 42), None, None, None, None, None, ) self.mixer.channel_strip(2).set_send_controls(tuple(send2_controls)) self.mixer.channel_strip(2).set_volume_control( SliderElement(MIDI_CC_TYPE, 0, 46)) send3_controls = ( SliderElement(MIDI_CC_TYPE, 0, 35), SliderElement(MIDI_CC_TYPE, 0, 39), SliderElement(MIDI_CC_TYPE, 0, 43), None, None, None, None, None, ) self.mixer.channel_strip(3).set_send_controls(tuple(send3_controls)) self.mixer.channel_strip(3).set_volume_control( SliderElement(MIDI_CC_TYPE, 0, 47)) # session global _session num_tracks = 4 num_scenes = 3 session_buttons = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] self._pads = [ ButtonElement(1, MIDI_CC_TYPE, 1, session_buttons[index]) for index in range(num_tracks * num_scenes) ] self._grid = ButtonMatrixElement(rows=[ self._pads[(index * num_tracks):(index * num_tracks) + num_tracks] for index in range(num_scenes) ]) self._session = SessionComponent(num_tracks, num_scenes) self._session.set_clip_launch_buttons(self._grid) self.set_highlighting_session_component(self._session) # session track stop stop_track_buttons = [12, 13, 14, 15] self._track_stop_buttons = [ ButtonElement(1, MIDI_CC_TYPE, 1, stop_track_buttons[index]) for index in range(num_tracks) ] self._session.set_stop_track_clip_buttons( tuple(self._track_stop_buttons)) # session navigation self.session_left = ButtonElement(1, MIDI_CC_TYPE, 3, 8) self._session.set_page_left_button(self.session_left) self.session_left.add_value_listener(self._reload_active_devices, identify_sender=False) self.session_right = ButtonElement(1, MIDI_CC_TYPE, 3, 11) self._session.set_page_right_button(self.session_right) self.session_right.add_value_listener(self._reload_active_devices, identify_sender=False) self.session_up = ButtonElement(1, MIDI_CC_TYPE, 3, 10) self._session.set_page_up_button(self.session_up) self.session_up.add_value_listener(self._reload_active_devices, identify_sender=False) self.session_down = ButtonElement(1, MIDI_CC_TYPE, 3, 13) self._session.set_page_down_button(self.session_down) self.session_down.add_value_listener(self._reload_active_devices, identify_sender=False) self._session._link() self._session.set_mixer(self.mixer) #self._session.set_mixer(self.mixer) self._mode1_devices() self.add_device_listeners() # button: next device self.next_device = ButtonElement(0, MIDI_CC_TYPE, 1, 25) self.next_device.add_value_listener(self._next_device_value, identify_sender=False) # button: prev device self.previous_device = ButtonElement(1, MIDI_CC_TYPE, 1, 24) self.previous_device.add_value_listener(self._prev_device_value, identify_sender=False) # transport global transport self.transport = TransportComponent() self.transport.name = 'Transport' loop_button = ButtonElement(1, MIDI_CC_TYPE, 1, 50) loop_button.name = 'loop_button' self.transport.set_loop_button(loop_button) stop_button = ButtonElement(1, MIDI_CC_TYPE, 1, 49) stop_button.name = 'stop_button' self.transport.set_stop_button(stop_button) play_button = ButtonElement(1, MIDI_CC_TYPE, 1, 48) play_button.name = 'play_button' self.transport.set_play_button(play_button) # button: track navigation right self.track_navigation_right = ButtonElement(1, MIDI_CC_TYPE, 3, 17) self.track_navigation_right.add_value_listener( self._track_navigation_right_track_nav, identify_sender=False) # button: track navigation left self.track_navigation_left = ButtonElement(1, MIDI_CC_TYPE, 3, 14) self.track_navigation_left.add_value_listener( self._track_navigation_left_track_nav, identify_sender=False) def _remove_mode1(self): # mixer global mixer self._remove_mode1_devices() self.remove_device_listeners() send0_controls = ( None, None, None, None, None, None, None, None, ) self.mixer.channel_strip(0).set_send_controls(tuple(send0_controls)) send1_controls = ( None, None, None, None, None, None, None, None, ) self.mixer.channel_strip(1).set_send_controls(tuple(send1_controls)) send2_controls = ( None, None, None, None, None, None, None, None, ) self.mixer.channel_strip(2).set_send_controls(tuple(send2_controls)) send3_controls = ( None, None, None, None, None, None, None, None, ) self.mixer.channel_strip(3).set_send_controls(tuple(send3_controls)) # session global _session self._session.set_clip_launch_buttons(None) self.set_highlighting_session_component(None) self._session.set_mixer(None) self._session.set_stop_all_clips_button(None) # session track stop self._track_stop_buttons = None self._session.set_stop_track_clip_buttons(None) # session scene launch self._scene_launch_buttons = None self._session.set_scene_launch_buttons(None) # session navigation self.session_left.remove_value_listener(self._reload_active_devices) self._session.set_page_left_button(None) self.session_right.remove_value_listener(self._reload_active_devices) self._session.set_page_right_button(None) self.session_up.remove_value_listener(self._reload_active_devices) self._session.set_page_up_button(None) self.session_down.remove_value_listener(self._reload_active_devices) self._session.set_page_down_button(None) self._session = None self.next_device.remove_value_listener(self._next_device_value) self.next_device = None self.previous_device.remove_value_listener(self._prev_device_value) self.previous_device = None # transport global transport self.transport.set_loop_button(None) self.transport.set_stop_button(None) self.transport.set_play_button(None) self.transport = None self.track_navigation_right.remove_value_listener( self._track_navigation_right_track_nav) self.track_navigation_right = None self.track_navigation_left.remove_value_listener( self._track_navigation_left_track_nav) self.track_navigation_left = None def _mode1_devices(self): global mixer global _session # device self.mixer.selected_strip().set_volume_control( SliderElement(MIDI_CC_TYPE, 0, 28)) self.mixer.selected_strip().set_pan_control( SliderElement(MIDI_CC_TYPE, 0, 29)) self.mixer.selected_strip().set_mute_button( ButtonElement(1, MIDI_CC_TYPE, 1, 28)) self.mixer.selected_strip().set_solo_button( ButtonElement(1, MIDI_CC_TYPE, 1, 29)) if (len(self.mixer.selected_strip()._track.devices) > 0): global device_tracktype_selected__chain_number_selected self.device_tracktype_selected__chain_number_selected = DeviceComponent( ) device_controls = ( SliderElement(MIDI_CC_TYPE, 0, 16), SliderElement(MIDI_CC_TYPE, 0, 17), SliderElement(MIDI_CC_TYPE, 0, 18), SliderElement(MIDI_CC_TYPE, 0, 19), SliderElement(MIDI_CC_TYPE, 0, 20), SliderElement(MIDI_CC_TYPE, 0, 21), SliderElement(MIDI_CC_TYPE, 0, 22), SliderElement(MIDI_CC_TYPE, 0, 23), ) self.device_tracktype_selected__chain_number_selected.set_parameter_controls( tuple(device_controls)) self.set_device_component( self.device_tracktype_selected__chain_number_selected) self.device_tracktype_selected__chain_number_selected.set_on_off_button( ButtonElement(1, MIDI_CC_TYPE, 1, 26)) self.device_tracktype_selected__chain_number_selected.set_bank_nav_buttons( ButtonElement(0, MIDI_CC_TYPE, 1, 31), ButtonElement(1, MIDI_CC_TYPE, 1, 33)) def _remove_mode1_devices(self): global mixer global _session # device if (hasattr(self, 'device_tracktype_selected__chain_number_selected')): global device_tracktype_selected__chain_number_selected device_controls = ( None, None, None, None, None, None, None, None, ) self.device_tracktype_selected__chain_number_selected.set_parameter_controls( tuple(device_controls)) self.device_tracktype_selected__chain_number_selected.set_on_off_button( None) self.device_tracktype_selected__chain_number_selected.set_bank_nav_buttons( None, None) self.set_device_component( self.device_tracktype_selected__chain_number_selected) def add_device_listeners(self): global mixer num_of_tracks = len(self.song().tracks) value = "add device listener" for index in range(num_of_tracks): self.song().tracks[index].add_devices_listener( self._reload_active_devices) def remove_device_listeners(self): global mixer num_of_tracks = len(self.song().tracks) value = "remove device listener" for index in range(num_of_tracks): self.song().tracks[index].remove_devices_listener( self._reload_active_devices) def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(self) self._display_reset_delay = 0 value = "selected track changed" self._reload_active_devices(value) def _reload_active_devices(self, value=None): self._remove_active_devices() self._set_active_devices() def _set_active_devices(self): global active_mode # activate mode if (active_mode == "_mode1") and (hasattr(self, '_mode1_devices')): self._mode1_devices() def _remove_active_devices(self): global active_mode # remove activate mode if (active_mode == "_mode1") and (hasattr(self, '_mode1_devices')): self._remove_mode1_devices() def _next_device_value(self, value): if value > 0: self._device = self.song().view.selected_track.view.selected_device if self._device is not None: self.song().view.select_device( self.song().view.selected_track.devices[ self.selected_device_idx() + 1]) def _prev_device_value(self, value): if value > 0: self._device = self.song().view.selected_track.view.selected_device if self._device is not None: self.song().view.select_device( self.song().view.selected_track.devices[ self.selected_device_idx() - 1]) def selected_device_idx(self): self._device = self.song().view.selected_track.view.selected_device return self.tuple_index(self.song().view.selected_track.devices, self._device) def _track_navigation_right_track_nav(self, value): if value > 0: self.song().view.selected_track = self.song().tracks[ self.selected_track_idx() + 1] def _track_navigation_left_track_nav(self, value): if value > 0: self.song().view.selected_track = self.song().tracks[ self.selected_track_idx() - 1] def selected_track_idx(self): return self.tuple_index(self.song().tracks, self.song().view.selected_track) def _set_active_mode(self): global active_mode # activate mode if active_mode == "_mode1": self._mode1() def _remove_active_mode(self): global active_mode # remove activate mode if active_mode == "_mode1": self._remove_mode1() def _activate_mode1(self, value): global active_mode if value > 0: self._remove_active_mode() active_mode = "_mode1" self._set_active_mode() def _activate_shift_mode1(self, value): global active_mode if value > 0: self._remove_active_mode() self._mode1() else: self._remove_mode1() self._set_active_mode() def tuple_index(self, tuple, obj): for i in xrange(0, len(tuple)): if (tuple[i] == obj): return i return (False) def disconnect(self): super(midi_twister_110, self).disconnect()
class OP1(ControlSurface): def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) self.c_instance = c_instance self.retries_count = 0 self.device_connected = False self.clip_color_callbacks = {} self.slot_callbacks = {} self.text_start_sequence = (0xf0, 0x0, 0x20, 0x76, 0x00, 0x03) self.text_end_sequence = (0xf7,) self.enable_sequence = (0xf0, 0x00, 0x20, 0x76, 0x00, 0x01, 0x02, 0xf7) self.disable_sequence = (0xf0, 0x00, 0x20, 0x76, 0x00, 0x01, 0x00, 0xf7) self.id_sequence = (0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7) self.text_color_start_sequence = (0xf0, 0x0, 0x20, 0x76, 0x00, 0x04) self.log('INITIALIZING') self.app = Live.Application.get_application() #maj = self.app.get_major_version() #min = self.app.get_minor_version() #bug = self.app.get_bugfix_version() #self.show_message(str(1) + "." + str(0) + "." + str(9)) self.show_message("Version " + VERSION) # reseting text self.write_text(' ') # reset display clips self.reset_display_clips() # getting browser visible state self.session_browser_visible = self.app.view.is_view_visible("Browser") # getting browser visible state self.arrange_browser_visible = self.app.view.is_view_visible("Browser") # getting session view visible state self.session_visible = self.app.view.is_view_visible("Session") # getting arrange view visible state self.arrange_visible = self.app.view.is_view_visible("Arranger") # getting detail view visible state self.detail_visible = self.app.view.is_view_visible("Detail") # getting back to arranger state self.back_to_arranger_state = self.song().back_to_arranger # initializing channel strip to null self._channel_strip = None # initializing transport component self._transport = TransportComponent() # initializing mixer component self._mixer = MixerComponent(NUM_TRACKS,2) # initializing session component self._session = SessionComponent(NUM_TRACKS,NUM_ROWS) self._session.add_offset_listener(self.session_offset_changed) # configuring operation mode selector buttons self._operation_mode_buttons = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_1_BUTTON), ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_2_BUTTON), ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_3_BUTTON), ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_4_BUTTON), # initializing operation mode selector self._operation_mode_selector = OP1ModeSelectorComponent(self, self._transport, self._mixer, self._session) # setting operation mode selector buttons self._operation_mode_selector.set_mode_buttons(self._operation_mode_buttons) # adding value listener for operation mode index self._operation_mode_selector.add_mode_index_listener(self.mode_index_changed) # setting global transport assignments self._transport.set_record_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_REC_BUTTON)) self._transport.set_play_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_PLAY_BUTTON)) self._transport.set_stop_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_STOP_BUTTON)) self._transport.set_metronome_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_METRONOME_BUTTON)) self._transport.set_tap_tempo_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_HELP_BUTTON)) self._transport.set_punch_buttons(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS1_BUTTON), ButtonElement(True,MIDI_CC_TYPE, CHANNEL, OP1_SS2_BUTTON)) self._transport.set_loop_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS3_BUTTON)) self._transport.set_overdub_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS4_BUTTON)) # setting global session assignments self._session.set_scene_bank_buttons(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_COM),ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MICRO)) # setting misc listeners self.browser_toggle_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL, 15) self.browser_toggle_button.add_value_listener(self.browser_toggle_button_callback) self.mainview_toggle_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL, 16) self.mainview_toggle_button.add_value_listener(self.mainview_toggle_button_callback) self.detailview_toggle_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL, 17) self.detailview_toggle_button.add_value_listener(self.detailview_toggle_button_callback) self.clear_track_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, 25) self.clear_track_button.add_value_listener(self.clear_track_button_callback) self.back_to_arranger_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, 26) self.back_to_arranger_button.add_value_listener(self.back_to_arranger_button_callback) # adding value listener for selected track change self.song().view.add_selected_track_listener(self.selected_track_changed) # adding value listener for selected scene change self.song().view.add_selected_scene_listener(self.selected_scene_changed) # setting assignments for currently selected track self.selected_track_changed() # setting assignments for currently selected scene self.selected_scene_changed() def handle_sysex(self, midi_bytes): if ((midi_bytes[6]==32) and (midi_bytes[7]==118)): self.device_connected = True self.log("OP-1 CONNECTED. SENDING ABLETON LIVE MODE INIT SEQUENCE") self._send_midi(self.enable_sequence) def add_clip_slot_listeners(self): #self.log('ADDING CLIP SLOT LISTENERS') # creating an empty list for all clip slots clip_slots = [] # getting a reference to all tracks tracks = self.song().tracks # appending all tracks clip slots to clip_slots for track in tracks: clip_slots.append(track.clip_slots) # iterating over all clip slots for t in range(len(clip_slots)): for c in range(len(clip_slots[t])): clip_slot = clip_slots[t][c] # adding has clip listener to clip slot self.add_slot_listener(clip_slot) # if clip slot has clip if clip_slot.has_clip: # adding clip listeners self.add_clip_listener(clip_slot.clip) def rem_clip_slot_listeners(self): #self.log('REMOVING CLIP SLOT LISTENERS') # iterate over all clip color change callbacks for c in self.clip_color_callbacks: # if clip still exists if c != None: # and it has a has clip listener if c.color_has_listener(self.clip_color_callbacks[c]) == 1: # remove it c.remove_color_listener(self.clip_color_callbacks[c]) # iterate over all clip slot callbacks for cs in self.slot_callbacks: # if clip slot still exists if cs != None: # and it has a has clip listener if cs.has_clip_has_listener(self.slot_callbacks[cs]) == 1: # remove it cs.remove_has_clip_listener(self.slot_callbacks[cs]) def add_slot_listener(self, cs): # setting has clip listener callback = lambda :self.has_clip_listener(cs) # if we don't have a clip slot has clip listener for this clip slot yet if not(self.slot_callbacks.has_key(cs)): # adding has clip callback to clip slot cs.add_has_clip_listener(callback) # saving callback for future release self.slot_callbacks[cs] = callback def add_clip_listener(self, clip): # setting callback for clip color change color_callback = lambda :self.update_display_clips() # if we don't have a clip color change callback for this clip yet if not(self.clip_color_callbacks.has_key(clip)): # adding clip color change callback clip.add_color_listener(color_callback) # saving callback for future release self.clip_color_callbacks[clip] = color_callback def has_clip_listener(self, cs): # clip slot has clip listener callback if cs.has_clip: # add clip listener self.add_clip_listener(cs.clip) else: # update display if clip slot was removed self.update_display_clips() def session_offset_changed(self): # if session component offset changes, update display self.update_display_clips() def selected_scene_changed(self): # if on clip mode update display if (self._operation_mode_selector.mode_index==OP1_MODE_CLIP): self.update_display_clip_mode() def mode_index_changed(self): # update display to current mode info if (self._operation_mode_selector.mode_index==OP1_MODE_PERFORM): self.update_display_perform_mode() elif (self._operation_mode_selector.mode_index==OP1_MODE_CLIP): self.update_display_clip_mode() elif (self._operation_mode_selector.mode_index==OP1_MODE_TRANSPORT): self.update_display_transport_mode() elif (self._operation_mode_selector.mode_index==OP1_MODE_MIXER): self.update_display_mixer_mode() def clear_track_button_callback(self, value): # if clear track button was called, reset track if (value==127): for i in range(len(self.song().tracks)): self.song().tracks[i].arm = 0 self.song().tracks[i].solo = 0 self.song().tracks[i].mute = 0 for i in range(len(self.song().return_tracks)): self.song().tracks[i].solo = 0 self.song().tracks[i].mute = 0 def clear_return_track_assignment(self, strip): # clear return track assingments strip.set_volume_control(None) strip.set_pan_control(None) strip.set_mute_button(None) strip.set_solo_button(None) def clear_track_assignment(self, strip): # clear track assignments strip.set_volume_control(None) strip.set_pan_control(None) strip.set_mute_button(None) strip.set_solo_button(None) strip.set_arm_button(None) def clear_tracks_assigments(self): # for all normal tracks, clear assignments for i in range(NUM_TRACKS): strip = self._mixer.channel_strip(i) if (strip!=None): self.clear_track_assignment(strip) # for all return tracks, clear assignments for i in range(2): return_strip = self._mixer.return_strip(i) if (return_strip!=None): self.clear_return_track_assignment(return_strip) def selected_track_changed(self): # if on mixer mode update display if (self._operation_mode_selector.mode_index==OP1_MODE_MIXER): self.update_display_mixer_mode() # clear track assignments self.clear_tracks_assigments() # getting selected strip self._channel_strip = self._mixer.selected_strip() # perform track assignments self._channel_strip.set_volume_control(EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_1, Live.MidiMap.MapMode.relative_two_compliment)) self._channel_strip.set_pan_control(EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_2, Live.MidiMap.MapMode.relative_two_compliment)) # setting a tuple of encoders to control sends send_controls = EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_3, Live.MidiMap.MapMode.relative_two_compliment), EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_4, Live.MidiMap.MapMode.relative_two_compliment), # setting send encoders self._channel_strip.set_send_controls(tuple(send_controls)) # setting solo button self._channel_strip.set_solo_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS6_BUTTON)) # if track can be armed, set arm button if (self._channel_strip._track.can_be_armed): self._channel_strip.set_arm_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS7_BUTTON)) # if track is no master, set mute button if (self._channel_strip._track!=self.song().master_track): self._channel_strip.set_mute_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS5_BUTTON)) def browser_toggle_button_callback(self, value): if (value==127): if (self.session_visible): if (self.session_browser_visible==True): self.session_browser_visible=False self.app.view.hide_view("Browser") else: self.session_browser_visible=True self.app.view.show_view("Browser") if (self.arrange_visible): if (self.arrange_browser_visible==True): self.arrange_browser_visible=False self.app.view.hide_view("Browser") else: self.arrange_browser_visible=True self.app.view.show_view("Browser") def back_to_arranger_button_callback(self, value): if (value==127): self.song().back_to_arranger = False def mainview_toggle_button_callback(self, value): if (value==127): if (self.session_visible==True): self.session_visible=False self.arrange_visible=True self.app.view.show_view("Arranger") self.arrange_browser_visible = self.app.view.is_view_visible("Browser"); else: self.session_visible=True self.arrange_visible=False self.app.view.show_view("Session") self.session_browser_visible = self.app.view.is_view_visible("Browser"); def detailview_toggle_button_callback(self, value): if (value==127): if (self.detail_visible==True): self.detail_visible=False self.app.view.hide_view("Detail") else: self.detail_visible=True self.app.view.show_view("Detail") def write_text(self, msg): text_list = [] sequence = () text_list.append(len(msg.strip())) for i in msg.strip(): text_list.append(ord(i)) sequence = self.text_start_sequence + tuple(text_list) + self.text_end_sequence self._send_midi(sequence) def suggest_input_port(self): return "OP-1 Midi Device" def suggest_output_port(self): return "OP-1 Midi Device" def update_display_perform_mode(self): self.write_text("perform\rmode") def reset_display_clips(self): count = 0 colors = [] length = [] sequence = () for i in range (NUM_TRACKS): count+=1 colors.append(0x00) colors.append(0x00) colors.append(0x00) length.append(count) sequence = self.text_color_start_sequence + tuple(length) + tuple(colors) + self.text_end_sequence self._send_midi(sequence) def update_display_clips(self): #self.log("UPDATING DISPLAY CLIPS") count = 0 colors = [] length = [] sequence = () tracks_len = len(self.song().tracks)-self._session._track_offset if (tracks_len>NUM_TRACKS): tracks_len = NUM_TRACKS for i in range (tracks_len): count+=1 clip_slot = self._session.scene(0).clip_slot(i) if (clip_slot!=None): if (clip_slot.has_clip()!=False): clip_color = clip_slot._clip_slot.clip.color colors.append(((clip_color>>16)&0x000000ff)>>1) colors.append(((clip_color>>8)&0x000000ff)>>1) colors.append((clip_color&0x000000ff)>>1) else: colors.append(0x00) colors.append(0x00) colors.append(0x00) else: colors.append(0x00) colors.append(0x00) colors.append(0x00) length.append(count) sequence = self.text_color_start_sequence + tuple(length) + tuple(colors) + self.text_end_sequence self._send_midi(sequence) def update_display_clip_mode(self): self.write_text("sel. scene\r" + str(self.song().view.selected_scene.name.lower().strip())) def update_display_transport_mode(self): song_time = str(self.song().get_current_beats_song_time()) self.write_text("song pos.\r" + song_time[:len(song_time)-4]) def update_display_mixer_mode(self): self.write_text("sel. track\r" + str(self.song().view.selected_track.name.lower())) def update_display(self): if not(self.device_connected): if (self.retries_count<5): self.log("TRYING OP-1 CONNECTION") self.retries_count+=1 self._send_midi(self.id_sequence) time.sleep(1) # if in transport mode, update display with song position if (self._operation_mode_selector.mode_index==OP1_MODE_TRANSPORT): self.update_display_transport_mode() # checking if app current view is session if (self.app.view.is_view_visible("Session")): # checking if session browser state is diferent from the internal if (self.session_browser_visible != self.app.view.is_view_visible("Browser")): self.session_browser_visible = self.app.view.is_view_visible("Browser") # checking if app current view is arrange if (self.app.view.is_view_visible("Arranger")): # checking if arrange browser state is diferent from the internal if (self.arrange_browser_visible != self.app.view.is_view_visible("Browser")): self.arrange_browser_visible = self.app.view.is_view_visible("Browser") # checking if app current view is detail if (self.app.view.is_view_visible("Detail")): # checking if detail state is diferent from the internal if (self.detail_visible != self.app.view.is_view_visible("Detail")): self.detail_visible = self.app.view.is_view_visible("Detail") def refresh_state(self): self.log("REFRESH STATE") self.retries_count = 0 self.device_connected = False def build_midi_map(self, midi_map_handle): #self.log("BUILD MIDI MAP") assert (self._suppress_requests_counter == 0) self._in_build_midi_map = True self._midi_map_handle = midi_map_handle self._forwarding_registry = {} for control in self.controls: if isinstance(control, InputControlElement): control.install_connections() self._midi_map_handle = None self._in_build_midi_map = False if (self._pad_translations != None): self._c_instance.set_pad_translation(self._pad_translations) # remove clip listeners self.rem_clip_slot_listeners() # add clip listeners self.add_clip_slot_listeners() # update display self.update_display_clips() def log(self, msg): self.c_instance.log_message("[TE OP-1] " + msg) def disconnect(self): # removing clip slots listeners self.rem_clip_slot_listeners() # removing value listener for track changed self.song().view.remove_selected_track_listener(self.selected_track_changed) # removing value listener for scene changed self.song().view.remove_selected_scene_listener(self.selected_scene_changed) # removing value listener for operation mode index self._operation_mode_selector.remove_mode_index_listener(self.mode_index_changed) # removing global transport assignments self._transport.set_punch_buttons(None, None) self._transport.set_loop_button(None) self._transport.set_overdub_button(None) self._transport.set_record_button(None) self._transport.set_play_button(None) self._transport.set_stop_button(None) self._transport.set_metronome_button(None) self._transport.set_tap_tempo_button(None) # removing global session assignments self._session.set_scene_bank_buttons(None, None) # removing misc listeners self.browser_toggle_button.remove_value_listener(self.browser_toggle_button_callback) self.mainview_toggle_button.remove_value_listener(self.mainview_toggle_button_callback) self.detailview_toggle_button.remove_value_listener(self.detailview_toggle_button_callback) self.clear_track_button.remove_value_listener(self.clear_track_button_callback) self.back_to_arranger_button.remove_value_listener(self.back_to_arranger_button_callback) # sending special ableton mode disable sequence self._send_midi(self.disable_sequence) # disconnecting control surface ControlSurface.disconnect(self) self.log("DISCONNECTED")
class MaschineChannelStripComponent(ChannelStripComponent): def __init__(self): ChannelStripComponent.__init__(self) self.deleted = {} self.clear_mode = False self.touch_mode = False self.send_control = None self.clear_vol_button = None self.clear_pan_button = None self.clear_send_button = None def set_touch_mode(self, touchchannel): self.touch_mode = True id_vol = self._volume_control.message_identifier() id_pan = self._pan_control.message_identifier() id_send = None for send in self._send_controls: if send: id_send = send.message_identifier() self.clear_vol_button = ButtonElement(False, MIDI_CC_TYPE, touchchannel, id_vol) self.clear_vol_button.add_value_listener(self._do_clear_vol) self.clear_pan_button = ButtonElement(False, MIDI_CC_TYPE, touchchannel, id_pan) self.clear_pan_button.add_value_listener(self._do_clear_pan) self.clear_send_button = ButtonElement(False, MIDI_CC_TYPE, touchchannel, id_send) self.clear_send_button.add_value_listener(self._do_clear_send) for send in self._send_controls: if send: self.send_control = send def enter_clear(self): self.clear_mode = True self.deleted = {} if not self.touch_mode: self.set_enabled(False) self._volume_control.add_value_listener(self._do_clear_vol) self._pan_control.add_value_listener(self._do_clear_pan) for send in self._send_controls: if send: self.send_control = send send.add_value_listener(self._do_clear_send) def exit_clear(self): self.clear_mode = False if not self.touch_mode: self._volume_control.remove_value_listener(self._do_clear_vol) self._pan_control.remove_value_listener(self._do_clear_pan) for send in self._send_controls: if send: send.remove_value_listener(self._do_clear_send) self.set_enabled(True) def _do_clear_vol(self, value): key = self._volume_control.message_identifier() if self.clear_mode and key not in self.deleted: self.deleted[key] = True playing_clip = self._get_playing_clip() if playing_clip: playing_clip.clear_envelope(self._track.mixer_device.volume) def _do_clear_pan(self, value): key = self._pan_control.message_identifier() if self.clear_mode and key not in self.deleted: self.deleted[key] = True playing_clip = self._get_playing_clip() if playing_clip: playing_clip.clear_envelope(self._track.mixer_device.panning) def _do_clear_send(self, value): key = self.send_control.message_identifier() if self.clear_mode and key not in self.deleted: send_index = len(self._send_controls) - 1 self.deleted[key] = True playing_clip = self._get_playing_clip() if playing_clip and send_index in range(len(self._track.mixer_device.sends)): playing_clip.clear_envelope(self._track.mixer_device.sends[send_index]) def _mute_value(self, value): super(MaschineChannelStripComponent, self)._mute_value(value) key = self._mute_button.message_identifier() if self.clear_mode and key not in self.deleted: self.deleted[key] = True playing_clip = self._get_playing_clip() if playing_clip: playing_clip.clear_envelope(self._track.mixer_device.track_activator) def _get_playing_clip(self): if self._track == None: return clips_slots = self._track.clip_slots for cs in clips_slots: if cs.has_clip and cs.is_playing: return cs.clip def disconnect(self): self.clear_pan_button = None self.clear_send_button = None if self.clear_vol_button != None: self.clear_vol_button.remove_value_listener(self._do_clear_vol) self.clear_vol_button = None if self.clear_pan_button != None: self.clear_pan_button.remove_value_listener(self._do_clear_pan) self.clear_pan_button = None if self.clear_send_button != None: self.clear_send_button.remove_value_listener(self._do_clear_send) self.clear_send_button = None if not self.touch_mode and self.clear_mode: if self.send_control != None: self.send_control.remove_value_listener(self._do_clear_send) self.send_control = None if self._volume_control != None: self._volume_control.remove_value_listener(self._do_clear_vol) self._volume_control = None if self._pan_control != None: self._pan_control.remove_value_listener(self._do_clear_pan) self._pan_control = None super(MaschineChannelStripComponent, self).disconnect()
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))
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))
class Oxygen_3rd_Gen(ControlSurface): """ Script for the 3rd generation of M-Audio's Oxygen controllers """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): is_momentary = True self._suggested_input_port = 'Oxygen' self._suggested_output_port = 'Oxygen' self._has_slider_section = True self._device_selection_follows_track_selection = True self._shift_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 57) self._shift_button.add_value_listener(self._shift_value) self._mixer = SpecialMixerComponent(NUM_TRACKS) self._mute_solo_buttons = [] self._track_up_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 111) self._track_down_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 110) self._master_slider = SliderElement(MIDI_CC_TYPE, GLOBAL_CHANNEL, 41) for index in range(NUM_TRACKS): self._mute_solo_buttons.append(ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 49 + index)) self._mixer.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, GLOBAL_CHANNEL, 33 + index)) self._shift_value(0) self._mixer.master_strip().set_volume_control(self._master_slider) self._mixer.selected_strip().set_volume_control(None) device = DeviceComponent() device.set_parameter_controls(tuple([ EncoderElement(MIDI_CC_TYPE, GLOBAL_CHANNEL, 17 + index, Live.MidiMap.MapMode.absolute) for index in range(8) ])) self.set_device_component(device) ffwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 115) rwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 114) loop_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 113) transport = TransportComponent() transport.set_stop_button(ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 116)) transport.set_play_button(ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 117)) transport.set_record_button(ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 118)) session = SessionComponent(0, 0) transport_view_modes = TransportViewModeSelector(transport, session, ffwd_button, rwd_button, loop_button) return def disconnect(self): self._shift_button.remove_value_listener(self._shift_value) self._shift_button = None ControlSurface.disconnect(self) return def refresh_state(self): ControlSurface.refresh_state(self) self.schedule_message(5, self._send_midi, IDENTITY_REQUEST) def handle_sysex(self, midi_bytes): if midi_bytes[0:5] == IDENTITY_RESPONSE: if midi_bytes[10] == 38: self._mixer.master_strip().set_volume_control(None) self._mixer.selected_strip().set_volume_control(self._master_slider) return def _shift_value(self, value): raise value in range(128) or AssertionError for index in range(NUM_TRACKS): if value == 0: self._mixer.channel_strip(index).set_solo_button(None) self._mixer.channel_strip(index).set_mute_button(self._mute_solo_buttons[index]) self._mixer.set_bank_buttons(None, None) self._mixer.set_select_buttons(self._track_up_button, self._track_down_button) else: self._mixer.channel_strip(index).set_mute_button(None) self._mixer.channel_strip(index).set_solo_button(self._mute_solo_buttons[index]) self._mixer.set_select_buttons(None, None) self._mixer.set_bank_buttons(self._track_up_button, self._track_down_button) return
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)
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)
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)
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 HyperionChan(CompoundComponent): def __init__(self, hyperion, mod_num, *a, **kw): super(HyperionChan, self).__init__(*a, **kw) self.hyperion = hyperion self.mod_num = mod_num self._track_selector_encoder = EncoderElement(MIDI_CC_TYPE, MIDI_MASTER_CH + 1 + mod_num, 0x15, Live.MidiMap.MapMode.relative_smooth_binary_offset) # Right encoder on Hyperion self._track_selector_encoder.add_value_listener(self._on_track_selector_encoder) self._fader = SliderElement(MIDI_CC_TYPE, MIDI_MASTER_CH + 1 + mod_num, 0x25) self._pots = [ EncoderElement(MIDI_CC_TYPE, MIDI_MASTER_CH + 1 + mod_num, 0x1E + num, Live.MidiMap.MapMode.absolute, name='Pot{}'.format(num)) for num in range(8) ] self._btns = [ ButtonElement(True, MIDI_CC_TYPE, MIDI_MASTER_CH + 1 + mod_num, 1 + num, name='Btn{}'.format(num)) for num in range(8) ] self._enc_right_btn = ButtonElement(True, MIDI_CC_TYPE, MIDI_MASTER_CH + 1 + mod_num, 10, name='EncRightBtn') self._enc_right_btn.add_value_listener(self._on_enc_right_btn) #self._cs = ChannelStripComponent() #self._cs.set_volume_control(self._fader) self._vu_slider = SliderElement(MIDI_CC_TYPE, MIDI_MASTER_CH + 1 + mod_num, 60) self._vu = VUMeter(self) self._track = None tracks = self._get_all_tracks(self.hyperion.song().tracks) if len(tracks) > self.mod_num: self._bind_to_track(tracks[self.mod_num]) else: self._bind_to_track(None) def log(self, msg, *args): self.hyperion.log_message(('HyperionChan({}): ' + msg).format(self.mod_num, *args)) def disconnect(self): super(HyperionChan, self).disconnect() self._enc_right_btn.remove_value_listener(self._on_enc_right_btn) def _get_parent_by_type(self, obj, parent_type): if not obj.canonical_parent: return if isinstance(obj.canonical_parent, parent_type): return obj.canonical_parent return self._get_parent_by_type(obj.canonical_parent, parent_type) def _on_enc_right_btn(self, value): if value and self._track: self.log('type {}',type(self._track)) song = self.hyperion.song() if isinstance(self._track, Live.Track.Track): song.view.selected_track = self._track elif isinstance(self._track, Live.DrumChain.DrumChain): parent_track = self._get_parent_by_type(self._track, Live.Track.Track) song.view.selected_track = parent_track try: song.view.selected_chain = self._track except: try: song.view.selected_track = parent_track song.view.selected_chain = self._track.canonical_parent.canonical_parent self._track.canonical_parent.view.selected_chain = self._track except: pass def _get_track_mapper_device(self, track): for device in track.devices: if device.name == 'MultiMapper16 V2.0': return device def _get_all_tracks(self, all_tracks): got_tracks = [] for cur_track in all_tracks: if isinstance(cur_track, (Live.Track.Track, Live.DrumChain.DrumChain)): got_tracks.append(cur_track) devices = list(cur_track.devices) if len(devices) and isinstance(devices[0], Live.RackDevice.RackDevice): got_tracks.extend(self._get_all_tracks(devices[0].chains)) return [track for track in got_tracks if self._get_track_mapper_device(track)] def _on_track_selector_encoder(self, value): direction = 1 if value > 64 else -1 tracks = self._get_all_tracks(self.hyperion.song().tracks) # for t in tracks: # self.log('AAAAA {}', t.name) try: cur_track_idx = tracks.index(self._track) except ValueError: self.log('track disappeared :(') self._bind_to_track(tracks[0]) else: cur_track_idx += direction if cur_track_idx == len(tracks): cur_track_idx = 0 if cur_track_idx == -1: cur_track_idx = len(tracks) - 1 self._bind_to_track(tracks[cur_track_idx]) def _bind_to_track(self, track): if self._track: #self._cs.set_track(None) self._fader.release_parameter() [pot.release_parameter() for pot in self._pots] [btn.release_parameter() for btn in self._btns] self._track.remove_name_listener(self._on_name_changed) self._track = None if not track: return self.log('binding to {}', track.name) self._track = track self._fader.connect_to(track.mixer_device.volume) mapper_dev = self._get_track_mapper_device(track) for num in range(8): self._pots[num].connect_to(mapper_dev.parameters[3 + num]) # MacroA0 MacroA1 etc self._btns[num].connect_to(mapper_dev.parameters[11 + num]) # MacroB0 MacroB1 etc # self._cs.set_track(track) if getattr(self._track, 'has_audio_output', False) and hasattr(self._track, 'add_output_meter_left_listener'): self._vu.set_vu_meter(track, self._vu_slider) else: self._vu.set_vu_meter(None, None) self._track.add_name_listener(self._on_name_changed) self._on_name_changed() def _on_name_changed(self): self.hyperion.sysex.set_title(self.mod_num, self._track.name if self._track else '-')
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)
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)
class Axiom_DirectLink(ControlSurface): """ Script for the M-Audio Axiom DirectLink """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self.set_pad_translations(PAD_TRANSLATIONS) self._device_selection_follows_track_selection = True self._suggested_input_port = "DirectLink" self._suggested_output_port = "DirectLink" self._waiting_for_first_response = True self._has_sliders = True self._current_midi_map = None self._display_reset_delay = -1 self._shift_pressed = False self._shift_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 13) self._master_slider = SliderElement(MIDI_CC_TYPE, 15, 41) self._next_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 111) self._prev_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 110) self._device_bank_buttons = None self._device_navigation = None self._shift_button.name = "Shift_Button" self._master_slider.name = "Master_Volume_Control" self._next_nav_button.name = "Next_Track_Button" self._prev_nav_button.name = "Prev_Track_Button" self._master_slider.add_value_listener(self._slider_value, identify_sender=True) self._shift_button.add_value_listener(self._shift_value) self._setup_mixer() self._setup_transport_and_session() self._setup_device() self._setup_display() for component in self.components: component.set_enabled(False) return def refresh_state(self): ControlSurface.refresh_state(self) self._waiting_for_first_response = True self.schedule_message(3, self._send_midi, SYSEX_START + (32, 46, 247)) def handle_sysex(self, midi_bytes): if midi_bytes[0:-2] == SYSEX_START + (32,) and midi_bytes[-2] != 0: self._has_sliders = midi_bytes[-2] & 8 != 0 if self._waiting_for_first_response: self._waiting_for_first_response = False self.schedule_message(1, self._show_startup_message) for component in self.components: component.set_enabled(True) if self._has_sliders: self._mixer.master_strip().set_volume_control(self._master_slider) self._mixer.update() else: self._mixer.master_strip().set_volume_control(None) self._mixer.selected_strip().set_volume_control(self._master_slider) self.request_rebuild_midi_map() return def disconnect(self): self._display_data_source.set_display_string(" ") self._shift_button.remove_value_listener(self._shift_value) self._inst_button.remove_value_listener(self._inst_value) for encoder in self._encoders: encoder.remove_value_listener(self._encoder_value) for slider in tuple(self._sliders) + (self._master_slider,): slider.remove_value_listener(self._slider_value) for button in tuple(self._strip_buttons) + (self._selected_mute_solo_button,): button.remove_value_listener(self._mixer_button_value) for button in self._device_bank_buttons: button.remove_value_listener(self._device_bank_value) self._encoders = None self._sliders = None self._strip_buttons = None self._master_slider = None self._current_midi_map = None self._selected_mute_solo_button = None self._inst_button = None self._shift_button = None self._device_navigation = None self._display = None ControlSurface.disconnect(self) self._send_midi(SYSEX_START + (32, 0, 247)) return def build_midi_map(self, midi_map_handle): self._current_midi_map = midi_map_handle ControlSurface.build_midi_map(self, midi_map_handle) def update_display(self): ControlSurface.update_display(self) if self._display_reset_delay >= 0: self._display_reset_delay -= 1 if self._display_reset_delay == -1: self._show_current_track_name() def _setup_mixer(self): self._selected_mute_solo_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 12) mute_solo_flip_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 57) self._strip_buttons = [] self._selected_mute_solo_button.name = "Selected_Mute_Button" mute_solo_flip_button.name = "Mute_Solo_Flip_Button" self._selected_mute_solo_button.add_value_listener(self._mixer_button_value, identify_sender=True) self._mixer = ShiftableMixerComponent(8) self._mixer.name = "Mixer" self._mixer.set_shift_button(self._shift_button) self._mixer.set_selected_mute_solo_button(self._selected_mute_solo_button) self._mixer.set_select_buttons(self._next_nav_button, self._prev_nav_button) self._mixer.selected_strip().name = "Selected_Channel_Strip" self._mixer.master_strip().name = "Master_Channel_Strip" self._mixer.master_strip().set_volume_control(self._master_slider) self._sliders = [] for index in range(8): strip = self._mixer.channel_strip(index) strip.name = "Channel_Strip_" + str(index) strip.set_invert_mute_feedback(True) self._sliders.append(SliderElement(MIDI_CC_TYPE, 15, 33 + index)) self._sliders[-1].name = str(index) + "_Volume_Control" self._sliders[-1].set_feedback_delay(-1) self._sliders[-1].add_value_listener(self._slider_value, identify_sender=True) strip.set_volume_control(self._sliders[-1]) self._strip_buttons.append(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 49 + index)) self._strip_buttons[-1].name = str(index) + "_Mute_Button" self._strip_buttons[-1].add_value_listener(self._mixer_button_value, identify_sender=True) self._mixer.set_strip_mute_solo_buttons(tuple(self._strip_buttons), mute_solo_flip_button) def _setup_transport_and_session(self): 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) play_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 117) stop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 116) rec_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 118) ffwd_button.name = "FFwd_Button" rwd_button.name = "Rwd_Button" loop_button.name = "Loop_Button" play_button.name = "Play_Button" stop_button.name = "Stop_Button" rec_button.name = "Record_Button" transport = ShiftableTransportComponent() transport.name = "Transport" transport.set_shift_button(self._shift_button) transport.set_stop_button(stop_button) transport.set_play_button(play_button) transport.set_record_button(rec_button) pads = [] for index in range(len(PAD_TRANSLATIONS)): pads.append(ButtonElement(IS_MOMENTARY, MIDI_NOTE_TYPE, 15, PAD_TRANSLATIONS[index][2])) pads[-1].name = "Pad_" + str(index) self._session = ShiftableSessionComponent(8, 0) self._session.name = "Session_Control" self._session.selected_scene().name = "Selected_Scene" self._session.set_mixer(self._mixer) self._session.set_shift_button(self._shift_button) self._session.set_clip_slot_buttons(tuple(pads)) transport_view_modes = TransportViewModeSelector(transport, self._session, ffwd_button, rwd_button, loop_button) transport_view_modes.name = "Transport_View_Modes" def _setup_device(self): 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._encoders[-1].add_value_listener(self._encoder_value, identify_sender=True) self._encoders[-1].name = "Device_Control_" + str(offset) prev_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 14) next_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 15) prev_bank_button.name = "Device_Bank_Down_Button" next_bank_button.name = "Device_Bank_Up_Button" device = BestBankDeviceComponent() device.name = "Device_Component" self.set_device_component(device) device.set_parameter_controls(tuple(self._encoders)) device.set_bank_nav_buttons(prev_bank_button, next_bank_button) self._device_bank_buttons = (prev_bank_button, next_bank_button) prev_bank_button.add_value_listener(self._device_bank_value) next_bank_button.add_value_listener(self._device_bank_value) self._inst_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 109) self._inst_button.name = "Inst_Button" self._inst_button.add_value_listener(self._inst_value) self._device_navigation = DetailViewCntrlComponent() self._device_navigation.name = "Device_Navigation_Component" def _setup_display(self): self._display = PhysicalDisplayElement(5, 1) self._display.name = "Display" self._display.set_message_parts(SYSEX_START + (17, 1, 0, 0), (247,)) self._display_data_source = DisplayDataSource() self._display.segment(0).set_data_source(self._display_data_source) def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(self) self._show_current_track_name() def _shift_value(self, value): if not value in range(128): raise AssertionError self._shift_pressed = value > 0 for encoder in self._encoders: encoder.set_peek_mode(self._shift_pressed) self._shift_pressed and self._mixer.set_select_buttons(None, None) self._session.set_track_bank_buttons(self._next_nav_button, self._prev_nav_button) self._device_component.set_bank_nav_buttons(None, None) self._device_navigation.set_device_nav_buttons(self._device_bank_buttons[0], self._device_bank_buttons[1]) else: self._session.set_track_bank_buttons(None, None) self._mixer.set_select_buttons(self._next_nav_button, self._prev_nav_button) self._device_navigation.set_device_nav_buttons(None, None) self._device_component.set_bank_nav_buttons(self._device_bank_buttons[0], self._device_bank_buttons[1]) self.request_rebuild_midi_map() return def _encoder_value(self, value, sender): if not sender in self._encoders: raise AssertionError if not value in range(128): raise AssertionError display_string = self._device_component.is_enabled() and " - " display_string = sender.mapped_parameter() != None and sender.mapped_parameter().name self._display_data_source.set_display_string(display_string) self._set_display_data_source(self._display_data_source) self._display_reset_delay = STANDARD_DISPLAY_DELAY return def _slider_value(self, value, sender): if not sender in tuple(self._sliders) + (self._master_slider,): raise AssertionError if not value in range(128): raise AssertionError if self._mixer.is_enabled(): display_string = " - " if sender.mapped_parameter() != None: master = self.song().master_track tracks = self.song().tracks returns = self.song().return_tracks track = None if sender == self._master_slider: track = self._has_sliders and master else: track = self.song().view.selected_track else: track = self._mixer.channel_strip(self._sliders.index(sender))._track display_string = track == master and "Ma" elif track in tracks: display_string = str(list(tracks).index(track) + 1) elif track in returns: display_string = str(chr(ord("A") + list(returns).index(track))) else: raise False or AssertionError display_string += " Vol" self._display_data_source.set_display_string(display_string) self._set_display_data_source(self._display_data_source) self._display_reset_delay = STANDARD_DISPLAY_DELAY return def _mixer_button_value(self, value, sender): if not sender in tuple(self._strip_buttons) + (self._selected_mute_solo_button,): raise AssertionError if not value in range(128): raise AssertionError if self._mixer.is_enabled() and value > 0: strip = None strip = sender == self._selected_mute_solo_button and self._mixer.selected_strip() else: strip = self._mixer.channel_strip(self._strip_buttons.index(sender)) strip != None and self._set_display_data_source(strip.track_name_data_source()) else: self._display_data_source.set_display_string(" - ") self._set_display_data_source(self._display_data_source) self._display_reset_delay = STANDARD_DISPLAY_DELAY return def _device_bank_value(self, value): if not value in range(128): raise AssertionError if self._device_component.is_enabled() and value > 0: data_source = self._device_component.bank_name_data_source() data_source = self._shift_pressed and self._device_component.device_name_data_source() self._set_display_data_source(data_source) self._display_reset_delay = STANDARD_DISPLAY_DELAY def _inst_value(self, value): if not value in range(128): raise AssertionError value > 0 and self._device_component.is_enabled() and self.song().view.selected_track.view.select_instrument() and self._set_display_data_source( self._device_component.device_name_data_source() ) self._display_reset_delay = STANDARD_DISPLAY_DELAY def _show_current_track_name(self): if self._display != None and self._mixer != None: self._set_display_data_source(self._mixer.selected_strip().track_name_data_source()) return def _show_startup_message(self): self._display.display_message("LIVE") self._display_reset_delay = INITIAL_DISPLAY_DELAY def _set_display_data_source(self, data_source): raise isinstance(data_source, DisplayDataSource) or AssertionError self._display.segment(0).set_data_source(data_source) data_source.update()
class Axiom_DirectLink(ControlSurface): """ Script for the M-Audio Axiom DirectLink """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self.set_pad_translations(PAD_TRANSLATIONS) self._device_selection_follows_track_selection = True self._suggested_input_port = 'DirectLink' self._suggested_output_port = 'DirectLink' self._waiting_for_first_response = True self._has_sliders = True self._current_midi_map = None self._display_reset_delay = -1 self._shift_pressed = False self._shift_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 13) self._master_slider = SliderElement(MIDI_CC_TYPE, 15, 41) self._next_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 111) self._prev_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 110) self._device_bank_buttons = None self._device_navigation = None self._shift_button.name = 'Shift_Button' self._master_slider.name = 'Master_Volume_Control' self._next_nav_button.name = 'Next_Track_Button' self._prev_nav_button.name = 'Prev_Track_Button' self._master_slider.add_value_listener(self._slider_value, identify_sender=True) self._shift_button.add_value_listener(self._shift_value) self._setup_mixer() self._setup_transport_and_session() self._setup_device() self._setup_display() 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(3, self._send_midi, SYSEX_START + (32, 46, 247)) def handle_sysex(self, midi_bytes): if midi_bytes[0:-2] == SYSEX_START + (32, ) and midi_bytes[-2] != 0: self._has_sliders = midi_bytes[-2] & 8 != 0 if self._waiting_for_first_response: self._waiting_for_first_response = False self.schedule_message(1, self._show_startup_message) for component in self.components: component.set_enabled(True) if self._has_sliders: self._mixer.master_strip().set_volume_control( self._master_slider) self._mixer.update() else: self._mixer.master_strip().set_volume_control(None) self._mixer.selected_strip().set_volume_control( self._master_slider) self.request_rebuild_midi_map() def disconnect(self): self._display_data_source.set_display_string(' ') self._shift_button.remove_value_listener(self._shift_value) self._inst_button.remove_value_listener(self._inst_value) for encoder in self._encoders: encoder.remove_value_listener(self._encoder_value) for slider in tuple(self._sliders) + (self._master_slider, ): slider.remove_value_listener(self._slider_value) for button in tuple( self._strip_buttons) + (self._selected_mute_solo_button, ): button.remove_value_listener(self._mixer_button_value) for button in self._device_bank_buttons: button.remove_value_listener(self._device_bank_value) self._encoders = None self._sliders = None self._strip_buttons = None self._master_slider = None self._current_midi_map = None self._selected_mute_solo_button = None self._inst_button = None self._shift_button = None self._device_navigation = None self._display = None ControlSurface.disconnect(self) self._send_midi(SYSEX_START + (32, 0, 247)) def build_midi_map(self, midi_map_handle): self._current_midi_map = midi_map_handle ControlSurface.build_midi_map(self, midi_map_handle) def update_display(self): ControlSurface.update_display(self) if self._display_reset_delay >= 0: self._display_reset_delay -= 1 if self._display_reset_delay == -1: self._show_current_track_name() def _setup_mixer(self): self._selected_mute_solo_button = ButtonElement( IS_MOMENTARY, MIDI_CC_TYPE, 15, 12) mute_solo_flip_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 57) self._strip_buttons = [] self._selected_mute_solo_button.name = 'Selected_Mute_Button' mute_solo_flip_button.name = 'Mute_Solo_Flip_Button' self._selected_mute_solo_button.add_value_listener( self._mixer_button_value, identify_sender=True) self._mixer = ShiftableMixerComponent(8) self._mixer.name = 'Mixer' self._mixer.set_shift_button(self._shift_button) self._mixer.set_selected_mute_solo_button( self._selected_mute_solo_button) self._mixer.set_select_buttons(self._next_nav_button, self._prev_nav_button) self._mixer.selected_strip().name = 'Selected_Channel_Strip' self._mixer.master_strip().name = 'Master_Channel_Strip' self._mixer.master_strip().set_volume_control(self._master_slider) self._sliders = [] for index in range(8): strip = self._mixer.channel_strip(index) strip.name = 'Channel_Strip_' + str(index) strip.set_invert_mute_feedback(True) self._sliders.append(SliderElement(MIDI_CC_TYPE, 15, 33 + index)) self._sliders[-1].name = str(index) + '_Volume_Control' self._sliders[-1].set_feedback_delay(-1) self._sliders[-1].add_value_listener(self._slider_value, identify_sender=True) strip.set_volume_control(self._sliders[-1]) self._strip_buttons.append( ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 49 + index)) self._strip_buttons[-1].name = str(index) + '_Mute_Button' self._strip_buttons[-1].add_value_listener( self._mixer_button_value, identify_sender=True) self._mixer.set_strip_mute_solo_buttons(tuple(self._strip_buttons), mute_solo_flip_button) def _setup_transport_and_session(self): 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) play_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 117) stop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 116) rec_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 118) ffwd_button.name = 'FFwd_Button' rwd_button.name = 'Rwd_Button' loop_button.name = 'Loop_Button' play_button.name = 'Play_Button' stop_button.name = 'Stop_Button' rec_button.name = 'Record_Button' transport = ShiftableTransportComponent() transport.name = 'Transport' transport.set_shift_button(self._shift_button) transport.set_stop_button(stop_button) transport.set_play_button(play_button) transport.set_record_button(rec_button) pads = [] for index in range(len(PAD_TRANSLATIONS)): pads.append( ButtonElement(IS_MOMENTARY, MIDI_NOTE_TYPE, 15, PAD_TRANSLATIONS[index][2])) pads[-1].name = 'Pad_' + str(index) self._session = ShiftableSessionComponent(8, 0) self._session.name = 'Session_Control' self._session.selected_scene().name = 'Selected_Scene' self._session.set_mixer(self._mixer) self._session.set_shift_button(self._shift_button) self._session.set_clip_slot_buttons(tuple(pads)) transport_view_modes = TransportViewModeSelector( transport, self._session, ffwd_button, rwd_button, loop_button) transport_view_modes.name = 'Transport_View_Modes' def _setup_device(self): 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._encoders[-1].add_value_listener(self._encoder_value, identify_sender=True) self._encoders[-1].name = 'Device_Control_' + str(offset) prev_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 14) next_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 15) prev_bank_button.name = 'Device_Bank_Down_Button' next_bank_button.name = 'Device_Bank_Up_Button' device = BestBankDeviceComponent() device.name = 'Device_Component' self.set_device_component(device) device.set_parameter_controls(tuple(self._encoders)) device.set_bank_nav_buttons(prev_bank_button, next_bank_button) self._device_bank_buttons = (prev_bank_button, next_bank_button) prev_bank_button.add_value_listener(self._device_bank_value) next_bank_button.add_value_listener(self._device_bank_value) self._inst_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 15, 109) self._inst_button.name = 'Inst_Button' self._inst_button.add_value_listener(self._inst_value) self._device_navigation = DetailViewCntrlComponent() self._device_navigation.name = 'Device_Navigation_Component' def _setup_display(self): self._display = PhysicalDisplayElement(5, 1) self._display.name = 'Display' self._display.set_message_parts(SYSEX_START + (17, 1, 0, 0), (247, )) self._display_data_source = DisplayDataSource() self._display.segment(0).set_data_source(self._display_data_source) def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(self) self._show_current_track_name() def _shift_value(self, value): if not value in range(128): raise AssertionError self._shift_pressed = value > 0 for encoder in self._encoders: encoder.set_peek_mode(self._shift_pressed) self._shift_pressed and self._mixer.set_select_buttons(None, None) self._session.set_track_bank_buttons(self._next_nav_button, self._prev_nav_button) self._device_component.set_bank_nav_buttons(None, None) self._device_navigation.set_device_nav_buttons( self._device_bank_buttons[0], self._device_bank_buttons[1]) else: self._session.set_track_bank_buttons(None, None) self._mixer.set_select_buttons(self._next_nav_button, self._prev_nav_button) self._device_navigation.set_device_nav_buttons(None, None) self._device_component.set_bank_nav_buttons( self._device_bank_buttons[0], self._device_bank_buttons[1]) self.request_rebuild_midi_map() def _encoder_value(self, value, sender): if not sender in self._encoders: raise AssertionError if not value in range(128): raise AssertionError display_string = self._device_component.is_enabled() and ' - ' display_string = sender.mapped_parameter( ) != None and sender.mapped_parameter().name self._display_data_source.set_display_string(display_string) self._set_display_data_source(self._display_data_source) self._display_reset_delay = STANDARD_DISPLAY_DELAY def _slider_value(self, value, sender): if not sender in tuple(self._sliders) + (self._master_slider, ): raise AssertionError if not value in range(128): raise AssertionError if self._mixer.is_enabled(): display_string = ' - ' if sender.mapped_parameter() != None: master = self.song().master_track tracks = self.song().tracks returns = self.song().return_tracks track = None if sender == self._master_slider: track = self._has_sliders and master else: track = self.song().view.selected_track else: track = self._mixer.channel_strip( self._sliders.index(sender))._track display_string = track == master and 'Ma' elif track in tracks: display_string = str(list(tracks).index(track) + 1) elif track in returns: display_string = str( chr(ord('A') + list(returns).index(track))) else: raise False or AssertionError display_string += ' Vol' self._display_data_source.set_display_string(display_string) self._set_display_data_source(self._display_data_source) self._display_reset_delay = STANDARD_DISPLAY_DELAY def _mixer_button_value(self, value, sender): if not sender in tuple( self._strip_buttons) + (self._selected_mute_solo_button, ): raise AssertionError if not value in range(128): raise AssertionError if self._mixer.is_enabled() and value > 0: strip = None strip = sender == self._selected_mute_solo_button and self._mixer.selected_strip( ) else: strip = self._mixer.channel_strip( self._strip_buttons.index(sender)) strip != None and self._set_display_data_source( strip.track_name_data_source()) else: self._display_data_source.set_display_string(' - ') self._set_display_data_source(self._display_data_source) self._display_reset_delay = STANDARD_DISPLAY_DELAY def _device_bank_value(self, value): if not value in range(128): raise AssertionError if self._device_component.is_enabled() and value > 0: data_source = self._device_component.bank_name_data_source() data_source = self._shift_pressed and self._device_component.device_name_data_source( ) self._set_display_data_source(data_source) self._display_reset_delay = STANDARD_DISPLAY_DELAY def _inst_value(self, value): if not value in range(128): raise AssertionError value > 0 and self._device_component.is_enabled() and self.song( ).view.selected_track.view.select_instrument( ) and self._set_display_data_source( self._device_component.device_name_data_source()) self._display_reset_delay = STANDARD_DISPLAY_DELAY def _show_current_track_name(self): if self._display != None and self._mixer != None: self._set_display_data_source( self._mixer.selected_strip().track_name_data_source()) def _show_startup_message(self): self._display.display_message('LIVE') self._display_reset_delay = INITIAL_DISPLAY_DELAY def _set_display_data_source(self, data_source): raise isinstance(data_source, DisplayDataSource) or AssertionError self._display.segment(0).set_data_source(data_source) data_source.update()
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)
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)
class OP1(ControlSurface): def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) self.c_instance = c_instance self.retries_count = 0 self.device_connected = False self.clip_color_callbacks = {} self.slot_callbacks = {} self.text_start_sequence = (0xf0, 0x0, 0x20, 0x76, 0x00, 0x03) self.text_end_sequence = (0xf7, ) self.enable_sequence = (0xf0, 0x00, 0x20, 0x76, 0x00, 0x01, 0x02, 0xf7) self.disable_sequence = (0xf0, 0x00, 0x20, 0x76, 0x00, 0x01, 0x00, 0xf7) self.id_sequence = (0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7) self.text_color_start_sequence = (0xf0, 0x0, 0x20, 0x76, 0x00, 0x04) self.log('INITIALIZING') self.app = Live.Application.get_application() #maj = self.app.get_major_version() #min = self.app.get_minor_version() #bug = self.app.get_bugfix_version() #self.show_message(str(1) + "." + str(0) + "." + str(9)) self.show_message("Version " + VERSION) # reseting text self.write_text(' ') # reset display clips self.reset_display_clips() # getting browser visible state self.session_browser_visible = self.app.view.is_view_visible("Browser") # getting browser visible state self.arrange_browser_visible = self.app.view.is_view_visible("Browser") # getting session view visible state self.session_visible = self.app.view.is_view_visible("Session") # getting arrange view visible state self.arrange_visible = self.app.view.is_view_visible("Arranger") # getting detail view visible state self.detail_visible = self.app.view.is_view_visible("Detail") # getting back to arranger state self.back_to_arranger_state = self.song().back_to_arranger # initializing channel strip to null self._channel_strip = None # initializing transport component self._transport = TransportComponent() # initializing mixer component self._mixer = MixerComponent(NUM_TRACKS, 2) # initializing session component self._session = SessionComponent(NUM_TRACKS, NUM_ROWS) self._session.add_offset_listener(self.session_offset_changed) # configuring operation mode selector buttons self._operation_mode_buttons = ButtonElement( True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_1_BUTTON), ButtonElement( True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_2_BUTTON), ButtonElement( True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_3_BUTTON), ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_4_BUTTON), # initializing operation mode selector self._operation_mode_selector = OP1ModeSelectorComponent( self, self._transport, self._mixer, self._session) # setting operation mode selector buttons self._operation_mode_selector.set_mode_buttons( self._operation_mode_buttons) # adding value listener for operation mode index self._operation_mode_selector.add_mode_index_listener( self.mode_index_changed) # setting global transport assignments self._transport.set_record_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_REC_BUTTON)) self._transport.set_play_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_PLAY_BUTTON)) self._transport.set_stop_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_STOP_BUTTON)) self._transport.set_metronome_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_METRONOME_BUTTON)) self._transport.set_tap_tempo_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_HELP_BUTTON)) self._transport.set_punch_buttons( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS1_BUTTON), ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS2_BUTTON)) self._transport.set_loop_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS3_BUTTON)) self._transport.set_overdub_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS4_BUTTON)) # setting global session assignments self._session.set_scene_bank_buttons( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_COM), ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MICRO)) # setting misc listeners self.browser_toggle_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL, 15) self.browser_toggle_button.add_value_listener( self.browser_toggle_button_callback) self.mainview_toggle_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL, 16) self.mainview_toggle_button.add_value_listener( self.mainview_toggle_button_callback) self.detailview_toggle_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL, 17) self.detailview_toggle_button.add_value_listener( self.detailview_toggle_button_callback) self.clear_track_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, 25) self.clear_track_button.add_value_listener( self.clear_track_button_callback) self.back_to_arranger_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, 26) self.back_to_arranger_button.add_value_listener( self.back_to_arranger_button_callback) # adding value listener for selected track change self.song().view.add_selected_track_listener( self.selected_track_changed) # adding value listener for selected scene change self.song().view.add_selected_scene_listener( self.selected_scene_changed) # setting assignments for currently selected track self.selected_track_changed() # setting assignments for currently selected scene self.selected_scene_changed() def handle_sysex(self, midi_bytes): if ((midi_bytes[6] == 32) and (midi_bytes[7] == 118)): self.device_connected = True self.log("OP-1 CONNECTED. SENDING ABLETON LIVE MODE INIT SEQUENCE") self._send_midi(self.enable_sequence) def add_clip_slot_listeners(self): #self.log('ADDING CLIP SLOT LISTENERS') # creating an empty list for all clip slots clip_slots = [] # getting a reference to all tracks tracks = self.song().tracks # appending all tracks clip slots to clip_slots for track in tracks: clip_slots.append(track.clip_slots) # iterating over all clip slots for t in range(len(clip_slots)): for c in range(len(clip_slots[t])): clip_slot = clip_slots[t][c] # adding has clip listener to clip slot self.add_slot_listener(clip_slot) # if clip slot has clip if clip_slot.has_clip: # adding clip listeners self.add_clip_listener(clip_slot.clip) def rem_clip_slot_listeners(self): #self.log('REMOVING CLIP SLOT LISTENERS') # iterate over all clip color change callbacks for c in self.clip_color_callbacks: # if clip still exists if c != None: # and it has a has clip listener if c.color_has_listener(self.clip_color_callbacks[c]) == 1: # remove it c.remove_color_listener(self.clip_color_callbacks[c]) # iterate over all clip slot callbacks for cs in self.slot_callbacks: # if clip slot still exists if cs != None: # and it has a has clip listener if cs.has_clip_has_listener(self.slot_callbacks[cs]) == 1: # remove it cs.remove_has_clip_listener(self.slot_callbacks[cs]) def add_slot_listener(self, cs): # setting has clip listener callback = lambda: self.has_clip_listener(cs) # if we don't have a clip slot has clip listener for this clip slot yet if not (self.slot_callbacks.has_key(cs)): # adding has clip callback to clip slot cs.add_has_clip_listener(callback) # saving callback for future release self.slot_callbacks[cs] = callback def add_clip_listener(self, clip): # setting callback for clip color change color_callback = lambda: self.update_display_clips() # if we don't have a clip color change callback for this clip yet if not (self.clip_color_callbacks.has_key(clip)): # adding clip color change callback clip.add_color_listener(color_callback) # saving callback for future release self.clip_color_callbacks[clip] = color_callback def has_clip_listener(self, cs): # clip slot has clip listener callback if cs.has_clip: # add clip listener self.add_clip_listener(cs.clip) else: # update display if clip slot was removed self.update_display_clips() def session_offset_changed(self): # if session component offset changes, update display self.update_display_clips() def selected_scene_changed(self): # if on clip mode update display if (self._operation_mode_selector.mode_index == OP1_MODE_CLIP): self.update_display_clip_mode() def mode_index_changed(self): # update display to current mode info if (self._operation_mode_selector.mode_index == OP1_MODE_PERFORM): self.update_display_perform_mode() elif (self._operation_mode_selector.mode_index == OP1_MODE_CLIP): self.update_display_clip_mode() elif (self._operation_mode_selector.mode_index == OP1_MODE_TRANSPORT): self.update_display_transport_mode() elif (self._operation_mode_selector.mode_index == OP1_MODE_MIXER): self.update_display_mixer_mode() def clear_track_button_callback(self, value): # if clear track button was called, reset track if (value == 127): for i in range(len(self.song().tracks)): self.song().tracks[i].arm = 0 self.song().tracks[i].solo = 0 self.song().tracks[i].mute = 0 for i in range(len(self.song().return_tracks)): self.song().tracks[i].solo = 0 self.song().tracks[i].mute = 0 def clear_return_track_assignment(self, strip): # clear return track assingments strip.set_volume_control(None) strip.set_pan_control(None) strip.set_mute_button(None) strip.set_solo_button(None) def clear_track_assignment(self, strip): # clear track assignments strip.set_volume_control(None) strip.set_pan_control(None) strip.set_mute_button(None) strip.set_solo_button(None) strip.set_arm_button(None) def clear_tracks_assigments(self): # for all normal tracks, clear assignments for i in range(NUM_TRACKS): strip = self._mixer.channel_strip(i) if (strip != None): self.clear_track_assignment(strip) # for all return tracks, clear assignments for i in range(2): return_strip = self._mixer.return_strip(i) if (return_strip != None): self.clear_return_track_assignment(return_strip) def selected_track_changed(self): # if on mixer mode update display if (self._operation_mode_selector.mode_index == OP1_MODE_MIXER): self.update_display_mixer_mode() # clear track assignments self.clear_tracks_assigments() # getting selected strip self._channel_strip = self._mixer.selected_strip() # perform track assignments self._channel_strip.set_volume_control( EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_1, Live.MidiMap.MapMode.relative_two_compliment)) self._channel_strip.set_pan_control( EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_2, Live.MidiMap.MapMode.relative_two_compliment)) # setting a tuple of encoders to control sends send_controls = EncoderElement( MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_3, Live.MidiMap.MapMode.relative_two_compliment), EncoderElement( MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_4, Live.MidiMap.MapMode.relative_two_compliment), # setting send encoders self._channel_strip.set_send_controls(tuple(send_controls)) # setting solo button self._channel_strip.set_solo_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS6_BUTTON)) # if track can be armed, set arm button if (self._channel_strip._track.can_be_armed): self._channel_strip.set_arm_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS7_BUTTON)) # if track is no master, set mute button if (self._channel_strip._track != self.song().master_track): self._channel_strip.set_mute_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS5_BUTTON)) def browser_toggle_button_callback(self, value): if (value == 127): if (self.session_visible): if (self.session_browser_visible == True): self.session_browser_visible = False self.app.view.hide_view("Browser") else: self.session_browser_visible = True self.app.view.show_view("Browser") if (self.arrange_visible): if (self.arrange_browser_visible == True): self.arrange_browser_visible = False self.app.view.hide_view("Browser") else: self.arrange_browser_visible = True self.app.view.show_view("Browser") def back_to_arranger_button_callback(self, value): if (value == 127): self.song().back_to_arranger = False def mainview_toggle_button_callback(self, value): if (value == 127): if (self.session_visible == True): self.session_visible = False self.arrange_visible = True self.app.view.show_view("Arranger") self.arrange_browser_visible = self.app.view.is_view_visible( "Browser") else: self.session_visible = True self.arrange_visible = False self.app.view.show_view("Session") self.session_browser_visible = self.app.view.is_view_visible( "Browser") def detailview_toggle_button_callback(self, value): if (value == 127): if (self.detail_visible == True): self.detail_visible = False self.app.view.hide_view("Detail") else: self.detail_visible = True self.app.view.show_view("Detail") def write_text(self, msg): text_list = [] sequence = () text_list.append(len(msg.strip())) for i in msg.strip(): text_list.append(ord(i)) sequence = self.text_start_sequence + tuple( text_list) + self.text_end_sequence self._send_midi(sequence) def suggest_input_port(self): return "OP-1 Midi Device" def suggest_output_port(self): return "OP-1 Midi Device" def update_display_perform_mode(self): self.write_text("perform\rmode") def reset_display_clips(self): count = 0 colors = [] length = [] sequence = () for i in range(NUM_TRACKS): count += 1 colors.append(0x00) colors.append(0x00) colors.append(0x00) length.append(count) sequence = self.text_color_start_sequence + tuple(length) + tuple( colors) + self.text_end_sequence self._send_midi(sequence) def update_display_clips(self): #self.log("UPDATING DISPLAY CLIPS") count = 0 colors = [] length = [] sequence = () tracks_len = len(self.song().tracks) - self._session._track_offset if (tracks_len > NUM_TRACKS): tracks_len = NUM_TRACKS for i in range(tracks_len): count += 1 clip_slot = self._session.scene(0).clip_slot(i) if (clip_slot != None): if (clip_slot.has_clip() != False): clip_color = clip_slot._clip_slot.clip.color colors.append(((clip_color >> 16) & 0x000000ff) >> 1) colors.append(((clip_color >> 8) & 0x000000ff) >> 1) colors.append((clip_color & 0x000000ff) >> 1) else: colors.append(0x00) colors.append(0x00) colors.append(0x00) else: colors.append(0x00) colors.append(0x00) colors.append(0x00) length.append(count) sequence = self.text_color_start_sequence + tuple(length) + tuple( colors) + self.text_end_sequence self._send_midi(sequence) def update_display_clip_mode(self): self.write_text( "sel. scene\r" + str(self.song().view.selected_scene.name.lower().strip())) def update_display_transport_mode(self): song_time = str(self.song().get_current_beats_song_time()) self.write_text("song pos.\r" + song_time[:len(song_time) - 4]) def update_display_mixer_mode(self): self.write_text("sel. track\r" + str(self.song().view.selected_track.name.lower())) def update_display(self): if not (self.device_connected): if (self.retries_count < 5): self.log("TRYING OP-1 CONNECTION") self.retries_count += 1 self._send_midi(self.id_sequence) time.sleep(1) # if in transport mode, update display with song position if (self._operation_mode_selector.mode_index == OP1_MODE_TRANSPORT): self.update_display_transport_mode() # checking if app current view is session if (self.app.view.is_view_visible("Session")): # checking if session browser state is diferent from the internal if (self.session_browser_visible != self.app.view.is_view_visible("Browser")): self.session_browser_visible = self.app.view.is_view_visible( "Browser") # checking if app current view is arrange if (self.app.view.is_view_visible("Arranger")): # checking if arrange browser state is diferent from the internal if (self.arrange_browser_visible != self.app.view.is_view_visible("Browser")): self.arrange_browser_visible = self.app.view.is_view_visible( "Browser") # checking if app current view is detail if (self.app.view.is_view_visible("Detail")): # checking if detail state is diferent from the internal if (self.detail_visible != self.app.view.is_view_visible("Detail")): self.detail_visible = self.app.view.is_view_visible("Detail") def refresh_state(self): self.log("REFRESH STATE") self.retries_count = 0 self.device_connected = False def build_midi_map(self, midi_map_handle): #self.log("BUILD MIDI MAP") assert (self._suppress_requests_counter == 0) self._in_build_midi_map = True self._midi_map_handle = midi_map_handle self._forwarding_registry = {} for control in self.controls: if isinstance(control, InputControlElement): control.install_connections() self._midi_map_handle = None self._in_build_midi_map = False if (self._pad_translations != None): self._c_instance.set_pad_translation(self._pad_translations) # remove clip listeners self.rem_clip_slot_listeners() # add clip listeners self.add_clip_slot_listeners() # update display self.update_display_clips() def log(self, msg): self.c_instance.log_message("[TE OP-1] " + msg) def disconnect(self): # removing clip slots listeners self.rem_clip_slot_listeners() # removing value listener for track changed self.song().view.remove_selected_track_listener( self.selected_track_changed) # removing value listener for scene changed self.song().view.remove_selected_scene_listener( self.selected_scene_changed) # removing value listener for operation mode index self._operation_mode_selector.remove_mode_index_listener( self.mode_index_changed) # removing global transport assignments self._transport.set_punch_buttons(None, None) self._transport.set_loop_button(None) self._transport.set_overdub_button(None) self._transport.set_record_button(None) self._transport.set_play_button(None) self._transport.set_stop_button(None) self._transport.set_metronome_button(None) self._transport.set_tap_tempo_button(None) # removing global session assignments self._session.set_scene_bank_buttons(None, None) # removing misc listeners self.browser_toggle_button.remove_value_listener( self.browser_toggle_button_callback) self.mainview_toggle_button.remove_value_listener( self.mainview_toggle_button_callback) self.detailview_toggle_button.remove_value_listener( self.detailview_toggle_button_callback) self.clear_track_button.remove_value_listener( self.clear_track_button_callback) self.back_to_arranger_button.remove_value_listener( self.back_to_arranger_button_callback) # sending special ableton mode disable sequence self._send_midi(self.disable_sequence) # disconnecting control surface ControlSurface.disconnect(self) self.log("DISCONNECTED")
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)