class JAMP_alpha(ControlSurface): __doc__ = " Script for JAMP_alpha in APC emulation mode " _active_instances = [] def _combine_active_instances(): track_offset = 0 scene_offset = 0 for instance in JAMP_alpha._active_instances: instance._activate_combination_mode(track_offset, scene_offset) track_offset += instance._session.width() _combine_active_instances = staticmethod(_combine_active_instances) def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) #self.set_suppress_rebuild_requests(True) with self.component_guard(): self._note_map = [] self._ctrl_map = [] self._load_MIDI_map() self._session = None self._session_zoom = None self._mixer = None self._setup_session_control() self._setup_mixer_control() self._session.set_mixer(self._mixer) self._setup_device_and_transport_control() self.set_highlighting_session_component(self._session) #self.set_suppress_rebuild_requests(False) self._pads = [] self._load_pad_translations() self._do_combine() def disconnect(self): self._note_map = None self._ctrl_map = None self._pads = None self._do_uncombine() self._shift_button = None self._session = None self._session_zoom = None self._mixer = None ControlSurface.disconnect(self) def _do_combine(self): if self not in JAMP_alpha._active_instances: JAMP_alpha._active_instances.append(self) JAMP_alpha._combine_active_instances() def _do_uncombine(self): if ((self in JAMP_alpha._active_instances) and JAMP_alpha._active_instances.remove(self)): self._session.unlink() JAMP_alpha._combine_active_instances() def _activate_combination_mode(self, track_offset, scene_offset): if TRACK_OFFSET != -1: track_offset = TRACK_OFFSET if SCENE_OFFSET != -1: scene_offset = SCENE_OFFSET self._session.link_with_track_offset(track_offset, scene_offset) def _setup_session_control(self): is_momentary = True self._session = SpecialSessionComponent(4, 4) self._session.name = 'Session_Control' self._session.set_track_bank_buttons(self._note_map[SESSIONRIGHT], self._note_map[SESSIONLEFT]) self._session.set_scene_bank_buttons(self._note_map[SESSIONDOWN], self._note_map[SESSIONUP]) self._session.set_select_buttons(self._note_map[SCENEDN], self._note_map[SCENEUP]) self._scene_launch_buttons = [ self._note_map[SCENELAUNCH[index]] for index in range(4) ] self._track_stop_buttons = [ self._note_map[TRACKSTOP[index]] for index in range(4) ] self._session.set_stop_all_clips_button(self._note_map[STOPALLCLIPS]) self._session.set_stop_track_clip_buttons( tuple(self._track_stop_buttons)) self._session.selected_scene().name = 'Selected_Scene' self._session.selected_scene().set_launch_button( self._note_map[SELSCENELAUNCH]) self._session.set_slot_launch_button(self._note_map[SELCLIPLAUNCH]) for scene_index in range(4): scene = self._session.scene(scene_index) scene.name = 'Scene_' + str(scene_index) button_row = [] scene.set_launch_button(self._scene_launch_buttons[scene_index]) scene.set_triggered_value(2) for track_index in range(4): button = self._note_map[CLIPNOTEMAP[scene_index][track_index]] button_row.append(button) clip_slot = scene.clip_slot(track_index) clip_slot.name = str(track_index) + '_Clip_Slot_' + str( scene_index) clip_slot.set_launch_button(button) self._session_zoom = SpecialZoomingComponent(self._session) self._session_zoom.name = 'Session_Overview' self._session_zoom.set_nav_buttons(self._note_map[ZOOMUP], self._note_map[ZOOMDOWN], self._note_map[ZOOMLEFT], self._note_map[ZOOMRIGHT]) def _setup_mixer_control(self): is_momentary = True self._mixer = SpecialMixerComponent(8) self._mixer.name = 'Mixer' self._mixer.master_strip().name = 'Master_Channel_Strip' self._mixer.master_strip().set_select_button(self._note_map[MASTERSEL]) self._mixer.selected_strip().name = 'Selected_Channel_Strip' self._mixer.set_select_buttons(self._note_map[TRACKRIGHT], self._note_map[TRACKLEFT]) self._mixer.set_crossfader_control(self._ctrl_map[CROSSFADER]) self._mixer.set_prehear_volume_control(self._ctrl_map[CUELEVEL]) self._mixer.master_strip().set_volume_control( self._ctrl_map[MASTERVOLUME]) for track in range(8): strip = self._mixer.channel_strip(track) strip.name = 'Channel_Strip_' + str(track) strip.set_arm_button(self._note_map[TRACKREC[track]]) strip.set_solo_button(self._note_map[TRACKSOLO[track]]) strip.set_mute_button(self._note_map[TRACKMUTE[track]]) strip.set_select_button(self._note_map[TRACKSEL[track]]) strip.set_volume_control(self._ctrl_map[TRACKVOL[track]]) strip.set_pan_control(self._ctrl_map[TRACKPAN[track]]) strip.set_send_controls((self._ctrl_map[TRACKSENDA[track]], self._ctrl_map[TRACKSENDB[track]], self._ctrl_map[TRACKSENDC[track]])) strip.set_invert_mute_feedback(True) def _setup_device_and_transport_control(self): is_momentary = True self._device = DeviceComponent() self._device.name = 'Device_Component' device_bank_buttons = [] device_param_controls = [] for index in range(8): device_param_controls.append(self._ctrl_map[PARAMCONTROL[index]]) device_bank_buttons.append(self._note_map[DEVICEBANK[index]]) if None not in device_bank_buttons: self._device.set_bank_buttons(tuple(device_bank_buttons)) if None not in device_param_controls: self._device.set_parameter_controls(tuple(device_param_controls)) self._device.set_on_off_button(self._note_map[DEVICEONOFF]) self._device.set_bank_nav_buttons(self._note_map[DEVICEBANKNAVLEFT], self._note_map[DEVICEBANKNAVRIGHT]) self._device.set_lock_button(self._note_map[DEVICELOCK]) self.set_device_component(self._device) detail_view_toggler = DetailViewControllerComponent() detail_view_toggler.name = 'Detail_View_Control' detail_view_toggler.set_device_clip_toggle_button( self._note_map[CLIPTRACKVIEW]) detail_view_toggler.set_detail_toggle_button( self._note_map[DETAILVIEW]) detail_view_toggler.set_device_nav_buttons( self._note_map[DEVICENAVLEFT], self._note_map[DEVICENAVRIGHT]) transport = SpecialTransportComponent() transport.name = 'Transport' transport.set_play_button(self._note_map[PLAY]) transport.set_stop_button(self._note_map[STOP]) transport.set_record_button(self._note_map[REC]) transport.set_nudge_buttons(self._note_map[NUDGEUP], self._note_map[NUDGEDOWN]) transport.set_undo_button(self._note_map[UNDO]) transport.set_redo_button(self._note_map[REDO]) transport.set_tap_tempo_button(self._note_map[TAPTEMPO]) transport.set_quant_toggle_button(self._note_map[RECQUANT]) transport.set_overdub_button(self._note_map[OVERDUB]) transport.set_metronome_button(self._note_map[METRONOME]) transport.set_tempo_control(self._ctrl_map[TEMPOCONTROL]) transport.set_loop_button(self._note_map[LOOP]) transport.set_seek_buttons(self._note_map[SEEKFWD], self._note_map[SEEKRWD]) transport.set_punch_buttons(self._note_map[PUNCHIN], self._note_map[PUNCHOUT]) ##transport.set_song_position_control(self._ctrl_map[SONGPOSITION]) #still not implemented as of Live 8.1.6 def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(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) def _load_pad_translations(self): if -1 not in DRUM_PADS: pad = [] for row in range(4): for col in range(4): pad = ( col, row, DRUM_PADS[row * 4 + col], PADCHANNEL, ) self._pads.append(pad) self.set_pad_translations(tuple(self._pads)) def _load_MIDI_map(self): is_momentary = True for note in range(128): button = ButtonElement(is_momentary, MESSAGETYPE, BUTTONCHANNEL, note) button.name = 'Note_' + str(note) self._note_map.append(button) self._note_map.append( None) #add None to the end of the list, selectable with [-1] if MESSAGETYPE == MIDI_CC_TYPE and BUTTONCHANNEL == SLIDERCHANNEL: for ctrl in range(128): self._ctrl_map.append(None) else: for ctrl in range(128): control = SliderElement(MIDI_CC_TYPE, SLIDERCHANNEL, ctrl) control.name = 'Ctrl_' + str(ctrl) self._ctrl_map.append(control) self._ctrl_map.append(None)
class Launchkey(ControlSurface): """ Script for Novation's Launchkey 25/49/61 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 = "Launchkey InControl" self._suggested_output_port = "Launchkey InControl" self._has_sliders = True self._current_midi_map = None self._master_slider = make_slider(7, "Master_Volume_Control") self._modes_buttons = [] for index in range(3): button = ButtonElement(IS_MOMENTARY, MIDI_NOTE_TYPE, 0, 13 + index) self._modes_buttons.append(button) self._modes_buttons[-1].add_value_listener(self._dummy_listener) self._setup_mixer() self._setup_session() self._setup_transport() self._setup_device() for component in self.components: component.set_enabled(False) def refresh_state(self): ControlSurface.refresh_state(self) self.schedule_message(2, self._send_midi, LIVE_MODE_ON) self.schedule_message(3, self._send_midi, SIZE_QUERY) def handle_sysex(self, midi_bytes): if midi_bytes[0:11] == SIZE_RESPONSE: self._has_sliders = midi_bytes[11] != 48 self._send_midi(LED_FLASHING_ON) self._update_mixer_offset() 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) for index in range(len(self._sliders)): self._mixer.channel_strip(index).set_volume_control(None) self._mixer.channel_strip(index).set_mute_button(None) slider = self._sliders[index] slider.release_parameter() self._mixer.selected_strip().set_volume_control(self._master_slider) self.request_rebuild_midi_map() def disconnect(self): ControlSurface.disconnect(self) for button in self._modes_buttons: if button.value_has_listener(self._dummy_listener): button.remove_value_listener(self._dummy_listener) self._modes_buttons = None self._encoders = None self._sliders = None self._strip_buttons = None self._master_slider = None self._current_midi_map = None self._transport_view_modes = None self._send_midi(LED_FLASHING_OFF) self._send_midi(LIVE_MODE_OFF) def build_midi_map(self, midi_map_handle): self._current_midi_map = midi_map_handle ControlSurface.build_midi_map(self, midi_map_handle) def _setup_mixer(self): self._next_nav_button = make_button(103, "Next_Track_Button") self._prev_nav_button = make_button(102, "Prev_Track_Button") mute_solo_flip_button = make_button(59, "Master_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 = [] self._strip_buttons = [] 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(make_slider(41 + index, "Volume_Control_%d" % index)) strip.set_volume_control(self._sliders[-1]) self._strip_buttons.append(make_button(51 + index, "Mute_Button_%d" % index)) self._mixer.set_strip_mute_solo_buttons(tuple(self._strip_buttons), mute_solo_flip_button) def _setup_session(self): scene_launch_button = make_configurable_button(104, "Scene_Launch_Button") scene_stop_button = make_configurable_button(120, "Scene_Stop_Button") self._session = SpecialSessionComponent(8, 0) self._session.name = "Session_Control" self._session.selected_scene().name = "Selected_Scene" self._session.selected_scene().set_launch_button(scene_launch_button) self._session.selected_scene().set_triggered_value(GREEN_BLINK) self._session.set_stop_all_clips_button(scene_stop_button) scene_stop_button.set_on_off_values(AMBER_FULL, LED_OFF) self._session.set_mixer(self._mixer) self._session.set_track_banking_increment(8) self._session.set_stop_track_clip_value(GREEN_BLINK) clip_launch_buttons = [] clip_stop_buttons = [] for index in range(8): clip_launch_buttons.append(make_configurable_button(96 + index, "Clip_Launch_%d" % index)) clip_stop_buttons.append(make_configurable_button(112 + index, "Clip_Stop_%d" % 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(clip_launch_buttons[-1]) clip_slot.name = "Selected_Clip_Slot_" + str(index) self._session.set_stop_track_clip_buttons(tuple(clip_stop_buttons)) def _setup_transport(self): rwd_button = make_button(112, "Rwd_Button") ffwd_button = make_button(113, "FFwd_Button") stop_button = make_button(114, "Stop_Button") play_button = make_button(115, "Play_Button") loop_button = make_button(116, "Loop_Button") rec_button = make_button(117, "Record_Button") transport = TransportComponent() transport.name = "Transport" transport.set_stop_button(stop_button) transport.set_play_button(play_button) transport.set_record_button(rec_button) transport.set_loop_button(loop_button) self._transport_view_modes = TransportViewModeSelector(transport, self._session, ffwd_button, rwd_button) self._transport_view_modes.name = "Transport_View_Modes" def _setup_device(self): encoders = [make_encoder(21 + index, "Device_Control_%d" % index) for index in xrange(8)] self._encoders = tuple(encoders) device = DeviceComponent() device.name = "Device_Component" self.set_device_component(device) device.set_parameter_controls(self._encoders) def _dummy_listener(self, value): pass def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(self) self._update_mixer_offset() def _update_mixer_offset(self): all_tracks = 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 self._session.set_offsets(new_offset, self._session.scene_offset())
class Oxygen_3rd_Gen(ControlSurface): """ Script for the 3rd generation of M-Audio's Oxygen controllers """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): is_momentary = True self._suggested_input_port = 'Oxygen' self._suggested_output_port = 'Oxygen' self._has_slider_section = True self._device_selection_follows_track_selection = True self._shift_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 57) self._shift_button.add_value_listener(self._shift_value) self._mixer = SpecialMixerComponent(NUM_TRACKS) self._mute_solo_buttons = [] self._track_up_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 111) self._track_down_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 110) self._master_slider = SliderElement(MIDI_CC_TYPE, GLOBAL_CHANNEL, 41) for index in range(NUM_TRACKS): self._mute_solo_buttons.append( ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 49 + index)) self._mixer.channel_strip(index).set_volume_control( SliderElement(MIDI_CC_TYPE, GLOBAL_CHANNEL, 33 + index)) self._shift_value(0) self._mixer.master_strip().set_volume_control(self._master_slider) self._mixer.selected_strip().set_volume_control(None) device = DeviceComponent() device.set_parameter_controls( tuple([ EncoderElement(MIDI_CC_TYPE, GLOBAL_CHANNEL, 17 + index, Live.MidiMap.MapMode.absolute) for index in range(8) ])) self.set_device_component(device) ffwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 115) rwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 114) loop_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 113) transport = TransportComponent() transport.set_stop_button( ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 116)) transport.set_play_button( ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 117)) transport.set_record_button( ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 118)) session = SessionComponent(0, 0) transport_view_modes = TransportViewModeSelector( transport, session, ffwd_button, rwd_button, loop_button) def disconnect(self): self._shift_button.remove_value_listener(self._shift_value) self._shift_button = None ControlSurface.disconnect(self) def refresh_state(self): ControlSurface.refresh_state(self) self.schedule_message(5, self._send_midi, IDENTITY_REQUEST) def handle_sysex(self, midi_bytes): if midi_bytes[0:5] == IDENTITY_RESPONSE: if midi_bytes[10] == 38: self._mixer.master_strip().set_volume_control(None) self._mixer.selected_strip().set_volume_control( self._master_slider) def _shift_value(self, value): raise value in range(128) or AssertionError for index in range(NUM_TRACKS): if value == 0: self._mixer.channel_strip(index).set_solo_button(None) self._mixer.channel_strip(index).set_mute_button( self._mute_solo_buttons[index]) self._mixer.set_bank_buttons(None, None) self._mixer.set_select_buttons(self._track_up_button, self._track_down_button) else: self._mixer.channel_strip(index).set_mute_button(None) self._mixer.channel_strip(index).set_solo_button( self._mute_solo_buttons[index]) self._mixer.set_select_buttons(None, None) self._mixer.set_bank_buttons(self._track_up_button, self._track_down_button)
class 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 Orsi(ControlSurface): __doc__ = " Script for FCB1010 in APC emulation mode " _active_instances = [] def _combine_active_instances(): track_offset = 0 scene_offset = 0 for instance in Orsi._active_instances: instance._activate_combination_mode(track_offset, scene_offset) track_offset += instance._session.width() _combine_active_instances = staticmethod(_combine_active_instances) def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self._note_map_scenes = [] self._note_map_buttons = [] self._ctrl_map_sliders = [] self._note_map_trk_stop_buttons = [] self._note_map_trk_sel_buttons = [] self._note_map_trk_mute_buttons = [] self._note_map_trk_solo_buttons = [] self._note_map_trk_rec_buttons = [] self._ctrl_map_trk_volume = [] self._ctrl_map_trk_pan = [] self._ctrl_map_senda = [] self._ctrl_map_sendb = [] self._ctrl_map_sendc = [] self._note_map_bank_buttons = [] self._ctrl_map_parameter = [] self._load_MIDI_map() self._session = None self._session_zoom = None self._mixer = None self._setup_session_control() self._setup_mixer_control() self._session.set_mixer(self._mixer) self._setup_device_and_transport_control() self.set_highlighting_session_component(self._session) self._pads = [] self._load_pad_translations() self._do_combine() def disconnect(self): self._note_map_scenes = None self._note_map_buttons = None self._ctrl_map_sliders = None self._note_map_trk_stop_buttons = None self._note_map_trk_sel_buttons = None self._note_map_trk_mute_buttons = None self._note_map_trk_solo_buttons = None self._note_map_trk_rec_buttons = None self._ctrl_map_trk_volume = None self._ctrl_map_trk_pan = None self._ctrl_map_senda = None self._ctrl_map_sendb = None self._ctrl_map_sendc = None self._note_map_bank_buttons = None self._ctrl_map_parameter = None self._pads = None self._do_uncombine() self._shift_button = None self._session = None self._session_zoom = None self._mixer = None ControlSurface.disconnect(self) def _do_combine(self): if self not in Orsi._active_instances: Orsi._active_instances.append(self) Orsi._combine_active_instances() def _do_uncombine(self): if ((self in Orsi._active_instances) and Orsi._active_instances.remove(self)): self._session.unlink() Orsi._combine_active_instances() def _activate_combination_mode(self, track_offset, scene_offset): if TRACK_OFFSET != -1: track_offset = TRACK_OFFSET if SCENE_OFFSET != -1: scene_offset = SCENE_OFFSET self._session.link_with_track_offset(track_offset, scene_offset) def _setup_session_control(self): is_momentary = True self._session = SpecialSessionComponent(TRACK_NUMBER, MATRIX_DEPTH) self._session.name = 'Session_Control' self._session.set_track_bank_buttons(self._note_map_buttons[25], self._note_map_buttons[24]) self._session.set_scene_bank_buttons(self._note_map_buttons[27], self._note_map_buttons[26]) self._session.set_select_buttons(self._note_map_buttons[34], self._note_map_buttons[35]) self._scene_launch_buttons = [ self._note_map_scenes[index] for index in range(MATRIX_DEPTH) ] self._track_stop_buttons = [ self._note_map_trk_stop_buttons[index] for index in range(TRACK_NUMBER) ] self._session.set_stop_all_clips_button(self._note_map_buttons[38]) self._session.set_stop_track_clip_buttons( tuple(self._track_stop_buttons)) self._session.selected_scene().name = 'Selected_Scene' self._session.selected_scene().set_launch_button( self._note_map_buttons[36]) self._session.set_slot_launch_button(self._note_map_buttons[37]) for scene_index in range(MATRIX_DEPTH): scene = self._session.scene(scene_index) scene.name = 'Scene_' + str(scene_index) button_row = [] scene.set_launch_button(self._scene_launch_buttons[scene_index]) scene.set_triggered_value(2) for track_index in range(TRACK_NUMBER): if (CLIPNOTEMAP[scene_index][track_index] == -1): button = None else: button = ButtonElement( is_momentary, CLIPNOTEMAP_TYPE[scene_index][track_index], CLIPNOTEMAP_CH[scene_index][track_index], CLIPNOTEMAP[scene_index][track_index]) button_row.append(button) clip_slot = scene.clip_slot(track_index) clip_slot.name = str(track_index) + '_Clip_Slot_' + str( scene_index) clip_slot.set_launch_button(button) self._session_zoom = SpecialZoomingComponent(self._session) self._session_zoom.name = 'Session_Overview' self._session_zoom.set_nav_buttons(self._note_map_buttons[28], self._note_map_buttons[29], self._note_map_buttons[30], self._note_map_buttons[31]) def _setup_mixer_control(self): is_momentary = True self._mixer = SpecialMixerComponent(TRACK_NUMBER) self._mixer.name = 'Mixer' self._mixer.master_strip().name = 'Master_Channel_Strip' self._mixer.master_strip().set_select_button( self._note_map_buttons[39]) self._mixer.selected_strip().name = 'Selected_Channel_Strip' self._mixer.set_select_buttons(self._note_map_buttons[33], self._note_map_buttons[32]) self._mixer.set_crossfader_control(self._ctrl_map_sliders[2]) self._mixer.set_prehear_volume_control(self._ctrl_map_sliders[1]) self._mixer.master_strip().set_volume_control( self._ctrl_map_sliders[0]) for track in range(TRACK_NUMBER): strip = self._mixer.channel_strip(track) strip.name = 'Channel_Strip_' + str(track) strip.set_arm_button(self._note_map_trk_rec_buttons[track]) strip.set_solo_button(self._note_map_trk_solo_buttons[track]) strip.set_mute_button(self._note_map_trk_mute_buttons[track]) strip.set_select_button(self._note_map_trk_sel_buttons[track]) strip.set_volume_control(self._ctrl_map_trk_volume[track]) strip.set_pan_control(self._ctrl_map_trk_pan[track]) strip.set_send_controls( (self._ctrl_map_senda[track], self._ctrl_map_sendb[track], self._ctrl_map_sendc[track])) strip.set_invert_mute_feedback(True) def _setup_device_and_transport_control(self): is_momentary = True self._device = DeviceComponent() self._device.name = 'Device_Component' device_bank_buttons = [] device_param_controls = [] for index in range(PARAMS_NUMBER): device_param_controls.append(self._ctrl_map_parameter[index]) for index in range(BANKS_NUMBER): device_bank_buttons.append(self._note_map_bank_buttons[index]) if None not in device_bank_buttons: self._device.set_bank_buttons(tuple(device_bank_buttons)) if None not in device_param_controls: self._device.set_parameter_controls(tuple(device_param_controls)) self._device.set_on_off_button(self._note_map_buttons[17]) self._device.set_bank_nav_buttons(self._note_map_buttons[20], self._note_map_buttons[21]) self._device.set_lock_button(self._note_map_buttons[16]) self.set_device_component(self._device) detail_view_toggler = DetailViewControllerComponent() detail_view_toggler.name = 'Detail_View_Control' detail_view_toggler.set_device_clip_toggle_button( self._note_map_buttons[15]) detail_view_toggler.set_detail_toggle_button( self._note_map_buttons[14]) detail_view_toggler.set_device_nav_buttons(self._note_map_buttons[18], self._note_map_buttons[19]) transport = SpecialTransportComponent() transport.name = 'Transport' transport.set_play_button(self._note_map_buttons[0]) transport.set_stop_button(self._note_map_buttons[1]) transport.set_record_button(self._note_map_buttons[2]) transport.set_nudge_buttons(self._note_map_buttons[4], self._note_map_buttons[5]) transport.set_undo_button(self._note_map_buttons[6]) transport.set_redo_button(self._note_map_buttons[7]) transport.set_tap_tempo_button(self._note_map_buttons[3]) transport.set_quant_toggle_button(self._note_map_buttons[13]) transport.set_overdub_button(self._note_map_buttons[11]) transport.set_metronome_button(self._note_map_buttons[12]) transport.set_tempo_control(self._ctrl_map_sliders[3]) transport.set_loop_button(self._note_map_buttons[8]) transport.set_seek_buttons(self._note_map_buttons[22], self._note_map_buttons[23]) transport.set_punch_buttons(self._note_map_buttons[9], self._note_map_buttons[10]) def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(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) def _load_pad_translations(self): if -1 not in DRUM_PADS: pad = [] for row in range(PAD_Y_NUMBER): for col in range(PAD_X_NUMBER): pad = ( col, row, DRUM_PADS[row * 4 + col], PADCHANNEL, ) self._pads.append(pad) self.set_pad_translations(tuple(self._pads)) def _load_MIDI_map(self): is_momentary = True # SCENELAUNCH Buttons for scene_id in range(MATRIX_DEPTH): if (SCENELAUNCH[scene_id] == -1): button = None else: button = ButtonElement(is_momentary, SCENELAUNCH_TYPE[scene_id], SCENELAUNCH_CH[scene_id], SCENELAUNCH[scene_id]) button.name = 'Scene_' + str(scene_id) self._note_map_scenes.append(button) # BUTTON_VECTOR Buttons for button_id in range(NUMBER_BUTTONS): if (BUTTON_VECTOR[button_id] == -1): button = None else: button = ButtonElement(is_momentary, BUTTON_VECTOR_TYPE[button_id], BUTTON_VECTOR_CH[button_id], BUTTON_VECTOR[button_id]) button.name = 'Global_Button_' + str(button_id) self._note_map_buttons.append(button) # SLIDER_VECTOR Sliders for slider_id in range(NUMBER_SLIDERS): if (SLIDER_VECTOR[slider_id] == -1): control = None else: control = SliderElement(MIDI_CC_TYPE, SLIDER_VECTOR_CH[slider_id], SLIDER_VECTOR[slider_id]) control.name = 'Global_Slider_' + str(slider_id) self._ctrl_map_sliders.append(control) # TRACKSTOP Buttons for track_id in range(TRACK_NUMBER): if (TRACKSTOP[track_id] == -1): button = None else: button = ButtonElement(is_momentary, TRACKSTOP_TYPE[track_id], TRACKSTOP_CH[track_id], TRACKSTOP[track_id]) button.name = 'Trk_Stop_Button_' + str(track_id) self._note_map_trk_stop_buttons.append(button) # TRACKSEL Buttons for track_id in range(TRACK_NUMBER): if (TRACKSEL[track_id] == -1): button = None else: button = ButtonElement(is_momentary, TRACKSEL_TYPE[track_id], TRACKSEL_CH[track_id], TRACKSEL[track_id]) button.name = 'Trk_Sel_Button_' + str(track_id) self._note_map_trk_sel_buttons.append(button) # TRACKMUTE Buttons for track_id in range(TRACK_NUMBER): if (TRACKMUTE[track_id] == -1): button = None else: button = ButtonElement(is_momentary, TRACKMUTE_TYPE[track_id], TRACKMUTE_CH[track_id], TRACKMUTE[track_id]) button.name = 'Trk_Mute_Button_' + str(track_id) self._note_map_trk_mute_buttons.append(button) # TRACKSOLO Buttons for track_id in range(TRACK_NUMBER): if (TRACKSOLO[track_id] == -1): button = None else: button = ButtonElement(is_momentary, TRACKSOLO_TYPE[track_id], TRACKSOLO_CH[track_id], TRACKSOLO[track_id]) button.name = 'Trk_Solo_Button_' + str(track_id) self._note_map_trk_solo_buttons.append(button) # TRACKREC Buttons for track_id in range(TRACK_NUMBER): if (TRACKREC[track_id] == -1): button = None else: button = ButtonElement(is_momentary, TRACKREC_TYPE[track_id], TRACKREC_CH[track_id], TRACKREC[track_id]) button.name = 'Trk_Rec_Button_' + str(track_id) self._note_map_trk_rec_buttons.append(button) # TRACKVOL Sliders for track_id in range(TRACK_NUMBER): if (TRACKVOL[track_id] == -1): control = None else: control = SliderElement(MIDI_CC_TYPE, TRACKVOL_CH[track_id], TRACKVOL[track_id]) control.name = 'Trk_Vol_Slider_' + str(track_id) self._ctrl_map_trk_volume.append(control) # TRACKPAN Sliders for track_id in range(TRACK_NUMBER): if (TRACKPAN[track_id] == -1): control = None else: control = SliderElement(MIDI_CC_TYPE, TRACKPAN_CH[track_id], TRACKPAN[track_id]) control.name = 'Trk_Pan_Slider_' + str(track_id) self._ctrl_map_trk_pan.append(control) # TRACKSENDA Sliders for track_id in range(TRACK_NUMBER): if (TRACKSENDA[track_id] == -1): control = None else: control = SliderElement(MIDI_CC_TYPE, TRACKSENDA_CH[track_id], TRACKSENDA[track_id]) control.name = 'Trk_SendA_Slider_' + str(track_id) self._ctrl_map_senda.append(control) # TRACKSENDB Sliders for track_id in range(TRACK_NUMBER): if (TRACKSENDB[track_id] == -1): control = None else: control = SliderElement(MIDI_CC_TYPE, TRACKSENDB_CH[track_id], TRACKSENDB[track_id]) control.name = 'Trk_SendB_Slider_' + str(track_id) self._ctrl_map_sendb.append(control) # TRACKSENDC Sliders for track_id in range(TRACK_NUMBER): if (TRACKSENDC[track_id] == -1): control = None else: control = SliderElement(MIDI_CC_TYPE, TRACKSENDC_CH[track_id], TRACKSENDC[track_id]) control.name = 'Trk_SendC_Slider_' + str(track_id) self._ctrl_map_sendc.append(control) # DEVICEBANK Buttons for bank_id in range(BANKS_NUMBER): if (DEVICEBANK[bank_id] == -1): button = None else: button = ButtonElement(is_momentary, DEVICEBANK_TYPE[bank_id], DEVICEBANK_CH[bank_id], DEVICEBANK[bank_id]) button.name = 'Bank_Button_' + str(bank_id) self._note_map_bank_buttons.append(button) # PARAMCONTROL Sliders for param_id in range(PARAMS_NUMBER): if (PARAMCONTROL[param_id] == -1): control = None else: control = SliderElement(MIDI_CC_TYPE, PARAMCONTROL_CH[param_id], PARAMCONTROL[param_id]) control.name = 'Slider_Param_' + str(param_id) self._ctrl_map_parameter.append(control)
class Oxygen_3rd_Gen(ControlSurface): """ Script for the 3rd generation of M-Audio's Oxygen controllers """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): is_momentary = True self._suggested_input_port = 'Oxygen' self._suggested_output_port = 'Oxygen' self._has_slider_section = True self._device_selection_follows_track_selection = True self._shift_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 57) self._shift_button.add_value_listener(self._shift_value) self._mixer = SpecialMixerComponent(NUM_TRACKS) self._mute_solo_buttons = [] self._track_up_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 111) self._track_down_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 110) self._master_slider = SliderElement(MIDI_CC_TYPE, GLOBAL_CHANNEL, 41) for index in range(NUM_TRACKS): self._mute_solo_buttons.append(ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 49 + index)) self._mixer.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, GLOBAL_CHANNEL, 33 + index)) self._shift_value(0) self._mixer.master_strip().set_volume_control(self._master_slider) self._mixer.selected_strip().set_volume_control(None) device = DeviceComponent() device.set_parameter_controls(tuple([ EncoderElement(MIDI_CC_TYPE, GLOBAL_CHANNEL, 17 + index, Live.MidiMap.MapMode.absolute) for index in range(8) ])) self.set_device_component(device) ffwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 115) rwd_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 114) loop_button = ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 113) transport = TransportComponent() transport.set_stop_button(ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 116)) transport.set_play_button(ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 117)) transport.set_record_button(ButtonElement(is_momentary, MIDI_CC_TYPE, GLOBAL_CHANNEL, 118)) session = SessionComponent(0, 0) transport_view_modes = TransportViewModeSelector(transport, session, ffwd_button, rwd_button, loop_button) return def disconnect(self): self._shift_button.remove_value_listener(self._shift_value) self._shift_button = None ControlSurface.disconnect(self) return def refresh_state(self): ControlSurface.refresh_state(self) self.schedule_message(5, self._send_midi, IDENTITY_REQUEST) def handle_sysex(self, midi_bytes): if midi_bytes[0:5] == IDENTITY_RESPONSE: if midi_bytes[10] == 38: self._mixer.master_strip().set_volume_control(None) self._mixer.selected_strip().set_volume_control(self._master_slider) return def _shift_value(self, value): raise value in range(128) or AssertionError for index in range(NUM_TRACKS): if value == 0: self._mixer.channel_strip(index).set_solo_button(None) self._mixer.channel_strip(index).set_mute_button(self._mute_solo_buttons[index]) self._mixer.set_bank_buttons(None, None) self._mixer.set_select_buttons(self._track_up_button, self._track_down_button) else: self._mixer.channel_strip(index).set_mute_button(None) self._mixer.channel_strip(index).set_solo_button(self._mute_solo_buttons[index]) self._mixer.set_select_buttons(None, None) self._mixer.set_bank_buttons(self._track_up_button, self._track_down_button) return
class Launchkey(ControlSurface): """ Script for Novation's Launchkey 25/49/61 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 = 'Launchkey InControl' self._suggested_output_port = 'Launchkey InControl' self._has_sliders = True self._current_midi_map = None self._master_slider = make_slider(7, 'Master_Volume_Control') self._modes_buttons = [] for index in range(3): button = ButtonElement(IS_MOMENTARY, MIDI_NOTE_TYPE, 0, 13 + index) self._modes_buttons.append(button) self._modes_buttons[-1].add_value_listener( self._dummy_listener) self._setup_mixer() self._setup_session() self._setup_transport() self._setup_device() for component in self.components: component.set_enabled(False) def refresh_state(self): ControlSurface.refresh_state(self) self.schedule_message(2, self._send_midi, LIVE_MODE_ON) self.schedule_message(3, self._send_midi, SIZE_QUERY) def handle_sysex(self, midi_bytes): if midi_bytes[0:11] == SIZE_RESPONSE: self._has_sliders = midi_bytes[11] != 48 self._send_midi(LED_FLASHING_ON) self._update_mixer_offset() 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) for index in range(len(self._sliders)): self._mixer.channel_strip(index).set_volume_control(None) self._mixer.channel_strip(index).set_mute_button(None) slider = self._sliders[index] slider.release_parameter() self._mixer.selected_strip().set_volume_control( self._master_slider) self.request_rebuild_midi_map() def disconnect(self): ControlSurface.disconnect(self) for button in self._modes_buttons: if button.value_has_listener(self._dummy_listener): button.remove_value_listener(self._dummy_listener) self._modes_buttons = None self._encoders = None self._sliders = None self._strip_buttons = None self._master_slider = None self._current_midi_map = None self._transport_view_modes = None self._send_midi(LED_FLASHING_OFF) self._send_midi(LIVE_MODE_OFF) def build_midi_map(self, midi_map_handle): self._current_midi_map = midi_map_handle ControlSurface.build_midi_map(self, midi_map_handle) def _setup_mixer(self): self._next_nav_button = make_button(103, 'Next_Track_Button') self._prev_nav_button = make_button(102, 'Prev_Track_Button') mute_solo_flip_button = make_button(59, 'Master_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 = [] self._strip_buttons = [] 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( make_slider(41 + index, 'Volume_Control_%d' % index)) strip.set_volume_control(self._sliders[-1]) self._strip_buttons.append( make_button(51 + index, 'Mute_Button_%d' % index)) self._mixer.set_strip_mute_solo_buttons(tuple(self._strip_buttons), mute_solo_flip_button) def _setup_session(self): scene_launch_button = make_configurable_button(104, 'Scene_Launch_Button') scene_stop_button = make_configurable_button(120, 'Scene_Stop_Button') self._session = SpecialSessionComponent(8, 0) self._session.name = 'Session_Control' self._session.selected_scene().name = 'Selected_Scene' self._session.selected_scene().set_launch_button(scene_launch_button) self._session.selected_scene().set_triggered_value(GREEN_BLINK) self._session.set_stop_all_clips_button(scene_stop_button) scene_stop_button.set_on_off_values(AMBER_FULL, LED_OFF) self._session.set_mixer(self._mixer) self._session.set_track_banking_increment(8) self._session.set_stop_track_clip_value(GREEN_BLINK) clip_launch_buttons = [] clip_stop_buttons = [] for index in range(8): clip_launch_buttons.append( make_configurable_button(96 + index, 'Clip_Launch_%d' % index)) clip_stop_buttons.append( make_configurable_button(112 + index, 'Clip_Stop_%d' % 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(clip_launch_buttons[-1]) clip_slot.name = 'Selected_Clip_Slot_' + str(index) self._session.set_stop_track_clip_buttons(tuple(clip_stop_buttons)) def _setup_transport(self): rwd_button = make_button(112, 'Rwd_Button') ffwd_button = make_button(113, 'FFwd_Button') stop_button = make_button(114, 'Stop_Button') play_button = make_button(115, 'Play_Button') loop_button = make_button(116, 'Loop_Button') rec_button = make_button(117, 'Record_Button') transport = TransportComponent() transport.name = 'Transport' transport.set_stop_button(stop_button) transport.set_play_button(play_button) transport.set_record_button(rec_button) transport.set_loop_button(loop_button) self._transport_view_modes = TransportViewModeSelector( transport, self._session, ffwd_button, rwd_button) self._transport_view_modes.name = 'Transport_View_Modes' def _setup_device(self): encoders = [ make_encoder(21 + index, 'Device_Control_%d' % index) for index in xrange(8) ] self._encoders = tuple(encoders) device = DeviceComponent() device.name = 'Device_Component' self.set_device_component(device) device.set_parameter_controls(self._encoders) def _dummy_listener(self, value): pass def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(self) self._update_mixer_offset() def _update_mixer_offset(self): all_tracks = 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 self._session.set_offsets(new_offset, self._session.scene_offset())
class FCB1020(ControlSurface): __doc__ = " Script for FCB1010 in APC emulation mode " _active_instances = [] def _combine_active_instances(): track_offset = 0 scene_offset = 0 for instance in FCB1020._active_instances: instance._activate_combination_mode(track_offset, scene_offset) track_offset += instance._session.width() _combine_active_instances = staticmethod(_combine_active_instances) def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) #self.set_suppress_rebuild_requests(True) with self.component_guard(): self._note_map = [] self._ctrl_map = [] self._load_MIDI_map() self._session = None self._session_zoom = None self._mixer = None self._setup_session_control() self._setup_mixer_control() self._session.set_mixer(self._mixer) self._setup_device_and_transport_control() self.set_highlighting_session_component(self._session) #self.set_suppress_rebuild_requests(False) self._pads = [] self._load_pad_translations() self._do_combine() def disconnect(self): self._note_map = None self._ctrl_map = None self._pads = None self._do_uncombine() self._shift_button = None self._session = None self._session_zoom = None self._mixer = None ControlSurface.disconnect(self) def _do_combine(self): if self not in FCB1020._active_instances: FCB1020._active_instances.append(self) FCB1020._combine_active_instances() def _do_uncombine(self): if ((self in FCB1020._active_instances) and FCB1020._active_instances.remove(self)): self._session.unlink() FCB1020._combine_active_instances() def _activate_combination_mode(self, track_offset, scene_offset): if TRACK_OFFSET != -1: track_offset = TRACK_OFFSET if SCENE_OFFSET != -1: scene_offset = SCENE_OFFSET self._session.link_with_track_offset(track_offset, scene_offset) def _setup_session_control(self): is_momentary = True self._session = SpecialSessionComponent(8, 5) self._session.name = 'Session_Control' self._session.set_track_bank_buttons(self._note_map[SESSIONRIGHT], self._note_map[SESSIONLEFT]) self._session.set_scene_bank_buttons(self._note_map[SESSIONDOWN], self._note_map[SESSIONUP]) self._session.set_select_buttons(self._note_map[SCENEDN], self._note_map[SCENEUP]) self._scene_launch_buttons = [self._note_map[SCENELAUNCH[index]] for index in range(5) ] self._track_stop_buttons = [self._note_map[TRACKSTOP[index]] for index in range(8) ] self._session.set_stop_all_clips_button(self._note_map[STOPALLCLIPS]) self._session.set_stop_track_clip_buttons(tuple(self._track_stop_buttons)) self._session.set_stop_track_clip_value(2) self._session.selected_scene().name = 'Selected_Scene' self._session.selected_scene().set_launch_button(self._note_map[SELSCENELAUNCH]) self._session.set_slot_launch_button(self._note_map[SELCLIPLAUNCH]) for scene_index in range(5): scene = self._session.scene(scene_index) scene.name = 'Scene_' + str(scene_index) button_row = [] scene.set_launch_button(self._scene_launch_buttons[scene_index]) scene.set_triggered_value(2) for track_index in range(8): button = self._note_map[CLIPNOTEMAP[scene_index][track_index]] button_row.append(button) clip_slot = scene.clip_slot(track_index) clip_slot.name = str(track_index) + '_Clip_Slot_' + str(scene_index) clip_slot.set_launch_button(button) self._session_zoom = SpecialZoomingComponent(self._session) self._session_zoom.name = 'Session_Overview' self._session_zoom.set_nav_buttons(self._note_map[ZOOMUP], self._note_map[ZOOMDOWN], self._note_map[ZOOMLEFT], self._note_map[ZOOMRIGHT]) def _setup_mixer_control(self): is_momentary = True self._mixer = SpecialMixerComponent(8) self._mixer.name = 'Mixer' self._mixer.master_strip().name = 'Master_Channel_Strip' self._mixer.master_strip().set_select_button(self._note_map[MASTERSEL]) self._mixer.selected_strip().name = 'Selected_Channel_Strip' self._mixer.set_select_buttons(self._note_map[TRACKRIGHT], self._note_map[TRACKLEFT]) self._mixer.set_crossfader_control(self._ctrl_map[CROSSFADER]) self._mixer.set_prehear_volume_control(self._ctrl_map[CUELEVEL]) self._mixer.master_strip().set_volume_control(self._ctrl_map[MASTERVOLUME]) for track in range(8): strip = self._mixer.channel_strip(track) strip.name = 'Channel_Strip_' + str(track) strip.set_arm_button(self._note_map[TRACKREC[track]]) strip.set_solo_button(self._note_map[TRACKSOLO[track]]) strip.set_mute_button(self._note_map[TRACKMUTE[track]]) strip.set_select_button(self._note_map[TRACKSEL[track]]) strip.set_volume_control(self._ctrl_map[TRACKVOL[track]]) strip.set_pan_control(self._ctrl_map[TRACKPAN[track]]) strip.set_send_controls((self._ctrl_map[TRACKSENDA[track]], self._ctrl_map[TRACKSENDB[track]], self._ctrl_map[TRACKSENDC[track]])) strip.set_invert_mute_feedback(True) def _setup_device_and_transport_control(self): is_momentary = True self._device = DeviceComponent() self._device.name = 'Device_Component' device_bank_buttons = [] device_param_controls = [] for index in range(8): device_param_controls.append(self._ctrl_map[PARAMCONTROL[index]]) device_bank_buttons.append(self._note_map[DEVICEBANK[index]]) if None not in device_bank_buttons: self._device.set_bank_buttons(tuple(device_bank_buttons)) if None not in device_param_controls: self._device.set_parameter_controls(tuple(device_param_controls)) self._device.set_on_off_button(self._note_map[DEVICEONOFF]) self._device.set_bank_nav_buttons(self._note_map[DEVICEBANKNAVLEFT], self._note_map[DEVICEBANKNAVRIGHT]) self._device.set_lock_button(self._note_map[DEVICELOCK]) self.set_device_component(self._device) detail_view_toggler = DetailViewControllerComponent() detail_view_toggler.name = 'Detail_View_Control' detail_view_toggler.set_device_clip_toggle_button(self._note_map[CLIPTRACKVIEW]) detail_view_toggler.set_detail_toggle_button(self._note_map[DETAILVIEW]) detail_view_toggler.set_device_nav_buttons(self._note_map[DEVICENAVLEFT], self._note_map[DEVICENAVRIGHT] ) transport = SpecialTransportComponent() transport.name = 'Transport' transport.set_play_button(self._note_map[PLAY]) transport.set_stop_button(self._note_map[STOP]) transport.set_record_button(self._note_map[REC]) transport.set_nudge_buttons(self._note_map[NUDGEUP], self._note_map[NUDGEDOWN]) transport.set_undo_button(self._note_map[UNDO]) transport.set_redo_button(self._note_map[REDO]) transport.set_tap_tempo_button(self._note_map[TAPTEMPO]) transport.set_quant_toggle_button(self._note_map[RECQUANT]) transport.set_overdub_button(self._note_map[OVERDUB]) transport.set_metronome_button(self._note_map[METRONOME]) transport.set_tempo_control(self._ctrl_map[TEMPOCONTROL]) transport.set_loop_button(self._note_map[LOOP]) transport.set_seek_buttons(self._note_map[SEEKFWD], self._note_map[SEEKRWD]) transport.set_punch_buttons(self._note_map[PUNCHIN], self._note_map[PUNCHOUT]) ##transport.set_song_position_control(self._ctrl_map[SONGPOSITION]) #still not implemented as of Live 8.1.6 def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(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) def _load_pad_translations(self): if -1 not in DRUM_PADS: pad = [] for row in range(4): for col in range(4): pad = (col, row, DRUM_PADS[row*4 + col], PADCHANNEL,) self._pads.append(pad) self.set_pad_translations(tuple(self._pads)) def _load_MIDI_map(self): is_momentary = True for note in range(128): button = ButtonElement(is_momentary, MESSAGETYPE, BUTTONCHANNEL, note) button.name = 'Note_' + str(note) self._note_map.append(button) self._note_map.append(None) #add None to the end of the list, selectable with [-1] if MESSAGETYPE == MIDI_CC_TYPE and BUTTONCHANNEL == SLIDERCHANNEL: for ctrl in range(128): self._ctrl_map.append(None) else: for ctrl in range(128): control = SliderElement(MIDI_CC_TYPE, SLIDERCHANNEL, ctrl) control.name = 'Ctrl_' + str(ctrl) self._ctrl_map.append(control) self._ctrl_map.append(None)
class Novation_Impulse2(ControlSurface): """ Script for Novation's Impulse keyboards """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) self.c_instance = c_instance with self.component_guard(): self.set_pad_translations(PAD_TRANSLATIONS) self._device_selection_follows_track_selection = True self._suggested_input_port = 'Impulse' self._suggested_output_port = 'Impulse' self._has_sliders = True self._current_midi_map = None self._display_reset_delay = -1 self._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 self._shift_pressed = False self._shift_button.add_value_listener(self._shift_value) 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.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_value) 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): 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.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.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): 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(' - ') 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_value(self, value): self.log("root shift handler") 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_value(value) self._transport._shift_value(value) self._transport_view_modes._shift_value(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 log(self, message): pass
class NanoKontrolLP95(ControlSurface): __module__ = __name__ __doc__ = " NanoKontrolLP95 controller script " def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) #self._suppress_session_highlight = True self._suppress_send_midi = True # Turn off rebuild MIDI map until after we're done setting up Live.Base.log(time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) + "--------------= NanoKontrolLP95 log opened =--------------") # Writes message into Live's main log file. This is a ControlSurface method. with self.component_guard(): # OBJECTS self._session = None #session object self._mixer = None #mixer object self._transport = None #transport object self._last_button_time = time.time() self._io_list_index = 0 self._setup_controls() self._setup_session_control() # Setup the session object self._setup_mixer_control() # Setup the mixer object self._session.set_mixer(self._mixer) # Bind mixer to session self._setup_transport_control() # Setup transport object self._set_mode_button() self._set_normal_mode() self._track = self.song().view.selected_track self.set_highlighting_session_component(self._session) self._flash_counter = 0 self._flash_on = True for component in self.components: component.set_enabled(True) self._suppress_send_midi = True # Turn rebuild back on, once we're done setting up Live.Base.log("NanoKontrolLP95 Loaded !") def disconnect(self): """clean things up on disconnect""" if self._cycle_button != None: self._cycle_button.remove_value_listener(self._cycle_button_value) self._clear_controls() self._transport.set_stop_button(None) self._transport.set_play_button(None) self._transport.set_rec_button(None) self._solo_buttons = None self._mute_buttons = None self._arm_buttons = None self._knobs = None self._faders = None self._ff_button = None self._rwd_button = None self._play_button = None self._stop_button = None self._rec_button = None self._track_left_button = None self._track_right_button = None self._cycle_button = None self._set_button = None self._mrk_left_button = None self._mrk_right_button = None self._session = None self._mixer = None self._transport = None ControlSurface.disconnect(self) def _setup_controls(self): self._track_left_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, track_left_btn) self._track_right_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, track_right_btn) self._cycle_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, cycle_btn) self._cycle_button_active = False self._set_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, set_btn) self._mrk_left_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, mrk_left_btn) self._mrk_right_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, mrk_right_btn) self._ff_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, ff_btn) self._rwd_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, rwd_btn) self._play_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, play_btn) self._stop_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, stop_btn) self._rec_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, rec_btn) self._solo_buttons = [ButtonElement(True, MIDI_CC_TYPE, CHANNEL, track_solo_cc[index]) for index in range(num_tracks)] self._mute_buttons = [ButtonElement(True, MIDI_CC_TYPE, CHANNEL, track_mute_cc[index]) for index in range(num_tracks)] self._arm_buttons = [ButtonElement(True, MIDI_CC_TYPE, CHANNEL, track_arm_cc[index]) for index in range(num_tracks)] self._knobs = [SliderElement(MIDI_CC_TYPE, CHANNEL, mixer_knob_cc[index]) for index in range(num_tracks)] self._faders = [SliderElement(MIDI_CC_TYPE, CHANNEL, mixer_fader_cc[index]) for index in range(num_tracks)] def _setup_session_control(self): # CREATE SESSION, SET OFFSETS, BUTTONS NAVIGATION AND BUTTON MATRIX self._session = SpecialSessionComponent(num_tracks, num_scenes) #(num_tracks, num_scenes) self._session.set_offsets(0, 0) def _setup_mixer_control(self): #CREATE MIXER, SET OFFSET (SPECIALMIXERCOMPONENT USES SPECIALCHANNELSTRIP THAT ALLOWS US TO UNFOLD TRACKS WITH TRACK SELECT BUTTON) self._mixer = SpecialMixerComponent(self, num_tracks, 0, False, False) # 8 tracks, 2 returns, no EQ, no filters self._mixer.name = 'Mixer' self._mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left) self._mixer.set_select_buttons(self._track_right_button,self._track_left_button) self._mixer.set_knobs(self._knobs) def _setup_transport_control(self): # CREATE TRANSPORT DEVICE self._transport = SpecialTransportComponent(self) self._transport.set_stop_button(self._stop_button) self._transport.set_play_button(self._play_button) self._transport.set_rec_button(self._rec_button) def connect_script_instances(self, instanciated_scripts): #Live.Base.log("connect_script_instances - Start") #Live.Base.log("connect_script_instances - self._control_surfaces()=" + str(self._control_surfaces())) if(linked): for control_surface in self._control_surfaces(): control_surface_type = str(control_surface) for sync_master in SYNC_TO_LIST: if(control_surface_type.count(sync_master)>0): control_surface_session = control_surface.highlighting_session_component() if control_surface_session: self._session.sync_to(control_surface_session) self._on_track_list_changed() break def _clear_controls(self): if (self._ff_button != None): self._ff_button.remove_value_listener(self._out_value) self._ff_button.turn_off() if (self._rwd_button != None): self._rwd_button.remove_value_listener(self._in_value) self._rwd_button.turn_off() if (self._set_button != None): self._set_button.remove_value_listener(self._monitor_value) self._set_button.remove_value_listener(self._dup_track_value) if (self._mrk_left_button != None): self._mrk_left_button.remove_value_listener(self._sub_in_value) self._mrk_left_button.remove_value_listener(self._new_midi_value) if (self._mrk_right_button != None): self._mrk_right_button.remove_value_listener(self._sub_out_value) self._mrk_right_button.remove_value_listener(self._new_audio_value) # SESSION resetsend_controls = [] self._mixer.send_controls = [] self._session.set_stop_track_clip_buttons(None) # MIXER self._mixer._set_send_nav(None, None) for track_index in range(num_tracks): strip = self._mixer.channel_strip(track_index) strip.set_solo_button(None) strip.set_mute_button(None) strip.set_arm_button(None) resetsend_controls.append(None) strip.set_select_button(None) for i in range(12): self._mixer.send_controls.append(None) strip.set_send_controls(tuple(self._mixer.send_controls)) self._mixer.set_resetsend_buttons(tuple(resetsend_controls)) self.log_message("Controls Cleared") def _set_mode_button(self): if self._cycle_button != None: self._cycle_button.remove_value_listener(self._cycle_button_value) self._cycle_button.add_value_listener(self._cycle_button_value) self._cycle_button.set_light(self._cycle_button_active) def _cycle_button_value(self, value): assert (value in range(128)) if self._cycle_button != None: if value is not 0: self._cycle_button_active = not self._cycle_button_active self._clear_controls() if self._cycle_button_active: self._set_alt_mode() else: self._set_normal_mode() self.update() def _set_normal_mode(self): for index in range(num_tracks): strip = self._mixer.channel_strip(index) strip.set_solo_button(self._solo_buttons[index]) strip.set_mute_button(self._mute_buttons[index]) strip.set_arm_button(self._arm_buttons[index]) strip.set_pan_control(self._knobs[index]) strip.set_volume_control(self._faders[index]) self._set_in_out_nav_listeners() self.show_message("IN/OUT SETUP - MUTE SOLO ARM") def _set_alt_mode(self): self._mixer._set_send_nav(self._ff_button, self._rwd_button) stop_track_controls = [] resetsend_controls = [] # SET SESSION TRACKSTOP, TRACK SELECT, RESET SEND KNOB for index in range(num_tracks): strip = self._mixer.channel_strip(index) strip.set_select_button(self._solo_buttons[index]) stop_track_controls.append(self._arm_buttons[index]) resetsend_controls.append(self._mute_buttons[index]) self._session.set_stop_track_clip_buttons(tuple(stop_track_controls)) self._mixer.set_resetsend_buttons(tuple(resetsend_controls)) self._mixer._update_send_index() self._set_create_track_listeners() self.show_message("TRACK CREATE DEL DUPE - SEL STOP RESET SEND") def _set_in_out_nav_listeners(self): if (self._ff_button != None): self._ff_button.add_value_listener(self._out_value) if (self._rwd_button != None): self._rwd_button.add_value_listener(self._in_value) if (self._set_button != None): self._set_button.add_value_listener(self._monitor_value) if (self._mrk_left_button != None): self._mrk_left_button.add_value_listener(self._sub_in_value) if (self._mrk_right_button != None): self._mrk_right_button.add_value_listener(self._sub_out_value) self.update() def _monitor_value(self, value): now = time.time() if(value is not 0): self._last_button_time = now else: song = self.song() if self._track in song.tracks: if now - self._last_button_time < LONG_PRESS: if not self._track.is_foldable: self._track.current_monitoring_state = (self._track.current_monitoring_state + 1) % 3 else: self._set_default_io() def _set_default_io(self): if self._track.has_midi_input: self._track.input_routing_type = list(self._track.available_input_routing_types)[0] if self._track.has_audio_output: if self._track.is_grouped: self._track.output_routing_type = list(self._track.available_output_routing_types)[2] else: self._track.output_routing_type = list(self._track.available_output_routing_types)[1] else: self._track.output_routing_type = list(self._track.available_output_routing_types)[-1] else: self._track.input_routing_type = list(self._track.available_input_routing_types)[-1] if self._track.is_grouped: self._track.output_routing_type = list(self._track.available_output_routing_types)[2] else: self._track.output_routing_type = list(self._track.available_output_routing_types)[1] self._track.input_routing_channel = list(self._track.available_input_routing_channels)[0] self._track.output_routing_channel = list(self._track.available_output_routing_channels)[0] self.show_message("TRACK: " + str(self._track.name) + ' INPUT - OUTPUT RESET ') def _in_value(self, value): if(value is not 0): routings = list(self._track.available_input_routing_types) current_routing = self._track.input_routing_type if current_routing in routings: new_index = (routings.index(current_routing) + 1) % len(routings) self._track.input_routing_type = routings[new_index] route = ' INPUT: ' + str(self._track.input_routing_type.display_name) self.show_message("TRACK: " + str(self._track.name) + route) self.update() def _out_value(self, value): if(value is not 0): routings = list(self._track.available_output_routing_types) current_routing = self._track.output_routing_type if current_routing in routings: new_index = (routings.index(current_routing) + 1) % len(routings) self._track.output_routing_type = routings[new_index] route = ' OUTPUT: ' + str(self._track.output_routing_type.display_name) self.show_message("TRACK: " + str(self._track.name) + route) self.update() def _sub_in_value(self, value): if(value is not 0): routings = list(self._track.available_input_routing_channels) current_routing = self._track.input_routing_channel if current_routing in routings: new_index = (routings.index(current_routing) + 1) % len(routings) self._track.input_routing_channel = routings[new_index] route = ' SUB_INPUT: ' + str(self._track.input_routing_channel.display_name) self.show_message("TRACK: " + str(self._track.name) + route) self.update() def _sub_out_value(self, value): if(value is not 0): routings = list(self._track.available_output_routing_channels) current_routing = self._track.output_routing_channel if current_routing in routings: new_index = (routings.index(current_routing) + 1) % len(routings) self._track.output_routing_channel = routings[new_index] route = ' SUB_OUTPUT: ' + str(self._track.output_routing_channel.display_name) self.show_message("TRACK: " + str(self._track.name) + route) self.update() def _on_selected_track_changed(self): # ALLOWS TO GRAB THE FIRST DEVICE OF A SELECTED TRACK IF THERE'S ANY ControlSurface._on_selected_track_changed(self) self._track = self.song().view.selected_track def update(self): ControlSurface.update(self) self._cycle_button.set_light(self._cycle_button_active) def _set_create_track_listeners(self): if (self._set_button != None): self._set_button.add_value_listener(self._dup_track_value) if (self._mrk_left_button != None): self._mrk_left_button.add_value_listener(self._new_midi_value) if (self._mrk_right_button != None): self._mrk_right_button.add_value_listener(self._new_audio_value) self.update() def _dup_track_value(self, value): now = time.time() if(value is not 0): self._last_button_time = now else: song = self.song() if self._track in song.tracks: if now - self._last_button_time < LONG_PRESS: song.duplicate_track(list(song.tracks).index(self._track)) else: song.delete_track(list(song.tracks).index(self._track)) def _new_audio_value(self, value): if(value is not 0): self._add_track(self.song().create_audio_track) def _new_midi_value(self, value): if(value is not 0): self._add_track(self.song().create_midi_track) def _add_track(self, func): song = self.song() index = list(song.tracks).index(self._track) + 1 if index < len(song.tracks) and index >0: track = song.tracks[index] if track.is_foldable or track.is_grouped: while index < len(song.tracks) and song.tracks[index].is_grouped: index += 1 func(index) @profile def update_display(self): super(NanoKontrolLP95, self).update_display() self._flash_counter = self._flash_counter + 1 if self._cycle_button_active == True: if(self._flash_counter % 2 == 0): if (self._flash_on == True): self._cycle_button.send_value(127) else: self._cycle_button.send_value(0) self._flash_on = not self._flash_on self._flash_counter = self._flash_counter % 4
class Novation_Impulse2(ControlSurface): """ Script for Novation's Impulse keyboards """ def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) self.c_instance = c_instance with self.component_guard(): self.set_pad_translations(PAD_TRANSLATIONS) self._device_selection_follows_track_selection = True self._suggested_input_port = 'Impulse' self._suggested_output_port = 'Impulse' self._has_sliders = True self._current_midi_map = None self._display_reset_delay = -1 self._string_to_display = None self.shift_pressed = False # special alternative buttons mode. for now only mixer buttons become record buttons. later we will add something more self.alternative_buttons_mode = False self._shift_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 39) self._preview_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 41) self._master_slider = SliderElement(MIDI_CC_TYPE, 0, 8) self._shift_button.name = 'Shift_Button' self._master_slider.name = 'Master_Volume_Control' self._master_slider.add_value_listener(self._slider_value, identify_sender=True) self._preview_button.add_value_listener(self._preview_value) self._setup_mixer() self._setup_session() self._setup_transport() self._setup_device() self._setup_name_display() device_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 1, 10) mixer_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 1, 9) device_button.name = 'Encoder_Device_Mode' mixer_button.name = 'Encoder_Mixer_Mode' self._encoder_modes = EncoderModeSelector(self._device_component, self._mixer, self._next_bank_button, self._prev_bank_button, self._encoders) self._encoder_modes.set_device_mixer_buttons(device_button, mixer_button) self._shift_button.add_value_listener(self._shift_button_handler) for component in self.components: component.set_enabled(False) # attributes def alternative_buttons_mode(self): return self.alternative_buttons_mode def alternative_buttons_mode(self,value): self.log ('alternative_buttons_mode_value ' + str(value)) self.alternative_buttons_mode = value def shift_pressed(self): return self.shift_pressed def shift_pressed(self,value): self.log ('shift_pressed value ' + str(value)) self.shift_pressed = value def refresh_state(self): ControlSurface.refresh_state(self) self.schedule_message(3, self._send_midi, SYSEX_START + (6, 1, 1, 1, 247)) def handle_sysex(self, midi_bytes): if midi_bytes[0:-2] == SYSEX_START + (7,) and midi_bytes[-2] != 0: self._has_sliders = midi_bytes[-2] != 25 self.schedule_message(1, self._show_startup_message) for control in self.controls: if isinstance(control, InputControlElement): control.clear_send_cache() for component in self.components: component.set_enabled(True) if self._has_sliders: self._mixer.master_strip().set_volume_control(self._master_slider) self._mixer.update() else: self._mixer.master_strip().set_volume_control(None) self._mixer.selected_strip().set_volume_control(self._master_slider) for index in range(len(self._sliders)): self._mixer.channel_strip(index).set_volume_control(None) slider = self._sliders[index] slider.release_parameter() if slider.value_has_listener(self._slider_value): slider.remove_value_listener(self._slider_value) self._encoder_modes.set_provide_volume_mode(not self._has_sliders) self.request_rebuild_midi_map() def disconnect(self): self.log('starting disconnect 1') self._name_display_data_source.set_display_string(' ') for encoder in self._encoders: encoder.remove_value_listener(self._encoder_value) self._master_slider.remove_value_listener(self._slider_value) if self._has_sliders: for slider in tuple(self._sliders): slider.remove_value_listener(self._slider_value) for button in self._strip_buttons: button.remove_value_listener(self._mixer_button_value) self._preview_button.remove_value_listener(self._preview_value) self.log('starting disconnect 3') ControlSurface.disconnect(self) self.log('starting disconnect 3') self._encoders = None self._sliders = None self._strip_buttons = None self._master_slider = None self._current_midi_map = None self._name_display = None self._prev_bank_button = None self._next_bank_button = None self._encoder_modes = None self._transport_view_modes = None self.log('starting disconnect 4') self._send_midi(SYSEX_START + (6, 0, 0, 0, 247)) self.log('starting disconnect 5') if self._shift_button != None: self._shift_button.remove_value_listener(self._shift_button_handler) self._shift_button = None self.log('starting disconnect 6') def build_midi_map(self, midi_map_handle): self._current_midi_map = midi_map_handle ControlSurface.build_midi_map(self, midi_map_handle) def update_display(self): ControlSurface.update_display(self) if self._string_to_display != None: self._name_display_data_source.set_display_string(self._string_to_display) self._string_to_display = None if self._display_reset_delay >= 0: self._display_reset_delay -= 1 if self._display_reset_delay == -1: self._show_current_track_name() def _setup_mixer(self): self.log('setup mixer') mute_solo_flip_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 34) self._next_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 37) self._prev_nav_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 38) self._strip_buttons = [] mute_solo_flip_button.name = 'Mute_Solo_Flip_Button' self._next_nav_button.name = 'Next_Track_Button' self._prev_nav_button.name = 'Prev_Track_Button' self._mixer = SpecialMixerComponent(self, 8, self.c_instance) self._mixer.name = 'Mixer' self._mixer.set_select_buttons(self._next_nav_button, self._prev_nav_button) self._mixer.selected_strip().name = 'Selected_Channel_Strip' self._mixer.master_strip().name = 'Master_Channel_Strip' self._mixer.master_strip().set_volume_control(self._master_slider) self._sliders = [] for index in range(8): strip = self._mixer.channel_strip(index) strip.name = 'Channel_Strip_' + str(index) strip.set_invert_mute_feedback(True) self._sliders.append(SliderElement(MIDI_CC_TYPE, 0, index)) self._sliders[-1].name = str(index) + '_Volume_Control' self._sliders[-1].set_feedback_delay(-1) self._sliders[-1].add_value_listener(self._slider_value, identify_sender=True) strip.set_volume_control(self._sliders[-1]) self._strip_buttons.append(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 9 + index)) self._strip_buttons[-1].name = str(index) + '_Mute_Button' self._strip_buttons[-1].add_value_listener(self._mixer_button_value, identify_sender=True) self._mixer.master_strip().set_mute_button(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 17)) self._mixer.set_strip_mute_solo_buttons(tuple(self._strip_buttons), mute_solo_flip_button) #self._mixer.set_shift_button(self._shift_button) self._mixer.updateMixerButtons() self._button9 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 9 + 8) def _setup_session(self): num_pads = len(PAD_TRANSLATIONS) self._session = SessionComponent(8, 0) self._session.name = 'Session_Control' self._session.selected_scene().name = 'Selected_Scene' self._session.set_mixer(self._mixer) # for ableton 9.1.1 and lower #self._session.set_track_banking_increment(num_pads) #self._session.set_track_bank_buttons(ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 35), ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 36)) # for ableton 9.1.1 and higher self._track_left_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 36) self._track_right_button = ButtonElement(not IS_MOMENTARY, MIDI_CC_TYPE, 0, 35) self._session.set_page_left_button(self._track_left_button) self._session.set_page_right_button(self._track_right_button) pads = [] for index in range(num_pads): pads.append(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 60 + index)) pads[-1].name = 'Pad_' + str(index) clip_slot = self._session.selected_scene().clip_slot(index) clip_slot.set_triggered_to_play_value(GREEN_BLINK) clip_slot.set_triggered_to_record_value(RED_BLINK) clip_slot.set_stopped_value(AMBER_FULL) clip_slot.set_started_value(GREEN_FULL) clip_slot.set_recording_value(RED_FULL) clip_slot.set_launch_button(pads[-1]) clip_slot.name = str(index) + '_Selected_Clip_Slot' def _setup_transport(self): rwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 27) ffwd_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 28) stop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 29) play_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 30) loop_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 31) rec_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 32) ffwd_button.name = 'FFwd_Button' rwd_button.name = 'Rwd_Button' loop_button.name = 'Loop_Button' play_button.name = 'Play_Button' stop_button.name = 'Stop_Button' rec_button.name = 'Record_Button' self._transport = ShiftableTransportComponent(self.c_instance,self._session, self, ffwd_button, rwd_button) self._transport.name = 'Transport' self._transport.set_stop_buttonOnInit(stop_button) self._transport.set_play_button(play_button) self._transport.set_record_buttonOnInit(rec_button) # self._transport.set_shift_button(self._shift_button) self._transport.set_mixer9_button(self._button9) self._transport_view_modes = TransportViewModeSelector(self,self.c_instance,self._transport, self._session, ffwd_button, rwd_button, loop_button) self._transport_view_modes.name = 'Transport_View_Modes' def _setup_device(self): encoders = [] for index in range(8): encoders.append(PeekableEncoderElement(MIDI_CC_TYPE, 1, index, Live.MidiMap.MapMode.relative_binary_offset)) encoders[-1].set_feedback_delay(-1) encoders[-1].add_value_listener(self._encoder_value, identify_sender=True) encoders[-1].name = 'Device_Control_' + str(index) self._encoders = tuple(encoders) self._prev_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 12) self._next_bank_button = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 11) self._prev_bank_button.name = 'Device_Bank_Down_Button' self._next_bank_button.name = 'Device_Bank_Up_Button' device = DeviceComponent() device.name = 'Device_Component' self.set_device_component(device) device.set_parameter_controls(self._encoders) device.set_bank_nav_buttons(self._prev_bank_button, self._next_bank_button) def _setup_name_display(self): self._name_display = PhysicalDisplayElement(16, 1) self._name_display.name = 'Display' self._name_display.set_message_parts(SYSEX_START + (8,), (247,)) self._name_display_data_source = DisplayDataSource() self._name_display.segment(0).set_data_source(self._name_display_data_source) def _encoder_value(self, value, sender): if not sender in self._encoders: raise AssertionError if not value in range(128): raise AssertionError # display_string = self._device_component.is_enabled() and ' - ' # display_string = sender.mapped_parameter() != None and sender.mapped_parameter().name display_string = '' if self._device_component.is_enabled(): # display_string = sender.name # track = self.song().view.selected_track # display_string = str(list(tracks).index(track) + 1) pass if (sender.mapped_parameter() != None): # display_string = display_string + '-' display_string = display_string + sender.mapped_parameter().name self._set_string_to_display(display_string) def _slider_value(self, value, sender): self.log ('_slider_value ' + str(value) + ' ' +str(sender)) if not sender in tuple(self._sliders) + (self._master_slider,): raise AssertionError if not value in range(128): raise AssertionError if self._mixer.is_enabled(): display_string = ' - ' master = self.song().master_track tracks = self.song().tracks returns = self.song().return_tracks track = None if sender.mapped_parameter() != None: self.log ('1') if sender == self._master_slider: self.log ('2') # track = self._has_sliders and master if self._has_sliders: track = master else: self.log ('2.1') track = self.song().view.selected_track else: self.log ('3') track = self._mixer.channel_strip(self._sliders.index(sender))._track else: self.log ('4') track = self.song().view.selected_track self.log('track='+str(track)) if track == master: display_string = 'Master' elif track in tracks: display_string = str(list(tracks).index(track) + 1) elif track in returns: display_string = str(chr(ord('A') + list(returns).index(track))) else: # raise False or AssertionError raise AssertionError display_string += ' Volume' self._set_string_to_display(display_string) def _mixer_button_value(self, value, sender): self.log ('__mixer_button_value ' + str(value) + ' ' +str(sender)) if not value in range(128): raise AssertionError #if self._mixer.is_enabled() and value > 0: if self._mixer.is_enabled(): strip = self._mixer.channel_strip(self._strip_buttons.index(sender)) #self._string_to_display = strip != None and None self._name_display.segment(0).set_data_source(strip.track_name_data_source()) self._name_display.update() self._display_reset_delay = STANDARD_DISPLAY_DELAY else: self._set_string_to_display(' - ') # if shift_pressed XOR alternative_mode if self.shift_pressed <> self.alternative_buttons_mode: self.log("_mixer_button_value") self.log(str(value)) if (value == 0): self.select_armed_track_if_only_one() def select_armed_track_if_only_one(self): self.log("select_armed_track_if_only_one") song = self.song() armed_tracks = [] tracks = song.tracks self.log("select_armed_track_if_only_one 2") for track in tracks: if track.can_be_armed and track.arm: armed_tracks.append(track) self.log(str(len(armed_tracks))) if (len(armed_tracks) == 1): self.log("selecting the track") sel_track = armed_tracks[0] self.song().view.selected_track = sel_track self._mixer._selected_tracks = [] self._mixer._selected_tracks.append(sel_track) self._mixer.on_selected_track_changed() def _preview_value(self, value): if not value in range(128): raise AssertionError for encoder in self._encoders: encoder.set_peek_mode(value > 0) def _show_current_track_name(self): if self._name_display != None and self._mixer != None: self._string_to_display = None self._name_display.segment(0).set_data_source(self._mixer.selected_strip().track_name_data_source()) self._name_display.update() def _show_startup_message(self): self._name_display.display_message('LIVE') self._display_reset_delay = INITIAL_DISPLAY_DELAY def _set_string_to_display(self, string_to_display): if not isinstance(string_to_display, (str, unicode)): raise AssertionError self._name_display.segment(0).set_data_source(self._name_display_data_source) self._string_to_display = string_to_display self._display_reset_delay = STANDARD_DISPLAY_DELAY def _on_selected_track_changed(self): self.log('_on_selected_track_changed') ControlSurface._on_selected_track_changed(self) self._show_current_track_name() #all_tracks = self._has_sliders or self._session.tracks_to_use() all_tracks2 = self._session.tracks_to_use() selected_track = self.song().view.selected_track num_strips = self._session.width() if selected_track in all_tracks2: track_index = list(all_tracks2).index(selected_track) self.log('track_index '+ str(track_index)) new_offset = track_index - track_index % num_strips self.log('new_offset '+ str(new_offset)) if not new_offset / num_strips == int(new_offset / num_strips): raise AssertionError self._session.set_offsets(new_offset, self._session.scene_offset()) def _shift_button_handler(self, value): self.log("root shift handler : "+ str(value)) if not self._shift_button != None: raise AssertionError if not value in range(128): raise AssertionError self.log("root shift handler 2") self.shift_pressed = value > 0 # calling other handlers self._mixer._shift_button_handler(value) self._transport._shift_button_handler(value) self._transport_view_modes._shift_button_handler(value) #clip stop self.log("root shift handler 3") num_pads = len(PAD_TRANSLATIONS) pads = [] for index in range(num_pads): pads.append(ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 0, 60 + index)) pads[-1].name = 'Pad_' + str(index) clip_slot = self._session.selected_scene().clip_slot(index) if self.shift_pressed: clip_slot.set_launch_button(None) else: clip_slot.set_launch_button(pads[index]) if self.shift_pressed: self._session.set_stop_track_clip_buttons(tuple(pads)) else: self._session.set_stop_track_clip_buttons(None) self.log("root shift handler 4") def flipAlternativeButtonMode(self): self.alternative_buttons_mode = not self.alternative_buttons_mode self.updateAlternativeButtonMode() def updateAlternativeButtonMode(self): self._mixer.updateMixerButtons() self._transport_view_modes.update() def log(self, message): pass
class QuNeo(ControlSurface): """ Script for Keith McMillen's QuNeo Multi-Touchpad Controller """ __module__ = __name__ _active_instances = [] def _combine_active_instances(): support_devices = False for instance in QuNeo._active_instances: support_devices |= instance._device_component != None track_offset = 0 for instance in QuNeo._active_instances: instance._activate_combination_mode(track_offset, support_devices) track_offset += instance._session.width() _combine_active_instances = staticmethod(_combine_active_instances) def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) self.set_suppress_rebuild_requests(True) self._suppress_session_highlight = True self._suppress_send_midi = True self._suggested_input_port = 'QUNEO' self._suggested_output_port = 'QUNEO' self.num_tracks = 7 self.num_scenes = 4 self.session = None self.mixer = None self.transport = None self.led_value = None self._note_input = [] self.shift_button = None self.sequencer_button = None self.launch_button = None self.seq_offset_down = None self.seq_offset_up = None self.seq_offset_left = None self.seq_offset_right = None self.stop_all_clips = None self.track_bank_right = None self.track_bank_left = None self.scene_bank_down = None self.scene_bank_up = None self.beat_table = [] self.sends = [] self.arm_buttons = None self.mute_buttons = None self.solo_buttons = None self.shift_buttons = [] self.sequencer_buttons = None self.scene_launch_buttons = None self.stop_track_buttons = None self.clip_slot_buttons = None self.instrument_buttons = None self.volume_control = None self.pan_control = None self.current_mode = 0 self.set_shift_button(ConfigurableButtonElement(True, MIDI_NOTE_TYPE, PAD_CHANNEL, SHIFT_BUTTON, 127)) self._setup_transport_control() self._setup_mixer_control() self._setup_session_control() self.session.set_mixer(self.mixer) self._shift_mode(0) self._set_mode(0) app = Live.Application.get_application() maj = app.get_major_version() min = app.get_minor_version() bug = app.get_bugfix_version() self.show_message(str(maj) + '.' + str(min) + '.' + str(bug)) self.set_suppress_rebuild_requests(False) def disconnect(self): self.mixer self.session if self.shift_button != None: self.shift_button.remove_value_listener(self._shift_value) self.shift_button = None if self.shift_buttons != None: for button in self.shift_buttons: button.remove_value_listener(self._shift_buttons_value) self.shift_buttons = None self._note_input = None ControlSurface.disconnect(self) def refresh_state(self): ControlSurface.refresh_state(self) def set_shift_button(self, button): if not (button == None or isinstance(button, ButtonElement)): raise AssertionError if self.shift_button != button: if self.shift_button != None: self.shift_button.remove_value_listener(self._shift_value) self.shift_button = button self.shift_button != None and self.shift_button.add_value_listener(self._shift_value) def update_mode(self, mode): if mode != None: self._set_mode(mode) self.current_mode = mode def set_shift_buttons(self, buttons): if buttons != None: if self.shift_buttons != buttons: self.shift_buttons.remove_value_listener(self._shift_buttons_value) self.shift_buttons = buttons if self.shift_buttons != None: for button in self.shift_buttons: raise isinstance(button, ButtonElement) or AssertionError button.add_value_listener(self._shift_buttons_value, identify_sender=True) else: if self.shift_buttons != None: for button in self.shift_buttons: button.remove_value_listener(self._shift_buttons_value) self.shift_buttons = None def _shift_buttons_value(self, value, sender): raise self.shift_buttons != None or AssertionError raise value in range(128) or AssertionError mode = int(sender._note * 0.5) self.update_mode(mode) def _shift_value(self, value): if not value in range(128): raise AssertionError raise self.shift_button != None or AssertionError value != 0 and self._shift_mode(1) self.shift_button.turn_on() else: self._shift_mode(0) self.shift_button.turn_off() def _shift_mode(self, value): if value != 0: self.set_suppress_rebuild_requests(True) self._reassign_grid(0) self._reassign_mixer_control(1) self.set_suppress_rebuild_requests(False) else: None self._set_mode(self.current_mode) self._reassign_mixer_control(1) def _update_grid(self): if self.sequencer_buttons != None: self.session.set_sequencer_buttons(self.sequencer_buttons) else: self.session.set_sequencer_buttons(None) if self.seq_offset_left != None and self.seq_offset_right != None: self.session.set_seq_measure_offset(self.seq_offset_left, self.seq_offset_right) else: self.session.set_seq_measure_offset(None, None) if self.seq_offset_up != None and self.seq_offset_down != None: self.session.set_seq_note_offset(self.seq_offset_up, self.seq_offset_down) else: self.session.set_seq_note_offset(None, None) if self.launch_button != None: self.session.set_slot_launch_button(self.launch_button) else: self.session.set_slot_launch_button(None) if self.scene_launch_buttons != None: for index in range(len(self.scene_launch_buttons)): self.session.scene(index).set_launch_button(self.scene_launch_buttons[index]) else: for index in range(4): self.session.scene(index).set_launch_button(None) if self.stop_track_buttons != None: self.session.set_stop_track_clip_buttons(tuple(self.stop_track_buttons)) else: self.session.set_stop_track_clip_buttons(None) if self.stop_all_clips != None: self.session.set_stop_all_clips_button(self.stop_all_clips) else: self.session.set_stop_all_clips_button(None) if self.track_bank_right != None and self.track_bank_left != None: self.session.set_track_bank_buttons(self.track_bank_right, self.track_bank_left) else: self.session.set_track_bank_buttons(None, None) if self.scene_bank_up != None and self.scene_bank_down != None: self.session.set_scene_bank_buttons(self.scene_bank_up, self.scene_bank_down) else: self.session.set_scene_bank_buttons(None, None) for row in range(4): for col in range(7): self.clip = self.session.scene(row).clip_slot(col) if self.clip_slot_buttons != None: self.clip.set_triggered_to_play_value(30) self.clip.set_triggered_to_record_value(RED_HI) self.clip.set_started_value(30) self.clip.set_recording_value(RED_HI) self.clip.set_stopped_value(80) self.clip.set_triggered_to_record_value(6) self.clip.set_launch_button(self.clip_slot_buttons[row][col]) else: self.clip.set_launch_button(None) def turn_off_all_buttons(self): self.arm_buttons = None self.mute_buttons = None self.solo_buttons = None self.scene_launch_buttons = None self.stop_track_buttons = None if self.clip_slot_buttons != None: for row in range(4): for col in range(7): button = self.clip_slot_buttons[row][col] button.turn_off() self.clip_slot_buttons = None if self.shift_buttons != None: for button in self.shift_buttons: button.turn_off() button.remove_value_listener(self._shift_buttons_value) if self.sequencer_buttons != None: for button in self.sequencer_buttons: button.count = 0 button.note_on() self.instrument_buttons = None self.shift_buttons = None self.sequencer_buttons = None self.clip_slot_buttons = None self.launch_button = None self.stop_all_clips = None self.track_bank_left = None self.track_bank_right = None self.scene_bank_up = None self.scene_bank_down = None self.seq_offset_left = None self.seq_offset_right = None self.seq_offset_up = None self.seq_offset_down = None def _set_mode(self, mode): self.turn_off_all_buttons() if mode == 0: self.stop_track_buttons = [] self.scene_launch_buttons = [] self.track_bank_left = self.button(PAD_CHANNEL, SESSION_LEFT) self.track_bank_right = self.button(PAD_CHANNEL, SESSION_RIGHT) self.scene_bank_up = self.button(PAD_CHANNEL, SESSION_UP) self.scene_bank_down = self.button(PAD_CHANNEL, SESSION_DOWN) self.stop_all_clips = self.led_button(GRID_CHANNEL, STOP_ALL_CLIPS, 100) self.launch_button = self.led_button(GRID_CHANNEL, SLOT_LAUNCH, RED_HI) self.clip_slot_buttons = [] for row in range(4): self.clip_slot_buttons.append([]) for col in range(7): self.clip_slot_buttons[row].append(self.button(GRID_CHANNEL, CLIP_NOTE_MAP[row][col])) self.mute_buttons = [] self.solo_buttons = [] self.arm_buttons = [] for index in range(7): self.mute_buttons.append(self.led_button(GRID_CHANNEL, TRACK_MUTE[index], GREEN_HI)) self.solo_buttons.append(self.led_button(GRID_CHANNEL, TRACK_SOLO[index], ORANGE_HI)) self.arm_buttons.append(self.led_button(GRID_CHANNEL, TRACK_ARM[index], RED_HI)) self.stop_track_buttons.append(self.led_button(GRID_CHANNEL, STOP_TRACK[index], 100)) for scene in range(4): self.scene_launch_buttons.append(self.led_button(GRID_CHANNEL, SCENE_LAUNCH[scene], GREEN_LO)) self._update_session() self._update_grid() elif mode == 1: self.seq_offset_left = self.button(PAD_CHANNEL, SESSION_LEFT) self.seq_offset_right = self.button(PAD_CHANNEL, SESSION_RIGHT) self.seq_offset_up = self.button(PAD_CHANNEL, SESSION_UP) self.seq_offset_down = self.button(PAD_CHANNEL, SESSION_DOWN) self.sequencer_buttons = [] for row in range(8): for col in range(8): self.sequencer_buttons.append(self.led_button(GRID_CHANNEL, CLIP_NOTE_MAP[row][col], GREEN_HI)) self._update_session() self._update_grid() self.session.clear_led() self.session.update_notes() self.session.on_device_changed() else: self.track_bank_left = self.button(PAD_CHANNEL, SESSION_LEFT) self.track_bank_right = self.button(PAD_CHANNEL, SESSION_RIGHT) self.scene_bank_up = self.button(PAD_CHANNEL, SESSION_UP) self.scene_bank_down = self.button(PAD_CHANNEL, SESSION_DOWN) self._update_session() self._update_grid() def _reassign_grid(self, value): if value == 0: self.turn_off_all_buttons() self.shift_buttons = [] for index in range(2): self.shift_buttons.append(self.led_button(GRID_CHANNEL, TRACK_ARM[index], 127)) if index == self.current_mode: self.shift_buttons[index].send_value(127, True) else: self.shift_buttons[index].send_value(40, True) self._update_session() self._update_grid() else: None def button(self, channel, value): is_momentary = True if value != -1: return ButtonElement(is_momentary, MIDI_NOTE_TYPE, channel, value) else: return None def led_button(self, channel, value, vel): is_momentary = True if value != -1: return ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, channel, value, vel) else: return None def slider(self, channel, value): if value != -1: return SliderElement(MIDI_CC_TYPE, channel, value) else: return None def assign_encoder(self, channel, value): if value != -1: return EncoderElement(MIDI_CC_TYPE, channel, value, Live.MidiMap.MapMode.relative_two_compliment) else: return None def _reassign_mixer_control(self, shift_value): if shift_value == 1: for index in range(2): self.sends.append(self.slider(SLIDER_CHANNEL, SELECTED_SENDS[index])) self.volume_control = self.slider(SLIDER_CHANNEL, SELECTED_VOL) self.pan_control = self.slider(SLIDER_CHANNEL, SELECTED_PAN) if self.sends != None: self.mixer.selected_strip().set_send_controls(tuple(self.sends)) else: self.mixer.selected_strip().set_send_controls(tuple(None)) if self.volume_control != None: self.mixer.selected_strip().set_volume_control(self.volume_control) else: self.mixer.selected_strip().set_volume_control(None) if self.pan_control != None: self.mixer.selected_strip().set_pan_control(self.pan_control) else: self.mixer.selected_strip().set_pan_control(None) def _update_session(self): if self.shift_buttons != None: self.set_shift_buttons(self.shift_buttons) else: self.set_shift_buttons(None) for index in range(7): if self.arm_buttons != None: self.mixer.channel_strip(index).set_arm_button(self.arm_buttons[index]) else: self.mixer.channel_strip(index).set_arm_button(None) if self.solo_buttons != None: self.mixer.channel_strip(index).set_solo_button(self.solo_buttons[index]) else: self.mixer.channel_strip(index).set_solo_button(None) if self.mute_buttons != None: self.mixer.channel_strip(index).set_invert_mute_feedback(True) self.mixer.channel_strip(index).set_mute_button(self.mute_buttons[index]) else: self.mixer.channel_strip(index).set_mute_button(None) def _setup_transport_control(self): self.transport = SpecialTransportComponent() self.transport.set_metronome_button(self.led_button(PAD_CHANNEL, METRONOME, 127)) self.transport.set_play_button(self.led_button(PAD_CHANNEL, PLAY, 127)) self.transport.set_stop_button(self.led_button(PAD_CHANNEL, STOP, 127)) self.transport.set_record_button(self.led_button(PAD_CHANNEL, REC, 127)) self.transport.set_overdub_button(self.led_button(PAD_CHANNEL, OVERDUB, 127)) self.transport.set_tempo_buttons(self.led_button(PAD_CHANNEL, TEMPO_UP, 127), self.led_button(PAD_CHANNEL, TEMPO_DOWN, 127)) def _setup_mixer_control(self): self.mixer = SpecialMixerComponent(self.num_tracks, self) self.mixer.name = 'Mixer' self.mixer.set_track_offset(0) self.mixer.set_select_buttons(self.button(PAD_CHANNEL, TRACK_RIGHT), self.button(PAD_CHANNEL, TRACK_LEFT)) self.mixer.set_crossfader_control(self.slider(SLIDER_CHANNEL, CROSSFADER)) for index in range(4): self.mixer.channel_strip(index).set_volume_control(self.slider(SLIDER_CHANNEL, TRACK_VOL[index])) self.num_o_tracks = self.song().visible_tracks if self.num_o_tracks != None: index_count = -1 index_table = [] for index in self.song().visible_tracks: index_count += 1 if index.has_midi_output != True: index_table.append(index_count) else: None if index_table != None: for index in range(len(index_table)): x = index_table[index] if x > 3: None else: None def _setup_session_control(self): self.session = SpecialSessionComponent(self.num_tracks, self.num_scenes, self) self.session.set_offsets(0, 0) self.session.set_select_buttons(self.button(PAD_CHANNEL, SCENE_DOWN), self.button(PAD_CHANNEL, SCENE_UP)) self.session.set_clip_loop_start(self.slider(SLIDER_CHANNEL, 6)) self.session.set_clip_loop_length(self.slider(SLIDER_CHANNEL, 7)) def _on_selected_scene_changed(self): ControlSurface._on_selected_scene_changed(self) def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(self) def _activate_combination_mode(self, track_offset, support_devices): self._session.link_with_track_offset(track_offset)
class Midi_Fighter_Twister(ControlSurface): __doc__ = " Script for Midi_Fighter_Twister in APC emulation mode " _active_instances = [] def _combine_active_instances(): track_offset = 0 scene_offset = 0 for instance in Midi_Fighter_Twister._active_instances: instance._activate_combination_mode(track_offset, scene_offset) track_offset += instance._session.width() _combine_active_instances = staticmethod(_combine_active_instances) def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) #self.set_suppress_rebuild_requests(True) with self.component_guard(): self._note_map = [] self._ctrl_map = [] self._shift_encoder_map = [] self._shift_bank_map = [] self._load_MIDI_map() self._session = None self._session_zoom = None self._mixer = None self._setup_session_control() self._setup_mixer_control() self._session.set_mixer(self._mixer) self._setup_device_and_transport_control() self.set_highlighting_session_component(self._session) #self.set_suppress_rebuild_requests(False) self._pads = [] self._load_pad_translations() self._do_combine() def disconnect(self): self._note_map = None self._ctrl_map = None self._shift_encoder_map = None self._shift_bank_map = None self._pads = None self._do_uncombine() self._shift_button = None self._session = None self._session_zoom = None self._mixer = None self._device = None ControlSurface.disconnect(self) def _do_combine(self): if self not in Midi_Fighter_Twister._active_instances: Midi_Fighter_Twister._active_instances.append(self) Midi_Fighter_Twister._combine_active_instances() def _do_uncombine(self): if ((self in Midi_Fighter_Twister._active_instances) and Midi_Fighter_Twister._active_instances.remove(self)): self._session.unlink() Midi_Fighter_Twister._combine_active_instances() def _activate_combination_mode(self, track_offset, scene_offset): if TRACK_OFFSET != -1: track_offset = TRACK_OFFSET if SCENE_OFFSET != -1: scene_offset = SCENE_OFFSET self._session.link_with_track_offset(track_offset, scene_offset) def _setup_session_control(self): is_momentary = True # sessionRight = ButtonElement(is_momentary, 1, 3, 11) # sessionLeft = ButtonElement(is_momentary, 1, 3, 8) self._session = SpecialSessionComponent(4, 4) self._session.name = 'Session_Control' self._session.set_track_bank_buttons( self._shift_bank_map[SESSIONRIGHT], self._shift_bank_map[SESSIONLEFT]) # self._session.set_track_bank_buttons(sessionRight, sessionLeft) self._session.set_scene_bank_buttons(self._note_map[SESSIONDOWN], self._note_map[SESSIONUP]) self._session.set_select_buttons(self._note_map[SCENEDN], self._note_map[SCENEUP]) self._scene_launch_buttons = [ self._note_map[SCENELAUNCH[index]] for index in range(4) ] self._track_stop_buttons = [ self._note_map[TRACKSTOP[index]] for index in range(4) ] self._session.set_stop_all_clips_button(self._note_map[STOPALLCLIPS]) self._session.set_stop_track_clip_buttons( tuple(self._track_stop_buttons)) self._session.selected_scene().name = 'Selected_Scene' self._session.selected_scene().set_launch_button( self._note_map[SELSCENELAUNCH]) self._session.set_slot_launch_button(self._note_map[SELCLIPLAUNCH]) for scene_index in range(4): scene = self._session.scene(scene_index) scene.name = 'Scene_' + str(scene_index) button_row = [] scene.set_launch_button(self._scene_launch_buttons[scene_index]) scene.set_triggered_value(2) for track_index in range(4): button = self._note_map[CLIPNOTEMAP[scene_index][track_index]] button_row.append(button) clip_slot = scene.clip_slot(track_index) clip_slot.name = str(track_index) + '_Clip_Slot_' + str( scene_index) clip_slot.set_launch_button(button) self._session_zoom = SpecialZoomingComponent(self._session) self._session_zoom.name = 'Session_Overview' self._session_zoom.set_nav_buttons(self._note_map[ZOOMUP], self._note_map[ZOOMDOWN], self._note_map[ZOOMLEFT], self._note_map[ZOOMRIGHT]) def _setup_mixer_control(self): is_momentary = True MasterVol = ButtonElement(is_momentary, 1, 4, 3) self._mixer = SpecialMixerComponent(4) self._mixer.name = 'Mixer' self._mixer.master_strip().name = 'Master_Channel_Strip' self._mixer.master_strip().set_select_button(self._note_map[MASTERSEL]) self._mixer.selected_strip().name = 'Selected_Channel_Strip' self._mixer.set_select_buttons(self._note_map[TRACKRIGHT], self._note_map[TRACKLEFT]) self._mixer.set_crossfader_control(self._ctrl_map[CROSSFADER]) self._mixer.set_prehear_volume_control(self._ctrl_map[CUELEVEL]) self._mixer.master_strip().set_volume_control( self._shift_encoder_map[MASTERVOLUME]) for track in range(4): strip = self._mixer.channel_strip(track) strip.name = 'Channel_Strip_' + str(track) strip.set_arm_button(self._note_map[TRACKREC[track]]) strip.set_solo_button(self._note_map[TRACKSOLO[track]]) strip.set_mute_button(self._note_map[TRACKMUTE[track]]) strip.set_select_button(self._note_map[TRACKSEL[track]]) strip.set_volume_control(self._ctrl_map[TRACKVOL[track]]) strip.set_pan_control(self._ctrl_map[TRACKPAN[track]]) strip.set_send_controls((self._ctrl_map[TRACKSENDA[track]], self._ctrl_map[TRACKSENDB[track]], self._ctrl_map[TRACKSENDC[track]])) strip.set_invert_mute_feedback(True) # have right side btns act as device next/prev & toggle on/off? def _setup_device_and_transport_control(self): is_momentary = True # self._device = DeviceComponent() # self._device.name = 'Device_Component' # uses BestBankDeviceComponent as pseudo for Device_Component self._device = BestBankDeviceComponent( device_selection_follows_track_selection=True) self._device.name = u'Device_Component' # device_bank_buttons = [] device_param_controls = [] # Accounts for mappings on top two rows of MFT for index in range(16): # handles all 16 encoder knobs device_param_controls.append(self._ctrl_map[PARAMCONTROL[index]]) for index in range(4): # 1st row, shift encoder hold device_param_controls.append( self._shift_encoder_map[PARAMCONTROL[index]]) for index in range(6): # 2nd row & left-half of 3rd row, CC hold device_param_controls.append(self._note_map[PARAMCONTROL[index + 4]]) # Accounts for mappings on third row of MFT # for index in range(4): # device_param_controls.append(self._shift_encoder_map[PARAMCONTROL[index + 8]]) # device_bank_buttons.append(self._note_map[DEVICEBANK[index]]) # if None not in device_bank_buttons: # self._device.set_bank_buttons(tuple(device_bank_buttons)) if None not in device_param_controls: self._device.set_parameter_controls(tuple(device_param_controls)) self._device.set_on_off_button(self._shift_bank_map[DEVICEONOFF]) # self._device.set_bank_nav_buttons(self._shift_bank_map[DEVICEBANKNAVLEFT], self._shift_bank_map[DEVICEBANKNAVRIGHT]) self._device.set_bank_nav_buttons(self._note_map[DEVICEBANKNAVLEFT], self._note_map[DEVICEBANKNAVRIGHT]) self._device.set_lock_button(self._note_map[DEVICELOCK]) self.set_device_component(self._device) detail_view_toggler = DetailViewControllerComponent() detail_view_toggler.name = 'Detail_View_Control' detail_view_toggler.set_device_clip_toggle_button( self._shift_bank_map[CLIPTRACKVIEW]) detail_view_toggler.set_detail_toggle_button( self._shift_bank_map[DETAILVIEW]) # detail_view_toggler.set_device_nav_buttons(self._note_map[DEVICENAVLEFT], self._note_map[DEVICENAVRIGHT] ) detail_view_toggler.set_device_nav_buttons( self._shift_bank_map[DEVICENAVLEFT], self._shift_bank_map[DEVICENAVRIGHT]) transport = SpecialTransportComponent() transport.name = 'Transport' transport.set_play_button(self._note_map[PLAY]) transport.set_stop_button(self._note_map[STOP]) transport.set_record_button(self._note_map[REC]) transport.set_nudge_buttons(self._note_map[NUDGEUP], self._note_map[NUDGEDOWN]) transport.set_undo_button(self._shift_bank_map[UNDO]) transport.set_redo_button(self._note_map[REDO]) transport.set_tap_tempo_button(self._note_map[TAPTEMPO]) transport.set_quant_toggle_button(self._note_map[RECQUANT]) transport.set_overdub_button(self._note_map[OVERDUB]) transport.set_metronome_button(self._note_map[METRONOME]) transport.set_tempo_control(self._ctrl_map[TEMPOCONTROL]) transport.set_loop_button(self._note_map[LOOP]) transport.set_seek_buttons(self._note_map[SEEKFWD], self._note_map[SEEKRWD]) transport.set_punch_buttons(self._note_map[PUNCHIN], self._note_map[PUNCHOUT]) ##transport.set_song_position_control(self._ctrl_map[SONGPOSITION]) #still not implemented as of Live 8.1.6 def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(self) # From Axiom_AIR_25_49_61.py line 202 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) # BEGIN update(self) FROM EncoderModeSelector.py # # todo: Move this block to a file where 'self._ctrl_map[PARAMCONTROL[index]]' # is accessible (MFT see line 164 for example) # if self.is_enabled(): # self._device.set_allow_update(False) # self._mixer.set_allow_update(False) # self._device.set_parameter_controls(()) # self._mixer.set_send_controls(()) # for index in range(len(self._encoders)): # strip = self._mixer.channel_strip(index) # encoder = self._encoders[index] # strip.set_volume_control(None) # strip.set_pan_control(None) # encoder.release_parameter() # if self._mode_index == 0: # strip.set_volume_control(encoder) # encoder.set_on_off_values(AMB_FULL, LED_OFF) # elif self._mode_index == 1: # strip.set_pan_control(encoder) # encoder.set_on_off_values(RED_FULL, LED_OFF) # elif self._mode_index == 2: # encoder.set_on_off_values(GRN_FULL, LED_OFF) # elif self._mode_index == 3: # encoder.set_on_off_values(RED_FULL, LED_OFF) # if self._mode_index == 0: # self._modes_buttons[0].send_value(AMB_FULL, True) # self._modes_buttons[1].send_value(LED_OFF, True) # elif self._mode_index == 1: # self._modes_buttons[0].send_value(RED_FULL, True) # self._modes_buttons[1].send_value(LED_OFF, True) # elif self._mode_index == 2: # self._modes_buttons[0].send_value(GRN_FULL, True) # self._modes_buttons[1].send_value(LED_OFF, True) # self._mixer.set_send_controls(self._encoders) # elif self._mode_index == 3: # self._modes_buttons[0].send_value(LED_OFF, True) # self._modes_buttons[1].send_value(RED_FULL, True) # self._device.set_parameter_controls(self._encoders) # self._device.set_allow_update(True) # # END update(self) FROM EncoderModeSelector.py def _load_pad_translations(self): if -1 not in DRUM_PADS: pad = [] for row in range(4): for col in range(4): pad = ( col, row, DRUM_PADS[row * 4 + col], PADCHANNEL, ) self._pads.append(pad) self.set_pad_translations(tuple(self._pads)) def _load_MIDI_map(self): is_momentary = True for note in range(128): button = ButtonElement(is_momentary, MESSAGETYPE, BUTTONCHANNEL, note) button.name = 'Note_' + str(note) self._note_map.append(button) # CC Hold, CC Toggle shift_bank_button = ButtonElement(is_momentary, MESSAGETYPE, SHIFTBANKCHANNEL, note) shift_bank_button.name = 'Note_' + str(note) self._shift_bank_map.append(shift_bank_button) # Shift Bank shift_encoder = ButtonElement(is_momentary, 1, ENCODERSHIFTCHANNEL, note) shift_encoder.name = 'Note_' + str(note) self._shift_encoder_map.append(shift_encoder) # Shift Encoder Hold self._note_map.append( None) #add None to the end of the list, selectable with [-1] self._shift_encoder_map.append(None) self._shift_bank_map.append(None) if MESSAGETYPE == MIDI_CC_TYPE and BUTTONCHANNEL == SLIDERCHANNEL: for ctrl in range(128): self._ctrl_map.append(None) else: for ctrl in range(128): control = SliderElement(MIDI_CC_TYPE, SLIDERCHANNEL, ctrl) control.name = 'Ctrl_' + str(ctrl) self._ctrl_map.append(control) # Standard Encoder self._ctrl_map.append(None)