def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): is_momentary = True self.set_pad_translations(PAD_TRANSLATIONS) self._suggested_input_port = 'HyperControl' self._suggested_output_port = 'HyperControl' self._display_on_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, 15, 79) self._waiting_for_first_response = True mixer1 = DisplayingMixerComponent(0) mixer1.set_select_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 111), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 110)) mixer1.set_mute_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 12)) mixer1.set_solo_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 13)) mixer2 = NotifyingMixerComponent(8) mixer2.set_bank_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 15), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 14)) mixer2.master_strip().set_volume_control(SliderElement(MIDI_CC_TYPE, 15, 41)) for index in range(8): mixer2.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, 15, 33 + index)) device = PageableDeviceComponent(device_selection_follows_track_selection=True) self.set_device_component(device) ffwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 115) rwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 114) loop_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 113) transport = TransportComponent() transport.set_stop_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 116)) transport.set_play_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 117)) transport.set_record_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 118)) session = SessionComponent(0, 0) transport_view_modes = TransportViewModeSelector(transport, session, ffwd_button, rwd_button, loop_button) select_button_modes = SelectButtonModeSelector(mixer2, tuple([ ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 49 + offset) for offset in range(8) ])) select_button_modes.set_mode_toggle(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 57)) self._mixer_encoder_modes = EncoderMixerModeSelector(mixer2) encoders = [] for offset in range(8): encoders.append(PeekableEncoderElement(MIDI_CC_TYPE, 15, 17 + offset, Live.MidiMap.MapMode.relative_smooth_two_compliment)) encoders[-1].set_feedback_delay(-1) mixer_or_device = MixerOrDeviceModeSelector(self._mixer_encoder_modes, device, tuple(encoders), tuple([ ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 74 + offset) for offset in range(4) ])) mixer_or_device.set_mode_toggle(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 109)) mixer_or_device.set_peek_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 78)) self._track_display = PhysicalDisplayElement(8, 1) self._track_display.set_clear_all_message(SYSEX_START + (16, 247)) self._track_display.set_message_parts(SYSEX_START + (17, 1, 0, 0), (247,)) self._track_display.segment(0).set_data_source(mixer1.selected_strip().track_name_data_source()) device_display = PhysicalDisplayElement(8, 1) device_display.set_message_parts(SYSEX_START + (17, 1, 0, 10), (247,)) parameter_display = PhysicalDisplayElement(16, 1) parameter_display.set_message_parts(SYSEX_START + (17, 2, 0, 0), (247,)) select_button_modes.set_mode_display(parameter_display) mixer1.set_display(parameter_display) mixer2.set_bank_display(parameter_display) page_displays = [] for index in range(4): page_displays.append(PhysicalDisplayElement(5, 1)) page_displays[-1].set_message_parts(SYSEX_START + (17, 4, index, 0), (247,)) encoder_display = PhysicalDisplayElement(80, 8) encoder_display.set_message_parts(SYSEX_START + (17, 3), (247,)) for index in range(8): pos_id = tuple() if index != 0: pos_id += (0,) if index > 3: pos_id += (index % 4, 13) else: pos_id += (index % 4, 0) encoder_display.segment(index).set_position_identifier(pos_id) mixer_or_device.set_displays(encoder_display, parameter_display, device_display, tuple(page_displays)) for component in self.components: component.set_enabled(False)
class Axiom_AIR_25_49_61(ControlSurface): """ Script for the M-Audio Axiom A.I.R. 25, 49 and 61 """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) self._alt_device_component = None with self.component_guard(): self.set_pad_translations(PAD_TRANSLATIONS) self._device_selection_follows_track_selection = True self._suggested_input_port = 'HyperControl' self._suggested_output_port = 'HyperControl' self._single_fader_button_modes = None self._has_faders = True self._display_reset_delay = -1 self._hc_byte = HC_BYTE self._waiting_for_first_response = True self._setup_controls() self._setup_displays() self._setup_mixer() self._setup_session() self._setup_transport() self._setup_device() self._setup_modes() self._drum_group_midi_button = None self._drum_group_hyper_button = None for component in self.components: component.set_enabled(False) return def disconnect(self): self._scheduled_messages = [] for encoder in self._encoders: encoder.remove_value_listener(self._encoder_value) for fader in self._faders: fader.remove_value_listener(self._fader_value) for fader_button in self._fader_buttons: fader_button.remove_value_listener(self._fader_button_value) self._master_fader.remove_value_listener(self._fader_value) self._master_fader_button.remove_value_listener( self._fader_button_value) self._select_button.remove_value_listener(self._select_button_value) self._identify_button.remove_value_listener(self._identify_value) self._fader_group_midi_button.remove_value_listener( self._midi_button_value) self._fader_group_mix_button.remove_value_listener( self._hyper_button_value) self._fader_group_fx_button.remove_value_listener( self._hyper_button_value) self._encoder_group_midi_button.remove_value_listener( self._midi_button_value) self._encoder_group_mix_button.remove_value_listener( self._hyper_button_value) self._encoder_group_fx_button.remove_value_listener( self._hyper_button_value) if self._drum_group_midi_button != None: self._drum_group_midi_button.remove_value_listener( self._midi_button_value) if self._drum_group_hyper_button != None: self._drum_group_hyper_button.remove_value_listener( self._hyper_button_value) self._alt_device_component = None self._name_display = None self._value_display = None self._bank_display = None self._pad_display = None self._name_display_data_source = None self._value_display_data_source = None self._bank_display_data_source = None self._pad_display_data_source = None self._select_button = None self._left_button = None self._right_button = None self._up_button = None self._down_button = None self._loop_button = None self._ffwd_button = None self._rwd_button = None self._play_button = None self._stop_button = None self._rec_button = None self._master_fader_button = None self._fader_buttons = None self._faders = None self._encoders = None self._drum_pads = None self._identify_button = None self._main_group_hyper_button = None self._main_group_track_button = None self._main_group_fx_button = None self._encoder_group_midi_button = None self._encoder_group_mix_button = None self._encoder_group_fx_button = None self._fader_group_mode_button = None self._fader_group_midi_button = None self._fader_group_mix_button = None self._fader_group_fx_button = None self._drum_group_midi_button = None self._drum_group_roll_button = None self._drum_group_hyper_button = None self._mixer_for_encoders = None self._mixer_for_faders = None self._device_for_encoders = None self._device_for_faders = None self._transport = None self._session = None ControlSurface.disconnect(self) self._send_midi(SYSEX_START + DISABLE_HYPERCONTROL) 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:10] == AXIOM_AIR_RESPONSE: if midi_bytes[12:15] < AXIOM_REV4_RESPONSE: self.schedule_message(1, self._send_midi, SYSEX_START + ENGAGE_HYPERCONTROL) self.schedule_message(2, self._send_midi, SYSEX_START + CLEAR_ALL) self.schedule_message(3, self._name_display.display_message, 'Firmware') self.schedule_message(13, self._name_display.display_message, 'Update') self.schedule_message(23, self._name_display.display_message, 'Required') self.schedule_message(33, self._send_midi, SYSEX_START + DISABLE_HYPERCONTROL) elif midi_bytes[12:15] >= AXIOM_REV4_RESPONSE: if self._waiting_for_first_response == True: self._waiting_for_first_response = False self._has_faders = midi_bytes[10] != 50 self.schedule_message(1, self._send_midi, SYSEX_START + ENGAGE_HYPERCONTROL) self.schedule_message(2, self._send_midi, SYSEX_START + SPECIAL_HYPERCONTROL) self.schedule_message(3, self._complete_setup) else: self._display_reset_delay = 0 elif midi_bytes[0:8] == REQUEST_HYPERCONTROL: self.schedule_message(5, self._send_midi, IDENTITY_REQUEST) 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._set_displays_to_default() def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(self) self._display_reset_delay = 0 def restore_bank(self, bank_index): ControlSurface.restore_bank(self, bank_index) if self._alt_device_component != None: self._alt_device_component.restore_bank(bank_index) return def set_appointed_device(self, device): ControlSurface.set_appointed_device(self, device) with self.component_guard(): if self._alt_device_component != None: self._alt_device_component.set_device(device) return def set_alt_device_component(self, device_component): self._alt_device_component = device_component def _update_device_selection(self): track = self.song().view.selected_track device_to_select = track.view.selected_device if device_to_select == None and len(track.devices) > 0: device_to_select = track.devices[0] if device_to_select != None: self.song().view.select_device(device_to_select) self._device_component.set_device(device_to_select) if self._alt_device_component != None: self._alt_device_component.set_device(device_to_select) return def _setup_controls(self): self._left_button = create_button(99, 'Left_Button') self._right_button = create_button(100, 'Right_Button') self._up_button = create_button(101, 'Up_Button') self._down_button = create_button(102, 'Down_Button') self._loop_button = create_button(113, 'Loop_Button') self._rwd_button = create_button(114, 'Rwd_Button') self._ffwd_button = create_button(115, 'FFwd_Button') self._stop_button = create_button(116, 'Stop_Button') self._play_button = create_button(117, 'Play_Button') self._rec_button = create_button(118, 'Record_Button') self._select_button = ConfigurableButtonElement( IS_MOMENTARY, MIDI_CC_TYPE, GLOBAL_CHANNEL, 98) self._select_button.name = 'Select_Button' self._select_button.add_value_listener(self._select_button_value) self._main_group_hyper_button = create_configurable_button( 104, 'Fader_Group_HyperControl_Button', 2, 14) self._main_group_track_button = create_configurable_button( 105, 'Main_Group_Track_Button', 2, 11) self._main_group_fx_button = create_configurable_button( 106, 'Main_Group_Inst_FX_Button', 2, 11) self._identify_button = create_configurable_button( 97, 'Identify_Button', 2, 16) self._identify_button.add_value_listener(self._identify_value) self._fader_buttons = [] for index in range(8): self._fader_buttons.append( create_configurable_button(49 + index, 'Fader_Button_%d' % index)) self._fader_buttons[-1].add_value_listener( self._fader_button_value, identify_sender=True) self._faders = [] for index in range(8): self._faders.append(create_slider(33 + index, 'Fader_%d' % index)) self._faders[-1].add_value_listener(self._fader_value, identify_sender=True) self._master_fader_button = create_configurable_button( 57, 'Master_Fader_Button') self._master_fader_button.add_value_listener(self._fader_button_value, identify_sender=True) self._master_fader = create_slider(41, 'Master_Fader') self._master_fader.add_value_listener(self._fader_value, identify_sender=True) self._fader_group_mode_button = create_configurable_button( 61, 'Fader_Group_Mode_Button') self._fader_group_midi_button = create_configurable_button( 60, 'Fader_Group_MIDI_Button') self._fader_group_midi_button.add_value_listener( self._midi_button_value, identify_sender=True) self._fader_group_mix_button = create_configurable_button( 58, 'Fader_Group_Mix_Button', 0, 1) self._fader_group_mix_button.add_value_listener( self._hyper_button_value, identify_sender=True) self._fader_group_fx_button = create_configurable_button( 59, 'Fader_Group_Inst_FX_Button', 0, -1) self._fader_group_fx_button.add_value_listener( self._hyper_button_value, identify_sender=True) self._encoders = [] for index in range(8): self._encoders.append( create_encoder(17 + index, 'Encoder_%d' % index)) self._encoders[-1].add_value_listener(self._encoder_value, identify_sender=True) self._encoder_group_midi_button = create_configurable_button( 27, 'Encoder_Group_MIDI_Button', 0, 72) self._encoder_group_midi_button.add_value_listener( self._midi_button_value, identify_sender=True) self._encoder_group_mix_button = create_configurable_button( 25, 'Encoder_Group_Mix_Button', 0, 72) self._encoder_group_mix_button.add_value_listener( self._hyper_button_value, identify_sender=True) self._encoder_group_fx_button = create_configurable_button( 26, 'Encoder_Group_Inst_FX_Button', 0, 72) self._encoder_group_fx_button.add_value_listener( self._hyper_button_value, identify_sender=True) def _setup_drum_pads(self): self._drum_pads = [] num_pads = 12 if self._has_faders else 16 for index in range(8): self._drum_pads.append( create_configurable_button(81 + index, 'Pad_%d' % index, 0, 0, MIDI_CC_TYPE)) for index in range(num_pads - 8): self._drum_pads.append( ConfigurableButtonElement(IS_MOMENTARY, MIDI_NOTE_TYPE, GLOBAL_CHANNEL - 1, 81 + index, GLOBAL_SEND_CHANNEL, 8, MIDI_CC_TYPE)) self._drum_pads[-1].name = 'Pad_' + str(index + 8) self._drum_group_midi_button = create_configurable_button( 91, 'Drum_Group_MIDI_Button', 2, -2) self._drum_group_midi_button.add_value_listener( self._midi_button_value, identify_sender=True) self._drum_group_roll_button = create_configurable_button( 90, 'Drum_Group_Roll_Button', -1) self._drum_group_hyper_button = create_configurable_button( 89, 'Drum_Group_HyperControl_Button', 2, 2) self._drum_group_hyper_button.add_value_listener( self._hyper_button_value, identify_sender=True) def _setup_displays(self): self._name_display = PhysicalDisplayElement(12, 1) self._name_display.name = 'Name_Display' self._name_display.set_message_parts(SYSEX_START + (21, ), (0, 247)) self._name_display.set_clear_all_message(CLEAR_NAME) self._name_display_data_source = DisplayDataSource() self._name_display.segment(0).set_data_source( self._name_display_data_source) self._value_display = NumericalDisplayElement(3, 1) self._value_display.name = 'Value_Display' self._value_display.set_message_parts(SYSEX_START + (20, 48), (0, 247)) self._value_display.set_clear_all_message(CLEAR_VALUE) self._value_display_data_source = DisplayDataSource() self._value_display.segment(0).set_data_source( self._value_display_data_source) self._bank_display = NumericalDisplayElement(3, 1) self._bank_display.name = 'Bank_Display' self._bank_display.set_message_parts(SYSEX_START + (19, ), (0, 247)) self._bank_display.set_clear_all_message(CLEAR_BANK) self._bank_display_data_source = DisplayDataSource() self._bank_display.segment(0).set_data_source( self._bank_display_data_source) self._pad_display = NumericalDisplayElement(2, 1) self._pad_display.name = 'Pad_Display' self._pad_display.set_message_parts(SYSEX_START + (18, ), (0, 247)) self._pad_display.set_clear_all_message(CLEAR_PAD) self._pad_display_data_source = DisplayDataSource() self._pad_display.segment(0).set_data_source( self._pad_display_data_source) def _setup_mixer(self): self._mixer_for_encoders = SpecialMixerComponent( self._name_display, self._value_display, 8) self._mixer_for_encoders.name = 'Mixer_for_encoders' self._mixer_for_faders = SpecialMixerComponent(self._name_display, self._value_display, 8) self._mixer_for_faders.name = 'Mixer_for_faders' def _setup_session(self): self._session = SpecialSessionComponent(8, 0) self._session.name = 'Session_Control' self._session.selected_scene().name = 'Selected_Scene' self._session.set_mixer(self._mixer_for_encoders) self._session.set_alt_mixer(self._mixer_for_faders) self._session.add_offset_listener(self._update_bank_value) def _setup_transport(self): self._transport = TransportComponent() self._transport.name = 'Transport' self._transport.set_stop_button(self._stop_button) self._transport.set_play_button(self._play_button) self._transport.set_record_button(self._rec_button) transport_view_modes = TransportViewModeSelector( self._transport, self._session, self._ffwd_button, self._rwd_button, self._loop_button) transport_view_modes.name = 'Transport_View_Modes' def _setup_device(self): self._device_for_encoders = BestBankDeviceComponent() self._device_for_encoders.name = 'Device_Component_for_encoders' self._device_for_faders = BestBankDeviceComponent() self._device_for_faders.name = 'Device_Component_for_faders' self.set_device_component(self._device_for_encoders) self.set_alt_device_component(self._device_for_faders) self._device_nav = DeviceNavComponent() self._device_nav.name = 'Device_Nav_Component' def _setup_modes(self): self._fader_button_modes = FaderButtonModeSelector( self._mixer_for_faders, tuple(self._fader_buttons)) self._fader_button_modes.name = 'Fader_Button_Modes' self._fader_button_modes.set_mode_toggle(self._fader_group_mode_button) self._fader_modes = FaderModeSelector(self._mixer_for_faders, self._device_for_faders, tuple(self._faders), self._fader_button_modes, self._master_fader_button) self._fader_modes.name = 'Fader_Modes' self._fader_modes.set_mode_buttons( (self._fader_group_mix_button, self._fader_group_fx_button)) self._encoder_modes = EncoderModeSelector(self._mixer_for_encoders, self._device_for_encoders, tuple(self._encoders)) self._encoder_modes.name = 'Encoder_Modes' self._encoder_modes.set_mode_buttons( (self._encoder_group_mix_button, self._encoder_group_fx_button)) main_modes = MainModeSelector(self._device_for_encoders, self._device_for_faders, self._session, self._mixer_for_faders, self._device_nav, self._up_button, self._down_button, self._left_button, self._right_button, self._select_button) main_modes.name = 'Main_Modes' main_modes.set_mode_buttons( (self._main_group_track_button, self._main_group_fx_button)) def _setup_master_fader(self): if self._has_faders: self._mixer_for_encoders.master_strip().set_volume_control( self._master_fader) else: self._mixer_for_encoders.selected_strip().set_volume_control( self._master_fader) def _setup_single_fader_button_modes(self): self._single_fader_button_modes = SingleFaderButtonModeSelector( self._mixer_for_encoders, self._fader_group_midi_button) self._single_fader_button_modes.name = 'Single_Fader_Button_Modes' self._single_fader_button_modes.set_mode_toggle( self._fader_group_mode_button) def _complete_setup(self): self._setup_drum_pads() self._set_drum_pads_to_hc() self._setup_master_fader() if not self._has_faders: self._setup_single_fader_button_modes() for control in self.controls: if isinstance(control, InputControlElement): control.clear_send_cache() for component in self.components: component.set_enabled(True) self._fader_group_midi_button.send_value(LED_OFF, True) self._encoder_group_midi_button.send_value(LED_OFF, True) self._main_group_hyper_button.send_value(AMB_FULL, True) self.request_rebuild_midi_map() self._on_selected_track_changed() self.schedule_message(1, self._show_startup_message) def _show_startup_message(self): self._send_midi(SYSEX_START + CLEAR_ALL) self._name_display.display_message('Ableton Live') self._display_reset_delay = INITIAL_DISPLAY_DELAY def _select_button_value(self, value): self._display_reset_delay = STANDARD_DISPLAY_DELAY def _identify_value(self, value): for encoder in self._encoders: encoder.set_identify_mode(value > 0) for fader in self._faders: fader.set_identify_mode(value > 0) self._master_fader.set_identify_mode(value > 0) self._display_reset_delay = 0 self._identify_button.turn_on( ) if value > 0 else self._identify_button.turn_off() def _midi_button_value(self, value, sender): if value > 0: if sender is self._drum_group_midi_button: hc_byte = self._hc_byte ^ PADS if hc_byte != self._hc_byte: self._hc_byte = hc_byte self._drum_group_hyper_button.send_value(LED_OFF, True) self.schedule_message( 1, self._send_midi, SYSEX_START + (32, self._hc_byte, 247)) elif sender is self._encoder_group_midi_button: hc_byte = self._hc_byte ^ ENCODERS if hc_byte != self._hc_byte: self._hc_byte = hc_byte self._encoder_group_mix_button.send_value(LED_OFF, True) self._encoder_group_fx_button.send_value(LED_OFF, True) if self._encoder_modes.mode_index < 3: self._encoder_modes.set_enabled(False) self.schedule_message( 1, self._send_midi, SYSEX_START + (32, self._hc_byte, 247)) elif sender is self._fader_group_midi_button: if self._has_faders: hc_byte = self._hc_byte ^ FADERS if hc_byte != self._hc_byte: self._hc_byte = hc_byte self._fader_group_mix_button.send_value(LED_OFF, True) self._fader_group_fx_button.send_value(LED_OFF, True) self._fader_group_mode_button.send_value(LED_OFF, True) if self._fader_modes.mode_index < 2: self._fader_modes.set_enabled(False) self._fader_button_modes.set_enabled(False) self.schedule_message( 1, self._send_midi, SYSEX_START + (32, self._hc_byte, 247)) else: self._display_reset_delay = STANDARD_DISPLAY_DELAY def _hyper_button_value(self, value, sender): if value > 0: if sender is self._drum_group_hyper_button: if self._hc_byte | PADS != self._hc_byte: self._hc_byte = self._hc_byte | PADS self._send_midi(SYSEX_START + (32, self._hc_byte, 247)) self.schedule_message(1, self._set_drum_pads_to_hc) elif sender is self._encoder_group_fx_button or sender is self._encoder_group_mix_button: if self._hc_byte | ENCODERS != self._hc_byte: self._hc_byte = self._hc_byte | ENCODERS self._send_midi(SYSEX_START + (32, self._hc_byte, 247)) self._encoder_group_midi_button.turn_off() if sender is self._encoder_group_fx_button: self._encoder_modes.set_enabled(True) self._display_reset_delay = 0 return else: self.schedule_message(1, self._encoder_modes.set_enabled, True) self.schedule_message(1, self._encoder_modes.update) self._display_reset_delay = 2 return elif sender is self._fader_group_fx_button or sender is self._fader_group_mix_button: if self._hc_byte | FADERS != self._hc_byte: self._hc_byte = self._hc_byte | FADERS self._send_midi(SYSEX_START + (32, self._hc_byte, 247)) self._fader_group_midi_button.turn_off() self._fader_button_modes.set_enabled(True) if sender is self._fader_group_fx_button: self._fader_modes.set_enabled(True) self._fader_button_modes.set_enabled(True) self._display_reset_delay = 0 return else: self.schedule_message(1, self._fader_modes.set_enabled, True) self.schedule_message(1, self._fader_modes.update) self.schedule_message( 1, self._fader_button_modes.set_enabled, True) self.schedule_message(1, self._fader_button_modes.update) self._display_reset_delay = 2 return self._display_reset_delay = 0 def _set_drum_pads_to_hc(self): self._drum_group_midi_button.send_value(LED_OFF, True) self._drum_group_hyper_button.send_value(RED_FULL, True) for index in range(len(self._drum_pads)): self._drum_pads[index].send_value(RED_LOW, True) def _fader_button_value(self, value, sender): self._display_reset_delay = STANDARD_DISPLAY_DELAY def _fader_value(self, value, sender): param = sender.mapped_parameter() if param != None: param_range = param.max - param.min if param.name == 'Track Volume': if sender == self._master_fader: if self._has_faders: name_string = 'Master Vol' else: name_string = self._mixer_for_faders.selected_strip( ).track_name_data_source().display_string() + ' Vol' else: name_string = self._mixer_for_faders.channel_strip( self._faders.index(sender)).track_name_data_source( ).display_string() + ' Vol' else: name_string = param.name value = int((param.value - param.min) / param_range * 127) value_string = str(value) else: name_string = '<unmapped>' value_string = None self.schedule_message(1, self._set_value_string) self._set_name_string(name_string) self._set_value_string(value_string) return def _encoder_value(self, value, sender): param = sender.mapped_parameter() if param != None: param_range = param.max - param.min if param.name == 'Track Volume': name_string = self._mixer_for_encoders.channel_strip( self._encoders.index(sender)).track_name_data_source( ).display_string() + ' Vol' value = int((param.value - param.min) / param_range * 127) elif param.name == 'Track Panning': name_string = self._mixer_for_encoders.channel_strip( self._encoders.index(sender)).track_name_data_source( ).display_string() + ' Pan' value = int(param.value / param_range * 127) if value < 0: name_string += ' L' elif value > 0: name_string += ' R' else: name_string += ' C' else: name_string = param.name value = int((param.value - param.min) / param_range * 127) value_string = str(value) else: name_string = '<unmapped>' value_string = None self.schedule_message(1, self._set_value_string) self._set_name_string(name_string) self._set_value_string(value_string) return def _set_displays_to_default(self): self._name_display.segment(0).set_data_source( self._mixer_for_encoders.selected_strip().track_name_data_source()) self._name_display.update() self._update_bank_value() self._set_value_string(None) self._send_midi(SYSEX_START + LCD_HC_DEFAULT) return def _set_name_string(self, name_string): self._name_display.segment(0).set_data_source( self._name_display_data_source) self._name_display_data_source.set_display_string(name_string) self._display_reset_delay = STANDARD_DISPLAY_DELAY def _set_value_string(self, value_string=None): if value_string != None: self._value_display_data_source.set_display_string(value_string) else: self._value_display.reset() return def _set_bank_string(self, bank_string=None): if bank_string != None: self._bank_display_data_source.set_display_string(bank_string) else: self._bank_display.reset() return def _update_bank_value(self): bank = (self._session.track_offset() + 1) / self._session.width() + 1 self._set_bank_string(str(bank)) def _install_mapping(self, midi_map_handle, control, parameter, feedback_delay, feedback_map): if not self._in_build_midi_map: raise AssertionError raise midi_map_handle != None or AssertionError raise control != None and parameter != None or AssertionError raise isinstance( parameter, Live.DeviceParameter.DeviceParameter) or AssertionError raise isinstance(control, InputControlElement) or AssertionError raise isinstance(feedback_delay, int) or AssertionError if not isinstance(feedback_map, tuple): raise AssertionError success = False feedback_rule = None feedback_rule = control.message_type( ) is MIDI_NOTE_TYPE and Live.MidiMap.NoteFeedbackRule() feedback_rule.note_no = 0 feedback_rule.vel_map = (0, ) elif control.message_type() is MIDI_CC_TYPE: feedback_rule = Live.MidiMap.CCFeedbackRule() feedback_rule.cc_no = 0 feedback_rule.cc_value_map = (0, ) elif control.message_type() is MIDI_PB_TYPE: feedback_rule = Live.MidiMap.PitchBendFeedbackRule() feedback_rule.value_pair_map = feedback_map raise feedback_rule != None or AssertionError feedback_rule.channel = control.message_channel() feedback_rule.delay_in_ms = feedback_delay success = control.message_type( ) is MIDI_NOTE_TYPE and Live.MidiMap.map_midi_note_with_feedback_map( midi_map_handle, parameter, control.message_channel(), control.message_identifier(), feedback_rule) elif control.message_type() is MIDI_CC_TYPE: success = Live.MidiMap.map_midi_cc_with_feedback_map( midi_map_handle, parameter, control.message_channel(), control.message_identifier(), control.message_map_mode(), feedback_rule, not control.needs_takeover()) elif control.message_type() is MIDI_PB_TYPE: success = Live.MidiMap.map_midi_pitchbend_with_feedback_map( midi_map_handle, parameter, control.message_channel(), feedback_rule, not control.needs_takeover()) return success
class AxiomPro(ControlSurface): """ Script for the M-Audio Axiom Pro """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): is_momentary = True self.set_pad_translations(PAD_TRANSLATIONS) self._suggested_input_port = 'HyperControl' self._suggested_output_port = 'HyperControl' self._display_on_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, 15, 79) self._waiting_for_first_response = True mixer1 = DisplayingMixerComponent(0) mixer1.set_select_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 111), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 110)) mixer1.set_mute_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 12)) mixer1.set_solo_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 13)) mixer2 = NotifyingMixerComponent(8) mixer2.set_bank_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 15), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 14)) mixer2.master_strip().set_volume_control(SliderElement(MIDI_CC_TYPE, 15, 41)) for index in range(8): mixer2.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, 15, 33 + index)) device = PageableDeviceComponent(device_selection_follows_track_selection=True) self.set_device_component(device) ffwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 115) rwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 114) loop_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 113) transport = TransportComponent() transport.set_stop_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 116)) transport.set_play_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 117)) transport.set_record_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 118)) session = SessionComponent(0, 0) transport_view_modes = TransportViewModeSelector(transport, session, ffwd_button, rwd_button, loop_button) select_button_modes = SelectButtonModeSelector(mixer2, tuple([ ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 49 + offset) for offset in range(8) ])) select_button_modes.set_mode_toggle(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 57)) self._mixer_encoder_modes = EncoderMixerModeSelector(mixer2) encoders = [] for offset in range(8): encoders.append(PeekableEncoderElement(MIDI_CC_TYPE, 15, 17 + offset, Live.MidiMap.MapMode.relative_smooth_two_compliment)) encoders[-1].set_feedback_delay(-1) mixer_or_device = MixerOrDeviceModeSelector(self._mixer_encoder_modes, device, tuple(encoders), tuple([ ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 74 + offset) for offset in range(4) ])) mixer_or_device.set_mode_toggle(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 109)) mixer_or_device.set_peek_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 78)) self._track_display = PhysicalDisplayElement(8, 1) self._track_display.set_clear_all_message(SYSEX_START + (16, 247)) self._track_display.set_message_parts(SYSEX_START + (17, 1, 0, 0), (247,)) self._track_display.segment(0).set_data_source(mixer1.selected_strip().track_name_data_source()) device_display = PhysicalDisplayElement(8, 1) device_display.set_message_parts(SYSEX_START + (17, 1, 0, 10), (247,)) parameter_display = PhysicalDisplayElement(16, 1) parameter_display.set_message_parts(SYSEX_START + (17, 2, 0, 0), (247,)) select_button_modes.set_mode_display(parameter_display) mixer1.set_display(parameter_display) mixer2.set_bank_display(parameter_display) page_displays = [] for index in range(4): page_displays.append(PhysicalDisplayElement(5, 1)) page_displays[-1].set_message_parts(SYSEX_START + (17, 4, index, 0), (247,)) encoder_display = PhysicalDisplayElement(80, 8) encoder_display.set_message_parts(SYSEX_START + (17, 3), (247,)) for index in range(8): pos_id = tuple() if index != 0: pos_id += (0,) if index > 3: pos_id += (index % 4, 13) else: pos_id += (index % 4, 0) encoder_display.segment(index).set_position_identifier(pos_id) mixer_or_device.set_displays(encoder_display, parameter_display, device_display, tuple(page_displays)) for component in self.components: component.set_enabled(False) def refresh_state(self): ControlSurface.refresh_state(self) self._waiting_for_first_response = True self.schedule_message(10, self._send_midi, SYSEX_START + (32, 46, 247)) def handle_sysex(self, midi_bytes): if midi_bytes[0:-2] == SYSEX_START + (32,): msg_id_byte = midi_bytes[-2] is_setup_response = msg_id_byte in (46, 38) has_sliders = msg_id_byte == 46 if is_setup_response: if self._waiting_for_first_response: self._waiting_for_first_response = False self._display_on_button.send_value(0) for component in self.components: component.set_enabled(True) self._display_on_button.send_value(127) self._send_midi(SYSEX_START + (16, 247)) self._send_midi(SYSEX_START + (17, 3, 0, 1, 65, 98, 108, 101, 116, 111, 110, 32, 76, 105, 118, 101, 32, 67, 111, 110, 116, 114, 111, 108, 32, 0, 1, 4, 83, 117, 114, 102, 97, 99, 101, 32, 118, 49, 46, 48, 46, 48, 46, 247)) self._mixer_encoder_modes.set_show_volume_page(not has_sliders) for display in self._displays: display.set_block_messages(False) self.schedule_message(25, self._refresh_displays) elif msg_id_byte == 43: self._send_midi(SYSEX_START + (16, 247)) for display in self._displays: if display is self._track_display: display.update() else: display.set_block_messages(True) def disconnect(self): ControlSurface.disconnect(self) self._send_midi(SYSEX_START + (32, 0, 247)) self._send_midi(SYSEX_START + (16, 247)) self._send_midi(SYSEX_START + (17, 3, 0, 4, 65, 98, 108, 101, 116, 111, 110, 32, 76, 105, 118, 101, 32, 67, 111, 110, 116, 114, 111, 108, 32, 0, 1, 4, 83, 117, 114, 102, 97, 99, 101, 32, 67, 108, 111, 115, 101, 100, 46, 247))
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 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()
def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): is_momentary = True self._device_selection_follows_track_selection = True self.set_pad_translations(PAD_TRANSLATIONS) self._suggested_input_port = 'HyperControl' self._suggested_output_port = 'HyperControl' self._display_on_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, 15, 79) self._waiting_for_first_response = True mixer1 = DisplayingMixerComponent(0) mixer1.set_select_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 111), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 110)) mixer1.set_mute_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 12)) mixer1.set_solo_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 13)) mixer2 = NotifyingMixerComponent(8) mixer2.set_bank_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 15), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 14)) mixer2.master_strip().set_volume_control(SliderElement(MIDI_CC_TYPE, 15, 41)) for index in range(8): mixer2.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, 15, 33 + index)) device = PageableDeviceComponent() self.set_device_component(device) ffwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 115) rwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 114) loop_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 113) transport = TransportComponent() transport.set_stop_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 116)) transport.set_play_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 117)) transport.set_record_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 118)) session = SessionComponent(0, 0) transport_view_modes = TransportViewModeSelector(transport, session, ffwd_button, rwd_button, loop_button) select_button_modes = SelectButtonModeSelector(mixer2, tuple([ ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 49 + offset) for offset in range(8) ])) select_button_modes.set_mode_toggle(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 57)) self._mixer_encoder_modes = EncoderMixerModeSelector(mixer2) encoders = [] for offset in range(8): encoders.append(PeekableEncoderElement(MIDI_CC_TYPE, 15, 17 + offset, Live.MidiMap.MapMode.relative_smooth_two_compliment)) encoders[-1].set_feedback_delay(-1) mixer_or_device = MixerOrDeviceModeSelector(self._mixer_encoder_modes, device, tuple(encoders), tuple([ ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 74 + offset) for offset in range(4) ])) mixer_or_device.set_mode_toggle(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 109)) mixer_or_device.set_peek_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 78)) self._track_display = PhysicalDisplayElement(8, 1) self._track_display.set_clear_all_message(SYSEX_START + (16, 247)) self._track_display.set_message_parts(SYSEX_START + (17, 1, 0, 0), (247,)) self._track_display.segment(0).set_data_source(mixer1.selected_strip().track_name_data_source()) device_display = PhysicalDisplayElement(8, 1) device_display.set_message_parts(SYSEX_START + (17, 1, 0, 10), (247,)) parameter_display = PhysicalDisplayElement(16, 1) parameter_display.set_message_parts(SYSEX_START + (17, 2, 0, 0), (247,)) select_button_modes.set_mode_display(parameter_display) mixer1.set_display(parameter_display) mixer2.set_bank_display(parameter_display) page_displays = [] for index in range(4): page_displays.append(PhysicalDisplayElement(5, 1)) page_displays[-1].set_message_parts(SYSEX_START + (17, 4, index, 0), (247,)) encoder_display = PhysicalDisplayElement(80, 8) encoder_display.set_message_parts(SYSEX_START + (17, 3), (247,)) for index in range(8): pos_id = tuple() if index != 0: pos_id += (0,) if index > 3: pos_id += (index % 4, 13) else: pos_id += (index % 4, 0) encoder_display.segment(index).set_position_identifier(pos_id) mixer_or_device.set_displays(encoder_display, parameter_display, device_display, tuple(page_displays)) for component in self.components: component.set_enabled(False)
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 Axiom_AIR_25_49_61(ControlSurface): """ Script for the M-Audio Axiom A.I.R. 25, 49 and 61 """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) self._alt_device_component = None with self.component_guard(): self.set_pad_translations(PAD_TRANSLATIONS) self._device_selection_follows_track_selection = True self._suggested_input_port = "HyperControl" self._suggested_output_port = "HyperControl" self._single_fader_button_modes = None self._has_faders = True self._display_reset_delay = -1 self._hc_byte = HC_BYTE self._waiting_for_first_response = True self._setup_controls() self._setup_displays() self._setup_mixer() self._setup_session() self._setup_transport() self._setup_device() self._setup_modes() self._drum_group_midi_button = None self._drum_group_hyper_button = None for component in self.components: component.set_enabled(False) def disconnect(self): self._scheduled_messages = [] for encoder in self._encoders: encoder.remove_value_listener(self._encoder_value) for fader in self._faders: fader.remove_value_listener(self._fader_value) for fader_button in self._fader_buttons: fader_button.remove_value_listener(self._fader_button_value) self._master_fader.remove_value_listener(self._fader_value) self._master_fader_button.remove_value_listener(self._fader_button_value) self._select_button.remove_value_listener(self._select_button_value) self._identify_button.remove_value_listener(self._identify_value) self._fader_group_midi_button.remove_value_listener(self._midi_button_value) self._fader_group_mix_button.remove_value_listener(self._hyper_button_value) self._fader_group_fx_button.remove_value_listener(self._hyper_button_value) self._encoder_group_midi_button.remove_value_listener(self._midi_button_value) self._encoder_group_mix_button.remove_value_listener(self._hyper_button_value) self._encoder_group_fx_button.remove_value_listener(self._hyper_button_value) if self._drum_group_midi_button != None: self._drum_group_midi_button.remove_value_listener(self._midi_button_value) if self._drum_group_hyper_button != None: self._drum_group_hyper_button.remove_value_listener(self._hyper_button_value) self._alt_device_component = None self._name_display = None self._value_display = None self._bank_display = None self._pad_display = None self._name_display_data_source = None self._value_display_data_source = None self._bank_display_data_source = None self._pad_display_data_source = None self._select_button = None self._left_button = None self._right_button = None self._up_button = None self._down_button = None self._loop_button = None self._ffwd_button = None self._rwd_button = None self._play_button = None self._stop_button = None self._rec_button = None self._master_fader_button = None self._fader_buttons = None self._faders = None self._encoders = None self._drum_pads = None self._identify_button = None self._main_group_hyper_button = None self._main_group_track_button = None self._main_group_fx_button = None self._encoder_group_midi_button = None self._encoder_group_mix_button = None self._encoder_group_fx_button = None self._fader_group_mode_button = None self._fader_group_midi_button = None self._fader_group_mix_button = None self._fader_group_fx_button = None self._drum_group_midi_button = None self._drum_group_roll_button = None self._drum_group_hyper_button = None self._mixer_for_encoders = None self._mixer_for_faders = None self._device_for_encoders = None self._device_for_faders = None self._transport = None self._session = None ControlSurface.disconnect(self) self._send_midi(SYSEX_START + DISABLE_HYPERCONTROL) 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:10] == AXIOM_AIR_RESPONSE: if midi_bytes[12:15] < AXIOM_REV4_RESPONSE: self.schedule_message(1, self._send_midi, SYSEX_START + ENGAGE_HYPERCONTROL) self.schedule_message(2, self._send_midi, SYSEX_START + CLEAR_ALL) self.schedule_message(3, self._name_display.display_message, "Firmware") self.schedule_message(13, self._name_display.display_message, "Update") self.schedule_message(23, self._name_display.display_message, "Required") self.schedule_message(33, self._send_midi, SYSEX_START + DISABLE_HYPERCONTROL) elif midi_bytes[12:15] >= AXIOM_REV4_RESPONSE: if self._waiting_for_first_response == True: self._waiting_for_first_response = False self._has_faders = midi_bytes[10] != 50 self.schedule_message(1, self._send_midi, SYSEX_START + ENGAGE_HYPERCONTROL) self.schedule_message(2, self._send_midi, SYSEX_START + SPECIAL_HYPERCONTROL) self.schedule_message(3, self._complete_setup) else: self._display_reset_delay = 0 elif midi_bytes[0:8] == REQUEST_HYPERCONTROL: self.schedule_message(5, self._send_midi, IDENTITY_REQUEST) 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._set_displays_to_default() def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(self) self._display_reset_delay = 0 def restore_bank(self, bank_index): ControlSurface.restore_bank(self, bank_index) if self._alt_device_component != None: self._alt_device_component.restore_bank(bank_index) def set_appointed_device(self, device): ControlSurface.set_appointed_device(self, device) with self.component_guard(): if self._alt_device_component != None: self._alt_device_component.set_device(device) def set_alt_device_component(self, device_component): self._alt_device_component = device_component def _update_device_selection(self): track = self.song().view.selected_track device_to_select = track.view.selected_device if device_to_select == None and len(track.devices) > 0: device_to_select = track.devices[0] if device_to_select != None: self.song().view.select_device(device_to_select) self._device_component.set_device(device_to_select) if self._alt_device_component != None: self._alt_device_component.set_device(device_to_select) def _setup_controls(self): self._left_button = create_button(99, "Left_Button") self._right_button = create_button(100, "Right_Button") self._up_button = create_button(101, "Up_Button") self._down_button = create_button(102, "Down_Button") self._loop_button = create_button(113, "Loop_Button") self._rwd_button = create_button(114, "Rwd_Button") self._ffwd_button = create_button(115, "FFwd_Button") self._stop_button = create_button(116, "Stop_Button") self._play_button = create_button(117, "Play_Button") self._rec_button = create_button(118, "Record_Button") self._select_button = ConfigurableButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, GLOBAL_CHANNEL, 98) self._select_button.name = "Select_Button" self._select_button.add_value_listener(self._select_button_value) self._main_group_hyper_button = create_configurable_button(104, "Fader_Group_HyperControl_Button", 2, 14) self._main_group_track_button = create_configurable_button(105, "Main_Group_Track_Button", 2, 11) self._main_group_fx_button = create_configurable_button(106, "Main_Group_Inst_FX_Button", 2, 11) self._identify_button = create_configurable_button(97, "Identify_Button", 2, 16) self._identify_button.add_value_listener(self._identify_value) self._fader_buttons = [] for index in range(8): self._fader_buttons.append(create_configurable_button(49 + index, "Fader_Button_%d" % index)) self._fader_buttons[-1].add_value_listener(self._fader_button_value, identify_sender=True) self._faders = [] for index in range(8): self._faders.append(create_slider(33 + index, "Fader_%d" % index)) self._faders[-1].add_value_listener(self._fader_value, identify_sender=True) self._master_fader_button = create_configurable_button(57, "Master_Fader_Button") self._master_fader_button.add_value_listener(self._fader_button_value, identify_sender=True) self._master_fader = create_slider(41, "Master_Fader") self._master_fader.add_value_listener(self._fader_value, identify_sender=True) self._fader_group_mode_button = create_configurable_button(61, "Fader_Group_Mode_Button") self._fader_group_midi_button = create_configurable_button(60, "Fader_Group_MIDI_Button") self._fader_group_midi_button.add_value_listener(self._midi_button_value, identify_sender=True) self._fader_group_mix_button = create_configurable_button(58, "Fader_Group_Mix_Button", 0, 1) self._fader_group_mix_button.add_value_listener(self._hyper_button_value, identify_sender=True) self._fader_group_fx_button = create_configurable_button(59, "Fader_Group_Inst_FX_Button", 0, -1) self._fader_group_fx_button.add_value_listener(self._hyper_button_value, identify_sender=True) self._encoders = [] for index in range(8): self._encoders.append(create_encoder(17 + index, "Encoder_%d" % index)) self._encoders[-1].add_value_listener(self._encoder_value, identify_sender=True) self._encoder_group_midi_button = create_configurable_button(27, "Encoder_Group_MIDI_Button", 0, 72) self._encoder_group_midi_button.add_value_listener(self._midi_button_value, identify_sender=True) self._encoder_group_mix_button = create_configurable_button(25, "Encoder_Group_Mix_Button", 0, 72) self._encoder_group_mix_button.add_value_listener(self._hyper_button_value, identify_sender=True) self._encoder_group_fx_button = create_configurable_button(26, "Encoder_Group_Inst_FX_Button", 0, 72) self._encoder_group_fx_button.add_value_listener(self._hyper_button_value, identify_sender=True) def _setup_drum_pads(self): self._drum_pads = [] num_pads = 12 if self._has_faders else 16 for index in range(8): self._drum_pads.append(create_configurable_button(81 + index, "Pad_%d" % index, 0, 0, MIDI_CC_TYPE)) for index in range(num_pads - 8): self._drum_pads.append( ConfigurableButtonElement( IS_MOMENTARY, MIDI_NOTE_TYPE, GLOBAL_CHANNEL - 1, 81 + index, GLOBAL_SEND_CHANNEL, 8, MIDI_CC_TYPE ) ) self._drum_pads[-1].name = "Pad_" + str(index + 8) self._drum_group_midi_button = create_configurable_button(91, "Drum_Group_MIDI_Button", 2, -2) self._drum_group_midi_button.add_value_listener(self._midi_button_value, identify_sender=True) self._drum_group_roll_button = create_configurable_button(90, "Drum_Group_Roll_Button", -1) self._drum_group_hyper_button = create_configurable_button(89, "Drum_Group_HyperControl_Button", 2, 2) self._drum_group_hyper_button.add_value_listener(self._hyper_button_value, identify_sender=True) def _setup_displays(self): self._name_display = PhysicalDisplayElement(12, 1) self._name_display.name = "Name_Display" self._name_display.set_message_parts(SYSEX_START + (21,), (0, 247)) self._name_display.set_clear_all_message(CLEAR_NAME) self._name_display_data_source = DisplayDataSource() self._name_display.segment(0).set_data_source(self._name_display_data_source) self._value_display = NumericalDisplayElement(3, 1) self._value_display.name = "Value_Display" self._value_display.set_message_parts(SYSEX_START + (20, 48), (0, 247)) self._value_display.set_clear_all_message(CLEAR_VALUE) self._value_display_data_source = DisplayDataSource() self._value_display.segment(0).set_data_source(self._value_display_data_source) self._bank_display = NumericalDisplayElement(3, 1) self._bank_display.name = "Bank_Display" self._bank_display.set_message_parts(SYSEX_START + (19,), (0, 247)) self._bank_display.set_clear_all_message(CLEAR_BANK) self._bank_display_data_source = DisplayDataSource() self._bank_display.segment(0).set_data_source(self._bank_display_data_source) self._pad_display = NumericalDisplayElement(2, 1) self._pad_display.name = "Pad_Display" self._pad_display.set_message_parts(SYSEX_START + (18,), (0, 247)) self._pad_display.set_clear_all_message(CLEAR_PAD) self._pad_display_data_source = DisplayDataSource() self._pad_display.segment(0).set_data_source(self._pad_display_data_source) def _setup_mixer(self): self._mixer_for_encoders = SpecialMixerComponent(self._name_display, self._value_display, 8) self._mixer_for_encoders.name = "Mixer_for_encoders" self._mixer_for_faders = SpecialMixerComponent(self._name_display, self._value_display, 8) self._mixer_for_faders.name = "Mixer_for_faders" def _setup_session(self): self._session = SpecialSessionComponent(8, 0) self._session.name = "Session_Control" self._session.selected_scene().name = "Selected_Scene" self._session.set_mixer(self._mixer_for_encoders) self._session.set_alt_mixer(self._mixer_for_faders) self._session.add_offset_listener(self._update_bank_value) def _setup_transport(self): self._transport = TransportComponent() self._transport.name = "Transport" self._transport.set_stop_button(self._stop_button) self._transport.set_play_button(self._play_button) self._transport.set_record_button(self._rec_button) transport_view_modes = TransportViewModeSelector( self._transport, self._session, self._ffwd_button, self._rwd_button, self._loop_button ) transport_view_modes.name = "Transport_View_Modes" def _setup_device(self): self._device_for_encoders = BestBankDeviceComponent() self._device_for_encoders.name = "Device_Component_for_encoders" self._device_for_faders = BestBankDeviceComponent() self._device_for_faders.name = "Device_Component_for_faders" self.set_device_component(self._device_for_encoders) self.set_alt_device_component(self._device_for_faders) self._device_nav = DeviceNavComponent() self._device_nav.name = "Device_Nav_Component" def _setup_modes(self): self._fader_button_modes = FaderButtonModeSelector(self._mixer_for_faders, tuple(self._fader_buttons)) self._fader_button_modes.name = "Fader_Button_Modes" self._fader_button_modes.set_mode_toggle(self._fader_group_mode_button) self._fader_modes = FaderModeSelector( self._mixer_for_faders, self._device_for_faders, tuple(self._faders), self._fader_button_modes, self._master_fader_button, ) self._fader_modes.name = "Fader_Modes" self._fader_modes.set_mode_buttons((self._fader_group_mix_button, self._fader_group_fx_button)) self._encoder_modes = EncoderModeSelector( self._mixer_for_encoders, self._device_for_encoders, tuple(self._encoders) ) self._encoder_modes.name = "Encoder_Modes" self._encoder_modes.set_mode_buttons((self._encoder_group_mix_button, self._encoder_group_fx_button)) main_modes = MainModeSelector( self._device_for_encoders, self._device_for_faders, self._session, self._mixer_for_faders, self._device_nav, self._up_button, self._down_button, self._left_button, self._right_button, self._select_button, ) main_modes.name = "Main_Modes" main_modes.set_mode_buttons((self._main_group_track_button, self._main_group_fx_button)) def _setup_master_fader(self): if self._has_faders: self._mixer_for_encoders.master_strip().set_volume_control(self._master_fader) else: self._mixer_for_encoders.selected_strip().set_volume_control(self._master_fader) def _setup_single_fader_button_modes(self): self._single_fader_button_modes = SingleFaderButtonModeSelector( self._mixer_for_encoders, self._fader_group_midi_button ) self._single_fader_button_modes.name = "Single_Fader_Button_Modes" self._single_fader_button_modes.set_mode_toggle(self._fader_group_mode_button) def _complete_setup(self): self._setup_drum_pads() self._set_drum_pads_to_hc() self._setup_master_fader() if not self._has_faders: self._setup_single_fader_button_modes() for control in self.controls: if isinstance(control, InputControlElement): control.clear_send_cache() for component in self.components: component.set_enabled(True) self._fader_group_midi_button.send_value(LED_OFF, True) self._encoder_group_midi_button.send_value(LED_OFF, True) self._main_group_hyper_button.send_value(AMB_FULL, True) self.request_rebuild_midi_map() self._on_selected_track_changed() self.schedule_message(1, self._show_startup_message) def _show_startup_message(self): self._send_midi(SYSEX_START + CLEAR_ALL) self._name_display.display_message("Ableton Live") self._display_reset_delay = INITIAL_DISPLAY_DELAY def _select_button_value(self, value): self._display_reset_delay = STANDARD_DISPLAY_DELAY def _identify_value(self, value): for encoder in self._encoders: encoder.set_identify_mode(value > 0) for fader in self._faders: fader.set_identify_mode(value > 0) self._master_fader.set_identify_mode(value > 0) self._display_reset_delay = 0 self._identify_button.turn_on() if value > 0 else self._identify_button.turn_off() def _midi_button_value(self, value, sender): if value > 0: if sender is self._drum_group_midi_button: hc_byte = self._hc_byte ^ PADS if hc_byte != self._hc_byte: self._hc_byte = hc_byte self._drum_group_hyper_button.send_value(LED_OFF, True) self.schedule_message(1, self._send_midi, SYSEX_START + (32, self._hc_byte, 247)) elif sender is self._encoder_group_midi_button: hc_byte = self._hc_byte ^ ENCODERS if hc_byte != self._hc_byte: self._hc_byte = hc_byte self._encoder_group_mix_button.send_value(LED_OFF, True) self._encoder_group_fx_button.send_value(LED_OFF, True) if self._encoder_modes.mode_index < 3: self._encoder_modes.set_enabled(False) self.schedule_message(1, self._send_midi, SYSEX_START + (32, self._hc_byte, 247)) elif sender is self._fader_group_midi_button: if self._has_faders: hc_byte = self._hc_byte ^ FADERS if hc_byte != self._hc_byte: self._hc_byte = hc_byte self._fader_group_mix_button.send_value(LED_OFF, True) self._fader_group_fx_button.send_value(LED_OFF, True) self._fader_group_mode_button.send_value(LED_OFF, True) if self._fader_modes.mode_index < 2: self._fader_modes.set_enabled(False) self._fader_button_modes.set_enabled(False) self.schedule_message(1, self._send_midi, SYSEX_START + (32, self._hc_byte, 247)) else: self._display_reset_delay = STANDARD_DISPLAY_DELAY def _hyper_button_value(self, value, sender): if value > 0: if sender is self._drum_group_hyper_button: if self._hc_byte | PADS != self._hc_byte: self._hc_byte = self._hc_byte | PADS self._send_midi(SYSEX_START + (32, self._hc_byte, 247)) self.schedule_message(1, self._set_drum_pads_to_hc) elif sender is self._encoder_group_fx_button or sender is self._encoder_group_mix_button: if self._hc_byte | ENCODERS != self._hc_byte: self._hc_byte = self._hc_byte | ENCODERS self._send_midi(SYSEX_START + (32, self._hc_byte, 247)) self._encoder_group_midi_button.turn_off() if sender is self._encoder_group_fx_button: self._encoder_modes.set_enabled(True) self._display_reset_delay = 0 return else: self.schedule_message(1, self._encoder_modes.set_enabled, True) self.schedule_message(1, self._encoder_modes.update) self._display_reset_delay = 2 return elif sender is self._fader_group_fx_button or sender is self._fader_group_mix_button: if self._hc_byte | FADERS != self._hc_byte: self._hc_byte = self._hc_byte | FADERS self._send_midi(SYSEX_START + (32, self._hc_byte, 247)) self._fader_group_midi_button.turn_off() self._fader_button_modes.set_enabled(True) if sender is self._fader_group_fx_button: self._fader_modes.set_enabled(True) self._fader_button_modes.set_enabled(True) self._display_reset_delay = 0 return else: self.schedule_message(1, self._fader_modes.set_enabled, True) self.schedule_message(1, self._fader_modes.update) self.schedule_message(1, self._fader_button_modes.set_enabled, True) self.schedule_message(1, self._fader_button_modes.update) self._display_reset_delay = 2 return self._display_reset_delay = 0 def _set_drum_pads_to_hc(self): self._drum_group_midi_button.send_value(LED_OFF, True) self._drum_group_hyper_button.send_value(RED_FULL, True) for index in range(len(self._drum_pads)): self._drum_pads[index].send_value(RED_LOW, True) def _fader_button_value(self, value, sender): self._display_reset_delay = STANDARD_DISPLAY_DELAY def _fader_value(self, value, sender): param = sender.mapped_parameter() if param != None: param_range = param.max - param.min if param.name == "Track Volume": if sender == self._master_fader: if self._has_faders: name_string = "Master Vol" else: name_string = ( self._mixer_for_faders.selected_strip().track_name_data_source().display_string() + " Vol" ) else: name_string = ( self._mixer_for_faders.channel_strip(self._faders.index(sender)) .track_name_data_source() .display_string() + " Vol" ) else: name_string = param.name value = int((param.value - param.min) / param_range * 127) value_string = str(value) else: name_string = "<unmapped>" value_string = None self.schedule_message(1, self._set_value_string) self._set_name_string(name_string) self._set_value_string(value_string) def _encoder_value(self, value, sender): param = sender.mapped_parameter() if param != None: param_range = param.max - param.min if param.name == "Track Volume": name_string = ( self._mixer_for_encoders.channel_strip(self._encoders.index(sender)) .track_name_data_source() .display_string() + " Vol" ) value = int((param.value - param.min) / param_range * 127) elif param.name == "Track Panning": name_string = ( self._mixer_for_encoders.channel_strip(self._encoders.index(sender)) .track_name_data_source() .display_string() + " Pan" ) value = int(param.value / param_range * 127) if value < 0: name_string += " L" elif value > 0: name_string += " R" else: name_string += " C" else: name_string = param.name value = int((param.value - param.min) / param_range * 127) value_string = str(value) else: name_string = "<unmapped>" value_string = None self.schedule_message(1, self._set_value_string) self._set_name_string(name_string) self._set_value_string(value_string) def _set_displays_to_default(self): self._name_display.segment(0).set_data_source( self._mixer_for_encoders.selected_strip().track_name_data_source() ) self._name_display.update() self._update_bank_value() self._set_value_string(None) self._send_midi(SYSEX_START + LCD_HC_DEFAULT) def _set_name_string(self, name_string): self._name_display.segment(0).set_data_source(self._name_display_data_source) self._name_display_data_source.set_display_string(name_string) self._display_reset_delay = STANDARD_DISPLAY_DELAY def _set_value_string(self, value_string=None): if value_string != None: self._value_display_data_source.set_display_string(value_string) else: self._value_display.reset() def _set_bank_string(self, bank_string=None): if bank_string != None: self._bank_display_data_source.set_display_string(bank_string) else: self._bank_display.reset() def _update_bank_value(self): bank = (self._session.track_offset() + 1) / self._session.width() + 1 self._set_bank_string(str(bank)) def _install_mapping(self, midi_map_handle, control, parameter, feedback_delay, feedback_map): if not self._in_build_midi_map: raise AssertionError raise midi_map_handle != None or AssertionError raise control != None and parameter != None or AssertionError raise isinstance(parameter, Live.DeviceParameter.DeviceParameter) or AssertionError raise isinstance(control, InputControlElement) or AssertionError raise isinstance(feedback_delay, int) or AssertionError if not isinstance(feedback_map, tuple): raise AssertionError success = False feedback_rule = None feedback_rule = control.message_type() is MIDI_NOTE_TYPE and Live.MidiMap.NoteFeedbackRule() feedback_rule.note_no = 0 feedback_rule.vel_map = (0,) elif control.message_type() is MIDI_CC_TYPE: feedback_rule = Live.MidiMap.CCFeedbackRule() feedback_rule.cc_no = 0 feedback_rule.cc_value_map = (0,) elif control.message_type() is MIDI_PB_TYPE: feedback_rule = Live.MidiMap.PitchBendFeedbackRule() feedback_rule.value_pair_map = feedback_map raise feedback_rule != None or AssertionError feedback_rule.channel = control.message_channel() feedback_rule.delay_in_ms = feedback_delay success = control.message_type() is MIDI_NOTE_TYPE and Live.MidiMap.map_midi_note_with_feedback_map( midi_map_handle, parameter, control.message_channel(), control.message_identifier(), feedback_rule ) elif control.message_type() is MIDI_CC_TYPE: success = Live.MidiMap.map_midi_cc_with_feedback_map( midi_map_handle, parameter, control.message_channel(), control.message_identifier(), control.message_map_mode(), feedback_rule, not control.needs_takeover(), ) elif control.message_type() is MIDI_PB_TYPE: success = Live.MidiMap.map_midi_pitchbend_with_feedback_map( midi_map_handle, parameter, control.message_channel(), feedback_rule, not control.needs_takeover() ) return success
class AxiomPro(ControlSurface): """ Script for the M-Audio Axiom Pro """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): is_momentary = True self._device_selection_follows_track_selection = True self.set_pad_translations(PAD_TRANSLATIONS) self._suggested_input_port = 'HyperControl' self._suggested_output_port = 'HyperControl' self._display_on_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, 15, 79) self._waiting_for_first_response = True mixer1 = DisplayingMixerComponent(0) mixer1.set_select_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 111), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 110)) mixer1.set_mute_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 12)) mixer1.set_solo_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 13)) mixer2 = NotifyingMixerComponent(8) mixer2.set_bank_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 15), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 14)) mixer2.master_strip().set_volume_control(SliderElement(MIDI_CC_TYPE, 15, 41)) for index in range(8): mixer2.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, 15, 33 + index)) device = PageableDeviceComponent() self.set_device_component(device) ffwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 115) rwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 114) loop_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 113) transport = TransportComponent() transport.set_stop_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 116)) transport.set_play_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 117)) transport.set_record_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 118)) session = SessionComponent(0, 0) transport_view_modes = TransportViewModeSelector(transport, session, ffwd_button, rwd_button, loop_button) select_button_modes = SelectButtonModeSelector(mixer2, tuple([ ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 49 + offset) for offset in range(8) ])) select_button_modes.set_mode_toggle(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 57)) self._mixer_encoder_modes = EncoderMixerModeSelector(mixer2) encoders = [] for offset in range(8): encoders.append(PeekableEncoderElement(MIDI_CC_TYPE, 15, 17 + offset, Live.MidiMap.MapMode.relative_smooth_two_compliment)) encoders[-1].set_feedback_delay(-1) mixer_or_device = MixerOrDeviceModeSelector(self._mixer_encoder_modes, device, tuple(encoders), tuple([ ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 74 + offset) for offset in range(4) ])) mixer_or_device.set_mode_toggle(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 109)) mixer_or_device.set_peek_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 78)) self._track_display = PhysicalDisplayElement(8, 1) self._track_display.set_clear_all_message(SYSEX_START + (16, 247)) self._track_display.set_message_parts(SYSEX_START + (17, 1, 0, 0), (247,)) self._track_display.segment(0).set_data_source(mixer1.selected_strip().track_name_data_source()) device_display = PhysicalDisplayElement(8, 1) device_display.set_message_parts(SYSEX_START + (17, 1, 0, 10), (247,)) parameter_display = PhysicalDisplayElement(16, 1) parameter_display.set_message_parts(SYSEX_START + (17, 2, 0, 0), (247,)) select_button_modes.set_mode_display(parameter_display) mixer1.set_display(parameter_display) mixer2.set_bank_display(parameter_display) page_displays = [] for index in range(4): page_displays.append(PhysicalDisplayElement(5, 1)) page_displays[-1].set_message_parts(SYSEX_START + (17, 4, index, 0), (247,)) encoder_display = PhysicalDisplayElement(80, 8) encoder_display.set_message_parts(SYSEX_START + (17, 3), (247,)) for index in range(8): pos_id = tuple() if index != 0: pos_id += (0,) if index > 3: pos_id += (index % 4, 13) else: pos_id += (index % 4, 0) encoder_display.segment(index).set_position_identifier(pos_id) mixer_or_device.set_displays(encoder_display, parameter_display, device_display, tuple(page_displays)) for component in self.components: component.set_enabled(False) def refresh_state(self): ControlSurface.refresh_state(self) self._waiting_for_first_response = True self.schedule_message(10, self._send_midi, SYSEX_START + (32, 46, 247)) def handle_sysex(self, midi_bytes): if midi_bytes[0:-2] == SYSEX_START + (32,): msg_id_byte = midi_bytes[-2] is_setup_response = msg_id_byte in (46, 38) has_sliders = msg_id_byte == 46 if is_setup_response: if self._waiting_for_first_response: self._waiting_for_first_response = False self._display_on_button.send_value(0) for component in self.components: component.set_enabled(True) self._display_on_button.send_value(127) self._send_midi(SYSEX_START + (16, 247)) self._send_midi(SYSEX_START + (17, 3, 0, 1, 65, 98, 108, 101, 116, 111, 110, 32, 76, 105, 118, 101, 32, 67, 111, 110, 116, 114, 111, 108, 32, 0, 1, 4, 83, 117, 114, 102, 97, 99, 101, 32, 118, 49, 46, 48, 46, 48, 46, 247)) self._mixer_encoder_modes.set_show_volume_page(not has_sliders) for display in self._displays: display.set_block_messages(False) self.schedule_message(25, self._refresh_displays) elif msg_id_byte == 43: self._send_midi(SYSEX_START + (16, 247)) for display in self._displays: if display is self._track_display: display.update() else: display.set_block_messages(True) def disconnect(self): ControlSurface.disconnect(self) self._send_midi(SYSEX_START + (32, 0, 247)) self._send_midi(SYSEX_START + (16, 247)) self._send_midi(SYSEX_START + (17, 3, 0, 4, 65, 98, 108, 101, 116, 111, 110, 32, 76, 105, 118, 101, 32, 67, 111, 110, 116, 114, 111, 108, 32, 0, 1, 4, 83, 117, 114, 102, 97, 99, 101, 32, 67, 108, 111, 115, 101, 100, 46, 247))
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()
def __init__(self, *a, **k): #super(Axiom_OJI, self).__init__(*a, **k) ControlSurface.__init__(self, *a, **k) with self.component_guard(): is_momentary = True #self.set_pad_translations(PAD_TRANSLATIONS) self._suggested_input_port = u'HyperControl' self._suggested_output_port = u'HyperControl' self._display_on_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, 15, 79) self._waiting_for_first_response = True self._mixer1 = DisplayingMixerComponent(0) self._mixer1.set_select_buttons( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 111), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 110)) self._mixer1.set_mute_button( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 12)) self._mixer1.set_solo_button( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 13)) self._mixer2 = NotifyingMixerComponent(8) self._mixer2.set_bank_buttons( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 15), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 14)) self._mixer2.master_strip().set_volume_control( SliderElement(MIDI_CC_TYPE, 15, 41)) for index in range(8): self._mixer2.channel_strip(index).set_volume_control( SliderElement(MIDI_CC_TYPE, 15, 33 + index)) self._device = PageableDeviceComponent( device_selection_follows_track_selection=True) self.set_device_component(self._device) self._ffwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 115) self._rwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 114) self._loop_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 113) self._transport = TransportComponent() self._transport.set_stop_button( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 116)) self._transport.set_play_button( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 117)) self._transport.set_record_button( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 118, name='RecordButton')) self._session = SessionComponent(0, 0) self._transport_view_modes = TransportViewModeSelector( self._transport, self._session, self._ffwd_button, self._rwd_button, self._loop_button) self._select_button_modes = SelectButtonModeSelector( self._mixer2, tuple([ ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 49 + offset) for offset in range(8) ])) self._select_button_modes.set_mode_toggle( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 57)) self._mixer_encoder_modes = EncoderMixerModeSelector(self._mixer2) self._encoders = [] for offset in range(8): self._encoders.append( PeekableEncoderElement( MIDI_CC_TYPE, 15, 17 + offset, Live.MidiMap.MapMode.relative_smooth_two_compliment)) self._encoders[-1].set_feedback_delay(-1) self._mixer_or_device = MixerOrDeviceModeSelector( self._mixer_encoder_modes, self._device, tuple(self._encoders), tuple([ ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 74 + offset) for offset in range(4) ])) self._mixer_or_device.set_mode_toggle( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 109)) self._mixer_or_device.set_peek_button( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 78)) self._track_display = PhysicalDisplayElement(8, 1) self._track_display.set_clear_all_message(SYSEX_START + (16, 247)) self._track_display.set_message_parts(SYSEX_START + (17, 1, 0, 0), (247, )) #self._track_display.segment(0).set_data_source(mixer1.selected_strip().track_name_data_source()) self._device_display = PhysicalDisplayElement(8, 1) self._device_display.set_message_parts( SYSEX_START + (17, 1, 0, 10), (247, )) self._parameter_display = PhysicalDisplayElement(16, 1) self._parameter_display.set_message_parts( SYSEX_START + (17, 2, 0, 0), (247, )) #self._select_button_modes.set_mode_display(parameter_display) #self._mixer1.set_display(parameter_display) #self._mixer2.set_bank_display(parameter_display) self._page_displays = [] for index in range(4): self._page_displays.append(PhysicalDisplayElement(5, 1)) self._page_displays[-1].set_message_parts( SYSEX_START + (17, 4, index, 0), (247, )) self._encoder_display = PhysicalDisplayElement(80, 8) self._encoder_display.set_message_parts(SYSEX_START + (17, 3), (247, )) for index in range(8): pos_id = tuple() if index != 0: pos_id += (0, ) if index > 3: pos_id += (index % 4, 13) else: pos_id += (index % 4, 0) self._encoder_display.segment(index).set_position_identifier( pos_id) self._data_sources = [ DisplayDataSource(' ') for index in range(7) ] top_display = PhysicalDisplayElement(20, 1) top_display.set_message_parts(SYSEX_START + (17, 1, 0, 0), (247, )) top_display.set_clear_all_message(SYSEX_START + (16, 247)) self._header_display = top_display self._display1 = top_display.segment(0) long_display = PhysicalDisplayElement(80, 4) long_display.set_message_parts(SYSEX_START + ( 17, 3, ), (247, )) self._display2 = long_display.segment(0) pos_id = tuple() pos_id += (0, 0) self._display2.set_position_identifier(pos_id) self._display3 = long_display.segment(1) pos_id = tuple() pos_id += (0, 1, 0) self._display3.set_position_identifier(pos_id) self._display4 = long_display.segment(2) pos_id = tuple() pos_id += (0, 2, 0) self._display4.set_position_identifier(pos_id) self._display5 = long_display.segment(3) pos_id = tuple() pos_id += (0, 3, 0) self._display5.set_position_identifier(pos_id) middle_display = PhysicalDisplayElement(20, 1) middle_display.set_message_parts(SYSEX_START + (17, 2, 0, 0), (247, )) self._display6 = middle_display.segment(0) bottom_display = PhysicalDisplayElement(20, 1) bottom_display.set_message_parts(SYSEX_START + (17, 4, 0, 0), (247, )) self._display7 = bottom_display.segment(0) self._browser_displays = [ self._display1, self._display2, self._display3, self._display4, self._display5, self._display6, self._display7 ] self._drumpads = [ ButtonElement(True, MIDI_NOTE_TYPE, 15, 81 + index, name='Pad_' + str(index)) for index in range(8) ] self._setup_m4l_interface() self.log_message('Axiom_OJI script installed')
class Axiom_OJI(AxiomPro): """ Script for the M-Audio Axiom Pro OJI version """ _browser_mode_enabled = False def __init__(self, *a, **k): #super(Axiom_OJI, self).__init__(*a, **k) ControlSurface.__init__(self, *a, **k) with self.component_guard(): is_momentary = True #self.set_pad_translations(PAD_TRANSLATIONS) self._suggested_input_port = u'HyperControl' self._suggested_output_port = u'HyperControl' self._display_on_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, 15, 79) self._waiting_for_first_response = True self._mixer1 = DisplayingMixerComponent(0) self._mixer1.set_select_buttons( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 111), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 110)) self._mixer1.set_mute_button( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 12)) self._mixer1.set_solo_button( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 13)) self._mixer2 = NotifyingMixerComponent(8) self._mixer2.set_bank_buttons( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 15), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 14)) self._mixer2.master_strip().set_volume_control( SliderElement(MIDI_CC_TYPE, 15, 41)) for index in range(8): self._mixer2.channel_strip(index).set_volume_control( SliderElement(MIDI_CC_TYPE, 15, 33 + index)) self._device = PageableDeviceComponent( device_selection_follows_track_selection=True) self.set_device_component(self._device) self._ffwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 115) self._rwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 114) self._loop_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 113) self._transport = TransportComponent() self._transport.set_stop_button( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 116)) self._transport.set_play_button( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 117)) self._transport.set_record_button( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 118, name='RecordButton')) self._session = SessionComponent(0, 0) self._transport_view_modes = TransportViewModeSelector( self._transport, self._session, self._ffwd_button, self._rwd_button, self._loop_button) self._select_button_modes = SelectButtonModeSelector( self._mixer2, tuple([ ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 49 + offset) for offset in range(8) ])) self._select_button_modes.set_mode_toggle( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 57)) self._mixer_encoder_modes = EncoderMixerModeSelector(self._mixer2) self._encoders = [] for offset in range(8): self._encoders.append( PeekableEncoderElement( MIDI_CC_TYPE, 15, 17 + offset, Live.MidiMap.MapMode.relative_smooth_two_compliment)) self._encoders[-1].set_feedback_delay(-1) self._mixer_or_device = MixerOrDeviceModeSelector( self._mixer_encoder_modes, self._device, tuple(self._encoders), tuple([ ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 74 + offset) for offset in range(4) ])) self._mixer_or_device.set_mode_toggle( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 109)) self._mixer_or_device.set_peek_button( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 78)) self._track_display = PhysicalDisplayElement(8, 1) self._track_display.set_clear_all_message(SYSEX_START + (16, 247)) self._track_display.set_message_parts(SYSEX_START + (17, 1, 0, 0), (247, )) #self._track_display.segment(0).set_data_source(mixer1.selected_strip().track_name_data_source()) self._device_display = PhysicalDisplayElement(8, 1) self._device_display.set_message_parts( SYSEX_START + (17, 1, 0, 10), (247, )) self._parameter_display = PhysicalDisplayElement(16, 1) self._parameter_display.set_message_parts( SYSEX_START + (17, 2, 0, 0), (247, )) #self._select_button_modes.set_mode_display(parameter_display) #self._mixer1.set_display(parameter_display) #self._mixer2.set_bank_display(parameter_display) self._page_displays = [] for index in range(4): self._page_displays.append(PhysicalDisplayElement(5, 1)) self._page_displays[-1].set_message_parts( SYSEX_START + (17, 4, index, 0), (247, )) self._encoder_display = PhysicalDisplayElement(80, 8) self._encoder_display.set_message_parts(SYSEX_START + (17, 3), (247, )) for index in range(8): pos_id = tuple() if index != 0: pos_id += (0, ) if index > 3: pos_id += (index % 4, 13) else: pos_id += (index % 4, 0) self._encoder_display.segment(index).set_position_identifier( pos_id) self._data_sources = [ DisplayDataSource(' ') for index in range(7) ] top_display = PhysicalDisplayElement(20, 1) top_display.set_message_parts(SYSEX_START + (17, 1, 0, 0), (247, )) top_display.set_clear_all_message(SYSEX_START + (16, 247)) self._header_display = top_display self._display1 = top_display.segment(0) long_display = PhysicalDisplayElement(80, 4) long_display.set_message_parts(SYSEX_START + ( 17, 3, ), (247, )) self._display2 = long_display.segment(0) pos_id = tuple() pos_id += (0, 0) self._display2.set_position_identifier(pos_id) self._display3 = long_display.segment(1) pos_id = tuple() pos_id += (0, 1, 0) self._display3.set_position_identifier(pos_id) self._display4 = long_display.segment(2) pos_id = tuple() pos_id += (0, 2, 0) self._display4.set_position_identifier(pos_id) self._display5 = long_display.segment(3) pos_id = tuple() pos_id += (0, 3, 0) self._display5.set_position_identifier(pos_id) middle_display = PhysicalDisplayElement(20, 1) middle_display.set_message_parts(SYSEX_START + (17, 2, 0, 0), (247, )) self._display6 = middle_display.segment(0) bottom_display = PhysicalDisplayElement(20, 1) bottom_display.set_message_parts(SYSEX_START + (17, 4, 0, 0), (247, )) self._display7 = bottom_display.segment(0) self._browser_displays = [ self._display1, self._display2, self._display3, self._display4, self._display5, self._display6, self._display7 ] self._drumpads = [ ButtonElement(True, MIDI_NOTE_TYPE, 15, 81 + index, name='Pad_' + str(index)) for index in range(8) ] self._setup_m4l_interface() self.log_message('Axiom_OJI script installed') """ def __init__(self, *a, **k): super(Axiom_OJI, self).__init__(*a, **k) with self.component_guard(): #self._data_sources = (DisplayDataSource('TEST') for index in range(7)) self._display1 = PhysicalDisplayElement(16, 1) self._display1.set_message_parts(SYSEX_START + (17, 1, 0, 0), (247,)) self._header_display = self._display1 self._header_display.set_clear_all_message(SYSEX_START + (16, 247)) self._display2 = PhysicalDisplayElement(16, 1) self._display2.set_message_parts(SYSEX_START + (17, 3, 0, 0), (247,)) self._display3 = PhysicalDisplayElement(16, 1) self._display3.set_message_parts(SYSEX_START + (17, 3, 1, 0), (247,)) self._display4 = PhysicalDisplayElement(16, 1) self._display4.set_message_parts(SYSEX_START + (17, 3, 2, 0), (247,)) self._display5 = PhysicalDisplayElement(16, 1) self._display5.set_message_parts(SYSEX_START + (17, 3, 3, 0), (247,)) self._display6 = PhysicalDisplayElement(16, 1) self._display6.set_message_parts(SYSEX_START + (17, 2, 0, 0), (247,)) self._display7 = PhysicalDisplayElement(16, 1) self._display7 .set_message_parts(SYSEX_START + (17, 4, 0, 0), (247,)) self._browser_displays = [self._display1, self._display2, self._display3, self._display4, self._display5, self._display6, self._display7] """ def _setup_m4l_interface(self): self._m4l_interface = M4LInterfaceComponent( controls=self.controls, component_guard=self.component_guard, priority=10) self._m4l_interface.name = "M4LInterface" self.get_control_names = self._m4l_interface.get_control_names self.get_control = self._m4l_interface.get_control self.grab_control = self._m4l_interface.grab_control self.release_control = self._m4l_interface.release_control def handle_sysex(self, midi_bytes): if midi_bytes[0:-2] == SYSEX_START + (32, ): msg_id_byte = midi_bytes[-2] is_setup_response = msg_id_byte in (46, 38) has_sliders = msg_id_byte == 46 if is_setup_response: if self._waiting_for_first_response: self._waiting_for_first_response = False self._display_on_button.send_value(0) if not self._browser_mode_enabled: for component in self.components: component.set_enabled(True) self._display_on_button.send_value(127) self._send_midi(SYSEX_START + (16, 247)) self._send_midi(SYSEX_START + (17, 3, 0, 1, 65, 98, 108, 101, 116, 111, 110, 32, 76, 105, 118, 101, 32, 67, 111, 110, 116, 114, 111, 108, 32, 0, 1, 4, 83, 117, 114, 102, 97, 99, 101, 32, 118, 49, 46, 48, 46, 48, 46, 247)) self._mixer_encoder_modes.set_show_volume_page(not has_sliders) #if not self._browser_mode_enabled: for display in self._displays: display.set_block_messages(False) self.schedule_message(25, self._refresh_displays) #self.schedule_message(30, self._enable_browser) elif msg_id_byte == 43: self._send_midi(SYSEX_START + (16, 247)) #if not self._browser_mode_enabled: for display in self._displays: if display is self._track_display: display.update() else: display.set_block_messages(True) def _enable_browser(self): self.enable_browser_mode(True) def enable_browser_mode(self, enable): self._browser_mode_enabled = enable > 0 debug('enable_browser_mode:' + str(enable)) if enable: for component in self.components: component.set_enabled(False) self._header_display.reset() self._track_display.segment(0).set_data_source(None) for index in range(7): debug('index: ' + str(index)) self._browser_displays[index].set_data_source( self._data_sources[index]) else: self._header_display.reset() for index in range(7): debug('index: ' + str(index)) self._browser_displays[index].set_data_source(None) for component in self.components: component.set_enabled(True) def _enable_browser_mode(self, enable): self._browser_mode_enabled = enable > 0 #debug('enable_browser_mode', enable) if enable: #debug('here 1') for component in self.components: component.set_enabled(False) self._header_display.reset() #debug('here 2') #for index, display in enumerate(self._browser_displays): #debug('index:', index, 'display:', display) #self._data_sources[index].clear() #display.set_data_source(self._data_sources[index]) else: for component in self.components: component.set_enabled(True) def write_to_lcd(self, display, message): if self._browser_mode_enabled and display in range(7): self._data_sources[display].set_display_string(message) def test_browser(self): debug('test_browser') browser = self.application.browser debug('browser is:', browser) user_folders = browser.user_folders debug('user_folders are:', user_folders) for item in user_folders: #debug('item is:', item, item.name) if item.name == 'defaultPresets': inneritems = item.iter_children for inneritem in inneritems: debug('inneritem:', inneritem) if inneritem.name == 'Default.aupreset': browser.load_item(inneritem) break def load_preset(self, target=None, folder=None, directory='defaultPresets'): debug('load_preset()', target, folder, directory) if not target is None: browser = Live.Application.get_application( ).browser ##if not self.application.view.browse_mode else self.application.browser.hotswap_target user_folders = browser.user_folders for item in user_folders: if item.name == directory: if not folder is None: folder_target = None item_iterator = item.iter_children inneritems = [inneritem for inneritem in item_iterator] for inneritem in inneritems: if inneritem.name == folder: folder_target = inneritem break if folder_target: item_iterator = folder_target.iter_children inneritems = [ inneritem for inneritem in item_iterator ] for inneritem in inneritems: if isinstance(target, int): if target < len(inneritems): if inneritems[target].is_loadable: browser.load_item( inneritems[target]) break elif inneritems[target].is_folder: debug(inneritems[target], '.is_folder') innertarget = inneritems[target] innertarget_iterator = innertarget.iter_children innertargetitems = [ innertargetitem for innertargetitem in innertarget_iterator ] #debug('innertargetitems:', innertargetitems) if len(innertargetitems ) > 0 and innertargetitems[ 0].is_loadable: browser.load_item( innertargetitems[0]) break else: debug(innertargetitems[0], 'item isnt loadable 0') break else: debug(inneritems[target], 'item isnt loadable 1') break else: if inneritem.name == target: if inneritem.is_loadable: browser.load_item(inneritem) else: debug(inneritem, 'item isnt loadable 2') break else: item_iterator = item.iter_children inneritems = [inneritem for inneritem in item_iterator] for inneritem in inneritems: if isinstance(target, int): if target < len(inneritems): if inneritems[target].is_loadable: browser.load_item(inneritems[target]) break else: debug(inneritems[target], 'item isnt loadable 3') break else: if inneritem.name == target: if inneritem.is_loadable: browser.load_item(inneritem) break else: debug(inneritem, 'item isnt loadable 4') break def get_preset_names(self, folder=None, directory='defaultPresets'): #debug('get_preset_names', folder, directory) preset_names = [ 'no target', 'no target', 'no target', 'no target', 'no target', 'no target', 'no target', 'no target' ] browser = Live.Application.get_application( ).browser ##if not self.application.view.browse_mode else self.application.browser.hotswap_target user_folders = browser.user_folders for item in user_folders: if item.name == directory: if not folder is None: folder_target = None item_iterator = item.iter_children inneritems = [inneritem for inneritem in item_iterator] for inneritem in inneritems: if inneritem.name == folder: folder_target = inneritem break if folder_target: item_iterator = folder_target.iter_children preset_names = [ inneritem.name for inneritem in item_iterator ] else: item_iterator = item.iter_children preset_names = [ inneritem.name for inneritem in item_iterator ] #debug('names:', preset_names) return preset_names def write_presets_to_lcd(self, folder=None, directory='defaultPresets'): #debug('write_presets_to_lcd') preset_names = self.get_preset_names(folder, directory) #debug('names:', preset_names) for i, name in enumerate(preset_names): if i < 7: #debug('name:', i, name) self.write_to_lcd(i, name[:20])
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 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