def _setup_session_control(self): is_momentary = True # Size of session box num_tracks = 8 # column num_scenes = 1 # row """ Buttons declaration """ # Navigation button_navig_up = ButtonElement(is_momentary, MIDI_CC_TYPE, midi_channel, midi_session_up) button_navig_down = ButtonElement(is_momentary, MIDI_CC_TYPE, midi_channel, midi_session_down) """ Declare our session box """ global session #We want to instantiate the global session as a SessionComponent object (it was a global "None" type up until now...) session = SessionComponent(num_tracks, num_scenes) #(num_tracks, num_scenes) A session highlight ("red box") will appear with any two non-zero values session.set_offsets(0, 0) #(track_offset, scene_offset) Sets the initial offset of the "red box" from top left session._do_show_highlight() #to ensure that this session will be highlighted """ Buttons association """ # Navigation up, down, left, right session.set_scene_bank_buttons(button_navig_down, button_navig_up) # Launch selected clip for index in range(num_tracks): session.scene(0).clip_slot(index).set_launch_button(ButtonElement(is_momentary, MIDI_CC_TYPE, midi_channel, midi_session_launch_clip[index])) # Stop selected track stop_track_buttons = [] for index in range(num_tracks): stop_track_buttons.append(ButtonElement(is_momentary, MIDI_CC_TYPE, midi_channel, midi_session_stop_track[index])) session.set_stop_track_clip_buttons(tuple(stop_track_buttons)) #array size needs to match num_tracks
class MaschinAble(ControlSurface): __module__ = __name__ __doc__ = '''Midi Remote Script for Clip launch control on the\n Native Instruments Maschine Controller''' def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) self.log_message("====================== MaschineAble Log opened ======================") self.set_suppress_rebuild_requests(True) self._suggested_input_port = 'Maschine Controller In' self._suggested_output_port = 'Maschine Controller Out' self.session = None self._setup_session_control() self.set_suppress_rebuild_requests(False) def _setup_session_control(self): is_momentary = True num_tracks = 4 num_scenes = 4 self.session = SessionComponent(num_tracks, num_scenes) self.session.name = 'MaschinAble_session_control' matrix = ButtonMatrixElement() self.session.set_offsets(0, 0) up_button = ButtonElement(is_momentary, 1, 1, 108) down_button = ButtonElement(is_momentary, 1, 1, 109) left_button = ButtonElement(is_momentary, 1, 1, 110) right_button = ButtonElement(is_momentary, 1, 1, 111) self.session.set_track_bank_buttons(right_button, left_button) self.session.set_scene_bank_buttons(down_button, up_button) launch_notes_start_from = 112 launch_notes = range(launch_notes_start_from, launch_notes_start_from + 16) current_scene = list( self.song().scenes).index(self.song().view.selected_scene) current_track = list( self.song().tracks).index(self.song().view.selected_track) for scene_index in range(num_scenes): button_row = [] for track_index in range(num_tracks): clip_slot = self.session.scene(num_scenes - 1 - scene_index + current_scene).clip_slot(track_index + current_track) button = ButtonElement(is_momentary, 0, 1, launch_notes[track_index+(4*scene_index)]) button_row.append(button) if clip_slot.has_clip: clip_slot.set_stopped_value(1) else: clip_slot.set_stopped_value(0) clip_slot.set_triggered_to_play_value(2) clip_slot.set_triggered_to_record_value(2) clip_slot.set_launch_button(button) matrix.add_row(tuple(button_row)) def disconnect(self): ControlSurface.disconnect(self) self.log_message("====================== MaschineAble Log closed ======================")
def _setup_session_control(self): is_momentary = True num_tracks = 1 #single column num_scenes = 7 #seven rows, which will be mapped to seven "white" notes global session #We want to instantiate the global session as a SessionComponent object (it was a global "None" type up until now...) session = SessionComponent( num_tracks, num_scenes ) #(num_tracks, num_scenes) A session highlight ("red box") will appear with any two non-zero values session.set_offsets( 0, 0 ) #(track_offset, scene_offset) Sets the initial offset of the "red box" from top left """set up the session navigation buttons""" session.set_select_buttons( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 25), ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 27) ) # (next_button, prev_button) Scene select buttons - up & down - we'll also use a second ControlComponent for this (yellow box) session.set_scene_bank_buttons( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 51), ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 49) ) # (up_button, down_button) This is to move the "red box" up or down (increment track up or down, not screen up or down, so they are inversed) #session.set_track_bank_buttons(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 56), ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 54)) # (right_button, left_button) This moves the "red box" selection set left & right. We'll put our track selection in Part B of the script, rather than here... session.set_stop_all_clips_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 70)) session.selected_scene().set_launch_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 30)) """Here we set up the scene launch assignments for the session""" launch_notes = [ 60, 62, 64, 65, 67, 69, 71 ] #this is our set of seven "white" notes, starting at C4 for index in range( num_scenes ): #launch_button assignment must match number of scenes session.scene(index).set_launch_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, launch_notes[index]) ) #step through the scenes (in the session) and assign corresponding note from the launch_notes array """Here we set up the track stop launch assignment(s) for the session""" #The following code is set up for a longer array (we only have one track, so it's over-complicated, but good for future adaptation).. stop_track_buttons = [] for index in range(num_tracks): stop_track_buttons.append( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 58 + index) ) #this would need to be adjusted for a longer array (because we've already used the next note numbers elsewhere) session.set_stop_track_clip_buttons( tuple(stop_track_buttons)) #array size needs to match num_tracks """Here we set up the clip launch assignments for the session""" clip_launch_notes = [ 48, 50, 52, 53, 55, 57, 59 ] #this is a set of seven "white" notes, starting at C3 for index in range(num_scenes): session.scene(index).clip_slot(0).set_launch_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, clip_launch_notes[index]) ) #step through scenes and assign a note to first slot of each """Here we set up a mixer and channel strip(s) which move with the session""" session.set_mixer( mixer) #Bind the mixer to the session so that they move together
def _setup_session_control(self): num_tracks = 7 num_scenes = 4 session_nav_button = [ ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, SESSION_NAV_BUTTONS[index]) for index in range(2) ] session_stop_button = [] matrix = ButtonMatrixElement() matrix.name = 'Button_Matrix' global session session = SessionComponent(num_tracks, num_scenes) session.name = 'Session_Control' session.set_offsets(0, 0) session.set_scene_bank_buttons(session_nav_button[1], session_nav_button[0]) #session.set_track_bank_buttons(session_nav_button[3], session_nav_button[2]) for row in xrange(num_scenes): scene_launch_button = ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, SCENE_LAUNCH_BUTTONS[row]) session_row = [] scene = session.scene(row) scene.name = 'Scene' + str(row) scene.set_launch_button(scene_launch_button) scene.set_triggered_value(2) #scene_launch_button._set_skin_light(68) for column in xrange(num_tracks): clip_launch_button = ButtonElement( is_momentary, MIDI_NOTE_TYPE, CHANNEL, CLIP_LAUNCH_BUTTONS[row][column]) clip_launch_button.name = str(column) + '_Clip_' + str( row) + '_Button' session_row.append(clip_launch_button) clip_slot = scene.clip_slot(column) clip_slot.name = str(column) + '_ClipSlot_' + str(row) clip_slot.set_launch_button(clip_launch_button) #clip_launch_button._set_skin_light(76) matrix.add_row(tuple(session_row)) for column in xrange(num_tracks): session_stop_button.append( ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, SESSION_STOP_BUTTONS[column])) self._supress_session_highlight = False self._supress_send_midi = False self.set_highlighting_session_component(session) session.set_stop_track_clip_buttons(tuple(session_stop_button))
def _setup_selection_box_control(self, indexDicer): is_momentary = True # Size of session box num_tracks = 1 #1 column num_scenes = 1 #1 row """ Buttons declaration """ # Navigation button_navig_up = ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel_red[indexDicer] - 1, midi_cc_normal[0]) button_navig_down = ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel_red[indexDicer] - 1, midi_cc_normal[1]) button_navig_left = ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel_red[indexDicer] - 1, midi_cc_normal[3]) button_navig_right = ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel_red[indexDicer] - 1, midi_cc_normal[4]) # Launch clip button_launch_clip = ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel_red[indexDicer] - 1, midi_cc_normal[2]) # Stop track button_stop_track = ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel_red[indexDicer] - 1, midi_cc_shifted[2]) # Stop all tracks #button_stop_track_all """ Declare our session box """ global session #We want to instantiate the global session as a SessionComponent object (it was a global "None" type up until now...) session = SessionComponent( num_tracks, num_scenes ) #(num_tracks, num_scenes) A session highlight ("red box") will appear with any two non-zero values session.set_offsets( indexDicer * 4, 0 ) #(track_offset, scene_offset) Sets the initial offset of the "red box" from top left session._do_show_highlight( ) #to ensure that this session will be highlighted """ Buttons association """ # Navigation up, down, left, right session.set_scene_bank_buttons(button_navig_down, button_navig_up) session.set_track_bank_buttons(button_navig_right, button_navig_left) # Launch selected clip session.scene(0).clip_slot(0).set_launch_button(button_launch_clip) # Stop selected track stop_track_buttons = [] stop_track_buttons.append(button_stop_track) session.set_stop_track_clip_buttons( tuple(stop_track_buttons)) #array size needs to match num_tracks
def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self._suppress_send_midi = True self._suppress_session_highlight = True self._control_is_with_automap = False is_momentary = True self._suggested_input_port = 'Akai MPD26' self._suggested_output_port = 'Akai MPD26' """SESSION ViEW""" session = SessionComponent(4,4) session.name = 'Session_Control' matrix = ButtonMatrixElement() matrix.name = 'Button_Matrix' up_button = ButtonElement(False, MIDI_CC_TYPE, 0, 115) down_button = ButtonElement(False, MIDI_CC_TYPE, 0, 116) up_button.name = 'Bank_Select_Up_Button' down_button.name = 'Bank_Select_Down_Button' session.set_scene_bank_buttons(down_button, up_button) for row in range(4): button_row = [] button_notes = [48, 44, 40, 36] scene = session.scene(row) scene.name = 'Scene_' + str(row) for column in range(4): button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, button_notes[row] + column ) button.name = str(column) + '_Clip_' + str(row) + '_Button' button_row.append(button) clip_slot = scene.clip_slot(column) clip_slot.name = str(column) + '_Clip_Slot_' + str(row) clip_slot.set_launch_button(button) matrix.add_row(tuple(button_row)) self._suppress_session_highlight = False self._suppress_send_midi = False self.set_highlighting_session_component(session) #self._set_session_highlight(0,session._scene_offset,4,4,False) """TRANSPORT CONTROLS""" stop_button = ButtonElement(False, MIDI_CC_TYPE, 0, 117) play_button = ButtonElement(False, MIDI_CC_TYPE, 0, 118) transport = TransportComponent() transport.set_stop_button(stop_button) transport.set_play_button(play_button)
def _setup_selection_box_control(self, indexDicer): is_momentary = True # Size of session box num_tracks = 1 #1 column num_scenes = 1 #1 row """ Buttons declaration """ # Navigation button_navig_up = ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel_red[indexDicer] - 1, midi_cc_normal[0]) button_navig_down = ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel_red[indexDicer] - 1, midi_cc_normal[1]) button_navig_left = ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel_red[indexDicer] - 1, midi_cc_normal[3]) button_navig_right = ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel_red[indexDicer] - 1, midi_cc_normal[4]) # Launch clip button_launch_clip = ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel_red[indexDicer] - 1, midi_cc_normal[2]) # Stop track button_stop_track = ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel_red[indexDicer] - 1, midi_cc_shifted[2]) # Stop all tracks #button_stop_track_all """ Declare our session box """ global session #We want to instantiate the global session as a SessionComponent object (it was a global "None" type up until now...) session = SessionComponent(num_tracks, num_scenes) #(num_tracks, num_scenes) A session highlight ("red box") will appear with any two non-zero values session.set_offsets(indexDicer * 4, 0) #(track_offset, scene_offset) Sets the initial offset of the "red box" from top left session._do_show_highlight() #to ensure that this session will be highlighted """ Buttons association """ # Navigation up, down, left, right session.set_scene_bank_buttons(button_navig_down, button_navig_up) session.set_track_bank_buttons(button_navig_right, button_navig_left) # Launch selected clip session.scene(0).clip_slot(0).set_launch_button(button_launch_clip) # Stop selected track stop_track_buttons = [] stop_track_buttons.append(button_stop_track) session.set_stop_track_clip_buttons(tuple(stop_track_buttons)) #array size needs to match num_tracks
def _create_session_control(self): is_momentary = True num_tracks = 1 num_scenes = 7 global session session = SessionComponent(num_tracks, num_scenes) session.set_offsets(0, 0) """set up the session navigation buttons""" session.set_select_buttons( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 25), ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 27)) session.set_scene_bank_buttons( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 51), ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 49)) session.set_stop_all_clips_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 70)) session.selected_scene().set_launch_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 30)) """Here we set up the scene launch assignments for the session""" launch_notes = [60, 62, 64, 65, 67, 69, 71] for index in range(num_scenes): session.scene(index).set_launch_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, launch_notes[index])) """Here we set up the track stop launch assignment(s) for the session""" stop_track_buttons = [] for index in range(num_tracks): stop_track_buttons.append( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 58 + index)) session.set_stop_track_clip_buttons(tuple(stop_track_buttons)) """Here we set up the clip launch assignments for the session""" clip_launch_notes = [48, 50, 52, 53, 55, 57, 59] for index in range(num_scenes): session.scene(index).clip_slot(0).set_launch_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, clip_launch_notes[index])) """Here we set up a mixer and channel strip(s) which move with the session""" self.log_message("Captain's log stardate 3")
class OP1(ControlSurface): def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) self.c_instance = c_instance self.retries_count = 0 self.device_connected = False self.clip_color_callbacks = {} self.slot_callbacks = {} self.text_start_sequence = (0xf0, 0x0, 0x20, 0x76, 0x00, 0x03) self.text_end_sequence = (0xf7,) self.enable_sequence = (0xf0, 0x00, 0x20, 0x76, 0x00, 0x01, 0x02, 0xf7) self.disable_sequence = (0xf0, 0x00, 0x20, 0x76, 0x00, 0x01, 0x00, 0xf7) self.id_sequence = (0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7) self.text_color_start_sequence = (0xf0, 0x0, 0x20, 0x76, 0x00, 0x04) self.log('INITIALIZING') self.app = Live.Application.get_application() #maj = self.app.get_major_version() #min = self.app.get_minor_version() #bug = self.app.get_bugfix_version() #self.show_message(str(1) + "." + str(0) + "." + str(9)) self.show_message("Version " + VERSION) # reseting text self.write_text(' ') # reset display clips self.reset_display_clips() # getting browser visible state self.session_browser_visible = self.app.view.is_view_visible("Browser") # getting browser visible state self.arrange_browser_visible = self.app.view.is_view_visible("Browser") # getting session view visible state self.session_visible = self.app.view.is_view_visible("Session") # getting arrange view visible state self.arrange_visible = self.app.view.is_view_visible("Arranger") # getting detail view visible state self.detail_visible = self.app.view.is_view_visible("Detail") # getting back to arranger state self.back_to_arranger_state = self.song().back_to_arranger # initializing channel strip to null self._channel_strip = None # initializing transport component self._transport = TransportComponent() # initializing mixer component self._mixer = MixerComponent(NUM_TRACKS,2) # initializing session component self._session = SessionComponent(NUM_TRACKS,NUM_ROWS) self._session.add_offset_listener(self.session_offset_changed) # configuring operation mode selector buttons self._operation_mode_buttons = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_1_BUTTON), ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_2_BUTTON), ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_3_BUTTON), ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_4_BUTTON), # initializing operation mode selector self._operation_mode_selector = OP1ModeSelectorComponent(self, self._transport, self._mixer, self._session) # setting operation mode selector buttons self._operation_mode_selector.set_mode_buttons(self._operation_mode_buttons) # adding value listener for operation mode index self._operation_mode_selector.add_mode_index_listener(self.mode_index_changed) # setting global transport assignments self._transport.set_record_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_REC_BUTTON)) self._transport.set_play_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_PLAY_BUTTON)) self._transport.set_stop_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_STOP_BUTTON)) self._transport.set_metronome_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_METRONOME_BUTTON)) self._transport.set_tap_tempo_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_HELP_BUTTON)) self._transport.set_punch_buttons(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS1_BUTTON), ButtonElement(True,MIDI_CC_TYPE, CHANNEL, OP1_SS2_BUTTON)) self._transport.set_loop_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS3_BUTTON)) self._transport.set_overdub_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS4_BUTTON)) # setting global session assignments self._session.set_scene_bank_buttons(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_COM),ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MICRO)) # setting misc listeners self.browser_toggle_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL, 15) self.browser_toggle_button.add_value_listener(self.browser_toggle_button_callback) self.mainview_toggle_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL, 16) self.mainview_toggle_button.add_value_listener(self.mainview_toggle_button_callback) self.detailview_toggle_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL, 17) self.detailview_toggle_button.add_value_listener(self.detailview_toggle_button_callback) self.clear_track_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, 25) self.clear_track_button.add_value_listener(self.clear_track_button_callback) self.back_to_arranger_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, 26) self.back_to_arranger_button.add_value_listener(self.back_to_arranger_button_callback) # adding value listener for selected track change self.song().view.add_selected_track_listener(self.selected_track_changed) # adding value listener for selected scene change self.song().view.add_selected_scene_listener(self.selected_scene_changed) # setting assignments for currently selected track self.selected_track_changed() # setting assignments for currently selected scene self.selected_scene_changed() def handle_sysex(self, midi_bytes): if ((midi_bytes[6]==32) and (midi_bytes[7]==118)): self.device_connected = True self.log("OP-1 CONNECTED. SENDING ABLETON LIVE MODE INIT SEQUENCE") self._send_midi(self.enable_sequence) def add_clip_slot_listeners(self): #self.log('ADDING CLIP SLOT LISTENERS') # creating an empty list for all clip slots clip_slots = [] # getting a reference to all tracks tracks = self.song().tracks # appending all tracks clip slots to clip_slots for track in tracks: clip_slots.append(track.clip_slots) # iterating over all clip slots for t in range(len(clip_slots)): for c in range(len(clip_slots[t])): clip_slot = clip_slots[t][c] # adding has clip listener to clip slot self.add_slot_listener(clip_slot) # if clip slot has clip if clip_slot.has_clip: # adding clip listeners self.add_clip_listener(clip_slot.clip) def rem_clip_slot_listeners(self): #self.log('REMOVING CLIP SLOT LISTENERS') # iterate over all clip color change callbacks for c in self.clip_color_callbacks: # if clip still exists if c != None: # and it has a has clip listener if c.color_has_listener(self.clip_color_callbacks[c]) == 1: # remove it c.remove_color_listener(self.clip_color_callbacks[c]) # iterate over all clip slot callbacks for cs in self.slot_callbacks: # if clip slot still exists if cs != None: # and it has a has clip listener if cs.has_clip_has_listener(self.slot_callbacks[cs]) == 1: # remove it cs.remove_has_clip_listener(self.slot_callbacks[cs]) def add_slot_listener(self, cs): # setting has clip listener callback = lambda :self.has_clip_listener(cs) # if we don't have a clip slot has clip listener for this clip slot yet if not(self.slot_callbacks.has_key(cs)): # adding has clip callback to clip slot cs.add_has_clip_listener(callback) # saving callback for future release self.slot_callbacks[cs] = callback def add_clip_listener(self, clip): # setting callback for clip color change color_callback = lambda :self.update_display_clips() # if we don't have a clip color change callback for this clip yet if not(self.clip_color_callbacks.has_key(clip)): # adding clip color change callback clip.add_color_listener(color_callback) # saving callback for future release self.clip_color_callbacks[clip] = color_callback def has_clip_listener(self, cs): # clip slot has clip listener callback if cs.has_clip: # add clip listener self.add_clip_listener(cs.clip) else: # update display if clip slot was removed self.update_display_clips() def session_offset_changed(self): # if session component offset changes, update display self.update_display_clips() def selected_scene_changed(self): # if on clip mode update display if (self._operation_mode_selector.mode_index==OP1_MODE_CLIP): self.update_display_clip_mode() def mode_index_changed(self): # update display to current mode info if (self._operation_mode_selector.mode_index==OP1_MODE_PERFORM): self.update_display_perform_mode() elif (self._operation_mode_selector.mode_index==OP1_MODE_CLIP): self.update_display_clip_mode() elif (self._operation_mode_selector.mode_index==OP1_MODE_TRANSPORT): self.update_display_transport_mode() elif (self._operation_mode_selector.mode_index==OP1_MODE_MIXER): self.update_display_mixer_mode() def clear_track_button_callback(self, value): # if clear track button was called, reset track if (value==127): for i in range(len(self.song().tracks)): self.song().tracks[i].arm = 0 self.song().tracks[i].solo = 0 self.song().tracks[i].mute = 0 for i in range(len(self.song().return_tracks)): self.song().tracks[i].solo = 0 self.song().tracks[i].mute = 0 def clear_return_track_assignment(self, strip): # clear return track assingments strip.set_volume_control(None) strip.set_pan_control(None) strip.set_mute_button(None) strip.set_solo_button(None) def clear_track_assignment(self, strip): # clear track assignments strip.set_volume_control(None) strip.set_pan_control(None) strip.set_mute_button(None) strip.set_solo_button(None) strip.set_arm_button(None) def clear_tracks_assigments(self): # for all normal tracks, clear assignments for i in range(NUM_TRACKS): strip = self._mixer.channel_strip(i) if (strip!=None): self.clear_track_assignment(strip) # for all return tracks, clear assignments for i in range(2): return_strip = self._mixer.return_strip(i) if (return_strip!=None): self.clear_return_track_assignment(return_strip) def selected_track_changed(self): # if on mixer mode update display if (self._operation_mode_selector.mode_index==OP1_MODE_MIXER): self.update_display_mixer_mode() # clear track assignments self.clear_tracks_assigments() # getting selected strip self._channel_strip = self._mixer.selected_strip() # perform track assignments self._channel_strip.set_volume_control(EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_1, Live.MidiMap.MapMode.relative_two_compliment)) self._channel_strip.set_pan_control(EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_2, Live.MidiMap.MapMode.relative_two_compliment)) # setting a tuple of encoders to control sends send_controls = EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_3, Live.MidiMap.MapMode.relative_two_compliment), EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_4, Live.MidiMap.MapMode.relative_two_compliment), # setting send encoders self._channel_strip.set_send_controls(tuple(send_controls)) # setting solo button self._channel_strip.set_solo_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS6_BUTTON)) # if track can be armed, set arm button if (self._channel_strip._track.can_be_armed): self._channel_strip.set_arm_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS7_BUTTON)) # if track is no master, set mute button if (self._channel_strip._track!=self.song().master_track): self._channel_strip.set_mute_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS5_BUTTON)) def browser_toggle_button_callback(self, value): if (value==127): if (self.session_visible): if (self.session_browser_visible==True): self.session_browser_visible=False self.app.view.hide_view("Browser") else: self.session_browser_visible=True self.app.view.show_view("Browser") if (self.arrange_visible): if (self.arrange_browser_visible==True): self.arrange_browser_visible=False self.app.view.hide_view("Browser") else: self.arrange_browser_visible=True self.app.view.show_view("Browser") def back_to_arranger_button_callback(self, value): if (value==127): self.song().back_to_arranger = False def mainview_toggle_button_callback(self, value): if (value==127): if (self.session_visible==True): self.session_visible=False self.arrange_visible=True self.app.view.show_view("Arranger") self.arrange_browser_visible = self.app.view.is_view_visible("Browser"); else: self.session_visible=True self.arrange_visible=False self.app.view.show_view("Session") self.session_browser_visible = self.app.view.is_view_visible("Browser"); def detailview_toggle_button_callback(self, value): if (value==127): if (self.detail_visible==True): self.detail_visible=False self.app.view.hide_view("Detail") else: self.detail_visible=True self.app.view.show_view("Detail") def write_text(self, msg): text_list = [] sequence = () text_list.append(len(msg.strip())) for i in msg.strip(): text_list.append(ord(i)) sequence = self.text_start_sequence + tuple(text_list) + self.text_end_sequence self._send_midi(sequence) def suggest_input_port(self): return "OP-1 Midi Device" def suggest_output_port(self): return "OP-1 Midi Device" def update_display_perform_mode(self): self.write_text("perform\rmode") def reset_display_clips(self): count = 0 colors = [] length = [] sequence = () for i in range (NUM_TRACKS): count+=1 colors.append(0x00) colors.append(0x00) colors.append(0x00) length.append(count) sequence = self.text_color_start_sequence + tuple(length) + tuple(colors) + self.text_end_sequence self._send_midi(sequence) def update_display_clips(self): #self.log("UPDATING DISPLAY CLIPS") count = 0 colors = [] length = [] sequence = () tracks_len = len(self.song().tracks)-self._session._track_offset if (tracks_len>NUM_TRACKS): tracks_len = NUM_TRACKS for i in range (tracks_len): count+=1 clip_slot = self._session.scene(0).clip_slot(i) if (clip_slot!=None): if (clip_slot.has_clip()!=False): clip_color = clip_slot._clip_slot.clip.color colors.append(((clip_color>>16)&0x000000ff)>>1) colors.append(((clip_color>>8)&0x000000ff)>>1) colors.append((clip_color&0x000000ff)>>1) else: colors.append(0x00) colors.append(0x00) colors.append(0x00) else: colors.append(0x00) colors.append(0x00) colors.append(0x00) length.append(count) sequence = self.text_color_start_sequence + tuple(length) + tuple(colors) + self.text_end_sequence self._send_midi(sequence) def update_display_clip_mode(self): self.write_text("sel. scene\r" + str(self.song().view.selected_scene.name.lower().strip())) def update_display_transport_mode(self): song_time = str(self.song().get_current_beats_song_time()) self.write_text("song pos.\r" + song_time[:len(song_time)-4]) def update_display_mixer_mode(self): self.write_text("sel. track\r" + str(self.song().view.selected_track.name.lower())) def update_display(self): if not(self.device_connected): if (self.retries_count<5): self.log("TRYING OP-1 CONNECTION") self.retries_count+=1 self._send_midi(self.id_sequence) time.sleep(1) # if in transport mode, update display with song position if (self._operation_mode_selector.mode_index==OP1_MODE_TRANSPORT): self.update_display_transport_mode() # checking if app current view is session if (self.app.view.is_view_visible("Session")): # checking if session browser state is diferent from the internal if (self.session_browser_visible != self.app.view.is_view_visible("Browser")): self.session_browser_visible = self.app.view.is_view_visible("Browser") # checking if app current view is arrange if (self.app.view.is_view_visible("Arranger")): # checking if arrange browser state is diferent from the internal if (self.arrange_browser_visible != self.app.view.is_view_visible("Browser")): self.arrange_browser_visible = self.app.view.is_view_visible("Browser") # checking if app current view is detail if (self.app.view.is_view_visible("Detail")): # checking if detail state is diferent from the internal if (self.detail_visible != self.app.view.is_view_visible("Detail")): self.detail_visible = self.app.view.is_view_visible("Detail") def refresh_state(self): self.log("REFRESH STATE") self.retries_count = 0 self.device_connected = False def build_midi_map(self, midi_map_handle): #self.log("BUILD MIDI MAP") assert (self._suppress_requests_counter == 0) self._in_build_midi_map = True self._midi_map_handle = midi_map_handle self._forwarding_registry = {} for control in self.controls: if isinstance(control, InputControlElement): control.install_connections() self._midi_map_handle = None self._in_build_midi_map = False if (self._pad_translations != None): self._c_instance.set_pad_translation(self._pad_translations) # remove clip listeners self.rem_clip_slot_listeners() # add clip listeners self.add_clip_slot_listeners() # update display self.update_display_clips() def log(self, msg): self.c_instance.log_message("[TE OP-1] " + msg) def disconnect(self): # removing clip slots listeners self.rem_clip_slot_listeners() # removing value listener for track changed self.song().view.remove_selected_track_listener(self.selected_track_changed) # removing value listener for scene changed self.song().view.remove_selected_scene_listener(self.selected_scene_changed) # removing value listener for operation mode index self._operation_mode_selector.remove_mode_index_listener(self.mode_index_changed) # removing global transport assignments self._transport.set_punch_buttons(None, None) self._transport.set_loop_button(None) self._transport.set_overdub_button(None) self._transport.set_record_button(None) self._transport.set_play_button(None) self._transport.set_stop_button(None) self._transport.set_metronome_button(None) self._transport.set_tap_tempo_button(None) # removing global session assignments self._session.set_scene_bank_buttons(None, None) # removing misc listeners self.browser_toggle_button.remove_value_listener(self.browser_toggle_button_callback) self.mainview_toggle_button.remove_value_listener(self.mainview_toggle_button_callback) self.detailview_toggle_button.remove_value_listener(self.detailview_toggle_button_callback) self.clear_track_button.remove_value_listener(self.clear_track_button_callback) self.back_to_arranger_button.remove_value_listener(self.back_to_arranger_button_callback) # sending special ableton mode disable sequence self._send_midi(self.disable_sequence) # disconnecting control surface ControlSurface.disconnect(self) self.log("DISCONNECTED")
class DV1(ControlSurface): def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) is_momentary = True self._timer = 0 #used for flashing states, and is incremented by each call from self._update_display() self._touched = 0 self.flash_status = 1 # Used in FlashingButtonElement (kludge for our purposes) self._device_selection_follows_track_selection = True with self.component_guard(): self._setup_transport_control() if USE_MIXER_CONTROLS == True: self.mixer_control() if USE_SESSION_VIEW == True: self.session_control() # self.setup_device_control() def _setup_transport_control(self): is_momentary = True # We'll only be using momentary buttons here self.transport = TransportComponent( ) #Instantiate a Transport Component """set up the buttons""" self.transport.set_play_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 60) ) #ButtonElement(is_momentary, msg_type, channel, identifier) Note that the MIDI_NOTE_TYPE constant is defined in the InputControlElement module self.transport.set_stop_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 61)) self.transport.set_record_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 62)) def mixer_control(self): is_momentary = True self.num_tracks = N_TRACKS if (USE_SENDS == True): self.mixer = MixerComponent(N_TRACKS, N_SENDS_PER_TRACK, USE_MIXER_EQ, USE_MIXER_FILTERS) else: self.mixer = MixerComponent(N_TRACKS, 0, USE_MIXER_EQ, USE_MIXER_FILTERS) self.mixer.name = 'Mixer' self.mixer.set_track_offset( 0) #Sets start point for mixer strip (offset from left) for index in range(N_TRACKS): self.mixer.channel_strip( index).name = 'Mixer_ChannelStrip_' + str(index) self.mixer.channel_strip(index)._invert_mute_feedback = True if (USE_SELECT_BUTTONS == True): self.selectbuttons = [None for index in range(N_TRACKS)] for index in range(len(SELECT_BUTTONS)): self.selectbuttons[index] = FlashingButtonElement( is_momentary, MIDI_NOTE_TYPE, CHANNEL, SELECT_BUTTONS[index], 'Select_Button', self) self.mixer.channel_strip(index).set_select_button( self.selectbuttons[index]) self.selectbuttons[index].set_on_value(SELECT_BUTTON_ON_COLOR) self.selectbuttons[index].set_off_value( SELECT_BUTTON_OFF_COLOR) if (USE_SOLO_BUTTONS == True): self.solobuttons = [None for index in range(N_TRACKS)] for index in range(len(SOLO_BUTTONS)): self.solobuttons[index] = FlashingButtonElement( is_momentary, MIDI_NOTE_TYPE, CHANNEL, SOLO_BUTTONS[index], 'Solo_Button', self) self.mixer.channel_strip(index).set_solo_button( self.solobuttons[index]) self.solobuttons[index].set_on_value(SOLO_BUTTON_ON_COLOR) self.solobuttons[index].set_off_value(SOLO_BUTTON_OFF_COLOR) if (USE_ARM_BUTTONS == True): self.armbuttons = [None for index in range(N_TRACKS)] for index in range(len(ARM_BUTTONS)): self.armbuttons[index] = FlashingButtonElement( is_momentary, MIDI_NOTE_TYPE, CHANNEL, ARM_BUTTONS[index], 'Arm_Button', self) self.mixer.channel_strip(index).set_arm_button( self.armbuttons[index]) self.armbuttons[index].set_on_value(ARM_BUTTON_ON_COLOR) self.armbuttons[index].set_off_value(ARM_BUTTON_OFF_COLOR) if (USE_MUTE_BUTTONS == True): self.mutebuttons = [None for index in range(N_TRACKS)] for index in range(len(MUTE_BUTTONS)): self.mutebuttons[index] = FlashingButtonElement( is_momentary, MIDI_NOTE_TYPE, CHANNEL, MUTE_BUTTONS[index], 'Mute_Button', self) self.mixer.channel_strip(index).set_mute_button( self.mutebuttons[index]) self.mutebuttons[index].set_on_value(MUTE_BUTTON_ON_COLOR) self.mutebuttons[index].set_off_value(MUTE_BUTTON_OFF_COLOR) if (USE_SENDS == True): self.sendencoders = [None for index in range(len(SEND_ENCODERS))] for index in range(len(SEND_ENCODERS)): # self.sendencoders[index] = EncoderElement(MIDI_CC_TYPE, CHANNEL, SEND_ENCODERS[index], Live.MidiMap.MapMode.absolute) self.sendencoders[index] = CMDEncoderElement( MIDI_CC_TYPE, CHANNEL, SEND_ENCODERS[index], Live.MidiMap.MapMode.relative_smooth_binary_offset, 20) for index in range(len(SEND_ENCODERS) / N_SENDS_PER_TRACK): self.mixer.channel_strip(index).set_send_controls( tuple(self.sendencoders[(index * N_SENDS_PER_TRACK):( (index * N_SENDS_PER_TRACK) + N_SENDS_PER_TRACK)]) ) # Pas -1, car tuple() fonctionne etrangement en Python ;) if (USE_VOLUME_CONTROLS == True): self.volencoders = [None for index in range(len(VOLUME_ENCODERS))] for index in range(len(VOLUME_ENCODERS)): #self.volencoders[index] = EncoderElement(MIDI_CC_TYPE, CHANNEL, VOLUME_ENCODERS[index], Live.MidiMap.MapMode.absolute) self.volencoders[index] = CMDEncoderElement( MIDI_CC_TYPE, CHANNEL, VOLUME_ENCODERS[index], Live.MidiMap.MapMode.relative_smooth_binary_offset, 20) self.mixer.channel_strip(index).set_volume_control( self.volencoders[index]) def session_control(self): is_momentary = True self._timer = 0 self.flash_status = 1 self.grid = [None for index in range(N_TRACKS * N_SCENES)] for index in range(N_TRACKS * N_SCENES): self.grid[index] = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, TRACK_CLIP_BUTTONS[index], 'Grid' + str(index), self) self.grid[index].set_off_value(0) self.grid[index].turn_off() self.matrix = ButtonMatrixElement() for row in range(N_SCENES): button_row = [] for column in range(N_TRACKS): button_row.append(self.grid[row + (column * N_SCENES)]) self.matrix.add_row(tuple(button_row)) self.session = SessionComponent(N_TRACKS, N_SCENES) self.session.name = "Session" self.session.set_offsets(0, 0) self.scene = [None for index in range(N_SCENES)] for row in range(N_SCENES): self.scene[row] = self.session.scene(row) self.scene[row].name = 'Scene_' + str(row) for column in range(N_TRACKS): clip_slot = self.scene[row].clip_slot(column) clip_slot.name = str(column) + '_Clip_Slot' + str(row) self.scene[row].clip_slot(column).set_triggered_to_play_value( CLIP_TRG_PLAY_COLOR) self.scene[row].clip_slot(column).set_stopped_value( CLIP_STOP_COLOR) self.scene[row].clip_slot(column).set_started_value( CLIP_STARTED_COLOR) self.set_highlighting_session_component(self.session) #self.session_zoom = DeprecatedSessionZoomingComponent(self.session) #this creates the ZoomingComponent that allows navigation when the shift button is pressed #self.session_zoom.name = 'Session_Overview' #name it so we can access it in m4l #self.session_zoom.set_stopped_value(ZOOM_STOPPED) #set the zooms stopped color #self.session_zoom.set_playing_value(ZOOM_PLAYING) #set the zooms playing color #self.session_zoom.set_selected_value(ZOOM_SELECTED) #set the zooms selected color #self.session_zoom.set_button_matrix(self.matrix) #assign the ButtonMatrixElement that we created in _setup_controls() to the zooming component so that we can control it #self._shift_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 84) #self.session_zoom.set_zoom_button(self._shift_button) #assign a shift button so that we can switch states between the SessionComponent and the SessionZoomingComponent #self.looper = LooperComponent(self) #self.log_message(str(len(STOP_BUTTONS))) #if(USE_STOP_BUTTONS == True): #self.stopbuttons = [None for index in range(N_TRACKS)] #for index in range(len(STOP_BUTTONS)): #self.stopbuttons[index] = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,STOP_BUTTONS[index], 'Stop_Button', self) #self.session.set_stop_track_clip_buttons(self.stopbuttons) #self.stopbuttons[index].set_on_value(STOP_BUTTON_ON_COLOR) #self.stopbuttons[index].set_off_value(STOP_BUTTON_OFF_COLOR) #self.scrollencoder = ScrollEncoderElement(MIDI_CC_TYPE, CHANNEL, 32, Live.MidiMap.MapMode.absolute, self.session, self.transport, self.mixer, self.looper) #self.scrollencoder.set_nav_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 80)) #self.scrollencoder.set_transport_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 81)) #self.scrollencoder.set_scene_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 82)) #self.scrollencoder.set_library_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 83)) #self.scrollencoder.set_button1(SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 66)) #self.scrollencoder.set_button2(SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 67)) #self.scrollencoder.set_button3(SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 64)) #self.scrollencoder.set_button4(SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 65)) #self.scrollencoder.set_encoder_button(SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 32)) self.button_left = SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, NAVBOX_LEFT_BUTTON) self.button_right = SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, NAVBOX_RIGHT_BUTTON) self.button_up = SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, NAVBOX_UP_BUTTON) self.button_down = SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, NAVBOX_DOWN_BUTTON) self.session.set_track_bank_buttons(self.button_right, self.button_left) self.session.set_scene_bank_buttons(self.button_down, self.button_up) for column in range(N_TRACKS): for row in range(N_SCENES): self.scene[row].clip_slot(column).set_launch_button( self.grid[row + (column * N_SCENES)]) for index in range(N_TRACKS * N_SCENES): self.grid[index].clear_send_cache() if USE_MIXER_CONTROLS == True: self.session.set_mixer(self.mixer) self.refresh_state() self.session.set_enabled(True) self.session.update() #def setup_device_control(self): #is_momentary = True #device_bank_buttons = [] #device_param_controls = [] #bank_button_labels = ('Clip_Track_Button', 'Device_On_Off_Button', 'Previous_Device_Button', 'Next_Device_Button') #for index in range(4): #device_bank_buttons.append(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 16 + index)) #device_bank_buttons[-1].name = bank_button_labels[index] #for index in range(8): ##ring_mode_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, 21 + index) #ringed_encoder = CMDEncoderElement(MIDI_CC_TYPE, CHANNEL, 16 + index, Live.MidiMap.MapMode.relative_binary_offset, 20) ##ringed_encoder.set_ring_mode_button(ring_mode_button) #ringed_encoder.name = 'Device_Control_' + str(index) ##ring_mode_button.name = ringed_encoder.name + '_Ring_Mode_Button' #device_param_controls.append(ringed_encoder) #device = ShiftableDeviceComponent() #device.name = 'Device_Component' #device.set_bank_buttons(tuple(device_bank_buttons)) ##device.set_shift_button(self._shift_button) #device.set_parameter_controls(tuple(device_param_controls)) #device.set_on_off_button(device_bank_buttons[1]) #self.set_device_component(device) #detail_view_toggler = DetailViewControllerComponent(self) #detail_view_toggler.name = 'Detail_View_Control' ##detail_view_toggler.set_shift_button(self._shift_button) #detail_view_toggler.set_device_clip_toggle_button(device_bank_buttons[0]) #detail_view_toggler.set_device_nav_buttons(device_bank_buttons[2], device_bank_buttons[3]) def update_display(self): ControlSurface.update_display(self) self._timer = (self._timer + 1) % 256 def disconnect(self): self._hosts = [] ControlSurface.disconnect(self) return None
class XoneK2(ControlSurface): def __init__(self, instance): global g_logger g_logger = self.log_message super(XoneK2, self).__init__(instance, False) with self.component_guard(): self._set_suppress_rebuild_requests(True) self.init_session() self.init_mixer() self.init_matrix() self.init_tempo() # connect mixer to session self.session.set_mixer(self.mixer) self.session.update() self.set_highlighting_session_component(self.session) self._set_suppress_rebuild_requests(False) def init_session(self): self.session = SessionComponent(NUM_TRACKS, NUM_SCENES) self.session.name = 'Session' self.session.set_scene_bank_buttons(button(BUTTON_LL), button(BUTTON_LR)) self.session.update() def init_mixer(self): self.mixer = MixerWithDevices(num_tracks=NUM_TRACKS, device_select=[ button(PUSH_ENCODERS[i]) for i in range(NUM_TRACKS) ], device_encoders=ENCODERS) self.mixer.id = 'Mixer' self.song().view.selected_track = self.mixer.channel_strip(0)._track for i in range(NUM_TRACKS): self.mixer.channel_strip(i).set_volume_control(fader(FADERS[i])) self.mixer.channel_strip(i).set_solo_button(button(BUTTONS3[i])) self.mixer.set_eq_controls( i, (knob(KNOBS3[i]), knob(KNOBS2[i]), knob(KNOBS1[i]))) self.mixer.set_device_controls(i, button(BUTTONS1[i])) self.master_encoder = DynamicEncoder( ENCODER_LR, self.song().master_track.mixer_device.volume) self.cue_encoder = DynamicEncoder( ENCODER_LL, self.song().master_track.mixer_device.cue_volume) self.mixer.update() def init_matrix(self): self.matrix = ButtonMatrixElement() for scene_index in range(NUM_SCENES): scene = self.session.scene(scene_index) scene.name = 'Scene ' + str(scene_index) button_row = [] for track_index in range(NUM_TRACKS): note_nr = GRID[scene_index][track_index] b = button(note_nr, name='Clip %d, %d button' % (scene_index, track_index)) button_row.append(b) clip_slot = scene.clip_slot(track_index) clip_slot.name = 'Clip slot %d, %d' % (scene_index, track_index) clip_slot.set_stopped_value(0) clip_slot.set_started_value(64) clip_slot.set_launch_button(b) self.matrix.add_row(tuple(button_row)) stop_buttons = [button(note_nr) for note_nr in BUTTONS2] self.session.set_stop_track_clip_buttons(stop_buttons) def init_tempo(self): self.transport = CustomTransportComponent() self.transport.set_tempo_bumpers(button(PUSH_ENCODER_LR), button(PUSH_ENCODER_LL))
class LaunchpadSimple(ControlSurface): def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self._suggested_input_port = 'Launchpad' self._suggested_output_port = 'Launchpad' # Launchpad configuration self._send_midi(LAUNCHPAD_RESET) self._send_midi(LAUNCHPAD_ENABLE_BLINKING) # make buttons top_buttons = [ make_button(MIDI_CC_TYPE, 104 + i) for i in range(8) ] side_buttons = [ make_button(MIDI_NOTE_TYPE, 8 + 16 * i) for i in range(8) ] matrix = ButtonMatrixElement() for row in range(8): button_row = [ make_button(MIDI_NOTE_TYPE, 16 * row + col) for col in range(8) ] matrix.add_row(tuple(button_row)) # mixer and session components self._mixer = MixerComponent(8) self._session = SessionComponent(8, SCENES_AMOUNT) self._session.set_mixer(self._mixer) self.set_highlighting_session_component(self._session) # navigation for button in top_buttons[:4]: button.set_on_off_values(GREEN_FULL, GREEN_THIRD) self._session.set_scene_bank_buttons(top_buttons[1], top_buttons[0]) self._session.set_track_bank_buttons(top_buttons[3], top_buttons[2]) # clip launch for scene_index in range(SCENES_AMOUNT): scene = self._session.scene(scene_index) scene.set_launch_button(side_buttons[scene_index]) scene.set_triggered_value(GREEN_BLINK) scene.set_scene_value(GREEN_THIRD) scene.set_no_scene_value(LED_OFF) for track_index in range(8): clip_slot = scene.clip_slot(track_index) clip_slot.set_launch_button( matrix.get_button(track_index, scene_index)) clip_slot.set_triggered_to_play_value(GREEN_BLINK) clip_slot.set_triggered_to_record_value(RED_BLINK) clip_slot.set_started_value(GREEN_FULL) clip_slot.set_stopped_value(AMBER_THIRD) clip_slot.set_recording_value(RED_FULL) # track stop self._session.set_stop_track_clip_buttons( [matrix.get_button(i, ROW_STOP) for i in range(8)]) self._session.set_stop_clip_value(RED_THIRD) self._session.set_stop_clip_triggered_value(RED_BLINK) button_stop_all = side_buttons[ROW_STOP] button_stop_all.set_on_off_values(RED_FULL, RED_THIRD) self._session.set_stop_all_clips_button(button_stop_all) # track select self._mixer.set_track_select_buttons( [matrix.get_button(i, ROW_SELECT) for i in range(8)]) self._mixer.set_track_select_values(AMBER_FULL, AMBER_THIRD, LED_OFF) button_select_master = side_buttons[ROW_SELECT] button_select_master.set_on_off_values(AMBER_FULL, AMBER_THIRD) self._mixer.set_master_select_button(button_select_master) # delete clip button self._delete_button = top_buttons[INDEX_DELETE_BUTTON] self._delete_button.set_on_off_values(RED_BLINK, RED_THIRD) self._delete_button.add_value_listener(self._delete_value_listener) self._del_pressed = False self._delete_button.turn_off() # quantization toggle self._quantization_toggle = QuantizationToggle( top_buttons[INDEX_QUANTIZATION_BUTTON], self.song(), GREEN_THIRD, RED_THIRD) # browser view toggle self._browser_view_toggle = ViewToggle( side_buttons[INDEX_BROWSER_VIEW_BUTTON], ABLETON_VIEW_BROWSER, GREEN_THIRD, RED_THIRD) # detail view toggle self._device_view_toggle = DetailViewToggle( side_buttons[INDEX_DETAIL_VIEW_BUTTON], GREEN_THIRD, RED_THIRD, LED_OFF) def disconnect(self): self._send_midi(LAUNCHPAD_RESET) ControlSurface.disconnect(self) self._delete_button.remove_value_listener(self._delete_value_listener) self._delete_button = None self._quantization_toggle.disconnect() self._quantization_toggle = None self._browser_view_toggle.disconnect() self._browser_view_toggle = None self._device_view_toggle.disconnect() self._device_view_toggle = None self._session = None self._mixer = None def receive_midi(self, midi_bytes): if self._del_pressed and self._delete_clip(midi_bytes): return else: ControlSurface.receive_midi(self, midi_bytes) def _delete_value_listener(self, value): self._del_pressed = (value == 127) self._delete_button.set_light(self._del_pressed) def _delete_clip(self, midi_bytes): if midi_bytes[0] == MIDI_NOTE_ON_VALUE: row, col = launchpad_button_loc(midi_bytes[1]) if row < SCENES_AMOUNT and col < 8: self._session.scene(row).clip_slot(col)._do_delete_clip() return True return False
def _setup_session_control(self): is_momentary = True right_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHAN, 43) left_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHAN, 42) up_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHAN, 44) down_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHAN, 45) right_button.name = 'Bank_Select_Right_Button' left_button.name = 'Bank_Select_Left_Button' up_button.name = 'Bank_Select_Up_Button' down_button.name = 'Bank_Select_Down_Button' global session session = SessionComponent(4, 4) session.name = 'Session_Control' session.set_track_bank_buttons(right_button, left_button) session.set_scene_bank_buttons(down_button, up_button) self._session = session matrix = ButtonMatrixElement() matrix.name = 'Button_Matrix' scene_launch_notes = [33,34,35,36] scene_launch_buttons = [ ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHAN, scene_launch_notes[index]) for index in range(4) ] #track_stop_buttons = [ ButtonElement(is_momentary, MIDI_NOTE_TYPE, index, 52) for index in range(4) ] for index in range(len(scene_launch_buttons)): scene_launch_buttons[index].name = 'Scene_'+ str(index) + '_Launch_Button' #for index in range(len(track_stop_buttons)): # track_stop_buttons[index].name = 'Track_' + str(index) + '_Stop_Button' #stop_all_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 81) #stop_all_button.name = 'Stop_All_Clips_Button' #self._session.set_stop_all_clips_button(stop_all_button) #self._session.set_stop_track_clip_buttons(tuple(track_stop_buttons)) #self._session.set_stop_clip_value(2) button_notes = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32] for scene_index in range(4): scene = session.scene(scene_index) scene.name = 'Scene_' + str(scene_index) button_row = [] scene.set_launch_button(scene_launch_buttons[scene_index]) #scene.set_triggered_value(2) for track_index in range(4): button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHAN, (track_index * 4) + scene_index + 1) button.name = str(track_index) + '_Clip_' + str(scene_index) + '_Button' 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_triggered_to_play_value(2) #clip_slot.set_triggered_to_record_value(4) clip_slot.set_stopped_value(0) clip_slot.set_started_value(64) #clip_slot.set_recording_value(3) clip_slot.set_launch_button(button) matrix.add_row(tuple(button_row)) #self._session.set_slot_launch_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 67)) session.selected_scene().name = 'Selected_Scene' #session.selected_scene().set_launch_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 64)) #session_zoom = SessionZoomingComponent(session) #session_zoom.name = 'Session_Overview' #session_zoom.set_button_matrix(matrix) #session_zoom.set_zoom_button(self._shift_button) #session_zoom.set_nav_buttons(up_button, down_button, left_button, right_button) #session_zoom.set_scene_bank_buttons(tuple(scene_launch_buttons)) #session_zoom.set_stopped_value(0) #session_zoom.set_selected_value(127) self.set_highlighting_session_component(session) session.set_mixer(mixer) return None #return session
class LaunchpadSimple(ControlSurface): def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self._suggested_input_port = "Launchpad" self._suggested_output_port = "Launchpad" # Launchpad configuration self._send_midi(LAUNCHPAD_RESET) self._send_midi(LAUNCHPAD_ENABLE_BLINKING) # make buttons top_buttons = [make_button(MIDI_CC_TYPE, 104 + i) for i in range(8)] side_buttons = [make_button(MIDI_NOTE_TYPE, 8 + 16 * i) for i in range(8)] matrix = ButtonMatrixElement() for row in range(8): button_row = [make_button(MIDI_NOTE_TYPE, 16 * row + col) for col in range(8)] matrix.add_row(tuple(button_row)) # mixer and session components self._mixer = MixerComponent(8) self._session = SessionComponent(8, SCENES_AMOUNT) self._session.set_mixer(self._mixer) self.set_highlighting_session_component(self._session) # navigation for button in top_buttons[:4]: button.set_on_off_values(GREEN_FULL, GREEN_THIRD) self._session.set_scene_bank_buttons(top_buttons[1], top_buttons[0]) self._session.set_track_bank_buttons(top_buttons[3], top_buttons[2]) # clip launch for scene_index in range(SCENES_AMOUNT): scene = self._session.scene(scene_index) scene.set_launch_button(side_buttons[scene_index]) scene.set_triggered_value(GREEN_BLINK) scene.set_scene_value(GREEN_THIRD) scene.set_no_scene_value(LED_OFF) for track_index in range(8): clip_slot = scene.clip_slot(track_index) clip_slot.set_launch_button(matrix.get_button(track_index, scene_index)) clip_slot.set_triggered_to_play_value(GREEN_BLINK) clip_slot.set_triggered_to_record_value(RED_BLINK) clip_slot.set_started_value(GREEN_FULL) clip_slot.set_stopped_value(AMBER_THIRD) clip_slot.set_recording_value(RED_FULL) # track stop self._session.set_stop_track_clip_buttons([matrix.get_button(i, ROW_STOP) for i in range(8)]) self._session.set_stop_clip_value(RED_THIRD) self._session.set_stop_clip_triggered_value(RED_BLINK) button_stop_all = side_buttons[ROW_STOP] button_stop_all.set_on_off_values(RED_FULL, RED_THIRD) self._session.set_stop_all_clips_button(button_stop_all) # track select self._mixer.set_track_select_buttons([matrix.get_button(i, ROW_SELECT) for i in range(8)]) self._mixer.set_track_select_values(AMBER_FULL, AMBER_THIRD, LED_OFF) button_select_master = side_buttons[ROW_SELECT] button_select_master.set_on_off_values(AMBER_FULL, AMBER_THIRD) self._mixer.set_master_select_button(button_select_master) # delete clip button self._delete_button = top_buttons[INDEX_DELETE_BUTTON] self._delete_button.set_on_off_values(RED_BLINK, RED_THIRD) self._delete_button.add_value_listener(self._delete_value_listener) self._del_pressed = False self._delete_button.turn_off() # quantization toggle self._quantization_toggle = QuantizationToggle( top_buttons[INDEX_QUANTIZATION_BUTTON], self.song(), GREEN_THIRD, RED_THIRD ) # browser view toggle self._browser_view_toggle = ViewToggle( side_buttons[INDEX_BROWSER_VIEW_BUTTON], ABLETON_VIEW_BROWSER, GREEN_THIRD, RED_THIRD ) # detail view toggle self._device_view_toggle = DetailViewToggle( side_buttons[INDEX_DETAIL_VIEW_BUTTON], GREEN_THIRD, RED_THIRD, LED_OFF ) def disconnect(self): self._send_midi(LAUNCHPAD_RESET) ControlSurface.disconnect(self) self._delete_button.remove_value_listener(self._delete_value_listener) self._delete_button = None self._quantization_toggle.disconnect() self._quantization_toggle = None self._browser_view_toggle.disconnect() self._browser_view_toggle = None self._device_view_toggle.disconnect() self._device_view_toggle = None self._session = None self._mixer = None def receive_midi(self, midi_bytes): if self._del_pressed and self._delete_clip(midi_bytes): return else: ControlSurface.receive_midi(self, midi_bytes) def _delete_value_listener(self, value): self._del_pressed = value == 127 self._delete_button.set_light(self._del_pressed) def _delete_clip(self, midi_bytes): if midi_bytes[0] == MIDI_NOTE_ON_VALUE: row, col = launchpad_button_loc(midi_bytes[1]) if row < SCENES_AMOUNT and col < 8: self._session.scene(row).clip_slot(col)._do_delete_clip() return True return False
class AumTroll_G(AumTroll): def __init__(self, *a, **k): super(AumTroll_G, self).__init__(*a, **k) with self.component_guard(): self._setup_session_recording_component() self._setup_APC_detail_component() self.log_message('Aumtroll G 4') def _setup_session_recording_component(self): self._recorder = SessionRecordingComponent(ClipCreator(), ViewControlComponent()) def _setup_APC_detail_component(self): self._alt_device_navigator = DetailViewCntrlComponent() """the mixer component corresponds and moves with our selection in Live, and allows us to assign physical controls""" """to Live's mixer functions without having to make all the links ourselves""" def _setup_mixer_control(self): is_momentary = True self._num_tracks = (8) #A mixer is one-dimensional; self._mixer = MixerComponent(8, 2, True, False) #These values represent the (Number_of_tracks, Number_of_returns, EQ_component, Filter_component) self._mixer.name = 'Mixer' #We name everything that we might want to access in m4l self._mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left) for index in range(8): #self._mixer.channel_strip(index).set_volume_control(self._fader[index]) #Since we gave our mixer 4 tracks above, we'll now assign our fader controls to it self._mixer.channel_strip(index).name = 'Mixer_ChannelStrip_' + str(index) #We also name the individual channel_strip so we can access it self._mixer.track_eq(index).name = 'Mixer_EQ_' + str(index) #We also name the individual EQ_component so we can access it self._mixer.channel_strip(index)._invert_mute_feedback = True #This makes it so that when a track is muted, the corresponding button is turned off self.song().view.selected_track = self._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 self._send_reset = ResetSendsComponent(self) #This creates a custom MonoComponent that allows us to reset all the sends on a track to zero with a single button self._send_reset.name = 'Sends_Reset' #We name it so that we can access it from m4l """the session component represents a grid of buttons that can be used to fire, stop, and navigate clips in the session view""" def _setup_session_control(self): is_momentary = True num_tracks = 8 #we are working with a 4x4 grid, num_scenes = 4 #so the height and width are both set to 4 self._session = SessionComponent(num_tracks, num_scenes) #we create our SessionComponent with the variables we set above it self._session.name = "Session" #we name it so we can access it in m4l self._session.set_offsets(0, 0) #we set the initial offset to the far left, top of the session grid self._session._track_banking_increment = 4 self._session.set_stop_clip_value(STOP_CLIP[self._rgb]) #we assign the colors that will be displayed when the stop_clip button is pressed. This value comes from CNTRLR_Map.py, which is imported in the header of our script self._scene = [None for index in range(4)] #we create an array to hold the Scene subcomponents so that we can get to them if we need them. for row in range(num_scenes): #now we'll fill the array with different objects that were created when we called the SessionComponent() module self._scene[row] = self._session.scene(row) #each session row is a SceneComponent self._scene[row].name = 'Scene_' + str(row) #name it so we can access it in m4l for column in range(num_tracks): #now we'll create holders and names for the contents of each scene clip_slot = self._scene[row].clip_slot(column) #we use our assignment of the scene above to gain access to the individual clipslots. Here, we are just assigning 'clip_slot' each time as a local variable so we can manipulated it's properties clip_slot.name = str(column) + '_Clip_Slot' + str(row) #name it so that we can acces it in m4l clip_slot.set_triggered_to_play_value(CLIP_TRG_PLAY[self._rgb]) #set its triggered to play color clip_slot.set_triggered_to_record_value(CLIP_TRG_REC[self._rgb])#set its triggered to record color clip_slot.set_stopped_value(CLIP_STOP[self._rgb]) #set its stop color clip_slot.set_started_value(CLIP_STARTED[self._rgb]) #set its started color clip_slot.set_recording_value(CLIP_RECORDING[self._rgb]) #set its recording value self._session.set_mixer(self._mixer) #now we link the MixerComponent we created in _setup_mixer_control() to our session component so that they will follow each other when either is navigated self.set_highlighting_session_component(self._session) self._session_zoom = SessionZoomingComponent(self._session) #this creates the ZoomingComponent that allows navigation when the shift button is pressed self._session_zoom.name = 'Session_Overview' #name it so we can access it in m4l self._session_zoom.set_stopped_value(ZOOM_STOPPED[self._rgb]) #set the zooms stopped color self._session_zoom.set_playing_value(ZOOM_PLAYING[self._rgb]) #set the zooms playing color self._session_zoom.set_selected_value(ZOOM_SELECTED[self._rgb]) #set the zooms selected color self._session_zoom.set_button_matrix(self._matrix) #assign the ButtonMatrixElement that we created in _setup_controls() to the zooming component so that we can control it self._session_zoom.set_zoom_button(self._button[31]) #assign a shift button so that we can switch states between the SessionComponent and the SessionZoomingComponent """this section is used so that we can reassign the color properties of each state. Legacy, from the OhmModes script, to support either RGB or Monochrome""" def _assign_session_colors(self): num_tracks = 8 num_scenes = 4 self._session.set_stop_clip_value(STOP_ALL[self._rgb]) for row in range(num_scenes): for column in range(num_tracks): self._scene[row].clip_slot(column).set_triggered_to_play_value(CLIP_TRG_PLAY[self._rgb]) self._scene[row].clip_slot(column).set_triggered_to_record_value(CLIP_TRG_REC[self._rgb]) self._scene[row].clip_slot(column).set_stopped_value(CLIP_STOP[self._rgb]) self._scene[row].clip_slot(column).set_started_value(CLIP_STARTED[self._rgb]) self._scene[row].clip_slot(column).set_recording_value(CLIP_RECORDING[self._rgb]) self._session_zoom.set_stopped_value(ZOOM_STOPPED[self._rgb]) self._session_zoom.set_playing_value(ZOOM_PLAYING[self._rgb]) self._session_zoom.set_selected_value(ZOOM_SELECTED[self._rgb]) self.refresh_state() def deassign_live_controls(self, *a, **k): for index in range(4): self._encoder[index].send_value(0, True) self._encoder[index].clear_send_cache() self._mixer.channel_strip(index+4).set_volume_control(None) #Since we gave our mixer 4 tracks above, we'll now assign our fader controls to it #for the left side of the mixer self._mixer.channel_strip(index+4).set_solo_button(None) #remove the solo button assignments self._mixer.channel_strip(index+4).set_arm_button(None) #remove the arm button assignments self._mixer.channel_strip(index+4).set_mute_button(None) #remove the mute button assignments self._mixer.channel_strip(index+4).set_select_button(None) #remove the select button assignments #self._alt_device_navigator.set_arrange_session_toggle_button(None) self._alt_device_navigator.set_device_clip_toggle_button(None) self._alt_device_navigator.set_detail_toggle_button(None) self._alt_device_navigator.set_enabled(False) #self._alt_device_navigator.set_shift_button(None) self._transport.set_nudge_buttons(None, None) self._recorder.set_record_button(None) self._recorder.set_re_enable_automation_button(None) super(AumTroll_G, self).deassign_live_controls(*a, **k) def assign_live_controls(self): """the following lines update all of the controls' last_sent properties, so that they forward the next value they receive regardless of whether or not it is the same as the last it recieved""" """we also reset the encoder rings and buttons, since the device component will not update them if it is not locked to a device in Live""" for index in range(16): self._grid[index].force_next_send() for index in range(32): #self._button[index].set_on_off_values(0, 127) self._button[index].send_value(0, True) self._button[index].force_next_send() for index in range(8): self._encoder_button[index+4].send_value(0, True) self._encoder_button[index+4].force_next_send() for index in range(12): self._encoder[index].send_value(0, True) self._encoder[index].force_next_send() """here we assign the left side of our mixer's buttons on the lower 32 keys""" if self._monohm is None: with self.component_guard(): for index in range(4): #we set up a recursive loop to assign all four of our track channel strips' controls self._button[index+16].set_on_value(MUTE[self._rgb]) #set the mute color from the Map.py self._mixer.channel_strip(index).set_mute_button(self._button[index+16]) #assign the mute buttons to our mixer channel strips self._button[index+28].set_on_value(MUTE[self._rgb]) #set the mute color from the Map.py self._mixer.channel_strip(index+4).set_mute_button(self._button[index+28]) #assign the mute buttons to our mixer channel strips self._button[index].set_on_off_values(SELECT[self._rgb], SELECT_OFF[self._rgb]) self._mixer.channel_strip(index).set_select_button(self._button[index]) #assign the select buttons to our mixer channel strips self._button[index+12].set_on_off_values(SELECT[self._rgb], SELECT_OFF[self._rgb]) #set the select color from the Map.py self._mixer.channel_strip(index+4).set_select_button(self._button[index+12]) #assign the select buttons to our mixer channel strips #self._session.set_stop_track_clip_buttons(tuple(self._button[index+4] for index in range(8))) #these last two lines assign the send_reset buttons and the stop_clip buttons for each track for index in range(8): #self._button[index + 4].set_on_off_values(SOLO[self._rgb], SOLO[self._rgb]) #this assigns the custom colors defined in the Map.py file to the stop_clip buttons. They have seperate on/off values, but we assign them both the same value so we can always identify them self._mixer.channel_strip(index).set_solo_button(self._button[index+4]) #self._button[index + 4].send_value(STOP_CLIP[self._rgb], True) #finally, we send the on/off colors out to turn the LEDs on for the stop clip buttons for index in range(4): #set up a for loop to generate an index for assigning the session nav buttons' colors self._button[index + 20].set_on_off_values(SESSION_NAV[self._rgb], SESSION_NAV_OFF[self._rgb]) #assign the colors from Map.py to the session nav buttons self._session.set_track_bank_buttons(self._button[21], self._button[20]) #set the track bank buttons for the Session navigation controls self._session.set_scene_bank_buttons(self._button[23], self._button[22]) #set the scnee bank buttons for the Session navigation controls """this section assigns the grid to the clip launch functionality of the SessionComponent""" for column in range(4): #we need to set up a double recursion so that we can generate the indexes needed to assign the grid buttons for row in range(4): #the first recursion passes the column index, the second the row index self._scene[row].clip_slot(column).set_launch_button(self._grid[(row*4)+column]) #we use the indexes to grab the first the scene and then the clip we assigned above, and then we use them again to define the button held in the grid array that we want to assign to the clip slot from the session component for index in range(4): #set up a for loop to generate an index for assigning the session nav buttons' colors self._button[index + 24].set_on_off_values(SHIFTS[self._rgb], SHIFTS_OFF[self._rgb]) #assign the colors from Map.py to the session nav buttons self._session.update() #tell the Session component to update so that the grid will display the currently selected session region self._session.set_enabled(True) #enable the Session Component self._session_zoom.set_enabled(True) #enable the Session Zoom #self._alt_device_navigator.set_arrange_session_toggle_button(self._encoder_button[4]) self._alt_device_navigator.set_device_clip_toggle_button(self._encoder_button[5]) self._alt_device_navigator.set_detail_toggle_button(self._encoder_button[6]) #self._device_navigator.set_shift_button(self._encoder_button[7]) self._session_zoom.set_zoom_button(self._encoder_button[7]) #assign the lower right key button to the shift function of the Zoom component self._session.set_scene_bank_buttons(self._button[25], self._button[24]) self._recorder.set_record_button(self._button[27]) self._recorder.set_re_enable_automation_button(self._button[26]) else: for index in range(8): self._mixer2.channel_strip(index).set_volume_control(self._fader[index]) self._mixer2.set_track_offset(TROLL_OFFSET) self._device_selector.set_mode_buttons(self._grid) if not self._shifted: self._assign_monomodular_controls() else: self._assign_shifted_controls() self._device1.set_parameter_controls(tuple([self._knobs[index] for index in range(8)])) self._device2.set_parameter_controls(tuple([self._knobs[index+12] for index in range(8)])) self._device1.set_enabled(True) self._device2.set_enabled(True) self._find_devices() self._device1.update() self._device2.update() """this section assigns the encoders and encoder buttons""" self._device.set_parameter_controls(tuple([self._encoder[index+4] for index in range(8)])) #assign the encoders from the device component controls - we are doing this here b #self._encoder_button[7].set_on_value(DEVICE_LOCK[self._rgb]) #set the on color for the Device lock encoder button #self._device.set_lock_button(self._encoder_button[7]) #assign encoder button 7 to the device lock control #self._encoder_button[4].set_on_value(DEVICE_ON[self._rgb]) #set the on color for the Device on/off encoder button #self._device.set_on_off_button(self._encoder_button[4]) #assing encoder button 4 to the device on/off control for index in range(2): #setup a recursion to generate indexes so that we can reference the correct controls to assing to the device_navigator functions self._encoder_button[index + 8].set_on_value(DEVICE_NAV[self._rgb]) #assign the on color for the device navigator self._encoder_button[index + 10].set_on_value(DEVICE_BANK[self._rgb]) #assign the on color for the device bank controls self._device_navigator.set_nav_buttons(self._encoder_button[10], self._encoder_button[11]) #set the device navigators controls to encoder buttons 10 and 11 self._device.set_bank_nav_buttons(self._encoder_button[8], self._encoder_button[9]) #set the device components bank nav controls to encoder buttons 8 and 9 """now we turn on and update some of the components we've just made assignments to""" self._device.set_enabled(True) #enable the Device Component self._device_navigator.set_enabled(True) #enable the Device Navigator self._alt_device_navigator.set_enabled(True) self._device.update() #tell the Device component to update its assingments so that it will detect the currently selected device parameters and display them on the encoder rings
class MidiFighterTwister(ControlSurface): __module__ = __name__ __doc__ = "MidiFighterTwister class" def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self.__c_instance = c_instance self.show_message('Script initiated') self.init() def init(self): # initialize listeners, caches and colors self.flush_all() self.mf_disable_bank_buttons() self.mf_init_page_config() self.mf_init_light_pages() # Start listeners to call dispatcher self.song().view.add_detail_clip_listener( self.dispatch_detail_clip_listener) self.song().add_current_song_time_listener( self.dispatch_current_song_time_listener) self.song().view.add_selected_track_listener( self.dispatch_selected_track_listener) self.device_listener_wrapper() # Initialize the sequencer buttons self.sequencer_init_buttons() self.sequencer_init_rotaries() self.init_clip_page() self.init_pad_page() self.init_device_params() def flush_all(self): for poti in range(64): for channel in range(4): self._send_midi((175 + channel, poti, 0)) def mf_init_page_config(self): # Initialize configuration parameters # Sequencer configuration self.sequencer_page_default_color = 1 self.sequencer_current_page_color_index = self.sequencer_page_default_color self.sequencer_base_default_note = 36 self.sequencer_current_selected_note = self.sequencer_base_default_note self.sequencer_clip_position_16th = None # Midi Channels self.rotary_midi_channel = 175 + 1 self.ring_midi_channel = 175 + 1 self.switch_midi_channel = 175 + 2 self.light_midi_channel = 175 + 2 # Pages cc map self.clip_page_cc = range(0, 16) self.sequencer_page_cc = range(16, 32) self.note_page_cc = range(32, 48) self.control_page_cc = range(48, 64) # Pages init color self.clip_page_colors = [1] * 16 self.sequencer_page_colors = [self.sequencer_page_default_color] * 16 self.note_page_colors = range(1, 127, 16) * 2 #self.note_page_colors = [0] * 16 self.control_page_colors = [1] * 16 # Status cache for sequencer self.switch_encoder_status_cache = [False] * 64 # List to store ButtonElements in self.switch_encoder_buttons = [False] * 64 # Status cache for rotaries self.rotary_encoder_potis = [False] * 64 def mf_init_light_pages(self): sequencer_page_map = zip(self.sequencer_page_cc, self.sequencer_page_colors) for light_encoder_cc, light_color_cc in sequencer_page_map: self._mf_set_light(light_encoder_cc, light_color_cc, False) note_page_map = zip(self.note_page_cc, self.note_page_colors) for light_encoder_cc, light_color_cc in note_page_map: self._mf_set_light(light_encoder_cc, light_color_cc, False) def _mf_set_light(self, light_encoder_cc, light_color_cc, status): # Sets color on midi channel 2 (177) end updates status cache # for sequencer to remember statuses self._send_midi( (self.light_midi_channel, light_encoder_cc, light_color_cc)) self.switch_encoder_status_cache[light_encoder_cc] = status def mf_disable_bank_buttons(self): # Workaround for not sending values to track when pressing bank buttons self.padm0 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 4, 0) self.padm1 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 4, 1) self.padm2 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 4, 2) self.padm3 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 4, 3) self.padm0.add_value_listener(self.bank_buttons_dummy, identify_sender=True) self.padm1.add_value_listener(self.bank_buttons_dummy, identify_sender=True) self.padm2.add_value_listener(self.bank_buttons_dummy, identify_sender=True) self.padm3.add_value_listener(self.bank_buttons_dummy, identify_sender=True) def bank_buttons_dummy(self): pass def dispatch_detail_clip_listener(self): self.current_clip = self.song().view.highlighted_clip_slot.clip self.init_sequencer() try: if self.current_clip.is_midi_clip and not self.current_clip.notes_has_listener: # Update leds when notes are added or removed self.current_clip.add_notes_listener( self._sequencer_update_notes_to_light) self.init_sequencer() else: self.sequencer_reset_colors() except AttributeError: pass def dispatch_current_song_time_listener(self): self.sequencer_light_follows_beat() def dispatch_selected_track_listener(self): self.device_auto_select() self.device_listener_wrapper() def device_listener_wrapper(self): selected_track = self.song().view.selected_track if not selected_track.devices_has_listener(self.device_auto_select): self.song().view.selected_track.add_devices_listener( self.device_auto_select) # Sequencer def init_sequencer(self): self.sequencer_current_selected_note = self.sequencer_base_default_note self.sequencer_current_page_color_index = self.sequencer_page_default_color self._sequencer_update_notes_to_light() def sequencer_init_buttons(self): for switch_encoder_cc in self.sequencer_page_cc: self.switch_encoder_buttons[switch_encoder_cc] = ButtonElement( IS_MOMENTARY, MIDI_CC_TYPE, 1, switch_encoder_cc) self.switch_encoder_buttons[switch_encoder_cc].add_value_listener( self.sequencer_button_press, identify_sender=True) self.padl14 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 14) self.padr17 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 17) self.padl16 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 16) self.padr19 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 19) self.padl14.add_value_listener(self.sequencer_side_button_press, identify_sender=True) self.padr17.add_value_listener(self.sequencer_side_button_press, identify_sender=True) self.padl16.add_value_listener(self.sequencer_side_button_press, identify_sender=True) self.padr19.add_value_listener(self.sequencer_side_button_press, identify_sender=True) def sequencer_init_rotaries(self): for rotary_encoder_cc in self.sequencer_page_cc: self.rotary_encoder_potis[rotary_encoder_cc] = EncoderElement( MIDI_CC_TYPE, 0, rotary_encoder_cc, Live.MidiMap.MapMode.absolute) self.rotary_encoder_potis[rotary_encoder_cc].add_value_listener( self.sequencer_rotary_change, identify_sender=True) def sequencer_rotary_change(self, value, sender): try: self.current_clip except AttributeError: return False if self.current_clip.is_midi_clip: cc_value = sender._msg_identifier if value > 0: if not self.switch_encoder_status_cache[cc_value]: self._send_midi((self.light_midi_channel, cc_value, self.sequencer_current_light_on_color)) self._send_midi((self.ring_midi_channel, cc_value, 100)) self.switch_encoder_status_cache[cc_value] = True self.current_clip.set_notes( ((self.sequencer_current_selected_note, cc_value % 16 * 0.25, 0.25, value, False), )) elif value == 0: self._send_midi((self.light_midi_channel, cc_value, self.sequencer_current_page_color)) self.current_clip.remove_notes( cc_value % 16 * 0.25, self.sequencer_current_selected_note, 0.25, 1) self.switch_encoder_status_cache[cc_value] = False def sequencer_button_press(self, value, sender): try: self.current_clip except AttributeError: return False if self.current_clip.is_midi_clip: cc_value = sender._msg_identifier if value > 0: if not self.switch_encoder_status_cache[cc_value]: self._send_midi((self.light_midi_channel, cc_value, self.sequencer_current_light_on_color)) self.current_clip.set_notes( ((self.sequencer_current_selected_note, cc_value % 16 * 0.25, 0.25, 100, False), )) self.switch_encoder_status_cache[cc_value] = True self._send_midi((self.ring_midi_channel, cc_value, 100)) else: self._send_midi((self.light_midi_channel, cc_value, self.sequencer_current_page_color)) self._send_midi((self.ring_midi_channel, cc_value, 0)) self.current_clip.remove_notes( cc_value % 16 * 0.25, self.sequencer_current_selected_note, 0.25, 1) self.switch_encoder_status_cache[cc_value] = False def sequencer_side_button_press(self, value, sender): try: cc_value = sender._msg_identifier if value > 0: # Note/clolor up/down if cc_value == 14 and self.sequencer_current_selected_note > 0: self.sequencer_current_selected_note = self.sequencer_current_selected_note - 1 self.sequencer_current_page_color_index = self.sequencer_current_page_color_index - 16 self._sequencer_update_notes_to_light() self.sequencer_clip_position_16th = None self.show_message( "Selected Midi Note: " + str(self.sequencer_current_selected_note)) if cc_value == 17 and self.sequencer_current_selected_note < 127: self.sequencer_current_selected_note = self.sequencer_current_selected_note + 1 self.sequencer_current_page_color_index = self.sequencer_current_page_color_index + 16 self._sequencer_update_notes_to_light() self.sequencer_clip_position_16th = None self.show_message( "Selected Midi Note: " + str(self.sequencer_current_selected_note)) # New/duplicate clip if cc_value == 16 and self.sequencer_current_selected_note > 0: self.duplicate_clip() if cc_value == 19 and self.sequencer_current_selected_note > 0: self.session_record() except AttributeError: pass def sequencer_light_follows_beat(self): try: if self.current_clip.is_midi_clip: if self.sequencer_clip_position_16th == None: self.sequencer_clip_position_16th = int( self.current_clip.playing_position / 0.25) if self.switch_encoder_status_cache[self.sequencer_page_cc[ self.sequencer_clip_position_16th]]: self._send_midi( (177, self.sequencer_page_cc[ self.sequencer_clip_position_16th], self.sequencer_current_light_on_color)) else: self._send_midi((177, self.sequencer_page_cc[ self.sequencer_clip_position_16th], self.sequencer_current_page_color)) elif self.sequencer_clip_position_16th != int( self.current_clip.playing_position / 0.25): if self.switch_encoder_status_cache[self.sequencer_page_cc[ self.sequencer_clip_position_16th]]: self._send_midi( (177, self.sequencer_page_cc[ self.sequencer_clip_position_16th], self.sequencer_current_light_on_color)) else: self._send_midi((177, self.sequencer_page_cc[ self.sequencer_clip_position_16th], self.sequencer_current_page_color)) self.sequencer_clip_position_16th = int( self.current_clip.playing_position / 0.25) self._send_midi((177, self.sequencer_page_cc[ self.sequencer_clip_position_16th], self.sequencer_current_light_beat_color)) except IndexError: pass @property def sequencer_current_light_on_color(self): # light on color to be relative to page color return self.sequencer_current_page_color + 32 % 128 @property def sequencer_current_light_beat_color(self): # light on color to be relative to page color return self.sequencer_current_page_color + 64 % 128 @property def sequencer_current_page_color(self): return self.sequencer_current_page_color_index % 128 def _sequencer_get_midi_notes(self, note): # self.current_clip.get_notes(start, self.sequencer_current_selected_note, # selection_length, hight) try: return self.current_clip.get_notes(0, note, 4, 1) except AttributeError: return [] def _sequencer_update_notes_to_light(self): self.sequencer_reset_colors() notes_for_current_selected_note = self._sequencer_get_midi_notes( self.sequencer_current_selected_note) for note in notes_for_current_selected_note: light_encoder_cc = int(note[1] * 4 + self.sequencer_page_cc[0]) self._send_midi( (self.ring_midi_channel, light_encoder_cc, note[3])) self._mf_set_light(light_encoder_cc, self.sequencer_current_light_on_color, True) def sequencer_reset_colors(self): for light_encoder_cc in self.sequencer_page_cc: self._mf_set_light(light_encoder_cc, self.sequencer_current_page_color, False) self._send_midi((self.ring_midi_channel, light_encoder_cc, 0)) def duplicate_clip(self): self.log_message("duplicate clip") #if self._clip_slot and self._clip_slot.has_clip: # slot_name = self._clip_slot.clip.name # track = self._clip_slot.canonical_parent current_track = self.song().view.selected_track current_clip_slot = self.song().view.highlighted_clip_slot self.song().duplicate_scene( list(current_track.clip_slots).index(current_clip_slot)) #new_clip = current_track.duplicate_clip_slot( # list(current_track.clip_slots).index(current_clip_slot)+1) #self.log_message(new_clip) #selected_track = self.song().view.selected_track #selected_track.duplicate_clip_slot(selected_track) def session_record(self): self.log_message("session record") #self.song().trigger_session_record() # Clip page setion def init_clip_page(self): num_tracks = 4 num_scenes = 3 self.flash_status = 1 self.Mixer = MixerComponent(4, 3) # Volencoder self.volencoders = [None for index in range(num_tracks)] for index in range(num_tracks): self.volencoders[index] = EncoderElement( MIDI_CC_TYPE, 0, index, Live.MidiMap.MapMode.absolute) self.Mixer.channel_strip(index).set_volume_control( self.volencoders[index]) # Sendencoder for index in range(num_tracks): encoder_cc_send_1 = index + num_tracks encoder_cc_send_2 = index + num_tracks * 2 send1 = EncoderElement(MIDI_CC_TYPE, 0, encoder_cc_send_1, Live.MidiMap.MapMode.absolute) send2 = EncoderElement(MIDI_CC_TYPE, 0, encoder_cc_send_2, Live.MidiMap.MapMode.absolute) self.Mixer.channel_strip(index).set_send_controls((send1, send2)) # Panencoder for index in range(num_tracks): encoder_cc_pan = index + num_tracks * 3 pan = EncoderElement(MIDI_CC_TYPE, 0, encoder_cc_pan, Live.MidiMap.MapMode.absolute) self.Mixer.channel_strip(index).set_pan_control(pan) # Arm-/selectbuttons for index in range(num_tracks): armbutton = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, index + 12) self.Mixer.channel_strip(index).set_arm_button(armbutton) self.Mixer.channel_strip(index).set_select_button(armbutton) # Navigation buttons self.padl11 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 11) self.padr8 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 8) self.padl10 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 10) self.padr13 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 13) self.grid = [None for index in range(num_tracks * 3)] for index in range(num_tracks * 3): self.grid[index] = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, index) self.matrix = ButtonMatrixElement() for row in range(num_scenes): button_row = [] for column in range(num_tracks): button_row.append(self.grid[column + (row * 4)]) self.log_message(str(column + (row * 4))) self.matrix.add_row(tuple(button_row)) self.Session = SessionComponent(num_tracks, num_scenes) self.Session.name = "Session" self.Session.set_offsets(0, 0) self.Session.set_mixer(self.Mixer) self.Session._do_show_highlight() self.set_highlighting_session_component(self.Session) self.Session.set_track_bank_buttons(self.padl11, self.padr8) self.Session.set_scene_bank_buttons(self.padr13, self.padl10) self.scene = [None for index in range(num_scenes)] for row in range(num_scenes): self.scene[row] = self.Session.scene(row) self.scene[row].name = 'Scene_' + str(row) for column in range(num_tracks): clip_slot = self.scene[row].clip_slot(column) clip_slot.name = str(column) + '_Clip_Slot' + str(row) self.scene[row].clip_slot(column).set_triggered_to_play_value( 35) self.scene[row].clip_slot(column).set_stopped_value(68) self.scene[row].clip_slot(column).set_started_value(45) self.scene[row].clip_slot( column).set_triggered_to_record_value(100) self.scene[row].clip_slot(column).set_recording_value(80) for column in range(num_tracks): for row in range(num_scenes): self.scene[row].clip_slot(column).set_launch_button( self.grid[column + (row * 4)]) for index in range(num_tracks * num_scenes): self.grid[index].clear_send_cache() def update_display(self): # Called every 100 ms ControlSurface.update_display(self) self.refresh_state() self.Session.set_enabled(True) self.Session.update() # Sequencer hack try: for light_encoder_cc in self.sequencer_page_cc: self._send_midi((self.ring_midi_channel, light_encoder_cc, 0)) notes_for_current_selected_note = self._sequencer_get_midi_notes( self.sequencer_current_selected_note) for note in notes_for_current_selected_note: light_encoder_cc = int(note[1] * 4 + self.sequencer_page_cc[0]) self._send_midi( (self.ring_midi_channel, light_encoder_cc, note[3])) except AttributeError: pass # Pad Section def init_pad_page(self): self.pad_device_params() PAD_TRANSLATION = ((0, 0, 32, 1), (1, 0, 33, 1), (2, 0, 34, 1), (3, 0, 35, 1), (0, 1, 36, 1), (1, 1, 37, 1), (2, 1, 38, 1), (3, 1, 39, 1), (0, 2, 40, 1), (1, 2, 41, 1), (2, 2, 42, 1), (3, 2, 43, 1), (0, 3, 44, 1), (1, 3, 45, 1), (2, 3, 46, 1), (3, 3, 47, 1)) self.set_pad_translations(PAD_TRANSLATION) self._device_selection_follows_track_selection = True def pad_device_params(self): device_param_controls = [] for param in self.note_page_cc[:8]: self.rotary_encoder_potis[param] = EncoderElement( MIDI_CC_TYPE, 0, param, Live.MidiMap.MapMode.absolute) self.rotary_encoder_potis[param].release_parameter() self.rotary_encoder_potis[param].send_value(0, True) self.rotary_encoder_potis[param].clear_send_cache() device_param_controls.append(self.rotary_encoder_potis[param]) device = DeviceComponent() device.name = 'Device_Component pad' device.set_parameter_controls(tuple(device_param_controls)) self.set_device_component(device) #def scrolling(self): # self.application().view.scroll_view(ndir, 'Detail/DeviceChain', True) # Live.Song.Song.View.selected_track #Live.Song.Song.View.select_device()[0] # Device parameter section def init_device_params(self): device_param_controls = [] device_bank_buttons = [] for param in self.control_page_cc[:8]: self.rotary_encoder_potis[param] = EncoderElement( MIDI_CC_TYPE, 0, param, Live.MidiMap.MapMode.absolute) self.switch_encoder_buttons[param] = ButtonElement( IS_MOMENTARY, MIDI_CC_TYPE, 1, param) self.rotary_encoder_potis[param].release_parameter() self.rotary_encoder_potis[param].send_value(0, True) self.rotary_encoder_potis[param].clear_send_cache() device_param_controls.append(self.rotary_encoder_potis[param]) device_bank_buttons.append(self.switch_encoder_buttons[param]) device = DeviceComponent() device.name = 'Device_Component' device.set_parameter_controls(tuple(device_param_controls)) device.set_bank_buttons(tuple(device_bank_buttons)) device.set_on_off_button( ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, 56)) self.set_device_component(device) def device_auto_select(self): # Iterates through devices within a track and assigns the first # DrumPad device to activate the individual drum's device. # Use first device in case none is a DrumPad device. selected_track = self.song().view.selected_track devices = selected_track.devices for device in devices: if device.can_have_drum_pads: self.current_drum_device = device pad_device = self.current_drum_device.view.selected_chain.devices[ 0] self.song().view.select_device(pad_device) if not self.current_drum_device.view.selected_drum_pad_has_listener( self.device_update_current_note): self.current_drum_device.view.add_selected_drum_pad_listener( self.device_update_current_note) break else: self.song().view.select_device(devices[0]) def device_update_current_note(self): current_note = self.current_drum_device.view.selected_drum_pad.note self.sequencer_current_selected_note = current_note # Update light of active pad #self._send_midi((self.light_midi_channel, light_encoder_cc, 63)) try: self.current_clip = self.song().view.highlighted_clip_slot.clip self.current_clip.is_midi_clip self._sequencer_update_notes_to_light() except AttributeError: pass
class CNTRL_R_LITE(ControlSurface): def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) is_momentary = True self._timer = 0 # Used in FlashingButtonElement (kludge for our purposes) self.flash_status = 1 # Used in FlashingButtonElement (kludge for our purposes) if USE_MIXER_CONTROLS == True: self.mixer_control() if USE_SESSION_VIEW == True: self.session_control() def mixer_control(self): is_momentary = True self.num_tracks = N_TRACKS if(USE_SENDS == True): self.mixer = MixerComponent(N_TRACKS, N_SENDS_PER_TRACK, USE_MIXER_EQ, USE_MIXER_FILTERS) else: self.mixer = MixerComponent(N_TRACKS,0, USE_MIXER_EQ, USE_MIXER_FILTERS) self.mixer.name = 'Mixer' self.mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left) for index in range(N_TRACKS): self.mixer.channel_strip(index).name = 'Mixer_ChannelStrip_' + str(index) self.mixer.channel_strip(index)._invert_mute_feedback = True self.song().view.selected_track = self.mixer.channel_strip(0)._track self.log_message(str(len(SOLO_BUTTONS))) self.log_message(str(len(MUTE_BUTTONS))) if(USE_SOLO_BUTTONS == True): self.solobuttons = [None for index in range(N_TRACKS)] for index in range(len(SOLO_BUTTONS)): self.solobuttons[index] = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,SOLO_BUTTONS[index], 'Solo_Button', self) self.mixer.channel_strip(index).set_solo_button(self.solobuttons[index]) self.solobuttons[index].set_on_value(SOLO_BUTTON_ON_COLOR) self.solobuttons[index].set_off_value(SOLO_BUTTON_OFF_COLOR) if(USE_MUTE_BUTTONS == True): self.mutebuttons = [None for index in range(N_TRACKS)] for index in range(len(MUTE_BUTTONS)): self.mutebuttons[index] = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,MUTE_BUTTONS[index], 'Mute_Button', self) self.mixer.channel_strip(index).set_mute_button(self.mutebuttons[index]) self.mutebuttons[index].set_on_value(MUTE_BUTTON_ON_COLOR) self.mutebuttons[index].set_off_value(MUTE_BUTTON_OFF_COLOR) if(USE_SENDS == True): self.sendencoders = [None for index in range(len(SEND_ENCODERS))] for index in range(len(SEND_ENCODERS)): self.sendencoders[index] = EncoderElement(MIDI_CC_TYPE, CHANNEL, SEND_ENCODERS[index], Live.MidiMap.MapMode.absolute) for index in range(len(SEND_ENCODERS)/N_SENDS_PER_TRACK): self.mixer.channel_strip(index).set_send_controls(tuple(self.sendencoders[(index*N_SENDS_PER_TRACK):((index*N_SENDS_PER_TRACK)+N_SENDS_PER_TRACK-1)])) if(USE_VOLUME_CONTROLS == True): self.volencoders = [None for index in range(len(VOLUME_ENCODERS))] for index in range (len(VOLUME_ENCODERS)): self.volencoders[index] = EncoderElement(MIDI_CC_TYPE, CHANNEL, VOLUME_ENCODERS[index], Live.MidiMap.MapMode.absolute) self.mixer.channel_strip(index).set_volume_control(self.volencoders[index]) def session_control(self): is_momentary = True self._timer = 0 self.flash_status = 1 self.grid = [None for index in range(N_TRACKS*N_SCENES)] for index in range(N_TRACKS*N_SCENES): self.grid[index] = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,TRACK_CLIP_BUTTONS[index], 'Grid' + str(index), self) self.matrix = ButtonMatrixElement() for row in range(N_SCENES): button_row = [] for column in range(N_TRACKS): button_row.append(self.grid[row+(column*4)]) self.matrix.add_row(tuple(button_row)) self.session = SessionComponent(N_TRACKS,N_SCENES) self.session.name = "Session" self.session.set_offsets(0,0) self.scene = [None for index in range(N_SCENES)] for row in range(N_SCENES): self.scene[row] = self.session.scene(row) self.scene[row].name = 'Scene_'+str(row) for column in range(N_TRACKS): clip_slot = self.scene[row].clip_slot(column) clip_slot.name = str(column)+'_Clip_Slot'+str(row) self.scene[row].clip_slot(column).set_triggered_to_play_value(CLIP_TRG_PLAY_COLOR) self.scene[row].clip_slot(column).set_stopped_value(CLIP_STOP_COLOR) self.scene[row].clip_slot(column).set_started_value(CLIP_STARTED_COLOR) # Clip trigger on grid assignments for column in range(N_TRACKS): for row in range(N_SCENES): self.scene[row].clip_slot(column).set_launch_button(self.grid[row+(column*4)]) for index in range(N_TRACKS*N_SCENES): self.grid[index].clear_send_cache() if USE_SESSION_NAV == True: self.navleft = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,NAVBOX_LEFT_BUTTON, 'Nav_Left_Button', self) self.navleft.clear_send_cache() self.navleft.set_on_off_values(NAVBOX_LEFT_BUTTON_C, NAVBOX_LEFT_BUTTON_C) self.navright = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,NAVBOX_RIGHT_BUTTON, 'Nav_Right_Button', self) self.navright.clear_send_cache() self.navright.set_on_off_values(NAVBOX_RIGHT_BUTTON_C, NAVBOX_RIGHT_BUTTON_C) self.navup = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,NAVBOX_UP_BUTTON, 'Nav_Up_Button', self) self.navup.clear_send_cache() self.navup.set_on_off_values(NAVBOX_UP_BUTTON_C, NAVBOX_UP_BUTTON_C) self.navdown = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,NAVBOX_DOWN_BUTTON, 'Nav_Down_Button', self) self.navdown.clear_send_cache() self.navdown.set_on_off_values(NAVBOX_DOWN_BUTTON_C, NAVBOX_DOWN_BUTTON_C) self.session.set_track_bank_buttons(self.navright, self.navleft) self.session.set_scene_bank_buttons(self.navdown, self.navup) if USE_MIXER_CONTROLS == True: self.session.set_mixer(self.mixer) self.refresh_state() self.session.set_enabled(True) self.session.update() def update_display(self): ControlSurface.update_display(self) self._timer = (self._timer + 1) % 256 self.flash() def flash(self): if(USE_SESSION_VIEW == True): for index in range(N_TRACKS*N_SCENES): if(self.grid[index]._flash_state > 0): self.grid[index].flash(self._timer) if(USE_SESSION_NAV == True): if(self.navleft._flash_state>0): self.navleft.flash(self._timer) if(self.navright._flash_state>0): self.navright.flash(self._timer) if(self.navup._flash_state>0): self.navup.flash(self._timer) if(self.navdown._flash_state>0): self.navdown.flash(self._timer) if(USE_MIXER_CONTROLS == True): for index in range(N_TRACKS): if(USE_SOLO_BUTTONS == True): if(self.solobuttons[index]._flash_state > 0): self.solobuttons[index].flash(self._timer) if(USE_MUTE_BUTTONS == True): if(self.mutebuttons[index]._flash_state > 0): self.mutebuttons[index].flash(self._timer) def disconnect(self): self._hosts = [] self.log_message("--------------= CNTRLR log closed =--------------") ControlSurface.disconnect(self) return None
def _setup_session_control(self): is_momentary = True self._shift_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 87) right_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 67) left_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 66) up_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 71) down_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 68) right_button.name = 'Bank_Select_Right_Button' left_button.name = 'Bank_Select_Left_Button' up_button.name = 'Bank_Select_Up_Button' down_button.name = 'Bank_Select_Down_Button' global session session = SessionComponent(7, 8) session.name = 'Session_Control' session.set_track_bank_buttons(right_button, left_button) session.set_scene_bank_buttons(down_button, up_button) matrix = ButtonMatrixElement() matrix.name = 'Button_Matrix' scene_launch_notes = [56,57,58,59,60,61,62,63] scene_launch_buttons = [ ButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, scene_launch_notes[index]) for index in range(8) ] #track_stop_buttons = [ ButtonElement(is_momentary, MIDI_NOTE_TYPE, index, 52) for index in range(8) ] for index in range(len(scene_launch_buttons)): scene_launch_buttons[index].name = 'Scene_'+ str(index) + '_Launch_Button' #for index in range(len(track_stop_buttons)): # track_stop_buttons[index].name = 'Track_' + str(index) + '_Stop_Button' #stop_all_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 81) #stop_all_button.name = 'Stop_All_Clips_Button' #self._session.set_stop_all_clips_button(stop_all_button) #self._session.set_stop_track_clip_buttons(tuple(track_stop_buttons)) #self._session.set_stop_track_clip_value(2) #button_notes = [0,8,16,24,32,40,48,56,1,9,17,25,33,41,49,57,2,10,18,26,34,42,50,58,3,11,19,27,35,43,51,59,4,12,20,28,36,44,52,60,5,13,21,29,37,45,53,61,6,14,22,30,38,46,54,62] for scene_index in range(8): scene = session.scene(scene_index) scene.name = 'Scene_' + str(scene_index) button_row = [] scene.set_launch_button(scene_launch_buttons[scene_index]) #scene.set_triggered_value(2) for track_index in range(7): button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, (track_index * 8) + scene_index) button.name = str(track_index) + '_Clip_' + str(scene_index) + '_Button' 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_triggered_to_play_value(2) #clip_slot.set_triggered_to_record_value(4) clip_slot.set_stopped_value(0) clip_slot.set_started_value(64) #clip_slot.set_recording_value(3) clip_slot.set_launch_button(button) matrix.add_row(tuple(button_row)) #self._session.set_slot_launch_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 67)) session.selected_scene().name = 'Selected_Scene' #session.selected_scene().set_launch_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 64)) #session_zoom = SessionZoomingComponent(session) #session_zoom.name = 'Session_Overview' #session_zoom.set_button_matrix(matrix) #session_zoom.set_zoom_button(self._shift_button) #session_zoom.set_nav_buttons(up_button, down_button, left_button, right_button) #session_zoom.set_scene_bank_buttons(tuple(scene_launch_buttons)) #session_zoom.set_stopped_value(0) #session_zoom.set_selected_value(127) session.set_mixer(mixer) self.set_highlighting_session_component(session) return None #return session
class Tweaker(ControlSurface): __module__ = __name__ __doc__ = " Tweaker control surface script " def __init__(self, c_instance, *a, **k): super(Tweaker, self).__init__(c_instance, *a, **k) with self.component_guard(): self._update_linked_device_selection = None self._tweaker_version_check = '0.3' self.log_message("--------------= Tweaker Session " + str(self._tweaker_version_check) + " log opened =--------------") self._timer = 0 self.flash_status = 1 self._last_selected_strip_number = 0 self._device_selection_follows_track_selection = False #self._pad_translations = PAD_TRANSLATION self._linked_session = None self._mixer_offset = 0 self._nav_lock = True self._setup_controls() self._setup_transport_control() self._setup_device_control() self._setup_mixer_control() self._setup_session_control() self._setup_crossfader() self._setup_modes() self._setup_pads() self._setup_navigation_lock() self._setup_arrange_session_toggle() #self.assign_main_configuration() #self.request_rebuild_midi_map() #self._mixer._reassign_tracks() #this is to update rebuild the cf_assign closure, otherwise the colors aren't correct #self.schedule_message(30, self._detect_devices) self.show_message('Tweaker Control Surface Loaded') self.show_message('Tweaker Control Surface Loaded') #self._shift_value(0) #this updates the pads so that they transmit to Live on the assigned PAD_CHANNEL...also, lights shift button self.assign_main_configuration() #self.schedule_message(2, self._shift_value, 0) self.schedule_message(3, self._mixer._reassign_tracks) """script initialization methods""" def _setup_controls(self): is_momentary = True self._grid = [None for index in range(8)] for column in range(8): self._grid[column] = [TweakerMonoButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, column + (row * 8) + 1, 'Grid_' + str(column) + '_' + str(row), self) for row in range(4)] self._button = [TweakerMonoButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, TWEAKER_BUTTONS[index], 'Button_' + str(index), self) for index in range(len(TWEAKER_BUTTONS))] self._nav = [TweakerMonoButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, TWEAKER_NAVS[index], 'Nav_' + str(index), self) for index in range(len(TWEAKER_NAVS))] self._encoder_button = [TweakerMonoButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, TWEAKER_ENCODER_BUTTONS[index], 'Encoder_Button_' + str(index), self) for index in range(len(TWEAKER_ENCODER_BUTTONS))] self._dial = [EncoderElement(MIDI_CC_TYPE, CHANNEL, TWEAKER_DIALS[index], Live.MidiMap.MapMode.absolute) for index in range(len(TWEAKER_DIALS))] self._fader = [EncoderElement(MIDI_CC_TYPE, CHANNEL, TWEAKER_FADERS[index], Live.MidiMap.MapMode.absolute) for index in range(len(TWEAKER_FADERS))] self._crossfader = EncoderElement(MIDI_CC_TYPE, CHANNEL, CROSSFADER, Live.MidiMap.MapMode.absolute) self._encoder = [EncoderElement(MIDI_CC_TYPE, CHANNEL, TWEAKER_ENCODERS[index], Live.MidiMap.MapMode.absolute) for index in range(len(TWEAKER_ENCODERS))] self._pad = [TweakerMonoButtonElement(False, MIDI_NOTE_TYPE, CHANNEL, TWEAKER_PADS[index], 'Pad_' + str(index), self) for index in range(len(TWEAKER_PADS))] for index in range(4): self._pad[index].set_enabled(False) self._pad[index].set_channel(PAD_CHANNEL) self._pad[index].set_identifier(index + 4) self._pad[index+4].set_enabled(False) self._pad[index+4].set_channel(PAD_CHANNEL) self._pad[index+4].set_identifier(index) self._pad_pressure = [EncoderElement(MIDI_CC_TYPE, CHANNEL, TWEAKER_PAD_PRESSURES[index], Live.MidiMap.MapMode.absolute) for index in range(len(TWEAKER_PADS))] for index in range(8): self._pad_pressure[index]._last_sent = 0 self._matrix = ButtonMatrixElement() self._matrix.name = 'Matrix' for row in range(4): button_row = [] for column in range(7): button_row.append(self._grid[column][row]) self._matrix.add_row(tuple(button_row)) self._send_midi(tuple([240,0,1,106,01,07,21,21,247])) #set all pots to walk mode self._send_midi(tuple([240, 0, 1, 106, 1, 6, 127 , 127, 25, 0, 15, 0, 9, PAD_SENSITIVITY, 247])) #set pads to sensitivity set in Map file def _setup_transport_control(self): self._transport = TransportComponent() self._transport.name = 'Transport' def _setup_mixer_control(self): is_momentary = True self._num_tracks = (2) #A mixer is one-dimensional; self._mixer = MixerComponent(2, 0, False, False) self._mixer.name = 'Mixer' self._mixer.tracks_to_use = self._mixer_tracks_to_use(self._mixer) self._device_navigator = [None for index in range(2)] self._mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left) for index in range(2): self._mixer.channel_strip(index).set_volume_control(self._fader[index]) self._mixer.channel_strip(index)._on_cf_assign_changed = self._channelstrip_on_cf_assign_changed(self._mixer.channel_strip(index)) self._mixer.channel_strip(index).name = 'Mixer_ChannelStrip_' + str(index) #mixer.track_filter(index).name = 'Mixer_TrackFilter_' + str(index) self._mixer.channel_strip(index)._invert_mute_feedback = True self._mixer.channel_strip(index)._device_component = self._device[index] self._mixer.channel_strip(index).update = self._channelstrip_update(self._mixer.channel_strip(index)) self._mixer.channel_strip(index)._select_value = self._channelstrip_select_value(self._mixer.channel_strip(index), index) self._device_navigator[index] = DetailViewControllerComponent(self, self._mixer.channel_strip(index)) self._device_navigator[index].name = 'Device_Navigator_'+str(index) self._mixer.channel_strip(0).set_track = self._channelstrip_set_track(self._mixer.channel_strip(0), self._channelstrip1_cb) self._mixer.channel_strip(1).set_track = self._channelstrip_set_track(self._mixer.channel_strip(1), self._channelstrip2_cb) self.song().view.selected_track = self._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 #self._mixer._reassign_tracks() def _setup_session_control(self): is_momentary = True num_tracks = NUM_TRACKS num_scenes = NUM_SCENES self._session = SessionComponent(num_tracks, num_scenes) self._session.name = "Session" self._session.set_offsets(0, 0) self._session.set_stop_track_clip_value(STOP_CLIP) self._scene = [None for index in range(3)] for row in range(num_scenes): self._scene[row] = self._session.scene(row) self._scene[row].name = 'Scene_' + str(row) for column in range(num_tracks): clip_slot = self._scene[row].clip_slot(column) clip_slot.name = str(column) + '_Clip_Slot_' + str(row) clip_slot.set_triggered_to_play_value(CLIP_TRG_PLAY) clip_slot.set_triggered_to_record_value(CLIP_TRG_REC) clip_slot.set_stopped_value(CLIP_STOP) clip_slot.set_started_value(CLIP_STARTED) clip_slot.set_recording_value(CLIP_RECORDING) self._session._stop_track_value = self._session_stop_track_value(self._session) self._session._on_fired_slot_index_changed = self._session_on_fired_slot_index_changed(self._session) self._session._change_offsets = self._session_change_offsets(self._session) self._session.update = self._session_update(self._session) #self._session.add_offset_listener(self._update_navigation_view) self._session.set_mixer(self._mixer) self.set_highlighting_session_component(self._session) self._session_zoom = SessionZoomingComponent(self._session) self._session_zoom.name = 'Session_Overview' self._session_zoom.set_stopped_value(ZOOM_STOPPED) self._session_zoom.set_playing_value(ZOOM_PLAYING) self._session_zoom.set_selected_value(ZOOM_SELECTED) #self._session_zoom.set_enabled(True) def _setup_device_control(self): self._device = [None for index in range(2)] for index in range(2): self._device[index] = DeviceComponent() self._device[index].name = 'Device_Component_'+str(index) self._device[index].set_enabled(True) self._device[index]._number_of_parameter_banks = self._device_number_of_parameter_banks(self._device[index]) self._device[index]._assign_parameters = self._device_assign_parameters(self._device[index]) self._device[index]._device_banks = DEVICE_DICT self._device[index]._device_best_banks = DEVICE_BOB_DICT self._device[index]._device_bank_names = BANK_NAME_DICT def _setup_crossfader(self): self._mixer.set_crossfader_control(self._crossfader) def _setup_modes(self): self._pad_offset = PadOffsetComponent(self) self._pad_offset._set_protected_mode_index(0) self._pad_offset.set_enabled(False) def _setup_pads(self): for pad in self._pad_pressure: pad.add_value_listener(self._light_pad, True) def _setup_navigation_lock(self): if(self._encoder_button[0].value_has_listener(self._nav_lock_value)): self._encoder_button[0].remove_value_listener(self._nav_lock_value) self._encoder_button[0].add_value_listener(self._nav_lock_value) def _setup_arrange_session_toggle(self): if(self._nav[1].value_has_listener(self._arrange_session_value)): self._nav[1].remove_value_listener(self._arrange_session_value) self._nav[1].add_value_listener(self._arrange_session_value) """configuration methods""" def assign_main_configuration(self): for column in range(7): for row in range(3): self._scene[row].clip_slot(column).set_launch_button(self._grid[column][row]) self._session.set_stop_track_clip_buttons(tuple([self._grid[index][3] for index in range(7)])) for row in range(3): self._scene[row].set_launch_button(self._grid[7][row]) self._device[0].set_parameter_controls(tuple([self._encoder[index+1] for index in range(3)])) self._device[0].set_enabled(True) self._device[1].set_parameter_controls(tuple([self._encoder[index+4] for index in range(3)])) self._device[1].set_enabled(True) for track in range(2): self._mixer.channel_strip(track).set_volume_control(self._fader[track]) self._mixer.channel_strip(track).set_solo_button(self._button[track*3]) self._button[track*3].set_on_off_values(SOLO, 0) self._mixer.channel_strip(track).set_arm_button(self._button[1 + (track*3)]) self._button[1 + (track*3)].set_on_off_values(ARM, 0) self._mixer.channel_strip(track).set_crossfade_toggle(self._button[2 + (track*3)]) self._mixer.master_strip().set_volume_control(self._dial[1]) self._mixer.set_prehear_volume_control(self._dial[0]) self._session.set_track_bank_buttons(self._nav[4], self._nav[3]) self._session.set_scene_bank_buttons(self._nav[2], self._nav[0]) self._session_zoom.set_zoom_button(self._grid[7][3]) self._session_zoom.set_nav_buttons(self._nav[0], self._nav[2], self._nav[3], self._nav[4]) self._session_zoom.set_button_matrix(self._matrix) self._device[0].set_on_off_button(self._encoder_button[1]) self._device_navigator[0].set_device_nav_buttons(self._encoder_button[2], self._encoder_button[3]) self._device[1].set_on_off_button(self._encoder_button[4]) self._device_navigator[1].set_device_nav_buttons(self._encoder_button[5], self._encoder_button[6]) for track in range(2): self._update_device(self._mixer.channel_strip(track)) #self._device.set_bank_nav_buttons(self._menu[0], self._menu[3]) self.assign_track_selector(self._encoder[0]) #for index in range(8): # self._pad[index].send_value(1, True) # self._pad[index].set_channel(1) # self._pad[index].set_identifier(index) # self._pad[index].set_enabled(False) #this has to happen for translate to work if not self._grid[7][3].value_has_listener(self._shift_value): self._grid[7][3].add_value_listener(self._shift_value) self._grid[7][3].send_value(127, True) self.request_rebuild_midi_map() """Tweaker custom methods""" def _shift_value(self, value): self._pad_offset.set_enabled(value>0) if value > 0: self._update_navigation_view() for pad in self._pad: pad.use_default_message() pad.set_enabled(True) self._pad_offset.set_mode_buttons(tuple(self._pad)) self.schedule_message(1, self._pad_offset.update) if self._session.is_enabled(): #self._update_navigation_view() #self.schedule_message(1, self._update_navigation_veiw) self._update_navigation_view() self._grid[7][3].send_value(SHIFT_ON) for track in range(2): self._mixer.channel_strip(track).set_crossfade_toggle(None) self._mixer.channel_strip(track).set_select_button(self._button[2 + (track*3)]) else: self._pad_offset.set_mode_buttons(None) for index in range(4): self._pad[index].set_enabled(False) self._pad[index].set_channel(PAD_CHANNEL) self._pad[index].set_identifier(index + 4 + (self._pad_offset._mode_index * 8)) self._pad[index+4].set_enabled(False) self._pad[index+4].set_channel(PAD_CHANNEL) self._pad[index+4].set_identifier(index + (self._pad_offset._mode_index * 8)) self._grid[7][3].send_value(SHIFT_OFF) for track in range(2): self._mixer.channel_strip(track).set_select_button(None) self._mixer.channel_strip(track).set_crossfade_toggle(self._button[2 + (track*3)]) def assign_track_selector(self, encoder): assert isinstance(encoder, EncoderElement) if not encoder.value_has_listener(self._track_selector_value): encoder.add_value_listener(self._track_selector_value) def deassign_track_selector(self, encoder): if encoder.value_has_listener(self._track_selector_value): encoder.remove_value_listener(self._track_selector_value) def _nav_lock_value(self, value): if value > 0: if self._nav_lock: self._mixer_offset = self._mixer_offset + self._session._track_offset self._mixer.set_track_offset(self._mixer_offset) else: if self._mixer_offset in range(self._session._track_offset, self._session._track_offset + 5): self._mixer_offset = self._mixer_offset - self._session._track_offset elif self._mixer_offset < self._session._track_offset: self._mixer_offset = 0 else: self._mixer_offset = min(self._session._track_offset+5, len(self._session.tracks_to_use())-2) self._mixer.set_track_offset(self._session._track_offset + self._mixer_offset) self._nav_lock = not self._nav_lock self._session.update() def _arrange_session_value(self, value): if value > 0: if (self.application().view.is_view_visible('Arranger')): self.application().view.show_view('Session') else: self.application().view.show_view('Arranger') def _track_selector_value(self, value): if(value is 1): if self._nav_lock: self._mixer_offset = min(self._mixer_offset + 1, min(NUM_TRACKS - 2, len(self._session.tracks_to_use())-self._session._track_offset-2)) else: self._mixer_offset = min(self._mixer_offset + 1, len(self._session.tracks_to_use())-2) elif(value is 127): self._mixer_offset = max(self._mixer_offset - 1, 0) if self._nav_lock: self._mixer.set_track_offset(self._session._track_offset + self._mixer_offset) #self._session.set_offsets(self._session._track_offset) ?? else: self._mixer.set_track_offset(self._mixer_offset) self._session.update() if self._mixer.channel_strip(self._last_selected_strip_number)._track != None: self.song().view.selected_track = self._mixer.channel_strip(self._last_selected_strip_number)._track if self._linked_session != None: if self._linked_session._is_linked(): self._linked_session._unlink() self._linked_session.set_offsets(self._mixer._track_offset, self._linked_session._scene_offset) self._linked_session._link() def _update_navigation_view(self): dif = self._mixer._track_offset - self._session._track_offset for index in range(7): #if (index + self._session._track_offset) in range(len(self._session.tracks_to_use())): if (index + self._session._track_offset) in range(0, len(self.song().visible_tracks)): self._grid[index][3].send_value(NAV_COLORS[int(index in range(dif, dif + 2))], True) elif (index + self._session._track_offset) in range(len(self.song().visible_tracks), len(self._session.tracks_to_use())): self._grid[index][3].send_value(RETURN_NAV_COLORS[int(index in range(dif, dif + 2))], True) else: self._grid[index][3].send_value(0, True) self._send_midi(tuple([240,0,1,106,01,07,21,21,247])) #set all pots to walk mode def _update_device(self, channelstrip): for control in channelstrip._device_component._parameter_controls: control.send_value(0, True) if channelstrip._device_component._on_off_button != None: channelstrip._device_component._on_off_button.turn_off() if not channelstrip._track is None: if not channelstrip._device_component._device in channelstrip._track.devices: track = channelstrip._track device_to_select = track.view.selected_device if (device_to_select == None) and (len(track.devices) > 0): device_to_select = track.devices[0] elif channelstrip._device_component and not type(channelstrip._device_component) is type(None): channelstrip._device_component.set_device(device_to_select) else: channelstrip._device_component.set_device(None) else: pass else: channelstrip._device_component.set_device(None) channelstrip._device_component._on_on_off_changed() def _light_pad(self, value, sender): if not self._pad_offset.is_enabled(): if value > sender._last_sent: if self._pad[self._pad_pressure.index(sender)]._last_sent_value < 1: self._pad[self._pad_pressure.index(sender)].send_value(127, True) else: self._pad[self._pad_pressure.index(sender)].send_value(0, True) sender._last_sent = value """called on timer""" def update_display(self): super(Tweaker, self).update_display() self._timer = (self._timer + 1) % 256 self.flash() def flash(self): if(self.flash_status > 0): for control in self.controls: if isinstance(control, TweakerMonoButtonElement): control.flash(self._timer) """m4l bridge""" def generate_strip_string(self, display_string): NUM_CHARS_PER_DISPLAY_STRIP = 12 if (not display_string): return (' ' * NUM_CHARS_PER_DISPLAY_STRIP) if ((len(display_string.strip()) > (NUM_CHARS_PER_DISPLAY_STRIP - 1)) and (display_string.endswith('dB') and (display_string.find('.') != -1))): display_string = display_string[:-2] if (len(display_string) > (NUM_CHARS_PER_DISPLAY_STRIP - 1)): for um in [' ', 'i', 'o', 'u', 'e', 'a']: while ((len(display_string) > (NUM_CHARS_PER_DISPLAY_STRIP - 1)) and (display_string.rfind(um, 1) != -1)): um_pos = display_string.rfind(um, 1) display_string = (display_string[:um_pos] + display_string[(um_pos + 1):]) else: display_string = display_string.center((NUM_CHARS_PER_DISPLAY_STRIP - 1)) ret = u'' for i in range((NUM_CHARS_PER_DISPLAY_STRIP - 1)): if ((ord(display_string[i]) > 127) or (ord(display_string[i]) < 0)): ret += ' ' else: ret += display_string[i] ret += ' ' return ret def notification_to_bridge(self, name, value, sender): if(isinstance(sender, MonoEncoderElement2)): self._monobridge._send(sender.name, 'lcd_name', str(self.generate_strip_string(name))) self._monobridge._send(sender.name, 'lcd_value', str(self.generate_strip_string(value))) def touched(self): if(self._shift_mode._mode_index < 2): if self._touched is 0: self._monobridge._send('touch', 'on') self.schedule_message(2, self.check_touch) self._touched +=1 def check_touch(self): if(self._shift_mode._mode_index < 2): if self._touched > 5: self._touched = 5 elif self._touched > 0: self._touched -= 1 if self._touched is 0: self._monobridge._send('touch', 'off') else: self.schedule_message(2, self.check_touch) def handle_sysex(self, midi_bytes): pass """general functionality""" def disconnect(self): """clean things up on disconnect""" #self._update_linked_device_selection = None if self._session.offset_has_listener(self._update_navigation_view): self._session.remove_offset_listener(self._update_navigation_view) if(self._nav[1].value_has_listener(self._arrange_session_value)): self._nav[1].remove_value_listener(self._arrange_session_value) if(self._encoder_button[0].value_has_listener(self._nav_lock_value)): self._encoder_button[0].remove_value_listener(self._nav_lock_value) for pad in self._pad_pressure: if pad.value_has_listener(self._light_pad): pad.remove_value_listener(self._light_pad) if self._grid[7][3].value_has_listener(self._shift_value): self._grid[7][3].remove_value_listener(self._shift_value) if self._session._is_linked(): self._session._unlink() self.deassign_track_selector(self._encoder[0]) self.log_message("--------------= Tweaker Session " + str(self._tweaker_version_check) + " log closed =--------------") #Create entry in log file super(Tweaker, self).disconnect() return None def _get_num_tracks(self): return self.num_tracks def _on_selected_track_changed(self): super(Tweaker, self)._on_selected_track_changed() if self._session.is_enabled(): self._session.update() for index in range(2): self._update_device(self._mixer.channel_strip(index)) self._mixer.on_selected_track_changed() def connect_script_instances(self, instanciated_scripts): link = False for s in instanciated_scripts: if '_tweaker_version' in dir(s): if s._tweaker_version == self._tweaker_version_check: link = True break if link == True: if not self._session._is_linked(): self._session._link() """SessionComponent overrides""" def _session_update(self, session): def _update(): SessionComponent.update(session) if session.is_enabled(): self._update_navigation_view() return _update def _session_change_offsets(self, session): def _change_offsets(track_increment, scene_increment): offsets_changed = (track_increment != 0) or (scene_increment != 0) if offsets_changed: session._track_offset += track_increment session._scene_offset += scene_increment assert (session._track_offset >= 0) assert (session._scene_offset >= 0) if (session._mixer != None): if(self._nav_lock): if (session.track_offset() + self._mixer_offset) > (len(session.tracks_to_use())-2): self._mixer_offset = max(len(session.tracks_to_use()) - session._track_offset - 2, 0) session._mixer.set_track_offset(max(0, session.track_offset() + self._mixer_offset)) session._reassign_tracks() if offsets_changed: session._reassign_scenes() # this is replaced by notify_offset() in Live9 #for callback in session._offset_callbacks: # this is replaced by notify_offset() in Live9 # callback() session.notify_offset() self._update_navigation_view() if self._mixer.channel_strip(self._last_selected_strip_number)._track != None: self.song().view.selected_track = self._mixer.channel_strip(self._last_selected_strip_number)._track if ((session.width() > 0) and (session.height() > 0)): session._do_show_highlight() return _change_offsets def _session_on_fired_slot_index_changed(self, session): def _on_fired_slot_index_changed(index): tracks_to_use = tuple(self.song().visible_tracks) + tuple(self.song().return_tracks) track_index = index + session.track_offset() if session.is_enabled() and session._stop_track_clip_buttons != None: if index < len(session._stop_track_clip_buttons): button = session._stop_track_clip_buttons[index] if button != None: if(track_index < len(tracks_to_use)) and (tracks_to_use[track_index].clip_slots) and (tracks_to_use[track_index].fired_slot_index == -2): button.send_value(session._stop_track_clip_value) #elif index in range(len(session.tracks_to_use())): # dif = self._mixer._track_offset - self._session._track_offset # button.send_value(NAV_COLORS[int(index in range(dif, dif + 2))], True) #else: # button.turn_off() else: self._update_navigation_view() return _on_fired_slot_index_changed def _session_stop_track_value(self, session): def _stop_track_value(value, sender): assert (session._stop_track_clip_buttons != None) assert (list(session._stop_track_clip_buttons).count(sender) == 1) assert (value in range(128)) if session.is_enabled(): if ((value is not 0) or (not sender.is_momentary())): tracks = session.tracks_to_use() track_index = (list(session._stop_track_clip_buttons).index(sender) + session.track_offset()) if (track_index in range(len(tracks))) and (tracks[track_index] in session.song().tracks): tracks[track_index].stop_all_clips() sender.send_value(3, True) self.schedule_message(10, self._update_navigation_view) return _stop_track_value """ChannelStripComponent overrides""" def _channelstrip_update(self, channelstrip): def _update(): ChannelStripComponent.update(channelstrip) self._update_device(channelstrip) return _update def _channelstrip_set_track(self, channelstrip, cb): def _set_track(track): assert ((track == None) or isinstance(track, Live.Track.Track)) if channelstrip._track != None and isinstance(channelstrip._track, Live.Track.Track): if channelstrip._track.devices_has_listener(cb): channelstrip._track.remove_devices_listener(cb) if (track != None): track.add_devices_listener(cb) ChannelStripComponent.set_track(channelstrip, track) return _set_track def _channelstrip_select_value(self, channelstrip, index): def _select_value(value): ChannelStripComponent._select_value(channelstrip, value) self._last_selected_strip_number = index return _select_value def _channelstrip_on_cf_assign_changed(self, channel_strip): def _on_cf_assign_changed(): if (channel_strip.is_enabled() and (channel_strip._crossfade_toggle != None)): if (channel_strip._track != None) and (channel_strip._track in chain(self.song().tracks, self.song().return_tracks)): if channel_strip._track.mixer_device.crossfade_assign == 1: #modified channel_strip._crossfade_toggle.turn_off() elif channel_strip._track.mixer_device.crossfade_assign == 0: channel_strip._crossfade_toggle.send_value(CROSSFADE_A) else: channel_strip._crossfade_toggle.send_value(CROSSFADE_B) return _on_cf_assign_changed def _channelstrip1_cb(self): self._on_selected_track_changed() def _channelstrip2_cb(self): self._on_selected_track_changed() """MixerComponent overrides""" def _mixer_tracks_to_use(self, mixer): def tracks_to_use(): return tuple(self.song().visible_tracks) + tuple(self.song().return_tracks) return tracks_to_use """SessionComponent overrides""" def _device_number_of_parameter_banks(self, device): def _number_of_parameter_banks(): return number_of_parameter_banks(device._device) #added return _number_of_parameter_banks def _device_assign_parameters(self, device): def _assign_parameters(): assert device.is_enabled() assert (device._device != None) assert (device._parameter_controls != None) device._bank_name = ('Bank ' + str(device._bank_index + 1)) #added if (device._device.class_name in device._device_banks.keys()): #modified assert (device._device.class_name in device._device_best_banks.keys()) banks = device._device_banks[device._device.class_name] bank = None if (not device._is_banking_enabled()): banks = device._device_best_banks[device._device.class_name] device._bank_name = 'Best of Parameters' #added if (len(banks) > device._bank_index): bank = banks[device._bank_index] if device._is_banking_enabled(): #added if device._device.class_name in device._device_bank_names.keys(): #added device._bank_name[device._bank_index] = device._device_bank_names[device._device.class_name] #added *recheck assert ((bank == None) or (len(bank) >= len(device._parameter_controls))) for index in range(len(device._parameter_controls)): parameter = None if (bank != None): parameter = get_parameter_by_name(device._device, bank[index]) if (parameter != None): device._parameter_controls[index].connect_to(parameter) else: device._parameter_controls[index].release_parameter() else: parameters = device._device_parameters_to_map() num_controls = len(device._parameter_controls) index = (device._bank_index * num_controls) for control in device._parameter_controls: if (index < len(parameters)): control.connect_to(parameters[index]) else: control.release_parameter() index += 1 return _assign_parameters
class MidiFighterTwister(ControlSurface): __module__ = __name__ __doc__ = "MidiFighterTwister class" def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self.__c_instance = c_instance self.show_message('Script initiated') self.init() def init(self): # initialize listeners, caches and colors self.flush_all() self.mf_disable_bank_buttons() self.mf_init_page_config() self.mf_init_light_pages() # Start listeners to call dispatcher self.song().view.add_detail_clip_listener( self.dispatch_detail_clip_listener) self.song().add_current_song_time_listener( self.dispatch_current_song_time_listener) self.song().view.add_selected_track_listener( self.dispatch_selected_track_listener) self.device_listener_wrapper() # Initialize the sequencer buttons self.sequencer_init_buttons() self.sequencer_init_rotaries() self.init_clip_page() self.init_pad_page() self.init_device_params() def flush_all(self): for poti in range(64): for channel in range(4): self._send_midi((175 + channel, poti, 0)) def mf_init_page_config(self): # Initialize configuration parameters # Sequencer configuration self.sequencer_page_default_color = 1 self.sequencer_current_page_color_index = self.sequencer_page_default_color self.sequencer_base_default_note = 36 self.sequencer_current_selected_note = self.sequencer_base_default_note self.sequencer_clip_position_16th = None # Midi Channels self.rotary_midi_channel = 175 + 1 self.ring_midi_channel = 175 + 1 self.switch_midi_channel = 175 + 2 self.light_midi_channel = 175 + 2 # Pages cc map self.clip_page_cc = range(0, 16) self.sequencer_page_cc = range(16, 32) self.note_page_cc = range(32, 48) self.control_page_cc = range(48, 64) # Pages init color self.clip_page_colors = [1] * 16 self.sequencer_page_colors = [self.sequencer_page_default_color] * 16 self.note_page_colors = range(1, 127, 16) * 2 #self.note_page_colors = [0] * 16 self.control_page_colors = [1] * 16 # Status cache for sequencer self.switch_encoder_status_cache = [False] * 64 # List to store ButtonElements in self.switch_encoder_buttons = [False] * 64 # Status cache for rotaries self.rotary_encoder_potis = [False] * 64 def mf_init_light_pages(self): sequencer_page_map = zip(self.sequencer_page_cc, self.sequencer_page_colors) for light_encoder_cc, light_color_cc in sequencer_page_map: self._mf_set_light(light_encoder_cc, light_color_cc, False) note_page_map = zip(self.note_page_cc, self.note_page_colors) for light_encoder_cc, light_color_cc in note_page_map: self._mf_set_light(light_encoder_cc, light_color_cc, False) def _mf_set_light(self, light_encoder_cc, light_color_cc, status): # Sets color on midi channel 2 (177) end updates status cache # for sequencer to remember statuses self._send_midi((self.light_midi_channel, light_encoder_cc, light_color_cc)) self.switch_encoder_status_cache[light_encoder_cc] = status def mf_disable_bank_buttons(self): # Workaround for not sending values to track when pressing bank buttons self.padm0 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 4, 0) self.padm1 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 4, 1) self.padm2 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 4, 2) self.padm3 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 4, 3) self.padm0.add_value_listener(self.bank_buttons_dummy, identify_sender=True) self.padm1.add_value_listener(self.bank_buttons_dummy, identify_sender=True) self.padm2.add_value_listener(self.bank_buttons_dummy, identify_sender=True) self.padm3.add_value_listener(self.bank_buttons_dummy, identify_sender=True) def bank_buttons_dummy(self): pass def dispatch_detail_clip_listener(self): self.current_clip = self.song().view.highlighted_clip_slot.clip self.init_sequencer() try: if self.current_clip.is_midi_clip and not self.current_clip.notes_has_listener: # Update leds when notes are added or removed self.current_clip.add_notes_listener( self._sequencer_update_notes_to_light) self.init_sequencer() else: self.sequencer_reset_colors() except AttributeError: pass def dispatch_current_song_time_listener(self): self.sequencer_light_follows_beat() def dispatch_selected_track_listener(self): self.device_auto_select() self.device_listener_wrapper() def device_listener_wrapper(self): selected_track = self.song().view.selected_track if not selected_track.devices_has_listener(self.device_auto_select): self.song().view.selected_track.add_devices_listener( self.device_auto_select) # Sequencer def init_sequencer(self): self.sequencer_current_selected_note = self.sequencer_base_default_note self.sequencer_current_page_color_index = self.sequencer_page_default_color self._sequencer_update_notes_to_light() def sequencer_init_buttons(self): for switch_encoder_cc in self.sequencer_page_cc: self.switch_encoder_buttons[switch_encoder_cc] = ButtonElement( IS_MOMENTARY, MIDI_CC_TYPE, 1, switch_encoder_cc) self.switch_encoder_buttons[switch_encoder_cc].add_value_listener( self.sequencer_button_press, identify_sender=True) self.padl14 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 14) self.padr17 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 17) self.padl16 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 16) self.padr19 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 19) self.padl14.add_value_listener(self.sequencer_side_button_press, identify_sender=True) self.padr17.add_value_listener(self.sequencer_side_button_press, identify_sender=True) self.padl16.add_value_listener(self.sequencer_side_button_press, identify_sender=True) self.padr19.add_value_listener(self.sequencer_side_button_press, identify_sender=True) def sequencer_init_rotaries(self): for rotary_encoder_cc in self.sequencer_page_cc: self.rotary_encoder_potis[rotary_encoder_cc] = EncoderElement( MIDI_CC_TYPE, 0, rotary_encoder_cc, Live.MidiMap.MapMode.absolute) self.rotary_encoder_potis[rotary_encoder_cc].add_value_listener(self.sequencer_rotary_change, identify_sender=True) def sequencer_rotary_change(self, value, sender): try: self.current_clip except AttributeError: return False if self.current_clip.is_midi_clip: cc_value = sender._msg_identifier if value > 0: if not self.switch_encoder_status_cache[cc_value]: self._send_midi((self.light_midi_channel, cc_value, self.sequencer_current_light_on_color)) self._send_midi(( self.ring_midi_channel, cc_value, 100)) self.switch_encoder_status_cache[cc_value] = True self.current_clip.set_notes(((self.sequencer_current_selected_note, cc_value % 16 * 0.25, 0.25, value, False),)) elif value == 0: self._send_midi((self.light_midi_channel, cc_value, self.sequencer_current_page_color)) self.current_clip.remove_notes( cc_value % 16 * 0.25, self.sequencer_current_selected_note, 0.25, 1) self.switch_encoder_status_cache[cc_value] = False def sequencer_button_press(self, value, sender): try: self.current_clip except AttributeError: return False if self.current_clip.is_midi_clip: cc_value = sender._msg_identifier if value > 0: if not self.switch_encoder_status_cache[cc_value]: self._send_midi((self.light_midi_channel, cc_value, self.sequencer_current_light_on_color)) self.current_clip.set_notes((( self.sequencer_current_selected_note, cc_value % 16 * 0.25, 0.25, 100, False),)) self.switch_encoder_status_cache[cc_value] = True self._send_midi((self.ring_midi_channel, cc_value, 100)) else: self._send_midi((self.light_midi_channel, cc_value, self.sequencer_current_page_color)) self._send_midi((self.ring_midi_channel, cc_value, 0)) self.current_clip.remove_notes( cc_value % 16 * 0.25, self.sequencer_current_selected_note, 0.25, 1) self.switch_encoder_status_cache[cc_value] = False def sequencer_side_button_press(self, value, sender): try: cc_value = sender._msg_identifier if value > 0: # Note/clolor up/down if cc_value == 14 and self.sequencer_current_selected_note > 0: self.sequencer_current_selected_note = self.sequencer_current_selected_note - 1 self.sequencer_current_page_color_index = self.sequencer_current_page_color_index - 16 self._sequencer_update_notes_to_light() self.sequencer_clip_position_16th = None self.show_message("Selected Midi Note: "+str(self.sequencer_current_selected_note)) if cc_value == 17 and self.sequencer_current_selected_note < 127: self.sequencer_current_selected_note = self.sequencer_current_selected_note + 1 self.sequencer_current_page_color_index = self.sequencer_current_page_color_index + 16 self._sequencer_update_notes_to_light() self.sequencer_clip_position_16th = None self.show_message("Selected Midi Note: "+str(self.sequencer_current_selected_note)) # New/duplicate clip if cc_value == 16 and self.sequencer_current_selected_note > 0: self.duplicate_clip() if cc_value == 19 and self.sequencer_current_selected_note > 0: self.session_record() except AttributeError: pass def sequencer_light_follows_beat(self): try: if self.current_clip.is_midi_clip: if self.sequencer_clip_position_16th == None: self.sequencer_clip_position_16th = int(self.current_clip.playing_position / 0.25) if self.switch_encoder_status_cache[self.sequencer_page_cc[self.sequencer_clip_position_16th]]: self._send_midi((177, self.sequencer_page_cc[self.sequencer_clip_position_16th], self.sequencer_current_light_on_color)) else: self._send_midi((177, self.sequencer_page_cc[self.sequencer_clip_position_16th], self.sequencer_current_page_color)) elif self.sequencer_clip_position_16th != int(self.current_clip.playing_position/0.25): if self.switch_encoder_status_cache[self.sequencer_page_cc[self.sequencer_clip_position_16th]]: self._send_midi((177, self.sequencer_page_cc[self.sequencer_clip_position_16th], self.sequencer_current_light_on_color)) else: self._send_midi((177, self.sequencer_page_cc[self.sequencer_clip_position_16th], self.sequencer_current_page_color)) self.sequencer_clip_position_16th = int(self.current_clip.playing_position/0.25) self._send_midi((177, self.sequencer_page_cc[self.sequencer_clip_position_16th], self.sequencer_current_light_beat_color)) except IndexError: pass @property def sequencer_current_light_on_color(self): # light on color to be relative to page color return self.sequencer_current_page_color + 32 % 128 @property def sequencer_current_light_beat_color(self): # light on color to be relative to page color return self.sequencer_current_page_color + 64 % 128 @property def sequencer_current_page_color(self): return self.sequencer_current_page_color_index % 128 def _sequencer_get_midi_notes(self, note): # self.current_clip.get_notes(start, self.sequencer_current_selected_note, # selection_length, hight) try: return self.current_clip.get_notes(0, note, 4, 1) except AttributeError: return [] def _sequencer_update_notes_to_light(self): self.sequencer_reset_colors() notes_for_current_selected_note = self._sequencer_get_midi_notes( self.sequencer_current_selected_note) for note in notes_for_current_selected_note: light_encoder_cc = int(note[1]*4+self.sequencer_page_cc[0]) self._send_midi((self.ring_midi_channel, light_encoder_cc, note[3])) self._mf_set_light(light_encoder_cc, self.sequencer_current_light_on_color, True) def sequencer_reset_colors(self): for light_encoder_cc in self.sequencer_page_cc: self._mf_set_light(light_encoder_cc, self.sequencer_current_page_color, False) self._send_midi((self.ring_midi_channel, light_encoder_cc, 0)) def duplicate_clip(self): self.log_message("duplicate clip") #if self._clip_slot and self._clip_slot.has_clip: # slot_name = self._clip_slot.clip.name # track = self._clip_slot.canonical_parent current_track = self.song().view.selected_track current_clip_slot = self.song().view.highlighted_clip_slot self.song().duplicate_scene(list(current_track.clip_slots).index(current_clip_slot)) #new_clip = current_track.duplicate_clip_slot( # list(current_track.clip_slots).index(current_clip_slot)+1) #self.log_message(new_clip) #selected_track = self.song().view.selected_track #selected_track.duplicate_clip_slot(selected_track) def session_record(self): self.log_message("session record") #self.song().trigger_session_record() # Clip page setion def init_clip_page(self): num_tracks = 4 num_scenes = 3 self.flash_status = 1 self.Mixer = MixerComponent(4, 3) # Volencoder self.volencoders = [None for index in range(num_tracks)] for index in range(num_tracks): self.volencoders[index] = EncoderElement( MIDI_CC_TYPE, 0, index, Live.MidiMap.MapMode.absolute) self.Mixer.channel_strip(index).set_volume_control( self.volencoders[index]) # Sendencoder for index in range(num_tracks): encoder_cc_send_1 = index + num_tracks encoder_cc_send_2 = index + num_tracks * 2 send1 = EncoderElement(MIDI_CC_TYPE, 0, encoder_cc_send_1, Live.MidiMap.MapMode.absolute) send2 = EncoderElement(MIDI_CC_TYPE, 0, encoder_cc_send_2, Live.MidiMap.MapMode.absolute) self.Mixer.channel_strip(index).set_send_controls((send1, send2)) # Panencoder for index in range(num_tracks): encoder_cc_pan = index + num_tracks * 3 pan = EncoderElement(MIDI_CC_TYPE, 0, encoder_cc_pan, Live.MidiMap.MapMode.absolute) self.Mixer.channel_strip(index).set_pan_control(pan) # Arm-/selectbuttons for index in range(num_tracks): armbutton = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 1, index + 12) self.Mixer.channel_strip(index).set_arm_button(armbutton) self.Mixer.channel_strip(index).set_select_button(armbutton) # Navigation buttons self.padl11 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 11) self.padr8 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 8) self.padl10 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 10) self.padr13 = ButtonElement(IS_MOMENTARY, MIDI_CC_TYPE, 3, 13) self.grid = [None for index in range(num_tracks * 3)] for index in range(num_tracks * 3): self.grid[index] = ButtonElement( IS_MOMENTARY, MIDI_CC_TYPE, 1, index) self.matrix = ButtonMatrixElement() for row in range(num_scenes): button_row = [] for column in range(num_tracks): button_row.append(self.grid[column+(row*4)]) self.log_message(str(column+(row*4))) self.matrix.add_row(tuple(button_row)) self.Session = SessionComponent(num_tracks, num_scenes) self.Session.name = "Session" self.Session.set_offsets(0, 0) self.Session.set_mixer(self.Mixer) self.Session._do_show_highlight() self.set_highlighting_session_component(self.Session) self.Session.set_track_bank_buttons(self.padl11, self.padr8) self.Session.set_scene_bank_buttons(self.padr13, self.padl10) self.scene = [None for index in range(num_scenes)] for row in range(num_scenes): self.scene[row] = self.Session.scene(row) self.scene[row].name = 'Scene_'+str(row) for column in range(num_tracks): clip_slot = self.scene[row].clip_slot(column) clip_slot.name = str(column)+'_Clip_Slot'+str(row) self.scene[row].clip_slot(column).set_triggered_to_play_value(35) self.scene[row].clip_slot(column).set_stopped_value(68) self.scene[row].clip_slot(column).set_started_value(45) self.scene[row].clip_slot(column).set_triggered_to_record_value(100) self.scene[row].clip_slot(column).set_recording_value(80) for column in range(num_tracks): for row in range(num_scenes): self.scene[row].clip_slot(column).set_launch_button(self.grid[column+(row*4)]) for index in range(num_tracks*num_scenes): self.grid[index].clear_send_cache() def update_display(self): # Called every 100 ms ControlSurface.update_display(self) self.refresh_state() self.Session.set_enabled(True) self.Session.update() # Sequencer hack try: for light_encoder_cc in self.sequencer_page_cc: self._send_midi((self.ring_midi_channel, light_encoder_cc, 0)) notes_for_current_selected_note = self._sequencer_get_midi_notes( self.sequencer_current_selected_note) for note in notes_for_current_selected_note: light_encoder_cc = int(note[1]*4+self.sequencer_page_cc[0]) self._send_midi((self.ring_midi_channel, light_encoder_cc, note[3])) except AttributeError: pass # Pad Section def init_pad_page(self): self.pad_device_params() PAD_TRANSLATION = ( (0, 0, 32, 1), (1, 0, 33, 1), (2, 0, 34, 1), (3, 0, 35, 1), (0, 1, 36, 1), (1, 1, 37, 1), (2, 1, 38, 1), (3, 1, 39, 1), (0, 2, 40, 1), (1, 2, 41, 1), (2, 2, 42, 1), (3, 2, 43, 1), (0, 3, 44, 1), (1, 3, 45, 1), (2, 3, 46, 1), (3, 3, 47, 1)) self.set_pad_translations(PAD_TRANSLATION) self._device_selection_follows_track_selection = True def pad_device_params(self): device_param_controls = [] for param in self.note_page_cc[:8]: self.rotary_encoder_potis[param] = EncoderElement( MIDI_CC_TYPE, 0, param, Live.MidiMap.MapMode.absolute) self.rotary_encoder_potis[param].release_parameter() self.rotary_encoder_potis[param].send_value(0, True) self.rotary_encoder_potis[param].clear_send_cache() device_param_controls.append(self.rotary_encoder_potis[param]) device = DeviceComponent() device.name = 'Device_Component pad' device.set_parameter_controls(tuple(device_param_controls)) self.set_device_component(device) #def scrolling(self): # self.application().view.scroll_view(ndir, 'Detail/DeviceChain', True) # Live.Song.Song.View.selected_track #Live.Song.Song.View.select_device()[0] # Device parameter section def init_device_params(self): device_param_controls = [] device_bank_buttons = [] for param in self.control_page_cc[:8]: self.rotary_encoder_potis[param] = EncoderElement( MIDI_CC_TYPE, 0, param, Live.MidiMap.MapMode.absolute) self.switch_encoder_buttons[param] = ButtonElement( IS_MOMENTARY, MIDI_CC_TYPE, 1, param) self.rotary_encoder_potis[param].release_parameter() self.rotary_encoder_potis[param].send_value(0, True) self.rotary_encoder_potis[param].clear_send_cache() device_param_controls.append(self.rotary_encoder_potis[param]) device_bank_buttons.append(self.switch_encoder_buttons[param]) device = DeviceComponent() device.name = 'Device_Component' device.set_parameter_controls(tuple(device_param_controls)) device.set_bank_buttons(tuple(device_bank_buttons)) device.set_on_off_button(ButtonElement( IS_MOMENTARY, MIDI_CC_TYPE, 1, 56)) self.set_device_component(device) def device_auto_select(self): # Iterates through devices within a track and assigns the first # DrumPad device to activate the individual drum's device. # Use first device in case none is a DrumPad device. selected_track = self.song().view.selected_track devices = selected_track.devices for device in devices: if device.can_have_drum_pads: self.current_drum_device = device pad_device = self.current_drum_device.view.selected_chain.devices[0] self.song().view.select_device(pad_device) if not self.current_drum_device.view.selected_drum_pad_has_listener( self.device_update_current_note): self.current_drum_device.view.add_selected_drum_pad_listener( self.device_update_current_note) break else: self.song().view.select_device(devices[0]) def device_update_current_note(self): current_note = self.current_drum_device.view.selected_drum_pad.note self.sequencer_current_selected_note = current_note # Update light of active pad #self._send_midi((self.light_midi_channel, light_encoder_cc, 63)) try: self.current_clip = self.song().view.highlighted_clip_slot.clip self.current_clip.is_midi_clip self._sequencer_update_notes_to_light() except AttributeError: pass
class XoneK2(ControlSurface): def __init__(self, instance): global g_logger g_logger = self.log_message super(XoneK2, self).__init__(instance, False) with self.component_guard(): self._set_suppress_rebuild_requests(True) self.init_session() self.init_mixer() self.init_matrix() self.init_tempo() # connect mixer to session self.session.set_mixer(self.mixer) self.session.update() self.set_highlighting_session_component(self.session) self._set_suppress_rebuild_requests(False) def init_session(self): self.session = SessionComponent(NUM_TRACKS, NUM_SCENES) self.session.name = 'Session' self.session.set_scene_bank_buttons(button(BUTTON_LL), button(BUTTON_LR)) self.session.update() def init_mixer(self): self.mixer = MixerWithDevices( num_tracks=NUM_TRACKS, device_select=[button(PUSH_ENCODERS[i]) for i in range(NUM_TRACKS)], device_encoders=ENCODERS ) self.mixer.id = 'Mixer' self.song().view.selected_track = self.mixer.channel_strip(0)._track for i in range(NUM_TRACKS): self.mixer.channel_strip(i).set_volume_control(fader(FADERS[i])) self.mixer.channel_strip(i).set_solo_button(button(BUTTONS3[i])) self.mixer.set_eq_controls(i, ( knob(KNOBS3[i]), knob(KNOBS2[i]), knob(KNOBS1[i]))) self.mixer.set_device_controls(i, button(BUTTONS1[i])) self.master_encoder = DynamicEncoder( ENCODER_LR, self.song().master_track.mixer_device.volume) self.cue_encoder = DynamicEncoder( ENCODER_LL, self.song().master_track.mixer_device.cue_volume) self.mixer.update() def init_matrix(self): self.matrix = ButtonMatrixElement() for scene_index in range(NUM_SCENES): scene = self.session.scene(scene_index) scene.name = 'Scene ' + str(scene_index) button_row = [] for track_index in range(NUM_TRACKS): note_nr = GRID[scene_index][track_index] b = button(note_nr, name='Clip %d, %d button' % (scene_index, track_index)) button_row.append(b) clip_slot = scene.clip_slot(track_index) clip_slot.name = 'Clip slot %d, %d' % (scene_index, track_index) clip_slot.set_stopped_value(0) clip_slot.set_started_value(64) clip_slot.set_launch_button(b) self.matrix.add_row(tuple(button_row)) stop_buttons = [button(note_nr) for note_nr in BUTTONS2] self.session.set_stop_track_clip_buttons(stop_buttons) def init_tempo(self): self.transport = CustomTransportComponent() self.transport.set_tempo_bumpers(button(PUSH_ENCODER_LR), button(PUSH_ENCODER_LL))
class LC1(ControlSurface): def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) is_momentary = True self._timer = 0 #used for flashing states, and is incremented by each call from self._update_display() self._touched = 0 self.flash_status = 1 with self.component_guard(): self._setup_transport_control() if USE_MIXER_CONTROLS == True: self.mixer_control() if USE_SESSION_VIEW == True: self.session_control() self.setup_device_control() def _setup_transport_control(self): is_momentary = True # We'll only be using momentary buttons here transport = TransportComponent() #Instantiate a Transport Component """set up the buttons""" transport.set_play_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 60)) #ButtonElement(is_momentary, msg_type, channel, identifier) Note that the MIDI_NOTE_TYPE constant is defined in the InputControlElement module transport.set_stop_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 61)) transport.set_record_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 62)) #transport.set_overdub_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 68)) #transport.set_nudge_buttons(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 75), ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 73)) #(up_button, down_button) # transport.set_tap_tempo_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 63)) #transport.set_metronome_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 80)) #For some reason, in Ver 7.x.x this method's name has no trailing "e" , and must be called as "set_metronom_button()"... #transport.set_loop_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 82)) #transport.set_punch_buttons(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 85), ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 87)) #(in_button, out_button) #transport.set_seek_buttons(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 90), ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 92)) # (ffwd_button, rwd_button) """set up the sliders""" #transport.set_tempo_control(SliderElement(MIDI_CC_TYPE, CHANNEL, 26), SliderElement(MIDI_CC_TYPE, CHANNEL, 25)) #(control, fine_control) #transport.set_song_position_control(SliderElement(MIDI_CC_TYPE, CHANNEL, 24)) def mixer_control(self): is_momentary = True self.num_tracks = N_TRACKS if(USE_SENDS == True): self.mixer = MixerComponent(N_TRACKS, N_SENDS_PER_TRACK, USE_MIXER_EQ, USE_MIXER_FILTERS) else: self.mixer = MixerComponent(N_TRACKS,0, USE_MIXER_EQ, USE_MIXER_FILTERS) self.mixer.name = 'Mixer' self.mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left) for index in range(N_TRACKS): self.mixer.channel_strip(index).name = 'Mixer_ChannelStrip_' + str(index) self.mixer.channel_strip(index)._invert_mute_feedback = True if(USE_SELECT_BUTTONS == True): self.selectbuttons = [None for index in range(N_TRACKS)] for index in range(len(SELECT_BUTTONS)): self.selectbuttons[index] = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,SELECT_BUTTONS[index], 'Select_Button', self) self.mixer.channel_strip(index).set_select_button(self.selectbuttons[index]) self.selectbuttons[index].set_on_value(SELECT_BUTTON_ON_COLOR) self.selectbuttons[index].set_off_value(SELECT_BUTTON_OFF_COLOR) if(USE_SOLO_BUTTONS == True): self.solobuttons = [None for index in range(N_TRACKS)] for index in range(len(SOLO_BUTTONS)): self.solobuttons[index] = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,SOLO_BUTTONS[index], 'Solo_Button', self) self.mixer.channel_strip(index).set_solo_button(self.solobuttons[index]) self.solobuttons[index].set_on_value(SOLO_BUTTON_ON_COLOR) self.solobuttons[index].set_off_value(SOLO_BUTTON_OFF_COLOR) if(USE_ARM_BUTTONS == True): self.armbuttons = [None for index in range(N_TRACKS)] for index in range(len(ARM_BUTTONS)): self.armbuttons[index] = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,ARM_BUTTONS[index], 'Arm_Button', self) self.mixer.channel_strip(index).set_arm_button(self.armbuttons[index]) self.armbuttons[index].set_on_value(ARM_BUTTON_ON_COLOR) self.armbuttons[index].set_off_value(ARM_BUTTON_OFF_COLOR) if(USE_MUTE_BUTTONS == True): self.mutebuttons = [None for index in range(N_TRACKS)] for index in range(len(MUTE_BUTTONS)): self.mutebuttons[index] = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,MUTE_BUTTONS[index], 'Mute_Button', self) self.mixer.channel_strip(index).set_mute_button(self.mutebuttons[index]) self.mutebuttons[index].set_on_value(MUTE_BUTTON_ON_COLOR) self.mutebuttons[index].set_off_value(MUTE_BUTTON_OFF_COLOR) if(USE_SENDS == True): self.sendencoders = [None for index in range(len(SEND_ENCODERS))] for index in range(len(SEND_ENCODERS)): self.sendencoders[index] = EncoderElement(MIDI_CC_TYPE, CHANNEL, SEND_ENCODERS[index], Live.MidiMap.MapMode.absolute) for index in range(len(SEND_ENCODERS)/N_SENDS_PER_TRACK): self.mixer.channel_strip(index).set_send_controls(tuple(self.sendencoders[(index*N_SENDS_PER_TRACK):((index*N_SENDS_PER_TRACK)+N_SENDS_PER_TRACK-1)])) if(USE_VOLUME_CONTROLS == True): self.volencoders = [None for index in range(len(VOLUME_ENCODERS))] for index in range (len(VOLUME_ENCODERS)): self.volencoders[index] = EncoderElement(MIDI_CC_TYPE, CHANNEL, VOLUME_ENCODERS[index], Live.MidiMap.MapMode.absolute) self.mixer.channel_strip(index).set_volume_control(self.volencoders[index]) def session_control(self): is_momentary = True self._timer = 0 self.flash_status = 1 self.grid = [None for index in range(N_TRACKS*N_SCENES)] for index in range(N_TRACKS*N_SCENES): self.grid[index] = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,TRACK_CLIP_BUTTONS[index], 'Grid' + str(index), self) self.grid[index].set_off_value(127) self.grid[index].turn_off() self.matrix = ButtonMatrixElement() for row in range(N_SCENES): button_row = [] for column in range(N_TRACKS): button_row.append(self.grid[row+(column*5)]) self.matrix.add_row(tuple(button_row)) self.session = SessionComponent(N_TRACKS,N_SCENES) self.session.name = "Session" self.session.set_offsets(0,0) self.scene = [None for index in range(N_SCENES)] for row in range(N_SCENES): self.scene[row] = self.session.scene(row) self.scene[row].name = 'Scene_'+str(row) for column in range(N_TRACKS): clip_slot = self.scene[row].clip_slot(column) clip_slot.name = str(column)+'_Clip_Slot'+str(row) self.scene[row].clip_slot(column).set_triggered_to_play_value(CLIP_TRG_PLAY_COLOR) self.scene[row].clip_slot(column).set_stopped_value(CLIP_STOP_COLOR) self.scene[row].clip_slot(column).set_started_value(CLIP_STARTED_COLOR) self.set_highlighting_session_component(self.session) self.session_zoom = DeprecatedSessionZoomingComponent(self.session) #this creates the ZoomingComponent that allows navigation when the shift button is pressed self.session_zoom.name = 'Session_Overview' #name it so we can access it in m4l self.session_zoom.set_stopped_value(ZOOM_STOPPED) #set the zooms stopped color self.session_zoom.set_playing_value(ZOOM_PLAYING) #set the zooms playing color self.session_zoom.set_selected_value(ZOOM_SELECTED) #set the zooms selected color self.session_zoom.set_button_matrix(self.matrix) #assign the ButtonMatrixElement that we created in _setup_controls() to the zooming component so that we can control it self._shift_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 63) self.session_zoom.set_zoom_button(self._shift_button) #assign a shift button so that we can switch states between the SessionComponent and the SessionZoomingComponent self.log_message(str(len(STOP_BUTTONS))) if(USE_STOP_BUTTONS == True): self.stopbuttons = [None for index in range(N_TRACKS)] for index in range(len(STOP_BUTTONS)): self.stopbuttons[index] = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,STOP_BUTTONS[index], 'Stop_Button', self) self.session.set_stop_track_clip_buttons(self.stopbuttons) self.stopbuttons[index].set_on_value(STOP_BUTTON_ON_COLOR) self.stopbuttons[index].set_off_value(STOP_BUTTON_OFF_COLOR) # Clip trigger on grid assignments for column in range(N_TRACKS): for row in range(N_SCENES): self.scene[row].clip_slot(column).set_launch_button(self.grid[row+(column*5)]) for index in range(N_TRACKS*N_SCENES): self.grid[index].clear_send_cache() if USE_SESSION_NAV == True: self.navleft = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,NAVBOX_LEFT_BUTTON, 'Nav_Left_Button', self) self.navleft.clear_send_cache() self.navleft.set_on_off_values(NAVBOX_LEFT_BUTTON_C, NAVBOX_LEFT_BUTTON_C) self.navright = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,NAVBOX_RIGHT_BUTTON, 'Nav_Right_Button', self) self.navright.clear_send_cache() self.navright.set_on_off_values(NAVBOX_RIGHT_BUTTON_C, NAVBOX_RIGHT_BUTTON_C) self.navup = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,NAVBOX_UP_BUTTON, 'Nav_Up_Button', self) self.navup.clear_send_cache() self.navup.set_on_off_values(NAVBOX_UP_BUTTON_C, NAVBOX_UP_BUTTON_C) self.navdown = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,NAVBOX_DOWN_BUTTON, 'Nav_Down_Button', self) self.navdown.clear_send_cache() self.navdown.set_on_off_values(NAVBOX_DOWN_BUTTON_C, NAVBOX_DOWN_BUTTON_C) self.session.set_track_bank_buttons(self.navright, self.navleft) self.session.set_scene_bank_buttons(self.navdown, self.navup) if USE_MIXER_CONTROLS == True: self.session.set_mixer(self.mixer) self.refresh_state() self.session.set_enabled(True) self.session.update() def setup_device_control(self): is_momentary = True device_bank_buttons = [] device_param_controls = [] bank_button_labels = ('Clip_Track_Button', 'Device_On_Off_Button', 'Previous_Device_Button', 'Next_Device_Button') for index in range(4): device_bank_buttons.append(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 16 + index)) device_bank_buttons[-1].name = bank_button_labels[index] for index in range(8): #ring_mode_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, 21 + index) ringed_encoder = CMDEncoderElement(MIDI_CC_TYPE, CHANNEL, 16 + index, Live.MidiMap.MapMode.relative_binary_offset, 20) #ringed_encoder.set_ring_mode_button(ring_mode_button) ringed_encoder.name = 'Device_Control_' + str(index) #ring_mode_button.name = ringed_encoder.name + '_Ring_Mode_Button' device_param_controls.append(ringed_encoder) device = ShiftableDeviceComponent() device.name = 'Device_Component' device.set_bank_buttons(tuple(device_bank_buttons)) device.set_shift_button(self._shift_button) device.set_parameter_controls(tuple(device_param_controls)) device.set_on_off_button(device_bank_buttons[1]) self.set_device_component(device) detail_view_toggler = DetailViewControllerComponent(self) detail_view_toggler.name = 'Detail_View_Control' detail_view_toggler.set_shift_button(self._shift_button) detail_view_toggler.set_device_clip_toggle_button(device_bank_buttons[0]) detail_view_toggler.set_device_nav_buttons(device_bank_buttons[2], device_bank_buttons[3]) def update_display(self): ControlSurface.update_display(self) self._timer = (self._timer + 1) % 256 self.flash() def flash(self): if(USE_SESSION_VIEW == True): for index in range(N_TRACKS*N_SCENES): if(self.grid[index]._flash_state > 0): self.grid[index].flash(self._timer) if(USE_SESSION_NAV == True): if(self.navleft._flash_state>0): self.navleft.flash(self._timer) if(self.navright._flash_state>0): self.navright.flash(self._timer) if(self.navup._flash_state>0): self.navup.flash(self._timer) if(self.navdown._flash_state>0): self.navdown.flash(self._timer) if(USE_MIXER_CONTROLS == True): for index in range(N_TRACKS): if(USE_SOLO_BUTTONS == True): if(self.solobuttons[index]._flash_state > 0): self.solobuttons[index].flash(self._timer) if(USE_MUTE_BUTTONS == True): if(self.mutebuttons[index]._flash_state > 0): self.mutebuttons[index].flash(self._timer) def disconnect(self): self._hosts = [] ControlSurface.disconnect(self) return None
class AumTroll_G(AumTroll): def __init__(self, *a, **k): super(AumTroll_G, self).__init__(*a, **k) with self.component_guard(): self._setup_session_recording_component() self._setup_APC_detail_component() self.log_message('Aumtroll G 4') def _setup_session_recording_component(self): self._recorder = SessionRecordingComponent(ClipCreator(), ViewControlComponent()) def _setup_APC_detail_component(self): self._alt_device_navigator = DetailViewCntrlComponent() """the mixer component corresponds and moves with our selection in Live, and allows us to assign physical controls""" """to Live's mixer functions without having to make all the links ourselves""" def _setup_mixer_control(self): is_momentary = True self._num_tracks = (8) #A mixer is one-dimensional; self._mixer = MixerComponent( 8, 2, True, False ) #These values represent the (Number_of_tracks, Number_of_returns, EQ_component, Filter_component) self._mixer.name = 'Mixer' #We name everything that we might want to access in m4l self._mixer.set_track_offset( 0) #Sets start point for mixer strip (offset from left) for index in range(8): #self._mixer.channel_strip(index).set_volume_control(self._fader[index]) #Since we gave our mixer 4 tracks above, we'll now assign our fader controls to it self._mixer.channel_strip( index ).name = 'Mixer_ChannelStrip_' + str( index ) #We also name the individual channel_strip so we can access it self._mixer.track_eq(index).name = 'Mixer_EQ_' + str( index ) #We also name the individual EQ_component so we can access it self._mixer.channel_strip( index )._invert_mute_feedback = True #This makes it so that when a track is muted, the corresponding button is turned off self.song().view.selected_track = self._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 self._send_reset = ResetSendsComponent( self ) #This creates a custom MonoComponent that allows us to reset all the sends on a track to zero with a single button self._send_reset.name = 'Sends_Reset' #We name it so that we can access it from m4l """the session component represents a grid of buttons that can be used to fire, stop, and navigate clips in the session view""" def _setup_session_control(self): is_momentary = True num_tracks = 8 #we are working with a 4x4 grid, num_scenes = 4 #so the height and width are both set to 4 self._session = SessionComponent( num_tracks, num_scenes ) #we create our SessionComponent with the variables we set above it self._session.name = "Session" #we name it so we can access it in m4l self._session.set_offsets( 0, 0 ) #we set the initial offset to the far left, top of the session grid self._session._track_banking_increment = 4 self._session.set_stop_clip_value( STOP_CLIP[self._rgb] ) #we assign the colors that will be displayed when the stop_clip button is pressed. This value comes from CNTRLR_Map.py, which is imported in the header of our script self._scene = [ None for index in range(4) ] #we create an array to hold the Scene subcomponents so that we can get to them if we need them. for row in range( num_scenes ): #now we'll fill the array with different objects that were created when we called the SessionComponent() module self._scene[row] = self._session.scene( row) #each session row is a SceneComponent self._scene[row].name = 'Scene_' + str( row) #name it so we can access it in m4l for column in range( num_tracks ): #now we'll create holders and names for the contents of each scene clip_slot = self._scene[row].clip_slot( column ) #we use our assignment of the scene above to gain access to the individual clipslots. Here, we are just assigning 'clip_slot' each time as a local variable so we can manipulated it's properties clip_slot.name = str(column) + '_Clip_Slot' + str( row) #name it so that we can acces it in m4l clip_slot.set_triggered_to_play_value( CLIP_TRG_PLAY[self._rgb]) #set its triggered to play color clip_slot.set_triggered_to_record_value( CLIP_TRG_REC[ self._rgb]) #set its triggered to record color clip_slot.set_stopped_value( CLIP_STOP[self._rgb]) #set its stop color clip_slot.set_started_value( CLIP_STARTED[self._rgb]) #set its started color clip_slot.set_recording_value( CLIP_RECORDING[self._rgb]) #set its recording value self._session.set_mixer( self._mixer ) #now we link the MixerComponent we created in _setup_mixer_control() to our session component so that they will follow each other when either is navigated self.set_highlighting_session_component(self._session) self._session_zoom = SessionZoomingComponent( self._session ) #this creates the ZoomingComponent that allows navigation when the shift button is pressed self._session_zoom.name = 'Session_Overview' #name it so we can access it in m4l self._session_zoom.set_stopped_value( ZOOM_STOPPED[self._rgb]) #set the zooms stopped color self._session_zoom.set_playing_value( ZOOM_PLAYING[self._rgb]) #set the zooms playing color self._session_zoom.set_selected_value( ZOOM_SELECTED[self._rgb]) #set the zooms selected color self._session_zoom.set_button_matrix( self._matrix ) #assign the ButtonMatrixElement that we created in _setup_controls() to the zooming component so that we can control it self._session_zoom.set_zoom_button( self._button[31] ) #assign a shift button so that we can switch states between the SessionComponent and the SessionZoomingComponent """this section is used so that we can reassign the color properties of each state. Legacy, from the OhmModes script, to support either RGB or Monochrome""" def _assign_session_colors(self): num_tracks = 8 num_scenes = 4 self._session.set_stop_clip_value(STOP_ALL[self._rgb]) for row in range(num_scenes): for column in range(num_tracks): self._scene[row].clip_slot(column).set_triggered_to_play_value( CLIP_TRG_PLAY[self._rgb]) self._scene[row].clip_slot( column).set_triggered_to_record_value( CLIP_TRG_REC[self._rgb]) self._scene[row].clip_slot(column).set_stopped_value( CLIP_STOP[self._rgb]) self._scene[row].clip_slot(column).set_started_value( CLIP_STARTED[self._rgb]) self._scene[row].clip_slot(column).set_recording_value( CLIP_RECORDING[self._rgb]) self._session_zoom.set_stopped_value(ZOOM_STOPPED[self._rgb]) self._session_zoom.set_playing_value(ZOOM_PLAYING[self._rgb]) self._session_zoom.set_selected_value(ZOOM_SELECTED[self._rgb]) self.refresh_state() def deassign_live_controls(self, *a, **k): for index in range(4): self._encoder[index].send_value(0, True) self._encoder[index].clear_send_cache() self._mixer.channel_strip(index + 4).set_volume_control( None ) #Since we gave our mixer 4 tracks above, we'll now assign our fader controls to it #for the left side of the mixer self._mixer.channel_strip(index + 4).set_solo_button( None) #remove the solo button assignments self._mixer.channel_strip(index + 4).set_arm_button( None) #remove the arm button assignments self._mixer.channel_strip(index + 4).set_mute_button( None) #remove the mute button assignments self._mixer.channel_strip(index + 4).set_select_button( None) #remove the select button assignments #self._alt_device_navigator.set_arrange_session_toggle_button(None) self._alt_device_navigator.set_device_clip_toggle_button(None) self._alt_device_navigator.set_detail_toggle_button(None) self._alt_device_navigator.set_enabled(False) #self._alt_device_navigator.set_shift_button(None) self._transport.set_nudge_buttons(None, None) self._recorder.set_record_button(None) self._recorder.set_re_enable_automation_button(None) super(AumTroll_G, self).deassign_live_controls(*a, **k) def assign_live_controls(self): """the following lines update all of the controls' last_sent properties, so that they forward the next value they receive regardless of whether or not it is the same as the last it recieved""" """we also reset the encoder rings and buttons, since the device component will not update them if it is not locked to a device in Live""" for index in range(16): self._grid[index].force_next_send() for index in range(32): #self._button[index].set_on_off_values(0, 127) self._button[index].send_value(0, True) self._button[index].force_next_send() for index in range(8): self._encoder_button[index + 4].send_value(0, True) self._encoder_button[index + 4].force_next_send() for index in range(12): self._encoder[index].send_value(0, True) self._encoder[index].force_next_send() """here we assign the left side of our mixer's buttons on the lower 32 keys""" if self._monohm is None: with self.component_guard(): for index in range( 4 ): #we set up a recursive loop to assign all four of our track channel strips' controls self._button[index + 16].set_on_value( MUTE[self._rgb]) #set the mute color from the Map.py self._mixer.channel_strip(index).set_mute_button( self._button[index + 16] ) #assign the mute buttons to our mixer channel strips self._button[index + 28].set_on_value( MUTE[self._rgb]) #set the mute color from the Map.py self._mixer.channel_strip(index + 4).set_mute_button( self._button[index + 28] ) #assign the mute buttons to our mixer channel strips self._button[index].set_on_off_values( SELECT[self._rgb], SELECT_OFF[self._rgb]) self._mixer.channel_strip(index).set_select_button( self._button[index] ) #assign the select buttons to our mixer channel strips self._button[index + 12].set_on_off_values( SELECT[self._rgb], SELECT_OFF[ self._rgb]) #set the select color from the Map.py self._mixer.channel_strip(index + 4).set_select_button( self._button[index + 12] ) #assign the select buttons to our mixer channel strips #self._session.set_stop_track_clip_buttons(tuple(self._button[index+4] for index in range(8))) #these last two lines assign the send_reset buttons and the stop_clip buttons for each track for index in range(8): #self._button[index + 4].set_on_off_values(SOLO[self._rgb], SOLO[self._rgb]) #this assigns the custom colors defined in the Map.py file to the stop_clip buttons. They have seperate on/off values, but we assign them both the same value so we can always identify them self._mixer.channel_strip(index).set_solo_button( self._button[index + 4]) #self._button[index + 4].send_value(STOP_CLIP[self._rgb], True) #finally, we send the on/off colors out to turn the LEDs on for the stop clip buttons for index in range( 4 ): #set up a for loop to generate an index for assigning the session nav buttons' colors self._button[index + 20].set_on_off_values( SESSION_NAV[self._rgb], SESSION_NAV_OFF[self._rgb] ) #assign the colors from Map.py to the session nav buttons self._session.set_track_bank_buttons( self._button[21], self._button[20] ) #set the track bank buttons for the Session navigation controls self._session.set_scene_bank_buttons( self._button[23], self._button[22] ) #set the scnee bank buttons for the Session navigation controls """this section assigns the grid to the clip launch functionality of the SessionComponent""" for column in range( 4 ): #we need to set up a double recursion so that we can generate the indexes needed to assign the grid buttons for row in range( 4 ): #the first recursion passes the column index, the second the row index self._scene[row].clip_slot(column).set_launch_button( self._grid[(row * 4) + column] ) #we use the indexes to grab the first the scene and then the clip we assigned above, and then we use them again to define the button held in the grid array that we want to assign to the clip slot from the session component for index in range( 4 ): #set up a for loop to generate an index for assigning the session nav buttons' colors self._button[index + 24].set_on_off_values( SHIFTS[self._rgb], SHIFTS_OFF[self._rgb] ) #assign the colors from Map.py to the session nav buttons self._session.update( ) #tell the Session component to update so that the grid will display the currently selected session region self._session.set_enabled(True) #enable the Session Component self._session_zoom.set_enabled(True) #enable the Session Zoom #self._alt_device_navigator.set_arrange_session_toggle_button(self._encoder_button[4]) self._alt_device_navigator.set_device_clip_toggle_button( self._encoder_button[5]) self._alt_device_navigator.set_detail_toggle_button( self._encoder_button[6]) #self._device_navigator.set_shift_button(self._encoder_button[7]) self._session_zoom.set_zoom_button( self._encoder_button[7] ) #assign the lower right key button to the shift function of the Zoom component self._session.set_scene_bank_buttons(self._button[25], self._button[24]) self._recorder.set_record_button(self._button[27]) self._recorder.set_re_enable_automation_button( self._button[26]) else: for index in range(8): self._mixer2.channel_strip(index).set_volume_control( self._fader[index]) self._mixer2.set_track_offset(TROLL_OFFSET) self._device_selector.set_mode_buttons(self._grid) if not self._shifted: self._assign_monomodular_controls() else: self._assign_shifted_controls() self._device1.set_parameter_controls( tuple([self._knobs[index] for index in range(8)])) self._device2.set_parameter_controls( tuple([self._knobs[index + 12] for index in range(8)])) self._device1.set_enabled(True) self._device2.set_enabled(True) self._find_devices() self._device1.update() self._device2.update() """this section assigns the encoders and encoder buttons""" self._device.set_parameter_controls( tuple([self._encoder[index + 4] for index in range(8)]) ) #assign the encoders from the device component controls - we are doing this here b #self._encoder_button[7].set_on_value(DEVICE_LOCK[self._rgb]) #set the on color for the Device lock encoder button #self._device.set_lock_button(self._encoder_button[7]) #assign encoder button 7 to the device lock control #self._encoder_button[4].set_on_value(DEVICE_ON[self._rgb]) #set the on color for the Device on/off encoder button #self._device.set_on_off_button(self._encoder_button[4]) #assing encoder button 4 to the device on/off control for index in range( 2 ): #setup a recursion to generate indexes so that we can reference the correct controls to assing to the device_navigator functions self._encoder_button[index + 8].set_on_value( DEVICE_NAV[ self._rgb]) #assign the on color for the device navigator self._encoder_button[index + 10].set_on_value( DEVICE_BANK[self._rgb] ) #assign the on color for the device bank controls self._device_navigator.set_nav_buttons( self._encoder_button[10], self._encoder_button[11] ) #set the device navigators controls to encoder buttons 10 and 11 self._device.set_bank_nav_buttons( self._encoder_button[8], self._encoder_button[9] ) #set the device components bank nav controls to encoder buttons 8 and 9 """now we turn on and update some of the components we've just made assignments to""" self._device.set_enabled(True) #enable the Device Component self._device_navigator.set_enabled(True) #enable the Device Navigator self._alt_device_navigator.set_enabled(True) self._device.update( ) #tell the Device component to update its assingments so that it will detect the currently selected device parameters and display them on the encoder rings
def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) self._device_selection_follows_track_selection = True with self.component_guard(): self._suppress_send_midi = True self._suppress_session_highlight = True self._control_is_with_automap = False is_momentary = True self._suggested_input_port = 'Akai MPK26' self._suggested_output_port = 'Akai MPK26' self.log("BEFORE mixer") self._setup_mixer_control() self._setup_device_control() # self.clipcontrol(8) self.log("AFTER MIXER") """SESSION ViEW""" global session session = SessionComponent(GRIDSIZE[0],GRIDSIZE[1]) session.name = 'Session_Control' matrix = ButtonMatrixElement() matrix.name = 'Button_Matrix' up_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL_MIXER, UP_BUTTON) down_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL_MIXER, DOWN_BUTTON) left_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL_MIXER, LEFT_BUTTON) right_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL_MIXER, RIGHT_BUTTON) session.set_scene_bank_buttons(down_button, up_button) session.set_track_bank_buttons(right_button, left_button) # session_zoom = SessionZoomingComponent(session) # session_zoom.set_nav_buttons(up_button,down_button,left_button,right_button) session_stop_buttons = [] self.log("SETTING UP GRID") for row in xrange(GRIDSIZE[1]): button_row = [] self.log("CZ ROW") self.log(str(row)) scene = session.scene(row) scene.name = 'Scene_' + str(row) scene.set_launch_button(ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, SCENE_BUTTONS[row])) scene.set_triggered_value(2) for column in xrange(GRIDSIZE[0]): self.log("CZ COLUMN") self.log(str(column)) button = ConfigurableButtonElement(True, MIDI_NOTE_TYPE, CHANNEL_MIXER, LAUNCH_BUTTONS[row][column]) button.name = str(column) + '_Clip_' + str(row) + '_Button' button_row.append(button) clip_slot = scene.clip_slot(column) clip_slot.name = str(column) + '_Clip_Slot_' + str(row) clip_slot.set_launch_button(button) matrix.add_row(tuple(button_row)) for column in xrange(GRIDSIZE[0]): session_stop_buttons.append((ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL_MIXER, TRACK_STOPS[column]))) self._suppress_session_highlight = False self._suppress_send_midi = False self.set_highlighting_session_component(session) session.set_stop_track_clip_buttons(tuple(session_stop_buttons)) session.set_mixer(mixer)
class DV1(ControlSurface): def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) is_momentary = True self._timer = 0 #used for flashing states, and is incremented by each call from self._update_display() self._touched = 0 self.flash_status = 1 # Used in FlashingButtonElement (kludge for our purposes) self._device_selection_follows_track_selection = True with self.component_guard(): self._setup_transport_control() if USE_MIXER_CONTROLS == True: self.mixer_control() if USE_SESSION_VIEW == True: self.session_control() # self.setup_device_control() def _setup_transport_control(self): is_momentary = True # We'll only be using momentary buttons here self.transport = TransportComponent() #Instantiate a Transport Component """set up the buttons""" self.transport.set_play_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 60)) #ButtonElement(is_momentary, msg_type, channel, identifier) Note that the MIDI_NOTE_TYPE constant is defined in the InputControlElement module self.transport.set_stop_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 61)) self.transport.set_record_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 62)) def mixer_control(self): is_momentary = True self.num_tracks = N_TRACKS if(USE_SENDS == True): self.mixer = MixerComponent(N_TRACKS, N_SENDS_PER_TRACK, USE_MIXER_EQ, USE_MIXER_FILTERS) else: self.mixer = MixerComponent(N_TRACKS,0, USE_MIXER_EQ, USE_MIXER_FILTERS) self.mixer.name = 'Mixer' self.mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left) for index in range(N_TRACKS): self.mixer.channel_strip(index).name = 'Mixer_ChannelStrip_' + str(index) self.mixer.channel_strip(index)._invert_mute_feedback = True if(USE_SELECT_BUTTONS == True): self.selectbuttons = [None for index in range(N_TRACKS)] for index in range(len(SELECT_BUTTONS)): self.selectbuttons[index] = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,SELECT_BUTTONS[index], 'Select_Button', self) self.mixer.channel_strip(index).set_select_button(self.selectbuttons[index]) self.selectbuttons[index].set_on_value(SELECT_BUTTON_ON_COLOR) self.selectbuttons[index].set_off_value(SELECT_BUTTON_OFF_COLOR) if(USE_SOLO_BUTTONS == True): self.solobuttons = [None for index in range(N_TRACKS)] for index in range(len(SOLO_BUTTONS)): self.solobuttons[index] = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,SOLO_BUTTONS[index], 'Solo_Button', self) self.mixer.channel_strip(index).set_solo_button(self.solobuttons[index]) self.solobuttons[index].set_on_value(SOLO_BUTTON_ON_COLOR) self.solobuttons[index].set_off_value(SOLO_BUTTON_OFF_COLOR) if(USE_ARM_BUTTONS == True): self.armbuttons = [None for index in range(N_TRACKS)] for index in range(len(ARM_BUTTONS)): self.armbuttons[index] = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,ARM_BUTTONS[index], 'Arm_Button', self) self.mixer.channel_strip(index).set_arm_button(self.armbuttons[index]) self.armbuttons[index].set_on_value(ARM_BUTTON_ON_COLOR) self.armbuttons[index].set_off_value(ARM_BUTTON_OFF_COLOR) if(USE_MUTE_BUTTONS == True): self.mutebuttons = [None for index in range(N_TRACKS)] for index in range(len(MUTE_BUTTONS)): self.mutebuttons[index] = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,MUTE_BUTTONS[index], 'Mute_Button', self) self.mixer.channel_strip(index).set_mute_button(self.mutebuttons[index]) self.mutebuttons[index].set_on_value(MUTE_BUTTON_ON_COLOR) self.mutebuttons[index].set_off_value(MUTE_BUTTON_OFF_COLOR) if(USE_SENDS == True): self.sendencoders = [None for index in range(len(SEND_ENCODERS))] for index in range(len(SEND_ENCODERS)): # self.sendencoders[index] = EncoderElement(MIDI_CC_TYPE, CHANNEL, SEND_ENCODERS[index], Live.MidiMap.MapMode.absolute) self.sendencoders[index] = CMDEncoderElement(MIDI_CC_TYPE, CHANNEL, SEND_ENCODERS[index], Live.MidiMap.MapMode.relative_smooth_binary_offset, 20) for index in range(len(SEND_ENCODERS)/N_SENDS_PER_TRACK): self.mixer.channel_strip(index).set_send_controls(tuple(self.sendencoders[(index*N_SENDS_PER_TRACK):((index*N_SENDS_PER_TRACK)+N_SENDS_PER_TRACK)])) # Pas -1, car tuple() fonctionne etrangement en Python ;) if(USE_VOLUME_CONTROLS == True): self.volencoders = [None for index in range(len(VOLUME_ENCODERS))] for index in range (len(VOLUME_ENCODERS)): #self.volencoders[index] = EncoderElement(MIDI_CC_TYPE, CHANNEL, VOLUME_ENCODERS[index], Live.MidiMap.MapMode.absolute) self.volencoders[index] = CMDEncoderElement(MIDI_CC_TYPE, CHANNEL, VOLUME_ENCODERS[index], Live.MidiMap.MapMode.relative_smooth_binary_offset, 20) self.mixer.channel_strip(index).set_volume_control(self.volencoders[index]) def session_control(self): is_momentary = True self._timer = 0 self.flash_status = 1 self.grid = [None for index in range(N_TRACKS*N_SCENES)] for index in range(N_TRACKS*N_SCENES): self.grid[index] = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,TRACK_CLIP_BUTTONS[index], 'Grid' + str(index), self) self.grid[index].set_off_value(0) self.grid[index].turn_off() self.matrix = ButtonMatrixElement() for row in range(N_SCENES): button_row = [] for column in range(N_TRACKS): button_row.append(self.grid[row+(column*N_SCENES)]) self.matrix.add_row(tuple(button_row)) self.session = SessionComponent(N_TRACKS,N_SCENES) self.session.name = "Session" self.session.set_offsets(0,0) self.scene = [None for index in range(N_SCENES)] for row in range(N_SCENES): self.scene[row] = self.session.scene(row) self.scene[row].name = 'Scene_'+str(row) for column in range(N_TRACKS): clip_slot = self.scene[row].clip_slot(column) clip_slot.name = str(column)+'_Clip_Slot'+str(row) self.scene[row].clip_slot(column).set_triggered_to_play_value(CLIP_TRG_PLAY_COLOR) self.scene[row].clip_slot(column).set_stopped_value(CLIP_STOP_COLOR) self.scene[row].clip_slot(column).set_started_value(CLIP_STARTED_COLOR) self.set_highlighting_session_component(self.session) #self.session_zoom = DeprecatedSessionZoomingComponent(self.session) #this creates the ZoomingComponent that allows navigation when the shift button is pressed #self.session_zoom.name = 'Session_Overview' #name it so we can access it in m4l #self.session_zoom.set_stopped_value(ZOOM_STOPPED) #set the zooms stopped color #self.session_zoom.set_playing_value(ZOOM_PLAYING) #set the zooms playing color #self.session_zoom.set_selected_value(ZOOM_SELECTED) #set the zooms selected color #self.session_zoom.set_button_matrix(self.matrix) #assign the ButtonMatrixElement that we created in _setup_controls() to the zooming component so that we can control it #self._shift_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 84) #self.session_zoom.set_zoom_button(self._shift_button) #assign a shift button so that we can switch states between the SessionComponent and the SessionZoomingComponent #self.looper = LooperComponent(self) #self.log_message(str(len(STOP_BUTTONS))) #if(USE_STOP_BUTTONS == True): #self.stopbuttons = [None for index in range(N_TRACKS)] #for index in range(len(STOP_BUTTONS)): #self.stopbuttons[index] = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,STOP_BUTTONS[index], 'Stop_Button', self) #self.session.set_stop_track_clip_buttons(self.stopbuttons) #self.stopbuttons[index].set_on_value(STOP_BUTTON_ON_COLOR) #self.stopbuttons[index].set_off_value(STOP_BUTTON_OFF_COLOR) #self.scrollencoder = ScrollEncoderElement(MIDI_CC_TYPE, CHANNEL, 32, Live.MidiMap.MapMode.absolute, self.session, self.transport, self.mixer, self.looper) #self.scrollencoder.set_nav_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 80)) #self.scrollencoder.set_transport_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 81)) #self.scrollencoder.set_scene_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 82)) #self.scrollencoder.set_library_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 83)) #self.scrollencoder.set_button1(SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 66)) #self.scrollencoder.set_button2(SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 67)) #self.scrollencoder.set_button3(SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 64)) #self.scrollencoder.set_button4(SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 65)) #self.scrollencoder.set_encoder_button(SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 32)) self.button_left = SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, NAVBOX_LEFT_BUTTON) self.button_right = SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, NAVBOX_RIGHT_BUTTON) self.button_up = SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, NAVBOX_UP_BUTTON) self.button_down = SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, NAVBOX_DOWN_BUTTON) self.session.set_track_bank_buttons(self.button_right, self.button_left) self.session.set_scene_bank_buttons(self.button_down, self.button_up) for column in range(N_TRACKS): for row in range(N_SCENES): self.scene[row].clip_slot(column).set_launch_button(self.grid[row+(column*N_SCENES)]) for index in range(N_TRACKS*N_SCENES): self.grid[index].clear_send_cache() if USE_MIXER_CONTROLS == True: self.session.set_mixer(self.mixer) self.refresh_state() self.session.set_enabled(True) self.session.update() #def setup_device_control(self): #is_momentary = True #device_bank_buttons = [] #device_param_controls = [] #bank_button_labels = ('Clip_Track_Button', 'Device_On_Off_Button', 'Previous_Device_Button', 'Next_Device_Button') #for index in range(4): #device_bank_buttons.append(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 16 + index)) #device_bank_buttons[-1].name = bank_button_labels[index] #for index in range(8): ##ring_mode_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, CHANNEL, 21 + index) #ringed_encoder = CMDEncoderElement(MIDI_CC_TYPE, CHANNEL, 16 + index, Live.MidiMap.MapMode.relative_binary_offset, 20) ##ringed_encoder.set_ring_mode_button(ring_mode_button) #ringed_encoder.name = 'Device_Control_' + str(index) ##ring_mode_button.name = ringed_encoder.name + '_Ring_Mode_Button' #device_param_controls.append(ringed_encoder) #device = ShiftableDeviceComponent() #device.name = 'Device_Component' #device.set_bank_buttons(tuple(device_bank_buttons)) ##device.set_shift_button(self._shift_button) #device.set_parameter_controls(tuple(device_param_controls)) #device.set_on_off_button(device_bank_buttons[1]) #self.set_device_component(device) #detail_view_toggler = DetailViewControllerComponent(self) #detail_view_toggler.name = 'Detail_View_Control' ##detail_view_toggler.set_shift_button(self._shift_button) #detail_view_toggler.set_device_clip_toggle_button(device_bank_buttons[0]) #detail_view_toggler.set_device_nav_buttons(device_bank_buttons[2], device_bank_buttons[3]) def update_display(self): ControlSurface.update_display(self) self._timer = (self._timer + 1) % 256 def disconnect(self): self._hosts = [] ControlSurface.disconnect(self) return None
class OP1(ControlSurface): def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) self.c_instance = c_instance self.retries_count = 0 self.device_connected = False self.clip_color_callbacks = {} self.slot_callbacks = {} self.text_start_sequence = (0xf0, 0x0, 0x20, 0x76, 0x00, 0x03) self.text_end_sequence = (0xf7, ) self.enable_sequence = (0xf0, 0x00, 0x20, 0x76, 0x00, 0x01, 0x02, 0xf7) self.disable_sequence = (0xf0, 0x00, 0x20, 0x76, 0x00, 0x01, 0x00, 0xf7) self.id_sequence = (0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7) self.text_color_start_sequence = (0xf0, 0x0, 0x20, 0x76, 0x00, 0x04) self.log('INITIALIZING') self.app = Live.Application.get_application() #maj = self.app.get_major_version() #min = self.app.get_minor_version() #bug = self.app.get_bugfix_version() #self.show_message(str(1) + "." + str(0) + "." + str(9)) self.show_message("Version " + VERSION) # reseting text self.write_text(' ') # reset display clips self.reset_display_clips() # getting browser visible state self.session_browser_visible = self.app.view.is_view_visible("Browser") # getting browser visible state self.arrange_browser_visible = self.app.view.is_view_visible("Browser") # getting session view visible state self.session_visible = self.app.view.is_view_visible("Session") # getting arrange view visible state self.arrange_visible = self.app.view.is_view_visible("Arranger") # getting detail view visible state self.detail_visible = self.app.view.is_view_visible("Detail") # getting back to arranger state self.back_to_arranger_state = self.song().back_to_arranger # initializing channel strip to null self._channel_strip = None # initializing transport component self._transport = TransportComponent() # initializing mixer component self._mixer = MixerComponent(NUM_TRACKS, 2) # initializing session component self._session = SessionComponent(NUM_TRACKS, NUM_ROWS) self._session.add_offset_listener(self.session_offset_changed) # configuring operation mode selector buttons self._operation_mode_buttons = ButtonElement( True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_1_BUTTON), ButtonElement( True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_2_BUTTON), ButtonElement( True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_3_BUTTON), ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MODE_4_BUTTON), # initializing operation mode selector self._operation_mode_selector = OP1ModeSelectorComponent( self, self._transport, self._mixer, self._session) # setting operation mode selector buttons self._operation_mode_selector.set_mode_buttons( self._operation_mode_buttons) # adding value listener for operation mode index self._operation_mode_selector.add_mode_index_listener( self.mode_index_changed) # setting global transport assignments self._transport.set_record_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_REC_BUTTON)) self._transport.set_play_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_PLAY_BUTTON)) self._transport.set_stop_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_STOP_BUTTON)) self._transport.set_metronome_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_METRONOME_BUTTON)) self._transport.set_tap_tempo_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_HELP_BUTTON)) self._transport.set_punch_buttons( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS1_BUTTON), ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS2_BUTTON)) self._transport.set_loop_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS3_BUTTON)) self._transport.set_overdub_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS4_BUTTON)) # setting global session assignments self._session.set_scene_bank_buttons( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_COM), ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_MICRO)) # setting misc listeners self.browser_toggle_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL, 15) self.browser_toggle_button.add_value_listener( self.browser_toggle_button_callback) self.mainview_toggle_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL, 16) self.mainview_toggle_button.add_value_listener( self.mainview_toggle_button_callback) self.detailview_toggle_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL, 17) self.detailview_toggle_button.add_value_listener( self.detailview_toggle_button_callback) self.clear_track_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, 25) self.clear_track_button.add_value_listener( self.clear_track_button_callback) self.back_to_arranger_button = ButtonElement(True, MIDI_CC_TYPE, CHANNEL, 26) self.back_to_arranger_button.add_value_listener( self.back_to_arranger_button_callback) # adding value listener for selected track change self.song().view.add_selected_track_listener( self.selected_track_changed) # adding value listener for selected scene change self.song().view.add_selected_scene_listener( self.selected_scene_changed) # setting assignments for currently selected track self.selected_track_changed() # setting assignments for currently selected scene self.selected_scene_changed() def handle_sysex(self, midi_bytes): if ((midi_bytes[6] == 32) and (midi_bytes[7] == 118)): self.device_connected = True self.log("OP-1 CONNECTED. SENDING ABLETON LIVE MODE INIT SEQUENCE") self._send_midi(self.enable_sequence) def add_clip_slot_listeners(self): #self.log('ADDING CLIP SLOT LISTENERS') # creating an empty list for all clip slots clip_slots = [] # getting a reference to all tracks tracks = self.song().tracks # appending all tracks clip slots to clip_slots for track in tracks: clip_slots.append(track.clip_slots) # iterating over all clip slots for t in range(len(clip_slots)): for c in range(len(clip_slots[t])): clip_slot = clip_slots[t][c] # adding has clip listener to clip slot self.add_slot_listener(clip_slot) # if clip slot has clip if clip_slot.has_clip: # adding clip listeners self.add_clip_listener(clip_slot.clip) def rem_clip_slot_listeners(self): #self.log('REMOVING CLIP SLOT LISTENERS') # iterate over all clip color change callbacks for c in self.clip_color_callbacks: # if clip still exists if c != None: # and it has a has clip listener if c.color_has_listener(self.clip_color_callbacks[c]) == 1: # remove it c.remove_color_listener(self.clip_color_callbacks[c]) # iterate over all clip slot callbacks for cs in self.slot_callbacks: # if clip slot still exists if cs != None: # and it has a has clip listener if cs.has_clip_has_listener(self.slot_callbacks[cs]) == 1: # remove it cs.remove_has_clip_listener(self.slot_callbacks[cs]) def add_slot_listener(self, cs): # setting has clip listener callback = lambda: self.has_clip_listener(cs) # if we don't have a clip slot has clip listener for this clip slot yet if not (self.slot_callbacks.has_key(cs)): # adding has clip callback to clip slot cs.add_has_clip_listener(callback) # saving callback for future release self.slot_callbacks[cs] = callback def add_clip_listener(self, clip): # setting callback for clip color change color_callback = lambda: self.update_display_clips() # if we don't have a clip color change callback for this clip yet if not (self.clip_color_callbacks.has_key(clip)): # adding clip color change callback clip.add_color_listener(color_callback) # saving callback for future release self.clip_color_callbacks[clip] = color_callback def has_clip_listener(self, cs): # clip slot has clip listener callback if cs.has_clip: # add clip listener self.add_clip_listener(cs.clip) else: # update display if clip slot was removed self.update_display_clips() def session_offset_changed(self): # if session component offset changes, update display self.update_display_clips() def selected_scene_changed(self): # if on clip mode update display if (self._operation_mode_selector.mode_index == OP1_MODE_CLIP): self.update_display_clip_mode() def mode_index_changed(self): # update display to current mode info if (self._operation_mode_selector.mode_index == OP1_MODE_PERFORM): self.update_display_perform_mode() elif (self._operation_mode_selector.mode_index == OP1_MODE_CLIP): self.update_display_clip_mode() elif (self._operation_mode_selector.mode_index == OP1_MODE_TRANSPORT): self.update_display_transport_mode() elif (self._operation_mode_selector.mode_index == OP1_MODE_MIXER): self.update_display_mixer_mode() def clear_track_button_callback(self, value): # if clear track button was called, reset track if (value == 127): for i in range(len(self.song().tracks)): self.song().tracks[i].arm = 0 self.song().tracks[i].solo = 0 self.song().tracks[i].mute = 0 for i in range(len(self.song().return_tracks)): self.song().tracks[i].solo = 0 self.song().tracks[i].mute = 0 def clear_return_track_assignment(self, strip): # clear return track assingments strip.set_volume_control(None) strip.set_pan_control(None) strip.set_mute_button(None) strip.set_solo_button(None) def clear_track_assignment(self, strip): # clear track assignments strip.set_volume_control(None) strip.set_pan_control(None) strip.set_mute_button(None) strip.set_solo_button(None) strip.set_arm_button(None) def clear_tracks_assigments(self): # for all normal tracks, clear assignments for i in range(NUM_TRACKS): strip = self._mixer.channel_strip(i) if (strip != None): self.clear_track_assignment(strip) # for all return tracks, clear assignments for i in range(2): return_strip = self._mixer.return_strip(i) if (return_strip != None): self.clear_return_track_assignment(return_strip) def selected_track_changed(self): # if on mixer mode update display if (self._operation_mode_selector.mode_index == OP1_MODE_MIXER): self.update_display_mixer_mode() # clear track assignments self.clear_tracks_assigments() # getting selected strip self._channel_strip = self._mixer.selected_strip() # perform track assignments self._channel_strip.set_volume_control( EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_1, Live.MidiMap.MapMode.relative_two_compliment)) self._channel_strip.set_pan_control( EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_2, Live.MidiMap.MapMode.relative_two_compliment)) # setting a tuple of encoders to control sends send_controls = EncoderElement( MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_3, Live.MidiMap.MapMode.relative_two_compliment), EncoderElement( MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_4, Live.MidiMap.MapMode.relative_two_compliment), # setting send encoders self._channel_strip.set_send_controls(tuple(send_controls)) # setting solo button self._channel_strip.set_solo_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS6_BUTTON)) # if track can be armed, set arm button if (self._channel_strip._track.can_be_armed): self._channel_strip.set_arm_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS7_BUTTON)) # if track is no master, set mute button if (self._channel_strip._track != self.song().master_track): self._channel_strip.set_mute_button( ButtonElement(True, MIDI_CC_TYPE, CHANNEL, OP1_SS5_BUTTON)) def browser_toggle_button_callback(self, value): if (value == 127): if (self.session_visible): if (self.session_browser_visible == True): self.session_browser_visible = False self.app.view.hide_view("Browser") else: self.session_browser_visible = True self.app.view.show_view("Browser") if (self.arrange_visible): if (self.arrange_browser_visible == True): self.arrange_browser_visible = False self.app.view.hide_view("Browser") else: self.arrange_browser_visible = True self.app.view.show_view("Browser") def back_to_arranger_button_callback(self, value): if (value == 127): self.song().back_to_arranger = False def mainview_toggle_button_callback(self, value): if (value == 127): if (self.session_visible == True): self.session_visible = False self.arrange_visible = True self.app.view.show_view("Arranger") self.arrange_browser_visible = self.app.view.is_view_visible( "Browser") else: self.session_visible = True self.arrange_visible = False self.app.view.show_view("Session") self.session_browser_visible = self.app.view.is_view_visible( "Browser") def detailview_toggle_button_callback(self, value): if (value == 127): if (self.detail_visible == True): self.detail_visible = False self.app.view.hide_view("Detail") else: self.detail_visible = True self.app.view.show_view("Detail") def write_text(self, msg): text_list = [] sequence = () text_list.append(len(msg.strip())) for i in msg.strip(): text_list.append(ord(i)) sequence = self.text_start_sequence + tuple( text_list) + self.text_end_sequence self._send_midi(sequence) def suggest_input_port(self): return "OP-1 Midi Device" def suggest_output_port(self): return "OP-1 Midi Device" def update_display_perform_mode(self): self.write_text("perform\rmode") def reset_display_clips(self): count = 0 colors = [] length = [] sequence = () for i in range(NUM_TRACKS): count += 1 colors.append(0x00) colors.append(0x00) colors.append(0x00) length.append(count) sequence = self.text_color_start_sequence + tuple(length) + tuple( colors) + self.text_end_sequence self._send_midi(sequence) def update_display_clips(self): #self.log("UPDATING DISPLAY CLIPS") count = 0 colors = [] length = [] sequence = () tracks_len = len(self.song().tracks) - self._session._track_offset if (tracks_len > NUM_TRACKS): tracks_len = NUM_TRACKS for i in range(tracks_len): count += 1 clip_slot = self._session.scene(0).clip_slot(i) if (clip_slot != None): if (clip_slot.has_clip() != False): clip_color = clip_slot._clip_slot.clip.color colors.append(((clip_color >> 16) & 0x000000ff) >> 1) colors.append(((clip_color >> 8) & 0x000000ff) >> 1) colors.append((clip_color & 0x000000ff) >> 1) else: colors.append(0x00) colors.append(0x00) colors.append(0x00) else: colors.append(0x00) colors.append(0x00) colors.append(0x00) length.append(count) sequence = self.text_color_start_sequence + tuple(length) + tuple( colors) + self.text_end_sequence self._send_midi(sequence) def update_display_clip_mode(self): self.write_text( "sel. scene\r" + str(self.song().view.selected_scene.name.lower().strip())) def update_display_transport_mode(self): song_time = str(self.song().get_current_beats_song_time()) self.write_text("song pos.\r" + song_time[:len(song_time) - 4]) def update_display_mixer_mode(self): self.write_text("sel. track\r" + str(self.song().view.selected_track.name.lower())) def update_display(self): if not (self.device_connected): if (self.retries_count < 5): self.log("TRYING OP-1 CONNECTION") self.retries_count += 1 self._send_midi(self.id_sequence) time.sleep(1) # if in transport mode, update display with song position if (self._operation_mode_selector.mode_index == OP1_MODE_TRANSPORT): self.update_display_transport_mode() # checking if app current view is session if (self.app.view.is_view_visible("Session")): # checking if session browser state is diferent from the internal if (self.session_browser_visible != self.app.view.is_view_visible("Browser")): self.session_browser_visible = self.app.view.is_view_visible( "Browser") # checking if app current view is arrange if (self.app.view.is_view_visible("Arranger")): # checking if arrange browser state is diferent from the internal if (self.arrange_browser_visible != self.app.view.is_view_visible("Browser")): self.arrange_browser_visible = self.app.view.is_view_visible( "Browser") # checking if app current view is detail if (self.app.view.is_view_visible("Detail")): # checking if detail state is diferent from the internal if (self.detail_visible != self.app.view.is_view_visible("Detail")): self.detail_visible = self.app.view.is_view_visible("Detail") def refresh_state(self): self.log("REFRESH STATE") self.retries_count = 0 self.device_connected = False def build_midi_map(self, midi_map_handle): #self.log("BUILD MIDI MAP") assert (self._suppress_requests_counter == 0) self._in_build_midi_map = True self._midi_map_handle = midi_map_handle self._forwarding_registry = {} for control in self.controls: if isinstance(control, InputControlElement): control.install_connections() self._midi_map_handle = None self._in_build_midi_map = False if (self._pad_translations != None): self._c_instance.set_pad_translation(self._pad_translations) # remove clip listeners self.rem_clip_slot_listeners() # add clip listeners self.add_clip_slot_listeners() # update display self.update_display_clips() def log(self, msg): self.c_instance.log_message("[TE OP-1] " + msg) def disconnect(self): # removing clip slots listeners self.rem_clip_slot_listeners() # removing value listener for track changed self.song().view.remove_selected_track_listener( self.selected_track_changed) # removing value listener for scene changed self.song().view.remove_selected_scene_listener( self.selected_scene_changed) # removing value listener for operation mode index self._operation_mode_selector.remove_mode_index_listener( self.mode_index_changed) # removing global transport assignments self._transport.set_punch_buttons(None, None) self._transport.set_loop_button(None) self._transport.set_overdub_button(None) self._transport.set_record_button(None) self._transport.set_play_button(None) self._transport.set_stop_button(None) self._transport.set_metronome_button(None) self._transport.set_tap_tempo_button(None) # removing global session assignments self._session.set_scene_bank_buttons(None, None) # removing misc listeners self.browser_toggle_button.remove_value_listener( self.browser_toggle_button_callback) self.mainview_toggle_button.remove_value_listener( self.mainview_toggle_button_callback) self.detailview_toggle_button.remove_value_listener( self.detailview_toggle_button_callback) self.clear_track_button.remove_value_listener( self.clear_track_button_callback) self.back_to_arranger_button.remove_value_listener( self.back_to_arranger_button_callback) # sending special ableton mode disable sequence self._send_midi(self.disable_sequence) # disconnecting control surface ControlSurface.disconnect(self) self.log("DISCONNECTED")
def _setup_session_control(self): is_momentary = True self._shift_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 87) right_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 78) left_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 77) up_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 71) down_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 79) right_button.name = 'Bank_Select_Right_Button' left_button.name = 'Bank_Select_Left_Button' up_button.name = 'Bank_Select_Up_Button' down_button.name = 'Bank_Select_Down_Button' global session session = SessionComponent(7, 8) session.name = 'Session_Control' session.set_track_bank_buttons(right_button, left_button) session.set_scene_bank_buttons(down_button, up_button) matrix = ButtonMatrixElement() matrix.name = 'Button_Matrix' scene_launch_notes = [56,57,58,59,60,61,62,63] scene_launch_buttons = [ ButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, scene_launch_notes[index]) for index in range(8) ] #track_stop_buttons = [ ButtonElement(is_momentary, MIDI_NOTE_TYPE, index, 52) for index in range(8) ] for index in range(len(scene_launch_buttons)): scene_launch_buttons[index].name = 'Scene_'+ str(index) + '_Launch_Button' #for index in range(len(track_stop_buttons)): # track_stop_buttons[index].name = 'Track_' + str(index) + '_Stop_Button' #stop_all_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 81) #stop_all_button.name = 'Stop_All_Clips_Button' #self._session.set_stop_all_clips_button(stop_all_button) #self._session.set_stop_track_clip_buttons(tuple(track_stop_buttons)) #self._session.set_stop_track_clip_value(2) #button_notes = [0,8,16,24,32,40,48,56,1,9,17,25,33,41,49,57,2,10,18,26,34,42,50,58,3,11,19,27,35,43,51,59,4,12,20,28,36,44,52,60,5,13,21,29,37,45,53,61,6,14,22,30,38,46,54,62] for scene_index in range(8): scene = session.scene(scene_index) scene.name = 'Scene_' + str(scene_index) button_row = [] scene.set_launch_button(scene_launch_buttons[scene_index]) #scene.set_triggered_value(2) for track_index in range(7): button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, (track_index * 8) + scene_index) button.name = str(track_index) + '_Clip_' + str(scene_index) + '_Button' 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_triggered_to_play_value(2) #clip_slot.set_triggered_to_record_value(4) clip_slot.set_stopped_value(0) clip_slot.set_started_value(64) #clip_slot.set_recording_value(3) clip_slot.set_launch_button(button) matrix.add_row(tuple(button_row)) #self._session.set_slot_launch_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 67)) session.selected_scene().name = 'Selected_Scene' #session.selected_scene().set_launch_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 64)) #session_zoom = SessionZoomingComponent(session) #session_zoom.name = 'Session_Overview' #session_zoom.set_button_matrix(matrix) #session_zoom.set_zoom_button(self._shift_button) #session_zoom.set_nav_buttons(up_button, down_button, left_button, right_button) #session_zoom.set_scene_bank_buttons(tuple(scene_launch_buttons)) #session_zoom.set_stopped_value(0) #session_zoom.set_selected_value(127) session.set_mixer(mixer) return None #return session