def _setup_mixer_control(self): is_momentary = True self._num_tracks = (7) #A mixer is one-dimensional; global mixer mixer = SpecialMixerComponent(7, 0, True, False) mixer.name = 'Mixer' self._mixer = mixer mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left) for index in range(7): mixer.channel_strip(index).set_volume_control(self._fader[index]) for index in range(7): mixer.channel_strip(index).name = 'Mixer_ChannelStrip_' + str(index) mixer.track_eq(index).name = 'Mixer_EQ_' + str(index) mixer.channel_strip(index)._invert_mute_feedback = True self.song().view.selected_track = mixer.channel_strip(0)._track #set the selected strip to the first track, so that we don't, for example, try to assign a button to arm the master track, which would cause an assertion error
def _setup_mixer_control(self): is_momentary = True self._num_tracks = (7) #A mixer is one-dimensional; global mixer mixer = SpecialMixerComponent(7, 0, True, False) mixer.name = 'Mixer' self._mixer = mixer mixer.set_track_offset( 0) #Sets start point for mixer strip (offset from left) for index in range(7): mixer.channel_strip(index).set_volume_control(self._fader[index]) for index in range(7): mixer.channel_strip( index).name = 'Mixer_ChannelStrip_' + str(index) mixer.track_eq(index).name = 'Mixer_EQ_' + str(index) mixer.channel_strip(index)._invert_mute_feedback = True self.song().view.selected_track = mixer.channel_strip( 0 )._track #set the selected strip to the first track, so that we don't, for example, try to assign a button to arm the master track, which would cause an assertion error
class QuNeo(ControlSurface): __doc__ = " Minimal Script for Volume control via _Framework by @djnsm / Data Mafia " __module__ = __name__ # INIT FUNCTION FOR QUNEO def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) # in aaa with self.component_guard(): # new for Live9 / Py self._suppress_session_highlight = True self._suppress_send_midi = True # self.session = None #=========== self.mixer = None self.box_width = box_width # self.transport = None -----marwei # self.led_value = None ------marwei #self._note_input = [] -------marwei # marwei added for web app++ self.gutter = gutter # see param info self.volume_control = None self._setup_mixer_control() #------- needed #self._setup_session_control() # ----------- #self.session.set_mixer(self.mixer) #---------- # @marwei --- needed? 8apr self._suppress_session_highlight = False # DISCONNECT FUNCTION def disconnect(self): self.mixer self.session #self._note_input = None ControlSurface.disconnect(self) return None # CREATE A SLIDER @marwei reqd def slider(self, channel, value): if (value != -1): return SliderElement(MIDI_CC_TYPE, channel, value) else: return None # REASSIGN MIXER def _reassign_mixer_control(self, shift_value): self.volume_control = self.slider(midi_channel, SELECTED_VOL) if (self.volume_control != None): self.mixer.selected_strip().set_volume_control(self.volume_control) else: self.mixer.selected_strip().set_volume_control(None) # SETUP MIXER def _setup_mixer_control(self): self.mixer = SpecialMixerComponent( self.box_width, self) # get a local mixer object ready self.mixer.name = 'Mixer' # name self.mixer.set_track_offset(self.gutter) # gutter ----marwei # compare width with track vol count to qualify -- put somewhere else for index in range( self.box_width): # @marwei must kill this style and count self.mixer.channel_strip(index).set_volume_control( self.slider(midi_channel, track_volume[index]))
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 QuNeo(ControlSurface): __doc__ = " Minimal Script for Volume control via _Framework by @djnsm / Data Mafia " __module__ = __name__ # INIT FUNCTION FOR QUNEO def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) # in aaa with self.component_guard(): # new for Live9 / Py self._suppress_session_highlight = True self._suppress_send_midi = True # self.session = None #=========== self.mixer = None self.box_width = box_width # self.transport = None -----marwei # self.led_value = None ------marwei #self._note_input = [] -------marwei # marwei added for web app++ self.gutter = gutter # see param info self.volume_control = None self._setup_mixer_control() #------- needed #self._setup_session_control() # ----------- #self.session.set_mixer(self.mixer) #---------- # @marwei --- needed? 8apr self._suppress_session_highlight = False # DISCONNECT FUNCTION def disconnect(self): self.mixer self.session #self._note_input = None ControlSurface.disconnect(self) return None # CREATE A SLIDER @marwei reqd def slider(self, channel, value): if (value != -1): return SliderElement(MIDI_CC_TYPE, channel, value) else: return None # REASSIGN MIXER def _reassign_mixer_control(self, shift_value): self.volume_control = self.slider(midi_channel, SELECTED_VOL) if (self.volume_control != None): self.mixer.selected_strip().set_volume_control(self.volume_control) else: self.mixer.selected_strip().set_volume_control(None) # SETUP MIXER def _setup_mixer_control(self): self.mixer = SpecialMixerComponent(self.box_width, self) # get a local mixer object ready self.mixer.name = 'Mixer' # name self.mixer.set_track_offset(self.gutter) # gutter ----marwei # compare width with track vol count to qualify -- put somewhere else for index in range(self.box_width): # @marwei must kill this style and count self.mixer.channel_strip(index).set_volume_control(self.slider(midi_channel, track_volume[index]))
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 NanoKontrolShift(ControlSurface): __module__ = __name__ __doc__ = " NanoKontrolShift 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 self.log_message(time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) + "--------------= NanoKontrolShift 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.view = None #clip/device view object self.device = None #device object self.transport = None #transport object # MODES self._shift_button = None self._shift_button_pressed = False self._alt_button = None self._alt_button_pressed = False self._ctrl_button = None self._ctrl_button_pressed = False # INITIALIZE MIXER, SESSIONS self._setup_session_control() # Setup the session object self._setup_mixer_control() # Setup the mixer object self._setup_view_control() # Setup the clip/view toggler self.session.set_mixer(self.mixer) # Bind mixer to session self._setup_device_control() # Setup the device object self._setup_transport_control() # Setup transport object self.set_device_component(self.device) # Bind device to control surface # SET INITIAL SESSION/MIXER AND MODIFIERS BUTTONS self._set_modifiers_buttons() self.__update_matrix() # self.set_highlighting_session_component(self.session) for component in self.components: component.set_enabled(True) # self._suppress_session_highlight = True self._suppress_send_midi = True # Turn rebuild back on, once we're done setting up def _setup_session_control(self): self.show_message("#################### SESSION: ON ##############################") is_momentary = True # CREATE SESSION, SET OFFSETS, BUTTONS NAVIGATION AND BUTTON MATRIX self.session = SessionComponent(num_tracks, num_scenes) #(num_tracks, num_scenes) self.session.set_offsets(0, 0) # self.session.set_scene_bank_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, session_down), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, session_up)) # self.session.set_track_bank_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, session_right), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, session_left)) # (right_button, left_button) This moves the "red box" selection set left & right. We'll use the mixer track selection instead... def _setup_mixer_control(self): is_momentary = True #CREATE MIXER, SET OFFSET (SPECIALMIXERCOMPONENT USES SPECIALCHANNELSTRIP THAT ALLOWS US TO UNFOLD TRACKS WITH TRACK SELECT BUTTON) self.mixer = SpecialMixerComponent(num_tracks, 0, False, False) # 4 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) def _setup_view_control(self): # CREATES OBJECT SO WE CAN TOGGLE DEVICE/CLIP, LOCK DEVICE self.view = ViewTogglerComponent(num_tracks, self) def _setup_device_control(self): # CREATE DEVICE TO ASSIGN PARAMETERS BANK self.device = DeviceComponent() self.device.name = 'Device_Component' def _setup_transport_control(self): # CREATE TRANSPORT DEVICE self.transport = SpecialTransportComponent(self) def _on_selected_scene_changed(self): # ALLOWS TO GRAB THE FIRST DEVICE OF A SELECTED TRACK IF THERE'S ANY ControlSurface._on_selected_track_changed(self) track = self.song().view.selected_track if (track.devices is not None): self._ignore_track_selection = True device_to_select = track.devices[0] self.song().view.select_device(device_to_select) self._device_component.set_device(device_to_select) self._ignore_track_selection = False """ LED ON, OFF, FLASH WITH SESSION CLIPS """ # UPDATING BUTTONS FROM CLIP MATRIX IN NK AS SESSION MOVES def __update_matrix(self): for scene_index in range(num_scenes): scene = self.session.scene(scene_index) for track_index in range(num_tracks): clip_slot = scene.clip_slot(track_index) button = clip_slot._launch_button_value.subject value_to_send = -1 if clip_slot._clip_slot != None: if clip_slot.has_clip(): value_to_send = 127 if clip_slot._clip_slot.clip.is_triggered: if clip_slot._clip_slot.clip.will_record_on_start: value_to_send = clip_slot._triggered_to_record_value else: value_to_send = clip_slot._triggered_to_play_value ''' elif clip_slot._clip_slot.clip.is_playing: if clip_slot._clip_slot.clip.is_recording: value_to_send = 127 ######### CLIPS PLAYING WILL FLASH for i in range(2000): if i % 50 == 0: button.send_value(127) else: button.send_value(0) else: for i in range(2000): if i % 50 == 0: button.send_value(127) else: button.send_value(0) ''' elif clip_slot._clip_slot.is_triggered: if clip_slot._clip_slot.will_record_on_start: value_to_send = clip_slot._triggered_to_record_value else: value_to_send = clip_slot._triggered_to_play_value elif clip_slot._clip_slot.is_playing: if clip_slot._clip_slot.is_recording: value_to_send = clip_slot._recording_value else: value_to_send = clip_slot._started_value elif clip_slot._clip_slot.controls_other_clips: value_to_send = 0 ''' if value_to_send in range(128): button.send_value(value_to_send) else: button.turn_off() ''' """ MODIFIERS, MODES, KEYS CONFIG """ #MODES ARE HERE: INITIALIZATIONS, DISCONNECTS BUTTONS, SLIDERS, ENCODERS def _clear_controls(self): # TURNING OFF ALL LEDS IN MATRIX self._turn_off_matrix() # SESSION resetsend_controls = [] self.mixer.send_controls = [] for scene_index in range(num_scenes): scene = self.session.scene(scene_index) scene.set_launch_button(None) for track_index in range(num_tracks): clip_slot = scene.clip_slot(track_index) clip_slot.set_launch_button(None) self.session.set_stop_track_clip_buttons(None) self.session.set_stop_all_clips_button(None) # REMOVE LISTENER TO SESSION MOVES if self.session.offset_has_listener(self.__update_matrix): self.session.remove_offset_listener(self.__update_matrix) self.session.set_stop_all_clips_button(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)) # VIEW self.view.set_device_nav_buttons(None, None) detailclip_view_controls = [] for track_index in range(num_tracks): detailclip_view_controls.append(None) self.view.set_buttons(tuple(detailclip_view_controls)) # DEVICE PARAMETERS device_param_controls = [] self.device.set_parameter_controls(tuple(device_param_controls)) self.device.set_on_off_button(None) self.device.set_lock_button(None) # TRANSPORT self.transport.set_stop_button(None) self.transport.set_play_button(None) self.transport.set_record_button(None) self.transport._set_quant_toggle_button(None) self.transport.set_metronome_button(None) self.transport._set_tempo_buttons(None, None) self.log_message("Controls Cleared") def _set_normal_mode(self): is_momentary = True self.mixer._set_send_nav(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, send_up), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, send_down)) for index in range(num_tracks): strip = self.mixer.channel_strip(index) strip.name = 'Mixer_ChannelStrip_' + str(index) self.mixer._update_send_index(self.mixer.sends_index) strip.set_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL, mixer_volumefader_cc[index])) self.mixer.send_controls[self.mixer.sends_index] = EncoderElement(MIDI_CC_TYPE, CHANNEL, mixer_sendknob_cc[index], Live.MidiMap.MapMode.absolute) strip.set_send_controls(tuple(self.mixer.send_controls)) strip._invert_mute_feedback = True ### SET ARM, SOLO, MUTE for index in range(num_tracks): strip = self.mixer.channel_strip(index) strip.set_send_controls(tuple(self.mixer.send_controls)) strip.set_solo_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, track_solo_cc[index])) strip.set_mute_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, track_mute_cc[index])) strip.set_arm_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, track_arm_cc[index])) # self.transport.set_stop_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, transport_stop_cc)) for i in range(12): self.mixer.send_controls.append(None) self.mixer.send_controls[self.mixer.sends_index] = EncoderElement(MIDI_CC_TYPE, CHANNEL, mixer_sendknob_cc[index], Live.MidiMap.MapMode.absolute) strip.set_send_controls(tuple(self.mixer.send_controls)) strip._invert_mute_feedback = True self.mixer._update_send_index(self.mixer.sends_index) def _set_alt_mode(self): is_momentary = True self.mixer._set_send_nav(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, send_up), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, send_down)) stop_track_controls = [] resetsend_controls = [] button = None buttons = None # SET SESSION TRACKSTOP, TRACK SELECT, RESET SEND KNOB for index in range(num_tracks): strip = self.mixer.channel_strip(index) strip.set_select_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, track_select_cc[index])) button = ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, stop_track_cc[index]) stop_track_controls.append(button) buttons = ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, track_resetsend_cc[index]) resetsend_controls.append(buttons) 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.mixer.sends_index) def _set_ctrl_mode(self): # CLIP/DEVICE VIEW TOGGLE is_momentary = True self.view.set_device_nav_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, device_left_cc), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, device_right_cc)) button = None detailclip_view_controls = [] for index in range(num_tracks): button = ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, detailclip_view_cc[index]) detailclip_view_controls.append(button) self.view.set_buttons(tuple(detailclip_view_controls)) # DEVICE ON/OFF, LOCK AND PARAMETERS device_param_controls = [] onoff_control = ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, onoff_device_cc) setlock_control = ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, lock_device_cc) for index in range(num_tracks): knob = None knob = EncoderElement(MIDI_CC_TYPE, CHANNEL, device_param_cc[index], Live.MidiMap.MapMode.absolute) device_param_controls.append(knob) if None not in device_param_controls: self.device.set_parameter_controls(tuple(device_param_controls)) self.device.set_on_off_button(onoff_control) self.device.set_lock_button(setlock_control) # TRANSPORT # self.transport.set_stop_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, transport_stop_cc)) # self.transport.set_play_button(ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, transport_play_cc)) # self.transport.set_record_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, transport_record_cc)) self.transport._set_quant_toggle_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, transport_quantization_cc)) self.transport.set_metronome_button(ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, transport_metronome_cc)) self.transport._set_tempo_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, transport_tempodown_cc), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, transport_tempoup_cc)) # SESSION STOP ALL CLIPS AND SCENE LAUNCH self.session.set_stop_all_clips_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, session_stopall_cc)) for index in range(num_scenes): self.session.scene(index).set_launch_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, session_scenelaunch_cc[index])) def _set_modifiers_buttons(self): is_momentary = True self._shift_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, shift_mod) self._alt_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, alt_mod) self._ctrl_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, ctrl_mod) if (self._shift_button != None): self._shift_button.add_value_listener(self._shift_value) if (self._alt_button != None): self._alt_button.add_value_listener(self._alt_value) if (self._ctrl_button != None): self._ctrl_button.add_value_listener(self._ctrl_value) #INIT NORMAL MODE self._manage_modes(0) # MODIFIERS LISTENERS FUNCS ARE HERE def _shift_value(self, value): assert isinstance(value, int) assert isinstance(self._shift_button, ButtonElement) if value == 127: if self._shift_button_pressed is False: self._unpress_modes() self._shift_button_pressed = True self._manage_modes(0) def _alt_value(self, value): assert isinstance(value, int) assert isinstance(self._alt_button, ButtonElement) if value == 127: if self._alt_button_pressed is False: self._unpress_modes() self._alt_button_pressed = True self._manage_modes(2) def _ctrl_value(self, value): assert isinstance(value, int) assert isinstance(self._ctrl_button, ButtonElement) if value == 127: if self._ctrl_button_pressed is False: self._unpress_modes() self._ctrl_button_pressed = True self._manage_modes(3) def _manage_modes(self, mode_index): if mode_index == 0: self._clear_controls() self._set_normal_mode() # self._shift_button.turn_on() self._alt_button.turn_on() self._ctrl_button.turn_on() self.log_message("NORMAL ON") elif mode_index == 2: self._clear_controls() self._set_alt_mode() self._alt_button.turn_on() self._shift_button.turn_off() self._ctrl_button.turn_off() self.log_message("ALT ON") elif mode_index == 3: self._clear_controls() self._set_ctrl_mode() self._ctrl_button.turn_on() self._shift_button.turn_off() self._alt_button.turn_off() self.log_message("CTRL ON") def _unpress_modes(self): self._shift_button_pressed = False self._alt_button_pressed = False self._ctrl_button_pressed = False def _turn_off_matrix(self): for index in range(24): self._send_midi(tuple([176,index+16,0])) def disconnect(self): """clean things up on disconnect""" self.log_message(time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) + "--------------= NanoKontrolShift log closed =--------------") #Create entry in log file self._clear_controls() self.session = None self.mixer = None self.view = None self.device = None self.transport = None # MODES self._shift_button = None self._alt_button = None self._ctrl_button = None # SENDS self.send_button_up = None self.send_button_down = None self.send_controls = [] self.send_reset = [] self.set_device_component(None) ControlSurface.disconnect(self) return None
class NanoKontrolShift(ControlSurface): __module__ = __name__ __doc__ = " NanoKontrolShift 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 self.log_message( time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) + "--------------= NanoKontrolShift 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.view = None # clip/device view object self.device = None # device object self.transport = None # transport object # MODES self._shift_button = None self._shift_button_pressed = False self._alt_button = None self._alt_button_pressed = False self._ctrl_button = None self._ctrl_button_pressed = False # INITIALIZE MIXER, SESSIONS self._setup_session_control() # Setup the session object self._setup_mixer_control() # Setup the mixer object self._setup_view_control() # Setup the clip/view toggler self.session.set_mixer(self.mixer) # Bind mixer to session self._setup_device_control() # Setup the device object self._setup_transport_control() # Setup transport object self.set_device_component( self.device) # Bind device to control surface # SET INITIAL SESSION/MIXER AND MODIFIERS BUTTONS self._set_modifiers_buttons() self.__update_matrix() self.set_highlighting_session_component(self.session) for component in self.components: component.set_enabled(True) # self._suppress_session_highlight = True self._suppress_send_midi = True # Turn rebuild back on, once we're done setting up def _setup_session_control(self): self.show_message( "#################### SESSION: ON ##############################") is_momentary = True # CREATE SESSION, SET OFFSETS, BUTTONS NAVIGATION AND BUTTON MATRIX self.session = SessionComponent(num_tracks, num_scenes) # (num_tracks, num_scenes) self.session.set_offsets(0, 0) # self.session.set_scene_bank_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, session_down), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, session_up)) self.session.set_track_bank_buttons( ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, session_right), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, session_left) ) # (right_button, left_button) This moves the "red box" selection set left & right. We'll use the mixer track selection instead... def _setup_mixer_control(self): is_momentary = True # CREATE MIXER, SET OFFSET (SPECIALMIXERCOMPONENT USES SPECIALCHANNELSTRIP THAT ALLOWS US TO UNFOLD TRACKS WITH TRACK SELECT BUTTON) self.mixer = SpecialMixerComponent( num_tracks, 0, False, False) # 4 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) def _setup_view_control(self): # CREATES OBJECT SO WE CAN TOGGLE DEVICE/CLIP, LOCK DEVICE self.view = ViewTogglerComponent(num_tracks, self) def _setup_device_control(self): # CREATE DEVICE TO ASSIGN PARAMETERS BANK self.device = DeviceComponent() self.device.name = 'Device_Component' def _setup_transport_control(self): # CREATE TRANSPORT DEVICE self.transport = SpecialTransportComponent(self) def _on_selected_scene_changed(self): # ALLOWS TO GRAB THE FIRST DEVICE OF A SELECTED TRACK IF THERE'S ANY ControlSurface._on_selected_track_changed(self) track = self.song().view.selected_track if (track.devices is not None): self._ignore_track_selection = True device_to_select = track.devices[0] self.song().view.select_device(device_to_select) self._device_component.set_device(device_to_select) self._ignore_track_selection = False """ LED ON, OFF, FLASH WITH SESSION CLIPS """ # UPDATING BUTTONS FROM CLIP MATRIX IN NK AS SESSION MOVES def __update_matrix(self): for scene_index in range(num_scenes): scene = self.session.scene(scene_index) for track_index in range(num_tracks): clip_slot = scene.clip_slot(track_index) button = clip_slot._launch_button_value.subject value_to_send = -1 if clip_slot._clip_slot != None: if clip_slot.has_clip(): value_to_send = 127 if clip_slot._clip_slot.clip.is_triggered: if clip_slot._clip_slot.clip.will_record_on_start: value_to_send = clip_slot._triggered_to_record_value else: value_to_send = clip_slot._triggered_to_play_value ''' elif clip_slot._clip_slot.clip.is_playing: if clip_slot._clip_slot.clip.is_recording: value_to_send = 127 ######### CLIPS PLAYING WILL FLASH for i in range(2000): if i % 50 == 0: button.send_value(127) else: button.send_value(0) else: for i in range(2000): if i % 50 == 0: button.send_value(127) else: button.send_value(0) ''' elif clip_slot._clip_slot.is_triggered: if clip_slot._clip_slot.will_record_on_start: value_to_send = clip_slot._triggered_to_record_value else: value_to_send = clip_slot._triggered_to_play_value elif clip_slot._clip_slot.is_playing: if clip_slot._clip_slot.is_recording: value_to_send = clip_slot._recording_value else: value_to_send = clip_slot._started_value elif clip_slot._clip_slot.controls_other_clips: value_to_send = 0 ''' if value_to_send in range(128): button.send_value(value_to_send) else: button.turn_off() ''' """ MODIFIERS, MODES, KEYS CONFIG """ # MODES ARE HERE: INITIALIZATIONS, DISCONNECTS BUTTONS, SLIDERS, ENCODERS def _clear_controls(self): # TURNING OFF ALL LEDS IN MATRIX self._turn_off_matrix() # SESSION resetsend_controls = [] self.mixer.send_controls = [] for scene_index in range(num_scenes): scene = self.session.scene(scene_index) scene.set_launch_button(None) for track_index in range(num_tracks): clip_slot = scene.clip_slot(track_index) clip_slot.set_launch_button(None) self.session.set_stop_track_clip_buttons(None) self.session.set_stop_all_clips_button(None) # REMOVE LISTENER TO SESSION MOVES if self.session.offset_has_listener(self.__update_matrix): self.session.remove_offset_listener(self.__update_matrix) self.session.set_stop_all_clips_button(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)) # VIEW self.view.set_device_nav_buttons(None, None) detailclip_view_controls = [] for track_index in range(num_tracks): detailclip_view_controls.append(None) self.view.set_buttons(tuple(detailclip_view_controls)) # DEVICE PARAMETERS device_param_controls = [] self.device.set_parameter_controls(tuple(device_param_controls)) self.device.set_on_off_button(None) self.device.set_lock_button(None) # TRANSPORT self.transport.set_stop_button(None) self.transport.set_play_button(None) self.transport.set_record_button(None) self.transport._set_quant_toggle_button(None) self.transport.set_metronome_button(None) self.transport._set_tempo_buttons(None, None) self.log_message("Controls Cleared") def _set_normal_mode(self): is_momentary = True self.mixer._set_send_nav( ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, send_up), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, send_down)) for index in range(num_tracks): strip = self.mixer.channel_strip(index) strip.name = 'Mixer_ChannelStrip_' + str(index) self.mixer._update_send_index(self.mixer.sends_index) strip.set_volume_control( SliderElement(MIDI_CC_TYPE, CHANNEL, mixer_volumefader_cc[index])) self.mixer.send_controls[self.mixer.sends_index] = EncoderElement( MIDI_CC_TYPE, CHANNEL, mixer_sendknob_cc[index], Live.MidiMap.MapMode.absolute) strip.set_send_controls(tuple(self.mixer.send_controls)) strip._invert_mute_feedback = True ### SET ARM, SOLO, MUTE for index in range(num_tracks): strip = self.mixer.channel_strip(index) strip.set_send_controls(tuple(self.mixer.send_controls)) strip.set_solo_button( ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, track_solo_cc[index])) strip.set_mute_button( ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, track_mute_cc[index])) strip.set_arm_button( ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, track_arm_cc[index])) # self.transport.set_stop_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, transport_stop_cc)) for i in range(12): self.mixer.send_controls.append(None) self.mixer.send_controls[self.mixer.sends_index] = EncoderElement( MIDI_CC_TYPE, CHANNEL, mixer_sendknob_cc[index], Live.MidiMap.MapMode.absolute) strip.set_send_controls(tuple(self.mixer.send_controls)) strip._invert_mute_feedback = True self.mixer._update_send_index(self.mixer.sends_index) def _set_alt_mode(self): is_momentary = True self.mixer._set_send_nav( ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, send_up), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, send_down)) stop_track_controls = [] resetsend_controls = [] button = None buttons = None # SET SESSION TRACKSTOP, TRACK SELECT, RESET SEND KNOB for index in range(num_tracks): strip = self.mixer.channel_strip(index) strip.set_select_button( ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, track_select_cc[index])) button = ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, stop_track_cc[index]) stop_track_controls.append(button) buttons = ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, track_resetsend_cc[index]) resetsend_controls.append(buttons) 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.mixer.sends_index) def _set_ctrl_mode(self): # CLIP/DEVICE VIEW TOGGLE is_momentary = True self.view.set_device_nav_buttons( ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, device_left_cc), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, device_right_cc)) button = None detailclip_view_controls = [] for index in range(num_tracks): button = ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, detailclip_view_cc[index]) detailclip_view_controls.append(button) self.view.set_buttons(tuple(detailclip_view_controls)) # DEVICE ON/OFF, LOCK AND PARAMETERS device_param_controls = [] onoff_control = ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, onoff_device_cc) setlock_control = ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, lock_device_cc) for index in range(num_tracks): knob = None knob = EncoderElement(MIDI_CC_TYPE, CHANNEL, device_param_cc[index], Live.MidiMap.MapMode.absolute) device_param_controls.append(knob) if None not in device_param_controls: self.device.set_parameter_controls(tuple(device_param_controls)) self.device.set_on_off_button(onoff_control) self.device.set_lock_button(setlock_control) # TRANSPORT # self.transport.set_stop_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, transport_stop_cc)) # self.transport.set_play_button(ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, transport_play_cc)) # self.transport.set_record_button(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, transport_record_cc)) self.transport._set_quant_toggle_button( ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, transport_quantization_cc)) self.transport.set_metronome_button( ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, transport_metronome_cc)) self.transport._set_tempo_buttons( ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, transport_tempodown_cc), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, transport_tempoup_cc)) # SESSION STOP ALL CLIPS AND SCENE LAUNCH self.session.set_stop_all_clips_button( ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, session_stopall_cc)) for index in range(num_scenes): self.session.scene(index).set_launch_button( ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, session_scenelaunch_cc[index])) def _set_modifiers_buttons(self): is_momentary = True self._shift_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, shift_mod) self._alt_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, alt_mod) self._ctrl_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, ctrl_mod) if (self._shift_button != None): self._shift_button.add_value_listener(self._shift_value) if (self._alt_button != None): self._alt_button.add_value_listener(self._alt_value) if (self._ctrl_button != None): self._ctrl_button.add_value_listener(self._ctrl_value) # INIT NORMAL MODE self._manage_modes(0) # MODIFIERS LISTENERS FUNCS ARE HERE def _shift_value(self, value): assert isinstance(value, int) assert isinstance(self._shift_button, ButtonElement) if value == 127: if self._shift_button_pressed is False: self._unpress_modes() self._shift_button_pressed = True self._manage_modes(0) def _alt_value(self, value): assert isinstance(value, int) assert isinstance(self._alt_button, ButtonElement) if value == 127: if self._alt_button_pressed is False: self._unpress_modes() self._alt_button_pressed = True self._manage_modes(2) def _ctrl_value(self, value): assert isinstance(value, int) assert isinstance(self._ctrl_button, ButtonElement) if value == 127: if self._ctrl_button_pressed is False: self._unpress_modes() self._ctrl_button_pressed = True self._manage_modes(3) def _manage_modes(self, mode_index): if mode_index == 0: self._clear_controls() self._set_normal_mode() # self._shift_button.turn_on() self._alt_button.turn_on() self._ctrl_button.turn_on() self.log_message("NORMAL ON") elif mode_index == 2: self._clear_controls() self._set_alt_mode() self._alt_button.turn_on() self._shift_button.turn_off() self._ctrl_button.turn_off() self.log_message("ALT ON") elif mode_index == 3: self._clear_controls() self._set_ctrl_mode() self._ctrl_button.turn_on() self._shift_button.turn_off() self._alt_button.turn_off() self.log_message("CTRL ON") def _unpress_modes(self): self._shift_button_pressed = False self._alt_button_pressed = False self._ctrl_button_pressed = False def _turn_off_matrix(self): for index in range(24): self._send_midi(tuple([176, index + 16, 0])) def disconnect(self): """clean things up on disconnect""" self.log_message( time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) + "--------------= NanoKontrolShift log closed =--------------" ) # Create entry in log file self._clear_controls() self.session = None self.mixer = None self.view = None self.device = None self.transport = None # MODES self._shift_button = None self._alt_button = None self._ctrl_button = None # SENDS self.send_button_up = None self.send_button_down = None self.send_controls = [] self.send_reset = [] self.set_device_component(None) ControlSurface.disconnect(self) return None