def _setup_mixer_control(self): is_momentary = True """ Instantiate a Mixer Component """ global mixer # We want to instantiate the global mixer as a MixerComponent object (it was a global "None" type up until now...) mixer = MixerComponent(mixer_num_tracks, 2, with_eqs=True, with_filters=True) # (num_tracks, num_returns, with_eqs, with_filters) mixer.set_track_offset(0) # Sets start point for mixer strip (offset from left) self.song().view.selected_track = mixer.channel_strip(0)._track # set the selected strip to the first track, so that we don't, for example, try to assign a button to arm the master track, which would cause an assertion error """ Buttons and Sliders association """ # Master channel mixer.master_strip().set_volume_control(SliderElement(MIDI_CC_TYPE, midi_channel, midi_mixer_volume_master)) # sets the continuous controller for volume # Other channels, same size as mixer_num_tracks # Set volume control, solo and mute buttons for index in range(mixer_num_tracks): # launch_button assignment must match number of scenes mixer.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, midi_channel, midi_mixer_volume_channels[index])) # sets the continuous controller for volume mixer.channel_strip(index).set_solo_button(ButtonElement(is_momentary, MIDI_CC_TYPE, midi_channel, midi_mixer_solo_channels[index])) # sets the solo button mixer.channel_strip(index).set_mute_button(ButtonElement(is_momentary, MIDI_CC_TYPE, midi_channel, midi_mixer_mute_channels[index])) # sets the mute ("activate") button """ Buttons to select track """ button_next_track = ButtonElement(is_momentary, MIDI_CC_TYPE, midi_channel, midi_track_select_next) button_previous_track = ButtonElement(is_momentary, MIDI_CC_TYPE, midi_channel, midi_track_select_previous) mixer.set_select_buttons(button_next_track, button_previous_track) """ Listeners """ # When selected track if changed self.song().view.add_selected_track_listener(self.on_track_selected)
def _setup_mixer_control(self): is_momentary = True # We use non-latching buttons (keys) throughout, so we'll set this as a constant num_tracks = 7 # Here we define the mixer width in tracks (a mixer has only one dimension) global mixer # We want to instantiate the global mixer as a MixerComponent object (it was a global "None" type up until now...) mixer = MixerComponent(num_tracks, 0, with_eqs=False, with_filters=False) #(num_tracks, num_returns, with_eqs, with_filters) mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left) """set up the mixer buttons""" self.song().view.selected_track = mixer.channel_strip(0)._track mixer.selected_strip().set_mute_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 64)) #mixer.selected_strip().set_solo_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 44)) mixer.selected_strip().set_arm_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 72)) track_select_notes = [65, 73, 66, 74, 67, 75, 68, 76] #more note numbers need to be added if num_scenes is increased slider_select_notes = [3, 2, 1, 0, 5, 4, 6, 7] #pan_select_notes = [21, 20, 13, 12, 3, 1, 0, 2] master_volume_control = SliderElement(MIDI_CC_TYPE, 0, 7) #master_select_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 76) #prehear_control = EncoderElement(MIDI_CC_TYPE, 0, 26, Live.MidiMap.MapMode.absolute) #crossfader = SliderElement(MIDI_CC_TYPE, 0, 24) for index in range(num_tracks): #mixer.channel_strip(index).set_select_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, track_select_notes[index])) mixer.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL, slider_select_notes[index])) #mixer.channel_strip(index).set_pan_control(EncoderElement(MIDI_CC_TYPE, CHANNEL, pan_select_notes[index], Live.MidiMap.MapMode.absolute)) #crossfader.name = 'Crossfader' master_volume_control.name = 'Master_Volume_Control' #master_select_button.name = 'Master_Select_Button' #prehear_control.name = 'Prehear_Volume_Control' #mixer.set_crossfader_control(crossfader) #mixer.set_prehear_volume_control(prehear_control) mixer.master_strip().set_volume_control(master_volume_control)
def _setup_mixer_control(self): is_momentary = True # We use non-latching buttons (keys) throughout, so we'll set this as a constant num_tracks = 7 # Here we define the mixer width in tracks (a mixer has only one dimension) global mixer # We want to instantiate the global mixer as a MixerComponent object (it was a global "None" type up until now...) mixer = MixerComponent(num_tracks, 0) #(num_tracks, num_returns, with_eqs, with_filters) mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left) """set up the mixer buttons""" self.song().view.selected_track = mixer.channel_strip(0)._track mixer.selected_strip().set_mute_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 64)) #mixer.selected_strip().set_solo_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 44)) mixer.selected_strip().set_arm_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 72)) track_select_notes = [65, 73, 66, 74, 67, 75, 68, 76] #more note numbers need to be added if num_scenes is increased slider_select_notes = [3, 2, 1, 0, 5, 4, 6, 7] #pan_select_notes = [21, 20, 13, 12, 3, 1, 0, 2] master_volume_control = SliderElement(MIDI_CC_TYPE, 0, 7) #master_select_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 76) #prehear_control = EncoderElement(MIDI_CC_TYPE, 0, 26, Live.MidiMap.MapMode.absolute) #crossfader = SliderElement(MIDI_CC_TYPE, 0, 24) for index in range(num_tracks): #mixer.channel_strip(index).set_select_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, track_select_notes[index])) mixer.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL, slider_select_notes[index])) #mixer.channel_strip(index).set_pan_control(EncoderElement(MIDI_CC_TYPE, CHANNEL, pan_select_notes[index], Live.MidiMap.MapMode.absolute)) #crossfader.name = 'Crossfader' master_volume_control.name = 'Master_Volume_Control' #master_select_button.name = 'Master_Select_Button' #prehear_control.name = 'Prehear_Volume_Control' #mixer.set_crossfader_control(crossfader) #mixer.set_prehear_volume_control(prehear_control) mixer.master_strip().set_volume_control(master_volume_control)
def _create_mixer_control(self): is_momentary = True num_tracks = 7 """Here we set up the global mixer""" global mixer mixer = MixerComponent(name='Mixer', num_tracks=num_tracks, is_enabled=False, num_returns=2) mixer.set_enabled(True) mixer.set_track_offset(0) self.song().view.selected_track = mixer.channel_strip(0)._track mixer.channel_strip(0) """set up the mixer buttons""" mixer.set_select_buttons( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 56), ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 54)) mixer.master_strip().set_select_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 94)) mixer.selected_strip().set_mute_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 42)) mixer.selected_strip().set_solo_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 44)) mixer.selected_strip().set_arm_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 46)) """set up the mixer sliders""" mixer.selected_strip().set_volume_control( SliderElement(MIDI_CC_TYPE, CHANNEL, 14)) """note that we have split the mixer functions across two scripts, in order to have two session highlight boxes (one red, one yellow), so there are a few things which we are not doing here... """ self.log_message("Captain's log stardate 2")
class Alias8(ControlSurface): num_tracks = 8 knobs_top = [1, 2, 3, 4, 5, 6, 7, 8] knobs_bottom = [9, 10, 11, 12, 13, 14, 15, 16] faders = [17, 18, 19, 20, 21, 22, 23, 24] master_fader = 25 encoder = 42 buttons_top = [0, 1, 2, 3, 4, 5, 6, 7] buttons_bottom = [8, 9, 10, 11, 12, 13, 14, 15] def __init__(self, instance): super(Alias8, self).__init__(instance, False) with self.component_guard(): self._set_suppress_rebuild_requests(True) self.init_session() self.init_mixer() # Connect mixer to session. self.session.set_mixer(self.mixer) self.session.update() # New in Live 9: must explicitly activate session component. self.set_highlighting_session_component(self.session) self._set_suppress_rebuild_requests(False) def init_session(self): self.session = SessionComponent(self.num_tracks, 1) self.session.name = 'Alias 8 Session' self.session.update() # Connect the encoder to track scroller. def scroll_cb(value): if value == 1: self.session._horizontal_banking.scroll_down() elif value == 127: self.session._horizontal_banking.scroll_up() self.track_encoder = EncoderElement(MIDI_CC_TYPE, 0, self.encoder, Live.MidiMap.MapMode.absolute) self.track_encoder.add_value_listener(scroll_cb) def init_mixer(self): self.mixer = MixerComponent(self.num_tracks, 0) self.mixer.id = 'Mixer' self.song().view.selected_track = self.mixer.channel_strip(0)._track for i in range(self.num_tracks): self.mixer.channel_strip(i).set_volume_control( fader(self.faders[i])) self.mixer.channel_strip(i).set_solo_button( button(self.buttons_top[i], color=CYAN)) self.mixer.channel_strip(i).set_arm_button( button(self.buttons_bottom[i], color=RED)) self.mixer.channel_strip(i).set_pan_control( knob(self.knobs_bottom[i])) self.mixer.master_strip().set_volume_control(fader(self.master_fader)) self.mixer.update()
def _setup_mixer_control(self): is_momentary = True num_tracks = 7 #A mixer is one-dimensional; here we define the width in tracks - seven columns, which we will map to seven "white" notes """Here we set up the global mixer""" #Note that it is possible to have more than one mixer... global mixer #We want to instantiate the global mixer as a MixerComponent object (it was a global "None" type up until now...) mixer = MixerComponent( num_tracks, 2, with_eqs=True, with_filters=True ) #(num_tracks, num_returns, with_eqs, with_filters) mixer.set_track_offset( 0) #Sets start point for mixer strip (offset from left) self.song().view.selected_track = mixer.channel_strip( 0 )._track #set the selected strip to the first track, so that we don't, for example, try to assign a button to arm the master track, which would cause an assertion error """set up the mixer buttons""" mixer.set_select_buttons( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 56), ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 54)) #left, right track select mixer.master_strip().set_select_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 94)) #jump to the master track mixer.selected_strip().set_mute_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 42)) #sets the mute ("activate") button mixer.selected_strip().set_solo_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 44)) #sets the solo button mixer.selected_strip().set_arm_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 46)) #sets the record arm button """set up the mixer sliders""" mixer.selected_strip().set_volume_control( SliderElement(MIDI_CC_TYPE, CHANNEL, 14)) #sets the continuous controller for volume """note that we have split the mixer functions across two scripts, in order to have two session highlight boxes (one red, one yellow), so there are a few things which we are not doing here..."""
def _setup_mixer_control(self): is_momentary = True num_tracks = 8 num_returns = 7 mixer = MixerComponent(num_tracks, num_returns) for track in range(num_tracks): strip = mixer.channel_strip(track) strip.set_volume_control( SliderElement(MIDI_CC_TYPE, 15, 54 - track)) strip.set_pan_control(SliderElement(MIDI_CC_TYPE, 15, 80 - track)) strip.set_mute_button( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 117 - track)) strip.set_invert_mute_feedback(True) for track in range(num_returns): strip = mixer.return_strip(track) strip.set_volume_control( SliderElement(MIDI_CC_TYPE, 15, 10 + track)) mixer.set_bank_buttons( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 108), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 109)) mixer.set_crossfader_control(SliderElement(MIDI_CC_TYPE, 15, 9)) mixer.master_strip().set_volume_control( SliderElement(MIDI_CC_TYPE, 15, 46)) session = SessionComponent(0, 0) session.set_select_buttons( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 95), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 92)) session.selected_scene().set_launch_button( ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 91))
def _setup_mixer_control(self): is_momentary = True mixer = MixerComponent(NUM_TRACKS, 2, with_eqs=True, with_filters=True) for track in range(NUM_TRACKS): strip = mixer.channel_strip(track) strip.set_volume_control(SliderElement(MIDI_CC_TYPE, track, 23)) strip.set_pan_control(EncoderElement(MIDI_CC_TYPE, track, 10, Live.MidiMap.MapMode.absolute)) strip.set_send_controls((EncoderElement(MIDI_CC_TYPE, track, 19, Live.MidiMap.MapMode.absolute), EncoderElement(MIDI_CC_TYPE, track, 20, Live.MidiMap.MapMode.absolute))) strip.set_solo_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, track, 64)) strip.set_mute_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, track, 63)) strip.set_crossfade_toggle(ButtonElement(is_momentary, MIDI_NOTE_TYPE, track, 65)) eq = mixer.track_eq(track) eq.set_gain_controls(tuple([ EncoderElement(MIDI_CC_TYPE, track, (18 - index), Live.MidiMap.MapMode.absolute) for index in range(3) ])) eq.set_cut_buttons(tuple([ ButtonElement(is_momentary, MIDI_NOTE_TYPE, track, (62 - index)) for index in range(3) ])) filter = mixer.track_filter(track) filter.set_filter_controls(EncoderElement(MIDI_CC_TYPE, track, 22, Live.MidiMap.MapMode.absolute), EncoderElement(MIDI_CC_TYPE, track, 21, Live.MidiMap.MapMode.absolute)) for ret_track in range(2): strip = mixer.return_strip(ret_track) strip.set_volume_control(SliderElement(MIDI_CC_TYPE, 12, (22 + ret_track))) strip.set_pan_control(EncoderElement(MIDI_CC_TYPE, 12, (20 + ret_track), Live.MidiMap.MapMode.absolute)) strip.set_mute_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, 12, (78 + ret_track))) mixer.set_crossfader_control(SliderElement(MIDI_CC_TYPE, 12, 8)) mixer.set_prehear_volume_control(EncoderElement(MIDI_CC_TYPE, 12, 24, Live.MidiMap.MapMode.absolute)) mixer.master_strip().set_volume_control(SliderElement(MIDI_CC_TYPE, 12, 7)) mixer.master_strip().set_pan_control(EncoderElement(MIDI_CC_TYPE, 12, 10, Live.MidiMap.MapMode.absolute)) return mixer
def _setup_mixer_control(self): is_momentary = True mixer = MixerComponent(NUM_TRACKS, 2, with_eqs=True, with_filters=True) for track in range(NUM_TRACKS): strip = mixer.channel_strip(track) strip.set_volume_control(SliderElement(MIDI_CC_TYPE, track, 23)) strip.set_pan_control( EncoderElement(MIDI_CC_TYPE, track, 10, Live.MidiMap.MapMode.absolute)) strip.set_send_controls( (EncoderElement(MIDI_CC_TYPE, track, 19, Live.MidiMap.MapMode.absolute), EncoderElement(MIDI_CC_TYPE, track, 20, Live.MidiMap.MapMode.absolute))) strip.set_solo_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, track, 64)) strip.set_mute_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, track, 63)) strip.set_crossfade_toggle( ButtonElement(is_momentary, MIDI_NOTE_TYPE, track, 65)) eq = mixer.track_eq(track) eq.set_gain_controls( tuple([ EncoderElement(MIDI_CC_TYPE, track, 18 - index, Live.MidiMap.MapMode.absolute) for index in range(3) ])) eq.set_cut_buttons( tuple([ ButtonElement(is_momentary, MIDI_NOTE_TYPE, track, 62 - index) for index in range(3) ])) filter = mixer.track_filter(track) filter.set_filter_controls( EncoderElement(MIDI_CC_TYPE, track, 22, Live.MidiMap.MapMode.absolute), EncoderElement(MIDI_CC_TYPE, track, 21, Live.MidiMap.MapMode.absolute)) for ret_track in range(2): strip = mixer.return_strip(ret_track) strip.set_volume_control( SliderElement(MIDI_CC_TYPE, 12, 22 + ret_track)) strip.set_pan_control( EncoderElement(MIDI_CC_TYPE, 12, 20 + ret_track, Live.MidiMap.MapMode.absolute)) strip.set_mute_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, 12, 78 + ret_track)) mixer.set_crossfader_control(SliderElement(MIDI_CC_TYPE, 12, 8)) mixer.set_prehear_volume_control( EncoderElement(MIDI_CC_TYPE, 12, 24, Live.MidiMap.MapMode.absolute)) mixer.master_strip().set_volume_control( SliderElement(MIDI_CC_TYPE, 12, 7)) mixer.master_strip().set_pan_control( EncoderElement(MIDI_CC_TYPE, 12, 10, Live.MidiMap.MapMode.absolute)) return mixer
def _setup_mixer_control(self): is_momentary = True self._num_tracks = (COLS) global mixer mixer = MixerComponent(COLS, 0, True, True) mixer.name = 'Mixer' self._mixer = mixer mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left) for index in range(COLS): #use the bottom row of encoders for volume, so add 24 to offset the index mixer.channel_strip(index).set_volume_control(self._dial[index+24]) for index in range(COLS): mixer.channel_strip(index).name = 'Mixer_ChannelStrip_' + str(index) mixer.track_eq(index).name = 'Mixer_EQ_' + str(index) mixer.track_filter(index).name = 'Mixer_Filter_' + str(index) #added by a mixer.channel_strip(index)._invert_mute_feedback = True #mixer.channel_strip(index).set_select_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CH, track_select_notes[index])) self.song().view.selected_track = mixer.channel_strip(0)._track #set the selected strip to the first track, so that we don't, for example, try to assign a button to arm the master track, which would cause an assertion error
def _setup_mixer_control(self): is_momentary = True # We use non-latching buttons (keys) throughout, so we'll set this as a constant num_tracks = 4 # Here we define the mixer width in tracks (a mixer has only one dimension) global mixer # We want to instantiate the global mixer as a MixerComponent object (it was a global "None" type up until now...) mixer = MixerComponent(num_tracks, 2, with_eqs=True, with_filters=False) #(num_tracks, num_returns, with_eqs, with_filters) mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left) """set up the mixer buttons""" self.song().view.selected_track = mixer.channel_strip(0)._track #mute_notes = [1,5,9,13] #solo_notes = [2,6,10,14] #arm_notes = [3,7,11,15] track_select_notes = [38,39,40,41]#more note numbers need to be added if num_scenes is increased send_ccs = [2,6,10,14,1,5,9,13] pan_ccs = [3,7,11,15] slider_ccs = [4,8,12,16] for index in range(num_tracks): mixer.channel_strip(index).set_select_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHAN, track_select_notes[index])) mixer.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, CHAN, slider_ccs[index])) mixer.channel_strip(index).set_pan_control(EncoderElement(MIDI_CC_TYPE, CHAN, pan_ccs[index], Live.MidiMap.MapMode.absolute)) #put send A and send B controllers into an array, which is then "tupled" for set_send_controls: send_controlers = [EncoderElement(MIDI_CC_TYPE, CHAN, send_ccs[index], Live.MidiMap.MapMode.absolute), EncoderElement(MIDI_CC_TYPE, CHAN, send_ccs[index+num_tracks], Live.MidiMap.MapMode.absolute)] mixer.channel_strip(index).set_send_controls(tuple(send_controlers)) crossfader = SliderElement(MIDI_CC_TYPE, CHAN, 28) master_volume_control = SliderElement(MIDI_CC_TYPE, CHAN, 32) returna_pan_control = SliderElement(MIDI_CC_TYPE, CHAN, 19) returna_volume_control = SliderElement(MIDI_CC_TYPE, CHAN, 20) returnb_pan_control = SliderElement(MIDI_CC_TYPE, CHAN, 23) returnb_volume_control = SliderElement(MIDI_CC_TYPE, CHAN, 24) master_select_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHAN, 31) prehear_control = EncoderElement(MIDI_CC_TYPE, CHAN, 30, Live.MidiMap.MapMode.absolute) crossfader.name = 'Crossfader' master_volume_control.name = 'Master_Volume_Control' returna_pan_control.name = 'ReturnA_Pan_Control' returna_volume_control.name = 'ReturnA_Volume_Control' returnb_pan_control.name = 'ReturnB_Pan_Control' returnb_volume_control.name = 'ReturnB_Volume_Control' master_select_button.name = 'Master_Select_Button' prehear_control.name = 'Prehear_Volume_Control' mixer.set_crossfader_control(crossfader) mixer.master_strip().set_volume_control(master_volume_control) mixer.master_strip().set_select_button(master_select_button) mixer.set_prehear_volume_control(prehear_control) mixer.return_strip(0).set_pan_control(returna_pan_control) mixer.return_strip(0).set_volume_control(returna_volume_control) mixer.return_strip(1).set_pan_control(returnb_pan_control) mixer.return_strip(1).set_volume_control(returnb_volume_control)
def _init_mixer_component(self): is_momentary = True global mixer mixer = MixerComponent(8) mixer.name = 'Mixer' mixer.set_track_offset(0) self.song().view.selected_track = mixer.channel_strip(0)._track for track in range(8): #self.log_message("Adding track " + str(track)) strip = mixer.channel_strip(track) strip.name = 'Channel_Strip_' + str(track) volume_control = SliderElement(MIDI_CC_TYPE, track, VOL_CC) snd_A_control = SliderElement(MIDI_CC_TYPE, track, SND_A_CC) snd_B_control = SliderElement(MIDI_CC_TYPE, track, SND_B_CC) pan_control = SliderElement(MIDI_CC_TYPE, track, PAN_CC) arm_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, track, ARM_CC) select_button = ButtonElement(is_momentary, MIDI_CC_TYPE, track, SEL_CC) mute_button = ButtonElement(not is_momentary, MIDI_CC_TYPE, track, MUTE_CC) volume_control.name = str(track) + '_Volume_Control' snd_A_control.name = str(track) + '_Send_A_Control' snd_B_control.name = str(track) + '_Send_B_Control' pan_control.name = str(track) + '_Pan_Control' arm_button.name = str(track) + '_arm_Button' select_button.name = str(track) + '_Select_Button' mute_button.name = str(track) + '_Mute_Button' strip.set_volume_control(volume_control) strip.set_send_controls([snd_A_control, snd_B_control]) strip.set_pan_control(pan_control) strip.set_arm_button(arm_button) strip.set_select_button(select_button) strip.set_mute_button(mute_button) return mixer
def _setup_mixer_control(self): is_momentary = True # We use non-latching buttons (keys) throughout, so we'll set this as a constant num_tracks = 8 # Here we define the mixer width in tracks (a mixer has only one dimension) global mixer # We want to instantiate the global mixer as a MixerComponent object (it was a global "None" type up until now...) mixer = MixerComponent( num_tracks, 0, with_eqs=False, with_filters=False ) #(num_tracks, num_returns, with_eqs, with_filters) mixer.set_track_offset( 0) #Sets start point for mixer strip (offset from left) """set up the mixer buttons""" self.song().view.selected_track = mixer.channel_strip(0)._track master_volume_control = SliderElement(MIDI_CC_TYPE, CHANNEL, 9) for index in range(num_tracks): mixer.channel_strip(index).set_mute_button( ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, (index + 19))) mixer.channel_strip(index).set_volume_control( SliderElement(MIDI_CC_TYPE, CHANNEL, (index + 1))) #mixer.channel_strip(index).set_pan_control(EncoderElement(MIDI_CC_TYPE, CHANNEL, (index+10), Live.MidiMap.MapMode.absolute)) master_volume_control.name = 'Master_Volume_Control' mixer.master_strip().set_volume_control(master_volume_control)
def _MG_setup(self): mixer = MixerComponent(8) mixer.set_track_offset( 0) #Sets start point for mixer strip (offset from left) transport = TransportComponent() mixer.set_track_offset(0) for i in xrange(len(KNOBS)): #set the functions of the knobs volume_knob = SliderElement(MIDI_CC_TYPE, 0, KNOBS[i]) pan_knob = SliderElement(MIDI_CC_TYPE, 1, KNOBS[i]) send_a = SliderElement(MIDI_CC_TYPE, 2, KNOBS[i]) send_b = SliderElement(MIDI_CC_TYPE, 3, KNOBS[i]) send_c = SliderElement(MIDI_CC_TYPE, 4, KNOBS[i]) send_d = SliderElement(MIDI_CC_TYPE, 5, KNOBS[i]) send_e = SliderElement(MIDI_CC_TYPE, 6, KNOBS[i]) send_f = SliderElement(MIDI_CC_TYPE, 7, KNOBS[i]) mixer.channel_strip(i).set_volume_control(volume_knob) mixer.channel_strip(i).set_pan_control(pan_knob) mixer.channel_strip(i).set_send_controls( [send_a, send_b, send_c, send_d, send_e, send_f]) # scenes are locked to channel 14 transport.set_overdub_button( ButtonElement(False, MIDI_CC_TYPE, 0, SCENES[0])) transport.set_stop_button( ButtonElement(False, MIDI_CC_TYPE, 0, SCENES[1]))
class FDRbox(ControlSurface): def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self._suggested_input_port = 'FDRbox' self._suggested_output_port = 'FDRbox' # ButtonElement( is_momentary, msg_type, channel, identifier ) faders = [ ButtonElement(False, MIDI_CC_TYPE, MIDI_CHANNEL, i) for i in range(8) ] self._mixer = MixerComponent(8) for i in range(8): self._mixer.channel_strip(i).set_volume_control(faders[i]) # self.log_message( 'init' ) def disconnect(self): ControlSurface.disconnect(self) self._mixer = None
def setup_mixer(self): global mixer mixer = MixerComponent(2, 2) mixer.set_track_offset(0) self.song().view.selected_track = mixer.channel_strip( 0 )._track # set the selected strip to the first track, so that we don't, for example, try to assign a button to arm the master track, which would cause an assertion error send_a = EncoderElement(MIDI_CC_TYPE, CHANNEL, SEND_A, mode_absolute) send_b = EncoderElement(MIDI_CC_TYPE, CHANNEL, SEND_B, mode_absolute) send_c = EncoderElement(MIDI_CC_TYPE, CHANNEL, SEND_C, mode_absolute) send_d = EncoderElement(MIDI_CC_TYPE, CHANNEL, SEND_D, mode_absolute) pan = EncoderElement(MIDI_CC_TYPE, CHANNEL, PAN, mode_absolute) mixer.selected_strip().set_send_controls( [send_a, send_b, send_c, send_d]) mixer.selected_strip().set_pan_control(pan)
def _setup_mixer_control(self): is_momentary = True self._num_tracks = (COLS) global mixer mixer = MixerComponent(COLS, 0, True, True) mixer.name = 'Mixer' self._mixer = mixer mixer.set_track_offset( 0) #Sets start point for mixer strip (offset from left) for index in range(COLS): #use the bottom row of encoders for volume, so add 24 to offset the index mixer.channel_strip(index).set_volume_control(self._dial[index + 24]) for index in range(COLS): mixer.channel_strip( index).name = 'Mixer_ChannelStrip_' + str(index) mixer.track_eq(index).name = 'Mixer_EQ_' + str(index) mixer.track_filter(index).name = 'Mixer_Filter_' + str( index) #added by a mixer.channel_strip(index)._invert_mute_feedback = True #mixer.channel_strip(index).set_select_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CH, track_select_notes[index])) self.song().view.selected_track = mixer.channel_strip( 0 )._track #set the selected strip to the first track, so that we don't, for example, try to assign a button to arm the master track, which would cause an assertion error
class midilooper(ControlSurface): def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self._instance = c_instance self._has_slider_section = True self.log_message("Midilooper initializing...") # register_sender(self) self._session = SessionComponent(NUM_TRACKS, NUM_ROWS) self._session.name = 'Session_Control' self._mixer = MixerComponent(NUM_TRACKS, NUM_RETURNS) for track in range(NUM_TRACKS): strip = self._mixer.channel_strip(track) strip.name = 'Channel_Strip_' + str(track) # encoder = EncoderElement(MIDI_CC_TYPE, 0, 20 + track, Live.MidiMap.MapMode.absolute) control = SliderElement(MIDI_CC_TYPE, 0, 20+track) control.name = str(track) + '_Volume_Control' strip.set_volume_control(control) for track in range(NUM_RETURNS): strip = self._mixer.return_strip(track) control = SliderElement(MIDI_CC_TYPE, 0, 40+track) control.name = str(track) + '_Return_Control' strip.set_volume_control(control) strip = self._mixer.master_strip() strip.name = 'Master_Channel_Strip' control = SliderElement(MIDI_CC_TYPE, 0, 50) control.name = 'Master_Volume_Control' strip.set_volume_control(control) self._session.set_offsets(0, 0); self._session.set_mixer(self._mixer) for row in range(NUM_ROWS): scene = self._session.scene(row) for track in range(NUM_TRACKS): slot = scene.clip_slot(track) button = ButtonElement(True, MIDI_NOTE_TYPE, track, 36+row) slot.set_launch_button(button) self.set_highlighting_session_component(self._session) self.request_rebuild_midi_map() self.log_message("Midilooper initialized.") def disconnect(self): ControlSurface.disconnect(self)
def _setup_mixer_control(self): is_momentary = True num_tracks = 8 num_returns = 7 mixer = MixerComponent(num_tracks, num_returns) for track in range(num_tracks): strip = mixer.channel_strip(track) strip.set_volume_control(SliderElement(MIDI_CC_TYPE, 15, 54 - track)) strip.set_pan_control(SliderElement(MIDI_CC_TYPE, 15, 80 - track)) strip.set_mute_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 117 - track)) strip.set_invert_mute_feedback(True) for track in range(num_returns): strip = mixer.return_strip(track) strip.set_volume_control(SliderElement(MIDI_CC_TYPE, 15, 10 + track)) mixer.set_bank_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 108), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 109)) mixer.set_crossfader_control(SliderElement(MIDI_CC_TYPE, 15, 9)) mixer.master_strip().set_volume_control(SliderElement(MIDI_CC_TYPE, 15, 46)) session = SessionComponent(0, 0) session.set_select_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 95), ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 92)) session.selected_scene().set_launch_button(ButtonElement(is_momentary, MIDI_CC_TYPE, 15, 91))
def _setup_mixer_control(self): num_tracks = 7 global mixer mixer = MixerComponent(num_tracks) mixer.set_track_offset(0) self.song().view.selected_track = mixer.channel_strip(0)._track master_volume_fader = SliderElement(MIDI_CC_TYPE, CHANNEL, MASTER_FADER) mixer.master_strip().set_volume_control(master_volume_fader) for index in range(num_tracks): mixer.channel_strip(index).set_volume_control( SliderElement(MIDI_CC_TYPE, CHANNEL, FADERS[index])) mixer.channel_strip(index).set_mute_button( ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, TRACK_MUTE_BUTTONS[index])) mixer.channel_strip(index).set_select_button( ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, TRACK_SELECT_BUTTONS[index])) #mixer.channel_strip(index).set_send_controls(SliderElement(MIDI_CC_TYPE, CHANNEL, SEND_KNOBS[index])) '''for index in range(6):
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 KeyPad(ControlSurface): """ Reloop KeyPad controller script. """ _encoder_range = range(73, 81) _product_model_id = 101 def __init__(self, c_instance): super(KeyPad, self).__init__(c_instance) with self.component_guard(): self._create_controls() self._setup_mixer() self._setup_transport() self._setup_session() self._setup_cue_control() self.set_pad_translations(PAD_TRANSLATIONS) def _preset_message(self, send_byte): """ Sysex message for setting the preset to #2. """ return (240, 38, self._product_model_id, send_byte, 17, 2, 247) def refresh_state(self): super(KeyPad, self).refresh_state() self.schedule_message(2, self._send_midi, self._preset_message(1)) def handle_sysex(self, midi_bytes): if midi_bytes != self._preset_message(2): super(KeyPad, self).handle_sysex(midi_bytes) else: map(lambda x: x.set_enabled(True), (self._mixer, self._session, self._transport, self._cue_control)) def _create_controls(self): def make_controls_range(maker, label, cc_range): ccs = [ (index + 1, cc) for index, cc in enumerate(cc_range) ] return [ maker(1, cc, label % index) for index, cc in ccs ] + [ maker(2, cc, label % (index + len(ccs))) for index, cc in ccs ] def make_controls(maker, label, cc_offset): return make_controls_range(maker, label, xrange(cc_offset, cc_offset + 8)) make_non_momentary_button = partial(make_button, is_momentary=False) self._encoders = make_controls(make_encoder, 'Encoder_%d', 57) self._rotaries_a = make_controls(make_slider, 'Rotary_A%d', 89) self._rotaries_b = make_controls(make_slider, 'Rotary_B%d', 97) self._faders = make_controls(make_slider, 'Fader_%d', 0) self._mute_buttons = make_controls(make_non_momentary_button, 'Mute_%d_Button', 8) self._solo_buttons = make_controls(make_button, 'Solo_%d_Button', 24) self._arm_buttons = make_controls(make_button, 'Arm_%d_Button', 40) self._play_button = make_button(1, 105, 'Play_Button') self._stop_button = make_button(1, 106, 'Stop_Button') self._record_button = make_button(1, 107, 'Record_Button') self._encoder_pushes = make_controls_range(partial(make_button, is_momentary=False), 'Encoder_%d_Button', self._encoder_range) self._shifted_mute_buttons = make_controls(make_non_momentary_button, 'Shifted_Mute_%d_Button', 16) self._shifted_solo_buttons = make_controls(make_button, 'Shifted_Solo_%d_Button', 32) self._all_shifted_arm_buttons = make_controls(make_button, 'Shifted_Arm_%d_Button', 49) self._shifted_arm_buttons = [ CombinedButtonsElement(buttons=(self._all_shifted_arm_buttons[index], self._all_shifted_arm_buttons[index + 8])) for index in xrange(8) ] self._shifted_play_button = make_button(1, 108, 'Shifted_Play_Button') self._shifted_stop_button = make_button(1, 109, 'Shifted_Stop_Button') self._shifted_record_button = make_button(1, 110, 'Shifted_Record_Button') self._shifted_octave_down_button = make_button(1, 111, 'Shifted_Octave_Down_Button') self._shifted_octave_up_button = make_button(1, 112, 'Shifted_Octave_Up_Button') def _setup_mixer(self): self._mixer = MixerComponent(NUM_CHANNEL_STRIPS) self._mixer.name = 'Mixer' self._mixer.set_enabled(False) for index in xrange(NUM_CHANNEL_STRIPS): strip = self._mixer.channel_strip(index) strip.set_invert_mute_feedback(True) sends = ButtonMatrixElement(name='%d_Send_Controls' % (index + 1), rows=[(self._rotaries_a[index], self._rotaries_b[index])]) strip.layer = Layer(volume_control=self._faders[index], pan_control=self._encoders[index], send_controls=sends, mute_button=self._mute_buttons[index], solo_button=self._solo_buttons[index], arm_button=self._arm_buttons[index], select_button=self._encoder_pushes[index]) def _setup_transport(self): self._transport = TransportComponent(name='Transport') self._transport.set_enabled(False) self._transport.layer = Layer(play_button=self._play_button, stop_button=self._stop_button, record_button=self._record_button, overdub_button=self._shifted_record_button, loop_button=self._shifted_arm_buttons[3], tap_tempo_button=self._shifted_arm_buttons[4], metronome_button=self._shifted_arm_buttons[5], nudge_down_button=self._shifted_arm_buttons[6], nudge_up_button=self._shifted_arm_buttons[7]) def _setup_session(self): self._session = SessionComponent(NUM_CHANNEL_STRIPS, name='Session_Control') self._session.set_enabled(False) stop_buttons = ButtonMatrixElement(name='Track_Stop_Buttons', rows=[self._shifted_solo_buttons]) self._session.layer = Layer(stop_all_clips_button=self._shifted_stop_button, stop_track_clip_buttons=stop_buttons, select_prev_button=self._shifted_octave_down_button, select_next_button=self._shifted_octave_up_button) self._session.selected_scene().name = 'Selected_Scene_Control' self._session.selected_scene().layer = Layer(launch_button=self._shifted_play_button) for index in xrange(NUM_CHANNEL_STRIPS): slot = self._session.selected_scene().clip_slot(index) slot.layer = Layer(launch_button=self._shifted_mute_buttons[index]) def _setup_cue_control(self): self._cue_control = CuePointControlComponent(name='Cue_Point_Control') self._cue_control.set_enabled(False) self._cue_control.layer = Layer(toggle_cue_button=self._shifted_arm_buttons[0], prev_cue_button=self._shifted_arm_buttons[1], next_cue_button=self._shifted_arm_buttons[2])
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 QuNexus_Basic(ControlSurface): __module__ = __name__ __doc__ = "QuNexus Keyboard controller script" def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self._setup_mixer_control() self._setup_session_control() self._setup_device_control() self._setup_transport_control() self.set_highlighting_session_component(self.session) def _setup_transport_control(self): self._transport = TransportComponent() self._transport.set_stop_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 68)) self._transport.set_record_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 66)) self._transport.set_play_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 70)) def _setup_session_control(self): num_tracks = 1 #one column (track) num_scenes = 8 #eight rows, which will be mapped to eight "white" notes #(num_tracks, num_scenes) a session highlight ("red box") will appear with any two non-zero values self.session = QuNexusSessionComponent(num_tracks, num_scenes) #(track_offset, scene_offset) Sets the initial offset of the "red box" from top left self.session.set_offsets(0, 0) self.session.set_select_buttons( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 63), ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 61)) self.session.set_scene_bank_buttons( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 51), ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 49)) self.session.set_track_bank_buttons( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 56), ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 54)) self.session.selected_scene().set_launch_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 62)) self.session.set_stop_all_clips_button( ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 58)) for row in range(num_scenes): for col in range(num_tracks): self.session.scene(row).clip_slot(col).set_started_value(127) self.session.scene(row).clip_slot(col).set_stopped_value(0) #here we set up the clip launch assignments for the session clip_launch_notes = [48, 50, 52, 53, 55, 57, 59, 60] #set of eight white notes starting at C3/C4 for index in range(num_scenes): #step though scenes and assign a note to first slot of each self.session.scene(index).clip_slot(0).set_started_value(127) self.session.scene(index).clip_slot(0).set_stopped_value(3) self.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.session.set_mixer( self.mixer ) #bind the mixer to the session so that they move together def _setup_mixer_control(self): #A mixer is one-dimensional; here we define the width in tracks num_tracks = 1 #set up the mixer self.mixer = MixerComponent( num_tracks, 2, with_eqs=True, with_filters=True ) #(num_tracks, num_returns, with_eqs, with_filters) self.mixer.set_track_offset( 0) #sets start point for mixer strip (offset from left) #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.song().view.selected_track = self.mixer.channel_strip(0)._track def _setup_device_control(self): sliders = [] pressures = [92, 94, 98, 102, 106, 108] for index in range(6): sliders.append( SliderElement(MIDI_CC_TYPE, CHANNEL, pressures[index])) self._sliders = tuple(sliders) device = DeviceComponent() self.set_device_component(device) device.set_parameter_controls(self._sliders) def disconnect(self): #clean things up on disconnect #create entry in log file self.log_message( time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) + "----------QuNexus Basic log closed----------") ControlSurface.disconnect(self) return None
class MaschineMk2(ControlSurface): __module__ = __name__ __doc__ = 'Control Script for Maschine Mk2 and Maschine Mikro Mk2' def __init__(self, c_instance): ControlSurface.__init__(self, c_instance, False) with self.component_guard(): self._suppress_send_midi = True self.togglecolor = (10, 30, 50, 70, 90) self.toggleindex = 0 self._c_ref = c_instance self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143 self._c_inst = c_instance is_momentary = True self._active = True self._modifier_down = False self._return_mode = 0 self._returntopad = False self._mode = CLIP_MODE self.init_slot = 0 self.init_done = False self._midi_pause_count = 0 self.nav_index = 0 self._base_note = 0 self._octave = 0.55 self._scale_select_mode = MODE_PRESS_NONE self.send_slider_index = 0 self._pad_mode = PM_OFF self._note_display_mode = ND_KEYBOARD1 self._set_suppress_rebuild_requests(True) self._scenematrix = SceneMatrix(self) self._master_knob = Mk2KnobControl(self) self._device = self._set_up_device_control() self.show_message(str('')) self.request_rebuild_midi_map() self._set_global_buttons() self._set_mode_buttons() self._setup_transport() self._set_modecontrol() self._set_up_session() self._set_up_mixer() self._set_up_timer() self._set_up_machine_knobs() self.current_scale_index = 0 self.assign_transpose(SCALES[self.current_scale_index]) self.set_highlighting_session_component(self._session) self._navigate_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 127) self._navigate_button.add_value_listener(self._do_focus_navigate) self.display_update_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 86) self.display_update_button.add_value_listener(self._a_display_update) self._set_suppress_rebuild_requests(False) self.song().view.add_detail_clip_listener(self.clip_handle) self.song().add_visible_tracks_listener(self.clip_handle) self.song().add_scenes_listener(self.clip_handle) self.application().view.add_view_focus_changed_listener(self.focus_changed) self.log_message('########## LIVE 9 MASCHINE MK2 V 1.02 #############') self._suppress_send_midi = False def _set_up_mixer(self): is_momentary = True self._mixer = MixerComponent(8) self.send_sliders = [] for track in range(8): self.send_sliders.append(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, SEND_CC_OFF + track)) for track in range(8): strip = self._mixer.channel_strip(track) strip.set_arm_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, ARM_CC_OFF + track)) strip.set_solo_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, SOLO_CC_OFF + track)) strip.set_mute_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, MUTE_CC_OFF + track)) strip.set_volume_control(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, LEVEL_CC_OFF + track)) strip.set_pan_control(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, PAN_CC_OFF + track)) strip.set_select_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, SELECT_CC_OFF + track)) st = tuple([self.send_sliders[track]]) strip.set_send_controls(st) self.send_slider_toggle_button = StateButton(False, MIDI_CC_TYPE, 0, 90) self.send_slider_toggle_button.add_value_listener(self._do_toggle_send) self._session.set_mixer(self._mixer) def _set_global_buttons(self): is_momentary = True self._undo_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 85) self._undo_button.add_value_listener(self._do_undo) self._redo_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 87) self._redo_button.add_value_listener(self._do_redo) self._armsolomode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 89) self._armsolomode_button.add_value_listener(self._do_armsolo_mode) self._fire_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 9) self._fire_button.add_value_listener(self._do_fire_button) self.track_left_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 120) self.track_right_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 121) self.track_left_button.add_value_listener(self._a_trk_left) self.track_right_button.add_value_listener(self._a_trk_right) self.test_button = StateButton(True, MIDI_CC_TYPE, 5, 60) self.note_repeat_button = StateButton(True, MIDI_CC_TYPE, 5, 61) self.test_button.add_value_listener(self.do_test) self.note_repeat_button.add_value_listener(self.do_note_repeat) self.reset_test_button = StateButton(True, MIDI_CC_TYPE, 5, 62) self.reset_test_button.add_value_listener(self.do_reset) def _set_mode_buttons(self): self.xfade_assign_button = StateButton(True, MIDI_CC_TYPE, 0, 116) self._pad_select_button = StateButton(False, MIDI_CC_TYPE, 0, 117) self._pad_solo_button = StateButton(False, MIDI_CC_TYPE, 0, 118) self._mute_button = StateButton(False, MIDI_CC_TYPE, 0, 119) self._pad_scale_up = GatedColorButton(True, MIDI_CC_TYPE, 83, 0) self._pad_scale_down = GatedColorButton(True, MIDI_CC_TYPE, 94, 16) self._pad_select_button.add_value_listener(self._do_pad_select_multi) self._mute_button.add_value_listener(self._do_mute_button) self._pad_solo_button.add_value_listener(self._do_pad_solo_multi) self.xfade_assign_button.add_value_listener(self._do_xfade_assign) self._pad_scale_up.add_value_listener(self._do_pad_note_up) self._pad_scale_down.add_value_listener(self._do_pad_note_down) def set_appointed_device(self, device): with self.component_guard(): self._device_component.set_device(device) def _set_up_device_control(self): is_momentary = True device = MaschineDeviceComponent(self) device.set_device_changed_listener(self._handle_device_changed) device.set_device_parm_listener(self._hande_device_parm_changed) param_controls = [] for index in range(8): param_controls.append(SliderElement(MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_CC_OFF + index)) device.set_parameter_controls(tuple(param_controls)) device.set_on_off_button(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF)) device.set_bank_nav_buttons(StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF + 4), ButtonElement(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF + 5)) self._device_nav_button_left = StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF + 6) self._device_nav_button_right = StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, DEVICE_BUTTON_CC_OFF + 7) self._device_nav_button_left.add_value_listener(self._nav_value_left) self._device_nav_button_right.add_value_listener(self._nav_value_right) device.name = 'Device_Component' self.set_device_component(device) return device def _setup_transport(self): is_momentary = True transport = TransportComponent() playButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 108) stopButton = StateButton(not is_momentary, MIDI_CC_TYPE, 0, 110) recordButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 109) overdubButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 107) metrononmeButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 104) playButton.name = 'Play' stopButton.name = 'Stop' recordButton.name = 'Record' overdubButton.name = 'Overdub' metrononmeButton.name = 'Metronome' transport.set_play_button(playButton) transport.set_stop_button(stopButton) transport.set_record_button(recordButton) transport.set_overdub_button(overdubButton) transport.set_metronome_button(metrononmeButton) transport.set_nudge_buttons(StateButton(is_momentary, MIDI_CC_TYPE, 1, 51), StateButton(is_momentary, MIDI_CC_TYPE, 1, 50)) punchinbutton = ToggleButton(MIDI_CC_TYPE, 1, 52) punchoutbutton = ToggleButton(MIDI_CC_TYPE, 1, 53) punchinbutton.name = 'Punch In' punchoutbutton.name = 'Punch Out' transport.set_punch_buttons(punchinbutton, punchoutbutton) transport.set_loop_button(StateButton(is_momentary, MIDI_CC_TYPE, 1, 54)) self.transp_ff_button = ButtonElement(True, MIDI_CC_TYPE, 1, 59) self.transp_rw_button = ButtonElement(True, MIDI_CC_TYPE, 1, 58) transport.set_seek_buttons(self.transp_ff_button, self.transp_rw_button) self.xfadeKnob = SliderElement(MIDI_CC_TYPE, 1, 100) self.xfadeKnob.connect_to(self.song().master_track.mixer_device.crossfader) self.tap_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 88) self.tap_button.add_value_listener(self._do_tap_tempo) self.cue_add_delete_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 55) self.cue_prev_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 56) self.cue_next_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 57) self.cue_add_delete_button.add_value_listener(self._do_toggle_cue) self.cue_prev_button.add_value_listener(self._do_toggle_prev_cue) self.cue_next_button.add_value_listener(self._do_toggle_next_cue) def _set_up_machine_knobs(self): master_track = self.song().master_track self.master_volume = SliderElement(MIDI_CC_TYPE, 0, 40) self.prehear = SliderElement(MIDI_CC_TYPE, 0, 41) self.master_volume.connect_to(master_track.mixer_device.volume) self.prehear.connect_to(master_track.mixer_device.cue_volume) def _set_up_session(self): is_momentary = True self._session = MaschineSessionComponent() self._session.add_offset_listener(self.notify_track_scroll) nhue = COLOR_HUE_NAV self.nav_buttons = (GatedColorButton(True, MIDI_CC_TYPE, 92, nhue), GatedColorButton(True, MIDI_CC_TYPE, 81, nhue), GatedColorButton(True, MIDI_CC_TYPE, 93, nhue), GatedColorButton(True, MIDI_CC_TYPE, 91, nhue)) self._session.set_scene_bank_buttons(self.nav_buttons[0], self.nav_buttons[1]) self._session.set_track_bank_buttons(self.nav_buttons[2], self.nav_buttons[3]) self._session.set_stop_all_clips_button(StateButton(is_momentary, MIDI_CC_TYPE, 0, 111)) track_stop_buttons = [ StateButton(is_momentary, MIDI_CC_TYPE, BASIC_CHANNEL, index + STOP_CC_OFF) for index in range(4) ] self._session.set_stop_track_clip_buttons(tuple(track_stop_buttons)) self._init_matrix() self._set_up_buttons() self._session._link() self._session.set_advance(STEP4) def _set_up_buttons(self): self._bmatrix = ButtonMatrixElement() for scene_index in range(4): button_row = [] scene = self._session.scene(scene_index) for track_index in range(4): button = self._matrix[scene_index][track_index] clip_slot = scene.clip_slot(track_index) clip_slot.set_launch_button(button) clip_slot.set_triggered_to_play_value(1) clip_slot.set_triggered_to_record_value(1) clip_slot.set_started_value(1) clip_slot.set_recording_value(1) clip_slot.set_stopped_value(1) self._bmatrix.add_row(tuple(button_row)) def _init_matrix(self): is_momentary = True self._button_sequence = [] self._matrix = [] for scene_index in range(4): button_row = [] for track_index in range(4): button = VarButtonElement(is_momentary, 0, scene_index, track_index, self) partner = TwinButton(is_momentary, 1, button) partner.add_value_listener(self.ox, True) button_row.append(button) self._matrix.append(tuple(button_row)) for scene_index in [3, 2, 1, 0]: for track_index in range(4): self._button_sequence.append(self._matrix[scene_index][track_index]) self._session.set_matrix(self._matrix) def set_pad_translations(self, pad_translations): ControlSurface.set_pad_translations(pad_translations) def refresh_state(self): ControlSurface.refresh_state(self) self._update_hardware() def ox(self, value, button): if not isinstance(button, TwinButton): raise AssertionError self._mode == PAD_MODE and button.fire(value) def _update_hardware(self): self._session.update() self._set_suppress_rebuild_requests(True) self._set_mode() self._master_knob.update() if self._scenematrix.soloexclusive: self._armsolomode_button.send_value(1, True) else: self._armsolomode_button.send_value(0, True) self._master_knob.start_up() self._pad_scale_up.activate() self._pad_scale_down.activate() self.current_scale_to_display() self.send_to_display(KEY_COLOR_MODES_STRINGS[self._note_display_mode], 1) for scene_index in range(4): scene = self._session.scene(scene_index) for track_index in range(4): button = self._matrix[scene_index][track_index] button.refresh() self._set_suppress_rebuild_requests(False) def get_color(self, value, track_index, scene_index): if not self._active: return if self._mode == SCENE_MODE or self._mode == CONTROL_MODE or self._pad_mode == PM_ON: element = self._scenematrix.get_element(scene_index, track_index) return element.get_color(value) elif self._mode == CLIP_MODE: scene = self._session.scene(scene_index) clip_slot = scene.clip_slot(track_index)._clip_slot cindex = 0 if value == 0: cindex = 1 if clip_slot != None: if clip_slot.has_clip: if clip_slot.clip.is_recording or clip_slot.clip.will_record_on_start: return PColor.CLIP_RECORD[cindex] if clip_slot.clip.is_playing: return PColor.CLIP_PLAY[cindex] elif clip_slot.clip.is_triggered: return PColor.CLIP_PLAY[cindex] else: return PColor.CLIP_STOPPED[cindex] elif clip_slot.will_record_on_start: return PColor.CLIP_RECORD[cindex] elif clip_slot.is_playing: return PColor.CLIP_GROUP_PLAY[cindex] elif clip_slot.controls_other_clips: return PColor.CLIP_GROUP_CONTROL[cindex] elif clip_slot.is_triggered: return PColor.CLIP_GROUP_TRIGGER[cindex] elif self._mode == PAD_MODE: button = self._matrix[scene_index][track_index] return self.get_color_by_note_mode(button.get_identifier(), value > 0) def step_key_color_mode(self): self._note_display_mode = (self._note_display_mode + 1) % len(KEY_COLOR_MODES_STRINGS) self.show_message('Pad Mode Key Color = ' + KEY_COLOR_MODES_STRINGS[self._note_display_mode]) self.send_to_display('Colors: ' + KEY_COLOR_MODES_STRINGS[self._note_display_mode], 1) if self._mode == PAD_MODE: for note_index in range(16): button = self._button_sequence[note_index] button.send_color_direct(self.get_color_by_note_mode(button.get_identifier(), False)) def get_color_by_note_mode(self, midi_note, on): if self._note_display_mode == ND_BASE_OTHER: interval = (midi_note + 12 - self._base_note) % 12 if on: return INTERVAL_COLOR_MAP[interval][0] else: return INTERVAL_COLOR_MAP[interval][1] elif on: return KEY_COLOR_MAP[midi_note % 12][0] else: return KEY_COLOR_MAP[midi_note % 12][1] def _send_midi(self, midi_bytes, **keys): self._c_ref.send_midi(midi_bytes) if self._midi_pause_count == 2: time.sleep(0.002) self._midi_pause_count = 0 else: self._midi_pause_count = self._midi_pause_count + 1 return True def clip_handle(self): if self._mode == SCENE_MODE or self._mode == CONTROL_MODE or self._modifier_down: self._scenematrix.update() def _a_display_update(self, value): if not self.display_update_button != None: raise AssertionError raise value in range(128) or AssertionError (value != 0 or not self.display_update_button.is_momentary()) and self._update_hardware() self.show_message('Maschine Display Updated') def _set_up_timer(self): self.blink_state = 1 def update_display(self): with self.component_guard(): with self._is_sending_scheduled_messages(): self._task_group.update(0.1) if self._mode == CLIP_MODE and not self._modifier_down: if self.blink_state == 0: self._session.notify(1, 0) elif self.blink_state == 1: self._session.notify(1, 1) elif self.blink_state == 3: self._session.notify(2, 0) elif self.blink_state == 4: self._session.notify(2, 1) elif self._mode == PAD_MODE: pass elif self.blink_state == 0: self._scenematrix.notify_scene_mode(1) elif self.blink_state == 2: self._scenematrix.notify_scene_mode(0) self.blink_state = (self.blink_state + 1) % 4 self.init_slot += 1 def _invoke_track_edit(self, mode): self._deassign_matrix() self._scenematrix.assign() self._scenematrix.set_mode(mode) self._pad_mode = PM_ON self.request_rebuild_midi_map() self._scenematrix.update() def _set_modecontrol(self): is_momentary = True self.scene_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 112) self.clip_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 113) self.pad_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 114) self.control_mode_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 115) self.xfade_assign_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 116) self.scene_mode_button.add_value_listener(self._a_mode_scene) self.clip_mode_button.add_value_listener(self._a_mode_clip) self.pad_mode_button.add_value_listener(self._a_mode_pad) self.control_mode_button.add_value_listener(self._a_mode_control) def _set_mode(self, mode = None): if mode == None: mode = self._mode if mode == SCENE_MODE: self.clip_mode_button.send_value(OFF_VALUE, True) self.pad_mode_button.send_value(OFF_VALUE, True) self.control_mode_button.send_value(OFF_VALUE, True) self.scene_mode_button.send_value(ON_VALUE, True) elif mode == CLIP_MODE: self.scene_mode_button.send_value(OFF_VALUE, True) self.pad_mode_button.send_value(OFF_VALUE, True) self.control_mode_button.send_value(OFF_VALUE, True) self.clip_mode_button.send_value(ON_VALUE, True) elif mode == PAD_MODE: self.scene_mode_button.send_value(OFF_VALUE, True) self.clip_mode_button.send_value(OFF_VALUE, True) self.control_mode_button.send_value(OFF_VALUE, True) self.pad_mode_button.send_value(ON_VALUE, True) elif mode == CONTROL_MODE: self.scene_mode_button.send_value(OFF_VALUE, True) self.clip_mode_button.send_value(OFF_VALUE, True) self.pad_mode_button.send_value(OFF_VALUE, True) self.control_mode_button.send_value(ON_VALUE, True) def _reset_matrix(self): for scene_index in range(4): scene = self._session.scene(scene_index) for track_index in range(4): button = self._matrix[scene_index][track_index] clip_slot = scene.clip_slot(track_index) clip_slot.set_launch_button(button) def update_button_matrix(self): self._session.update() for scene_index in range(4): scene = self._session.scene(scene_index) for track_index in range(4): button = self._matrix[scene_index][track_index] clip_slot = scene.clip_slot(track_index) if clip_slot._clip_slot != None and clip_slot._clip_slot.clip != None: button.send_value(1, True) else: button.send_value(0, True) def _deassign_matrix(self): for scene_index in range(4): scene = self._session.scene(scene_index) for track_index in range(4): clip_slot = scene.clip_slot(track_index) clip_slot.set_launch_button(None) def _from_pad_mode(self, matrix_mode): self._mode = SCENE_MODE self._register_buttons() self._scenematrix.assign() self._scenematrix.set_mode(matrix_mode) self._set_suppress_rebuild_requests(True) self.request_rebuild_midi_map() self._scenematrix.update() self._set_suppress_rebuild_requests(False) def _enter_pad_mode(self): self._set_mode(PAD_MODE) if self._mode == CLIP_MODE: self._deassign_matrix() elif self._mode == SCENE_MODE: self._scenematrix.deassign() elif self._mode == CONTROL_MODE: self._scenematrix.deassign() self._master_knob.exit_matrix_mode() self._mode = PAD_MODE self._set_suppress_rebuild_requests(True) for row in range(4): for column in range(4): button = self._matrix[row][column] button.send_value(0, True) button.set_to_notemode(True) self._forwarding_registry[MIDI_NOTE_ON_STATUS, button.get_identifier()] = button self._forwarding_registry[MIDI_NOTE_OFF_STATUS, button.get_identifier()] = button self._set_suppress_rebuild_requests(False) def _register_buttons(self, update = False): self._set_suppress_rebuild_requests(True) for row in range(4): for column in range(4): button = self._matrix[row][column] button.set_to_notemode(False) if update: button.send_value(127, True) fwkey = [MIDI_NOTE_ON_STATUS] fwkey.append(button.get_identifier()) self._forwarding_registry[tuple(fwkey)] = button self._forwarding_registry[MIDI_NOTE_OFF_STATUS, button.get_identifier()] = button self._set_suppress_rebuild_requests(False) def _back_to_clip_mode(self): self._pad_mode = PM_OFF self._scenematrix.set_mode(SCENE_MODE_NORMAL) self._scenematrix.deassign() self._set_up_clip_matrix() def _set_up_clip_matrix(self): for row in range(4): for column in range(4): button = self._matrix[row][column] button.set_to_notemode(False) self._set_suppress_rebuild_requests(True) self.request_rebuild_midi_map() self._reset_matrix() self.update_button_matrix() self._set_suppress_rebuild_requests(False) def _enter_scene_mode(self): self._set_mode(SCENE_MODE) if self._mode == CLIP_MODE: self._deassign_matrix() elif self._mode == CONTROL_MODE: self._master_knob.exit_matrix_mode() elif self._mode == PAD_MODE: self._register_buttons() self._mode = SCENE_MODE self._scenematrix.assign() self._scenematrix.set_mode(SCENE_MODE_NORMAL) self._return_mode = SCENE_MODE_NORMAL self.request_rebuild_midi_map() def _enter_clip_mode(self): self._set_suppress_rebuild_requests(True) self._set_mode(CLIP_MODE) if self._mode == SCENE_MODE: self._scenematrix.deassign() elif self._mode == CONTROL_MODE: self._master_knob.exit_matrix_mode() self._mode = CLIP_MODE self._set_up_clip_matrix() self.request_rebuild_midi_map() self._set_suppress_rebuild_requests(False) def _enter_control_mode(self): self._set_mode(CONTROL_MODE) if self._mode == CLIP_MODE: self._deassign_matrix() elif self._mode == PAD_MODE: self._mode = CONTROL_MODE self._register_buttons() self._mode = CONTROL_MODE self._set_suppress_rebuild_requests(True) self._scenematrix.set_mode(SCENE_MODE_CONTROL) self._return_mode = SCENE_MODE_CONTROL self._scenematrix.assign() self._master_knob.switch_to_matrix_mode() self._set_suppress_rebuild_requests(False) self.request_rebuild_midi_map() self._scenematrix.update() def _a_mode_scene(self, value): if not self.scene_mode_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.show_message('SCENE MODE') self._enter_scene_mode() def _a_mode_clip(self, value): if not self.clip_mode_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.show_message('CLIP MODE') self._enter_clip_mode() def _a_mode_pad(self, value): if not self.pad_mode_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.show_message('PAD MODE') self._enter_pad_mode() def _a_mode_control(self, value): if not self.control_mode_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self.show_message('CONTROL MODE') self._enter_control_mode() def _do_pad_select_multi(self, value): if not value in range(128): raise AssertionError self._modifier_down = value != 0 if self._mode == PAD_MODE or self._returntopad: value != 0 and self._from_pad_mode(SCENE_MODE_SELECT) self._returntopad = True else: self._returntopad = False self._enter_pad_mode() elif self._mode == CLIP_MODE: if value != 0: self._invoke_track_edit(SCENE_MODE_SELECT) else: self._back_to_clip_mode() elif self._mode != PAD_MODE: if value == 0: self._scenematrix.set_mode(self._return_mode) else: if self._scenematrix.in_main_mode(): self._return_mode = self._scenematrix.mode self._scenematrix.set_mode(SCENE_MODE_SELECT) def _do_mute_button(self, value): if not self._mute_button != None: raise AssertionError if not value in range(128): raise AssertionError self._modifier_down = value != 0 (self._mode == PAD_MODE or self._returntopad) and value != 0 and self._from_pad_mode(SCENE_MODE_MUTE) self._returntopad = True else: self._returntopad = False self._enter_pad_mode() elif self._mode == SCENE_MODE or self._mode == CONTROL_MODE: if value == 0: self._scenematrix.set_mode(self._return_mode) self._pad_mode = PM_OFF else: if self._scenematrix.in_main_mode(): self._return_mode = self._scenematrix.mode self._scenematrix.set_mode(SCENE_MODE_MUTE) self._pad_mode = PM_ON elif self._mode == CLIP_MODE: if value > 0: self._invoke_track_edit(SCENE_MODE_MUTE) else: self._back_to_clip_mode() self._pad_mode = PM_OFF def _do_pad_solo_multi(self, value): if not value in range(128): raise AssertionError self._modifier_down = value != 0 if self._mode == PAD_MODE or self._returntopad: value != 0 and self._from_pad_mode(SCENE_MODE_SOLO) self._returntopad = True else: self._returntopad = False self._enter_pad_mode() elif self._mode == CLIP_MODE: if value != 0: self._invoke_track_edit(SCENE_MODE_SOLO) else: self._back_to_clip_mode() elif self._mode != PAD_MODE: if value == 0: self._scenematrix.set_mode(self._return_mode) else: if self._scenematrix.in_main_mode(): self._return_mode = self._scenematrix.mode self._scenematrix.set_mode(SCENE_MODE_SOLO) def _do_xfade_assign(self, value): if not self.xfade_assign_button != None: raise AssertionError if not value in range(128): raise AssertionError (self._mode == PAD_MODE or self._returntopad) and value != 0 and self._from_pad_mode(SCENE_MODE_XFADE) self._returntopad = True else: self._returntopad = False self._enter_pad_mode() elif self._mode == CLIP_MODE: if value != 0: self._invoke_track_edit(SCENE_MODE_XFADE) else: self._back_to_clip_mode() elif self._mode == SCENE_MODE or self._mode == CONTROL_MODE: if value == 0: self._scenematrix.set_mode(self._return_mode) else: if self._scenematrix.in_main_mode(): self._return_mode = self._scenematrix.mode self._scenematrix.set_mode(SCENE_MODE_XFADE) def _do_pad_note_up(self, value): if not self._pad_scale_up != None: raise AssertionError if not value in range(128): raise AssertionError self._pad_scale_up.send_value(value, True) self._modifier_down = value != 0 (self._mode == PAD_MODE or self._returntopad) and value != 0 and self._from_pad_mode(SCENE_MODE_ARM) self._returntopad = True else: self._returntopad = False self._enter_pad_mode() elif self._mode == CLIP_MODE: self.show_message('Arm tracks with pads') if value != 0: self._invoke_track_edit(SCENE_MODE_ARM) else: self._back_to_clip_mode() elif self._mode == SCENE_MODE or self._mode == CONTROL_MODE: self.show_message('Arm tracks with pads') if value == 0: self._scenematrix.set_mode(self._return_mode) else: if self._scenematrix.in_main_mode(): self._return_mode = self._scenematrix.mode self._scenematrix.set_mode(SCENE_MODE_ARM) def _do_pad_note_down(self, value): if not self._pad_scale_down != None: raise AssertionError if not value in range(128): raise AssertionError self._pad_scale_down.send_value(value, True) self._modifier_down = value != 0 (self._mode == PAD_MODE or self._returntopad) and value != 0 and self._from_pad_mode(SCENE_MODE_STOP) self._returntopad = True else: self._returntopad = False self._enter_pad_mode() elif self._mode == CLIP_MODE: self.show_message('Stop tracks with pads') if value != 0: self._invoke_track_edit(SCENE_MODE_STOP) else: self._back_to_clip_mode() elif self._mode == SCENE_MODE or self._mode == CONTROL_MODE: self.show_message('Stop tracks with pads') if value == 0: self._scenematrix.set_mode(self._return_mode) else: if self._scenematrix.in_main_mode(): self._return_mode = self._scenematrix.mode self._scenematrix.set_mode(SCENE_MODE_STOP) def modify_track_offset(self, delta): self._scenematrix.mod_track_offset(delta) def modify_scene_offset(self, delta): self._scenematrix.mod_scene_offset(delta) def move_view_horizontal(self, delta): if delta == 1: self._session.bank_right() else: self._session.bank_left() if self._mode == CONTROL_MODE: self._scenematrix.update() def inc_octave(self, inc): scale = SCALES[self.current_scale_index] octave = scale.to_octave(self._octave) newoctave = octave + inc if newoctave < 0: newoctave = 0 elif newoctave > scale.octave_range: newoctave = scale.octave_range self._octave = scale.to_relative(newoctave, self._octave) scale = SCALES[self.current_scale_index] self.show_message(' OCTAVE ' + BASE_NOTE[self._base_note] + str(newoctave - 2) + ' to ' + scale.name) self.current_scale_to_display() def inc_base_note(self, inc): newbase = self._base_note + inc if newbase < 0: self._base_note = 0 elif newbase > 11: self._base_note = 11 else: self._base_note = newbase scale = SCALES[self.current_scale_index] self.show_message(' Base Note ' + BASE_NOTE[self._base_note] + ' to ' + scale.name) self.current_scale_to_display() def current_scale_to_display(self): scale = SCALES[self.current_scale_index] text = scale.name + ' ' + BASE_NOTE[self._base_note] + str(scale.to_octave(self._octave)) self.send_to_display(text) def inc_scale(self, inc): nr_of_scales = len(SCALES) newindex = self.current_scale_index + inc if newindex < 0: newindex = 0 elif newindex >= nr_of_scales: newindex = nr_of_scales - 1 else: self.current_scale_index += inc newscale = SCALES[self.current_scale_index] self.show_message(' PAD Scale ' + newscale.name + ' ' + BASE_NOTE[self._base_note] + str(newscale.to_octave(self._octave) - 2)) self.current_scale_to_display() def update_transpose(self): self.assign_transpose(SCALES[self.current_scale_index]) self._set_suppress_rebuild_requests(True) self.request_rebuild_midi_map() self._set_suppress_rebuild_requests(False) def set_scale(self, scale): raise isinstance(scale, PadScale) or AssertionError scale_len = len(scale.notevalues) octave = scale.to_octave(self._octave) def assign_transpose(self, scale): raise isinstance(scale, PadScale) or AssertionError scale_len = len(scale.notevalues) octave = scale.to_octave(self._octave) last_note_val = None for note_index in range(16): button = self._button_sequence[note_index] scale_index = note_index % scale_len octave_offset = note_index / scale_len note_value = scale.notevalues[scale_index] + self._base_note + octave * 12 + octave_offset * 12 if note_value < 128: last_note_val = note_value elif last_note_val != None: note_value = last_note_val button.set_send_note(note_value) if self._mode == PAD_MODE: button.send_color_direct(self.get_color_by_note_mode(note_value, False)) def do_reset(self, value): if value == 0: return for row in range(4): for column in range(4): button = self._matrix[row][column] data_byte1 = button._original_identifier button.send_midi((MIDI_CC_STATUS + 2, data_byte1, 0)) def do_test(self, value): color = self.togglecolor[self.toggleindex] self.toggleindex = (self.toggleindex + 1) % len(self.togglecolor) if value == 0: return for row in range(4): for column in range(4): button = self._matrix[row][column] self.schedule_message(1, self.dosend, (color, 127, 127, row, column)) def dosend(self, parm = None): button = self._matrix[parm[3]][parm[4]] data_byte1 = button._original_identifier button.send_midi((MIDI_CC_STATUS + 0, data_byte1, parm[0])) button.send_midi((MIDI_CC_STATUS + 1, data_byte1, parm[1])) button.send_midi((MIDI_CC_STATUS + 2, data_byte1, parm[2])) def do_note_repeat(self, value): nrvalue = 0 if value != 0: nrvalue = 1 self._c_ref.set_note_repeat_state(nrvalue) def _do_toggle_send(self, value): nr_of_tracks = len(self.song().return_tracks) if value == 0 or nr_of_tracks < 1: return prev = self.send_slider_index self.send_slider_index += 1 if self.send_slider_index >= nr_of_tracks: self.send_slider_index = 0 self.show_message(' Set Send ' + str(SENDS[self.send_slider_index])) if prev != self.send_slider_index: for track in range(8): strip = self._mixer.channel_strip(track) slider_list = [] for index in range(self.send_slider_index + 1): if index < self.send_slider_index - 1: slider_list.append(None) else: slider_list.append(self.send_sliders[track]) strip.set_send_controls(tuple(slider_list)) def _do_armsolo_mode(self, value): if not self._armsolomode_button != None: raise AssertionError raise value in range(128) or AssertionError value != 0 and self._scenematrix.set_armsolo_exclusive(self._armsolomode_button) def _do_fire_button(self, value): if not self._fire_button != None: raise AssertionError if not value in range(128): raise AssertionError clip_slot = (value != 0 or not self._mute_button.is_momentary()) and self.song().view.highlighted_clip_slot clip_slot and clip_slot.fire() def _do_undo(self, value): if not self._undo_button != None: raise AssertionError if not value in range(128): raise AssertionError (value != 0 or not self._undo_button.is_momentary()) and self.song().can_undo == 1 and self.song().undo() self.show_message(str('UNDO')) def _do_redo(self, value): if not self._redo_button != None: raise AssertionError if not value in range(128): raise AssertionError (value != 0 or not self._redo_button.is_momentary()) and self.song().can_redo == 1 and self.song().redo() self.show_message(str('REDO')) def _a_trk_left(self, value): if not value in range(128): raise AssertionError if value != 0: direction = self.application().view.is_view_visible('Session') and Live.Application.Application.View.NavDirection.left self.application().view.scroll_view(direction, 'Session', True) def _a_trk_right(self, value): if not value in range(128): raise AssertionError if value != 0: direction = self.application().view.is_view_visible('Session') and Live.Application.Application.View.NavDirection.right self.application().view.scroll_view(direction, 'Session', True) def _nav_value_left(self, value): if not self._device_nav_button_left != None: raise AssertionError if not value in range(128): raise AssertionError modifier_pressed = True value > 0 and (not self.application().view.is_view_visible('Detail') or not self.application().view.is_view_visible('Detail/DeviceChain')) and self.application().view.show_view('Detail') self.application().view.show_view('Detail/DeviceChain') else: direction = Live.Application.Application.View.NavDirection.left self.application().view.scroll_view(direction, 'Detail/DeviceChain', not modifier_pressed) def _nav_value_right(self, value): if not self._device_nav_button_right != None: raise AssertionError if not value in range(128): raise AssertionError modifier_pressed = value > 0 and True (not self.application().view.is_view_visible('Detail') or not self.application().view.is_view_visible('Detail/DeviceChain')) and self.application().view.show_view('Detail') self.application().view.show_view('Detail/DeviceChain') else: direction = Live.Application.Application.View.NavDirection.right self.application().view.scroll_view(direction, 'Detail/DeviceChain', not modifier_pressed) def _do_tap_tempo(self, value): if not value in range(128): raise AssertionError value > 0 and self.song().tap_tempo() def _do_toggle_cue(self, value): if not value in range(128): raise AssertionError value > 0 and self.song().set_or_delete_cue() def _do_toggle_prev_cue(self, value): if not value in range(128): raise AssertionError value > 0 and self.song().jump_to_prev_cue() def _do_toggle_next_cue(self, value): if not value in range(128): raise AssertionError value > 0 and self.song().jump_to_next_cue() def focus_changed(self): pass def _handle_device_changed(self, device): pass def _hande_device_parm_changed(self): pass def _do_focus_navigate(self, value): if not self._navigate_button != None: raise AssertionError raise value in range(128) or AssertionError self.nav_index = value != 0 and (self.nav_index + 1) % len(VIEWS_ALL) self.application().view.focus_view(VIEWS_ALL[self.nav_index]) self.show_message('Focus on : ' + str(VIEWS_ALL[self.nav_index])) def scroll_focus(self, delta): if delta == 1: self.nav_index = (self.nav_index + 1) % len(VIEWS_ALL) elif self.nav_index == 0: self.nav_index = len(VIEWS_ALL) - 1 else: self.nav_index -= 1 self.show_message('Focus on : ' + str(VIEWS_ALL[self.nav_index])) self.application().view.focus_view(VIEWS_ALL[self.nav_index]) def scroll_device(self, delta): if not (delta == 1 or delta == -1): raise AssertionError direction = delta == 1 and Live.Application.Application.View.NavDirection.right else: direction = Live.Application.Application.View.NavDirection.left self.application().view.scroll_view(direction, 'Detail/DeviceChain', True) def scroll_scene(self, delta): if not self.track_left_button != None: raise AssertionError raise delta == 1 or delta == -1 or AssertionError direction = delta == 1 and Live.Application.Application.View.NavDirection.down else: direction = Live.Application.Application.View.NavDirection.up self.application().view.scroll_view(direction, 'Session', True) def index_in_strip(self, track): for ind in range(len(self._mixer._channel_strips)): strack = self._mixer._channel_strips[ind]._track if strack == track: return ind return -1 def notify_track_scroll(self): self._scenematrix.update_control_selection() if self._mode == CONTROL_MODE: self._scenematrix.eval_matrix() self._scenematrix.fire_values() def send_to_display(self, text, grid = 0): if USE_DISPLAY == False: return if len(text) > 28: text = text[:27] msgsysex = [240, 0, 0, 102, 23, 18, min(grid, 3) * 28] filled = text.ljust(28) for c in filled: msgsysex.append(ord(c)) msgsysex.append(247) self._send_midi(tuple(msgsysex)) def send_color(self, button, hue, sat, bright): raise isinstance(button, ButtonElement) or AssertionError raise hue in range(128) or AssertionError raise sat in range(128) or AssertionError raise bright in range(128) or AssertionError data_byte1 = button._original_identifier button.send_midi((MIDI_CC_STATUS + 2, data_byte1, bright)) button.send_midi((MIDI_CC_STATUS + 1, data_byte1, sat)) button.send_midi((MIDI_CC_STATUS + 0, data_byte1, hue)) def turn_off_matrix(self): for row in range(4): for column in range(4): button = self._matrix[row][column] self.send_color(button, 2, 0, 0) button.set_to_notemode(False) def remove_listener(self, control, callback): if control != None and control.value_has_listener(callback): control.remove_value_listener(callback) control.disconnect() def disconnect(self): self.turn_off_matrix() self.scene_mode_button.send_value(0, True) self.clip_mode_button.send_value(0, True) self.pad_mode_button.send_value(0, True) self.control_mode_button.send_value(0, True) time.sleep(0.2) self._active = False self._suppress_send_midi = True self.remove_listener(self.scene_mode_button, self._a_mode_scene) self.remove_listener(self.clip_mode_button, self._a_mode_clip) self.remove_listener(self.pad_mode_button, self._a_mode_pad) self.remove_listener(self.control_mode_button, self._a_mode_control) self.remove_listener(self._undo_button, self._do_undo) self.remove_listener(self._redo_button, self._do_redo) self.remove_listener(self._armsolomode_button, self._do_armsolo_mode) self.remove_listener(self.xfade_assign_button, self._do_xfade_assign) self.remove_listener(self._fire_button, self._do_fire_button) self._session.remove_offset_listener(self.notify_track_scroll) self._mixer.disconnect() ControlSurface.disconnect(self)
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
class KorgKaossDJ(ControlSurface): __module__ = __name__ __doc__ = " Korg Kaoss DJ controller script " def __init__(self, c_instance): """everything except the '_on_selected_track_changed' override and 'disconnect' runs from here""" ControlSurface.__init__(self, c_instance) self._selected_track = None self._current_clip = None with self.component_guard(): self._create_controls() self._setup_transport_control( ) # Run the transport setup part of the script self._setup_loop_control() self._setup_scrub_control() self._setup_fx_control() self._setup_mixer_control() # Setup the mixer object self._setup_session_control() # Setup the session object def _create_controls(self): # ------ SLIDER self._crossfader_slider = SliderElement(MIDI_CC_TYPE, CHANNEL_CENTER, 23) self._left_volume_slider = SliderElement(MIDI_CC_TYPE, CHANNEL_LEFT, 24) self._right_volume_slider = SliderElement(MIDI_CC_TYPE, CHANNEL_RIGHT, 24) self._left_tempo_fader = SliderElement(MIDI_CC_TYPE, CHANNEL_LEFT, 25) self._right_tempo_fader = SliderElement(MIDI_CC_TYPE, CHANNEL_RIGHT, 25) # ------ BUTTONS self._left_play_button = ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL_LEFT, 27) self._right_play_button = ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL_RIGHT, 27) self._left_prelisten_button = ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL_LEFT, 25) self._right_prelisten_button = ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL_RIGHT, 25) self._left_fx_button = ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL_LEFT, 24) self._right_fx_button = ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL_RIGHT, 24) self._left_A_button = ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL_LEFT, 14) self._right_B_button = ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL_RIGHT, 14) self._left_shift_button = ButtonElement( True, MIDI_NOTE_TYPE, CHANNEL_LEFT, 26, name='Shift_Button', resource_type=PrioritizedResource) self._right_shift_button = ButtonElement( True, MIDI_NOTE_TYPE, CHANNEL_RIGHT, 26, name='Shift_Button', resource_type=PrioritizedResource) self._left_sync_button = ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL_LEFT, 29) self._right_sync_button = ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL_RIGHT, 29) self._left_cue_button = ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL_LEFT, 30) self._right_cue_button = ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL_RIGHT, 30) self._left_sync_button_shift = ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL_LEFT, 47) self._right_sync_button_shift = ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL_RIGHT, 47) self._left_cue_button_shift = ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL_LEFT, 48) self._right_cue_button_shift = ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL_RIGHT, 48) for i in range(3): for side, channel in zip(['_left', '_right'], [CHANNEL_LEFT, CHANNEL_RIGHT]): setattr(self, side + '_loop_' + str(i + 1), ButtonElement(True, MIDI_NOTE_TYPE, channel, 15 + i)) setattr(self, side + '_loop_' + str(i + 1) + '_shift', ButtonElement(True, MIDI_NOTE_TYPE, channel, 40 + i)) setattr(self, side + '_hotcue_' + str(i + 1), ButtonElement(True, MIDI_NOTE_TYPE, channel, 18 + i)) setattr(self, side + '_hotcue_' + str(i + 1) + '_shift', ButtonElement(True, MIDI_NOTE_TYPE, channel, 43 + i)) setattr(self, side + '_nolight_' + str(i + 1), ButtonElement(True, MIDI_NOTE_TYPE, channel, 21 + i)) # ------ ENCODER # browser self._center_browse_encoder = EncoderElement( MIDI_CC_TYPE, CHANNEL_CENTER, 30, Live.MidiMap.MapMode.relative_smooth_two_compliment) # gain left self._left_gain_encoder = EncoderElement(MIDI_CC_TYPE, CHANNEL_LEFT, 26, Live.MidiMap.MapMode.absolute) # gain right self._right_gain_encoder = EncoderElement( MIDI_CC_TYPE, CHANNEL_RIGHT, 26, Live.MidiMap.MapMode.absolute) # middle light off -> does not send on-off messages! self._left_jogwheel_encoder = EncoderElement( MIDI_CC_TYPE, CHANNEL_LEFT, 14, Live.MidiMap.MapMode.relative_smooth_two_compliment) self._right_jogwheel_encoder = EncoderElement( MIDI_CC_TYPE, CHANNEL_RIGHT, 14, Live.MidiMap.MapMode.relative_smooth_two_compliment) self._left_jogwheel_encoder_shift = EncoderElement( MIDI_CC_TYPE, CHANNEL_LEFT, 15, Live.MidiMap.MapMode.relative_smooth_two_compliment) self._right_jogwheel_encoder_shift = EncoderElement( MIDI_CC_TYPE, CHANNEL_RIGHT, 15, Live.MidiMap.MapMode.relative_smooth_two_compliment) # middle light on -> sends on-off message on channel 31! self._left_jogwheel_encoder_active = EncoderElement( MIDI_CC_TYPE, CHANNEL_LEFT, 16, Live.MidiMap.MapMode.relative_smooth_two_compliment) self._left_jogwheel_encoder_active_button = ButtonElement( True, MIDI_NOTE_TYPE, CHANNEL_LEFT, 31) self._right_jogwheel_encoder_active = EncoderElement( MIDI_CC_TYPE, CHANNEL_RIGHT, 16, Live.MidiMap.MapMode.relative_smooth_two_compliment) self._right_jogwheel_encoder_active_button = ButtonElement( True, MIDI_NOTE_TYPE, CHANNEL_RIGHT, 31) # FX touchpad (same for both channels so we need to read only one) self._touchpad_x_encoder = EncoderElement( MIDI_CC_TYPE, CHANNEL_LEFT, 12, Live.MidiMap.MapMode.absolute) self._touchpad_y_encoder = EncoderElement( MIDI_CC_TYPE, CHANNEL_LEFT, 13, Live.MidiMap.MapMode.absolute) self._touchpad_x_encoder_shift = EncoderElement( MIDI_CC_TYPE, CHANNEL_CENTER, 17, Live.MidiMap.MapMode.absolute) self._touchpad_y_encoder_shift = EncoderElement( MIDI_CC_TYPE, CHANNEL_CENTER, 18, Live.MidiMap.MapMode.absolute) # hi-mid-lo encoders _device_MSG_IDS = [27, 28, 29] self._device_encoders = ButtonMatrixElement( rows=[[ EncoderElement(MIDI_CC_TYPE, CHANNEL_LEFT, MSG_ID, Live.MidiMap.MapMode.absolute) for MSG_ID in _device_MSG_IDS ], [ EncoderElement(MIDI_CC_TYPE, CHANNEL_RIGHT, MSG_ID, Live.MidiMap.MapMode.absolute) for MSG_ID in _device_MSG_IDS ]]) def _setup_loop_control(self): # set looping function ality to Loop- and HotCue buttons self._looper_left = LooperComponent(self, assign_track=0, move_increment=4, increase_factor=(0, 2), decrease_factor=(0, 2), start_loop_length=32, quantize_start=4) self._looper_right = LooperComponent(self, assign_track=1, move_increment=4, increase_factor=(0, 2), decrease_factor=(0, 2), start_loop_length=32, quantize_start=1) self._looper_left_fine = LooperComponent(self, assign_track=0, move_increment=1, increase_factor=(1, 1), decrease_factor=(1, 1), start_loop_length=16, quantize_start=1) self._looper_right_fine = LooperComponent(self, assign_track=1, move_increment=1, increase_factor=(1, 1), decrease_factor=(1, 1), start_loop_length=16, quantize_start=1) self._looper_left.set_loop_decrease_button(self._left_loop_1) self._looper_left.set_loop_start_button(self._left_loop_2) self._looper_left.set_loop_increase_button(self._left_loop_3) self._looper_left.set_loop_move_left_button(self._left_loop_1_shift) self._looper_left.set_loop_toggle_button(self._left_loop_2_shift) self._looper_left.set_loop_move_right_button(self._left_loop_3_shift) self._looper_left_fine.set_loop_decrease_button(self._left_hotcue_1) self._looper_left_fine.set_loop_start_button(self._left_hotcue_2) self._looper_left_fine.set_loop_increase_button(self._left_hotcue_3) self._looper_left_fine.set_loop_move_left_button( self._left_hotcue_1_shift) self._looper_left_fine.set_loop_toggle_button( self._left_hotcue_2_shift) self._looper_left_fine.set_loop_move_right_button( self._left_hotcue_3_shift) self._looper_right.set_loop_decrease_button(self._right_loop_1) self._looper_right.set_loop_start_button(self._right_loop_2) self._looper_right.set_loop_increase_button(self._right_loop_3) self._looper_right.set_loop_move_left_button(self._right_loop_1_shift) self._looper_right.set_loop_toggle_button(self._right_loop_2_shift) self._looper_right.set_loop_move_right_button(self._right_loop_3_shift) self._looper_right_fine.set_loop_decrease_button(self._right_hotcue_1) self._looper_right_fine.set_loop_start_button(self._right_hotcue_2) self._looper_right_fine.set_loop_increase_button(self._right_hotcue_3) self._looper_right_fine.set_loop_move_left_button( self._right_hotcue_1_shift) self._looper_right_fine.set_loop_toggle_button( self._right_hotcue_2_shift) self._looper_right_fine.set_loop_move_right_button( self._right_hotcue_3_shift) def _setup_scrub_control(self): self._scrub_left = ScrubComponent(self, assign_track=LEFT_STRIP_ID, increment_scrub=1, increment_fine=0.1) self._scrub_right = ScrubComponent(self, assign_track=RIGHT_STRIP_ID, increment_scrub=1, increment_fine=0.1) self._scrub_left.set_move_position_button(self._left_jogwheel_encoder) self._scrub_left.set_move_position_coarse_button( self._left_jogwheel_encoder_shift) self._scrub_left.set_scrub_position_button( self._left_jogwheel_encoder_active) self._scrub_left.set_scrub_on_off_button( self._left_jogwheel_encoder_active_button) self._scrub_right.set_move_position_button( self._right_jogwheel_encoder) self._scrub_right.set_move_position_coarse_button( self._right_jogwheel_encoder_shift) self._scrub_right.set_scrub_position_button( self._right_jogwheel_encoder_active) self._scrub_right.set_scrub_on_off_button( self._right_jogwheel_encoder_active_button) def _setup_fx_control(self): self._fx_left = FXComponent(self, assign_track=LEFT_STRIP_ID) self._fx_left.set_touchpad_x_button(self._touchpad_x_encoder) self._fx_left.set_touchpad_y_button(self._touchpad_y_encoder) self._fx_left.set_touchpad_x_shift_button( self._touchpad_x_encoder_shift) self._fx_left.set_touchpad_y_shift_button( self._touchpad_y_encoder_shift) self._fx_left.set_fx_on_off_button(self._left_fx_button) self._fx_left.set_gain_encoder_button(self._left_gain_encoder) self._fx_left.set_warping_button(self._left_sync_button_shift) self._fx_left.set_warp_mode_button(self._left_sync_button) self._fx_left.set_pitch_down_button(self._left_nolight_1) self._fx_left.set_pitch_up_button(self._left_nolight_3) self._fx_right = FXComponent(self, assign_track=RIGHT_STRIP_ID) self._fx_right.set_touchpad_x_button(self._touchpad_x_encoder) self._fx_right.set_touchpad_y_button(self._touchpad_y_encoder) self._fx_right.set_touchpad_x_shift_button( self._touchpad_x_encoder_shift) self._fx_right.set_touchpad_y_shift_button( self._touchpad_y_encoder_shift) self._fx_right.set_fx_on_off_button(self._right_fx_button) self._fx_right.set_gain_encoder_button(self._right_gain_encoder) self._fx_right.set_warping_button(self._right_sync_button_shift) self._fx_right.set_warp_mode_button(self._right_sync_button) def _setup_transport_control(self): """set up the sliders""" self._transport = TransportComponent(self, name=u'Transport', is_enabled=False) #set tempo-fader self._transport.set_tempo_control( self._left_tempo_fader, fine_control=self._right_tempo_fader) #(control, fine_control) self._transport.set_enabled(True) def _setup_mixer_control(self): self._mixer = MixerComponent(num_tracks=2, num_returns=0, name=u'Mixer', is_enabled=False) self._mixer.set_crossfader_control(self._crossfader_slider) # set volume sliders self._mixer.channel_strip(LEFT_STRIP_ID).set_volume_control( self._left_volume_slider) self._mixer.channel_strip(RIGHT_STRIP_ID).set_volume_control( self._right_volume_slider) # set prelisten buttons self._mixer.channel_strip(LEFT_STRIP_ID).set_solo_button( self._left_prelisten_button) self._mixer.channel_strip(RIGHT_STRIP_ID).set_solo_button( self._right_prelisten_button) # use fx buttons to select a track self._mixer.channel_strip(LEFT_STRIP_ID).set_select_button( self._left_A_button) self._mixer.channel_strip(RIGHT_STRIP_ID).set_select_button( self._right_B_button) self._mixer.set_enabled(True) def _setup_session_control(self): self._session = SessionComponent(num_tracks=2, num_scenes=1, name=u'Session', is_enabled=False) # set horizontal scene selector (this is why we import SessionComponent from _Arturia!) self._session.set_scene_select_control(self._center_browse_encoder) # set launch-buttons for scene self._session.selected_scene().clip_slot(0).set_launch_button( self._left_play_button) self._session.selected_scene().clip_slot(1).set_launch_button( self._right_play_button) # hightlite the current selection self.set_highlighting_session_component(self._session) self._session.set_enabled(True) # ----------- add functionality to turn playing-light on-off def update_lights(track, button): playing_clip_idx = track.playing_slot_index if playing_clip_idx >= 0: button.turn_on() else: button.turn_off() def update_playlight_left(): track = self.song().tracks[LEFT_STRIP_ID] update_lights(track, self._left_play_button) def update_playlight_right(): track = self.song().tracks[RIGHT_STRIP_ID] update_lights(track, self._right_play_button) self.song().tracks[LEFT_STRIP_ID].add_playing_slot_index_listener( update_playlight_left) self.song().tracks[RIGHT_STRIP_ID].add_playing_slot_index_listener( update_playlight_right) # override the selected scene change behaviour of the playing light self.song().view.add_selected_scene_listener(update_playlight_left) self.song().view.add_selected_scene_listener(update_playlight_right)
class DC1(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) 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(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, 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.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, 0)) self.scrollencoder.set_transport_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 7)) self.scrollencoder.set_scene_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 3)) self.scrollencoder.set_library_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 4)) self.scrollencoder.set_button1(SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 1)) self.scrollencoder.set_button2(SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 2)) self.scrollencoder.set_button3(SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 5)) self.scrollencoder.set_button4(SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 6)) self.scrollencoder.set_encoder_button(SimpleButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 32)) 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 matmacx16v1(ControlSurface): def __init__(self, c_instance): super(matmacx16v1, self).__init__(c_instance) with self.component_guard(): global _map_modes _map_modes = Live.MidiMap.MapMode # mixer global mixer num_tracks = 128 num_returns = 24 self.mixer = MixerComponent(num_tracks, num_returns) global active_mode active_mode = "_mode1" self._set_active_mode() self.show_message("Powered by mtmc") def _mode1(self): self.show_message("_mode1 is active") # mixer global mixer # volumes self.mixer.channel_strip(7).set_volume_control(EncoderElement(MIDI_CC_TYPE, 14, 25, _map_modes.absolute)) self.mixer.channel_strip(6).set_volume_control(EncoderElement(MIDI_CC_TYPE, 14, 24, _map_modes.absolute)) self.mixer.channel_strip(5).set_volume_control(EncoderElement(MIDI_CC_TYPE, 14, 23, _map_modes.absolute)) self.mixer.channel_strip(4).set_volume_control(EncoderElement(MIDI_CC_TYPE, 14, 22, _map_modes.absolute)) self.mixer.channel_strip(3).set_volume_control(EncoderElement(MIDI_CC_TYPE, 14, 17, _map_modes.absolute)) self.mixer.channel_strip(2).set_volume_control(EncoderElement(MIDI_CC_TYPE, 14, 16, _map_modes.absolute)) self.mixer.channel_strip(1).set_volume_control(EncoderElement(MIDI_CC_TYPE, 14, 15, _map_modes.absolute)) self.mixer.channel_strip(0).set_volume_control(EncoderElement(MIDI_CC_TYPE, 14, 14, _map_modes.absolute)) # pan self.mixer.channel_strip(7).set_pan_control(EncoderElement(MIDI_CC_TYPE, 14, 29, _map_modes.absolute)) self.mixer.channel_strip(6).set_pan_control(EncoderElement(MIDI_CC_TYPE, 14, 28, _map_modes.absolute)) self.mixer.channel_strip(5).set_pan_control(EncoderElement(MIDI_CC_TYPE, 14, 27, _map_modes.absolute)) self.mixer.channel_strip(4).set_pan_control(EncoderElement(MIDI_CC_TYPE, 14, 26, _map_modes.absolute)) self.mixer.channel_strip(3).set_pan_control(EncoderElement(MIDI_CC_TYPE, 14, 21, _map_modes.absolute)) self.mixer.channel_strip(2).set_pan_control(EncoderElement(MIDI_CC_TYPE, 14, 20, _map_modes.absolute)) self.mixer.channel_strip(1).set_pan_control(EncoderElement(MIDI_CC_TYPE, 14, 19, _map_modes.absolute)) self.mixer.channel_strip(0).set_pan_control(EncoderElement(MIDI_CC_TYPE, 14, 18, _map_modes.absolute)) def _remove_mode1(self): # mixer global mixer # volumes self.mixer.channel_strip(7).set_volume_control(None) self.mixer.channel_strip(6).set_volume_control(None) self.mixer.channel_strip(5).set_volume_control(None) self.mixer.channel_strip(4).set_volume_control(None) self.mixer.channel_strip(3).set_volume_control(None) self.mixer.channel_strip(2).set_volume_control(None) self.mixer.channel_strip(1).set_volume_control(None) self.mixer.channel_strip(0).set_volume_control(None) # pan self.mixer.channel_strip(7).set_pan_control(None) self.mixer.channel_strip(6).set_pan_control(None) self.mixer.channel_strip(5).set_pan_control(None) self.mixer.channel_strip(4).set_pan_control(None) self.mixer.channel_strip(3).set_pan_control(None) self.mixer.channel_strip(2).set_pan_control(None) self.mixer.channel_strip(1).set_pan_control(None) self.mixer.channel_strip(0).set_pan_control(None) def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(self) self._display_reset_delay = 0 value = "selected track changed" if (hasattr(self, '_set_track_select_led')): self._set_track_select_led() if (hasattr(self, '_reload_active_devices')): self._reload_active_devices(value) if (hasattr(self, 'update_all_ab_select_LEDs')): self.update_all_ab_select_LEDs(1) def _is_prev_device_on_or_off(self): self._device = self.song().view.selected_track.view.selected_device self._device_position = self.selected_device_idx() if (self._device is None) or (self._device_position == 0): on_off = "off" else: on_off = "on" return on_off def _is_nxt_device_on_or_off(self): self._selected_device = self.selected_device_idx() + 1 # add one as this starts from zero if (self._device is None) or (self._selected_device == len(self.song().view.selected_track.devices)): on_off = "off" else: on_off = "on" return on_off def _set_active_mode(self): global active_mode # activate mode if active_mode == "_mode1": self._mode1() if hasattr(self, '_set_track_select_led'): self._set_track_select_led() if hasattr(self, '_turn_on_device_select_leds'): self._turn_off_device_select_leds() self._turn_on_device_select_leds() if hasattr(self, '_all_prev_device_leds'): self._all_prev_device_leds() if hasattr(self, '_all_nxt_device_leds'): self._all_nxt_device_leds() if hasattr(self, 'update_all_ab_select_LEDs'): self.update_all_ab_select_LEDs(1) def _remove_active_mode(self): global active_mode # remove activate mode if active_mode == "_mode1": self._remove_mode1() def _activate_mode1(self,value): global active_mode global shift_previous_is_active if value > 0: shift_previous_is_active = "off" self._remove_active_mode() active_mode = "_mode1" self._set_active_mode() def _activate_shift_mode1(self,value): global active_mode global previous_shift_mode1 global shift_previous_is_active if value > 0: shift_previous_is_active = "on" previous_shift_mode1 = active_mode self._remove_active_mode() active_mode = "_mode1" self._set_active_mode() elif shift_previous_is_active == "on": try: previous_shift_mode1 except NameError: self.log_message("previous shift mode not defined yet") else: self._remove_active_mode() active_mode = previous_shift_mode1 self._set_active_mode() def selected_device_idx(self): self._device = self.song().view.selected_track.view.selected_device return self.tuple_index(self.song().view.selected_track.devices, self._device) def selected_track_idx(self): self._track = self.song().view.selected_track self._track_num = self.tuple_index(self.song().tracks, self._track) self._track_num = self._track_num + 1 return self._track_num def tuple_index(self, tuple, obj): for i in xrange(0, len(tuple)): if (tuple[i] == obj): return i return(False) def disconnect(self): super(matmacx16v1, self).disconnect()
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 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 midi_twister_110(ControlSurface): def __init__(self, c_instance): super(midi_twister_110, self).__init__(c_instance) with self.component_guard(): global active_mode active_mode = "_mode1" self._set_active_mode() self.show_message("Modified by XXPW") def _mode1(self): self.show_message("_mode1 is active") # mixer global mixer num_tracks = 32 num_returns = 7 self.mixer = MixerComponent(num_tracks, num_returns) self.mixer.set_track_offset(0) self.song().view.selected_track = self.mixer.channel_strip(0)._track # sends send0_controls = ( SliderElement(MIDI_CC_TYPE, 0, 32), SliderElement(MIDI_CC_TYPE, 0, 36), SliderElement(MIDI_CC_TYPE, 0, 40), None, None, None, None, None, ) self.mixer.channel_strip(0).set_send_controls(tuple(send0_controls)) self.mixer.channel_strip(0).set_volume_control( SliderElement(MIDI_CC_TYPE, 0, 44)) send1_controls = ( SliderElement(MIDI_CC_TYPE, 0, 33), SliderElement(MIDI_CC_TYPE, 0, 37), SliderElement(MIDI_CC_TYPE, 0, 41), None, None, None, None, None, ) self.mixer.channel_strip(1).set_send_controls(tuple(send1_controls)) self.mixer.channel_strip(1).set_volume_control( SliderElement(MIDI_CC_TYPE, 0, 45)) send2_controls = ( SliderElement(MIDI_CC_TYPE, 0, 34), SliderElement(MIDI_CC_TYPE, 0, 38), SliderElement(MIDI_CC_TYPE, 0, 42), None, None, None, None, None, ) self.mixer.channel_strip(2).set_send_controls(tuple(send2_controls)) self.mixer.channel_strip(2).set_volume_control( SliderElement(MIDI_CC_TYPE, 0, 46)) send3_controls = ( SliderElement(MIDI_CC_TYPE, 0, 35), SliderElement(MIDI_CC_TYPE, 0, 39), SliderElement(MIDI_CC_TYPE, 0, 43), None, None, None, None, None, ) self.mixer.channel_strip(3).set_send_controls(tuple(send3_controls)) self.mixer.channel_strip(3).set_volume_control( SliderElement(MIDI_CC_TYPE, 0, 47)) # session global _session num_tracks = 4 num_scenes = 3 session_buttons = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] self._pads = [ ButtonElement(1, MIDI_CC_TYPE, 1, session_buttons[index]) for index in range(num_tracks * num_scenes) ] self._grid = ButtonMatrixElement(rows=[ self._pads[(index * num_tracks):(index * num_tracks) + num_tracks] for index in range(num_scenes) ]) self._session = SessionComponent(num_tracks, num_scenes) self._session.set_clip_launch_buttons(self._grid) self.set_highlighting_session_component(self._session) # session track stop stop_track_buttons = [12, 13, 14, 15] self._track_stop_buttons = [ ButtonElement(1, MIDI_CC_TYPE, 1, stop_track_buttons[index]) for index in range(num_tracks) ] self._session.set_stop_track_clip_buttons( tuple(self._track_stop_buttons)) # session navigation self.session_left = ButtonElement(1, MIDI_CC_TYPE, 3, 8) self._session.set_page_left_button(self.session_left) self.session_left.add_value_listener(self._reload_active_devices, identify_sender=False) self.session_right = ButtonElement(1, MIDI_CC_TYPE, 3, 11) self._session.set_page_right_button(self.session_right) self.session_right.add_value_listener(self._reload_active_devices, identify_sender=False) self.session_up = ButtonElement(1, MIDI_CC_TYPE, 3, 10) self._session.set_page_up_button(self.session_up) self.session_up.add_value_listener(self._reload_active_devices, identify_sender=False) self.session_down = ButtonElement(1, MIDI_CC_TYPE, 3, 13) self._session.set_page_down_button(self.session_down) self.session_down.add_value_listener(self._reload_active_devices, identify_sender=False) self._session._link() self._session.set_mixer(self.mixer) #self._session.set_mixer(self.mixer) self._mode1_devices() self.add_device_listeners() # button: next device self.next_device = ButtonElement(0, MIDI_CC_TYPE, 1, 25) self.next_device.add_value_listener(self._next_device_value, identify_sender=False) # button: prev device self.previous_device = ButtonElement(1, MIDI_CC_TYPE, 1, 24) self.previous_device.add_value_listener(self._prev_device_value, identify_sender=False) # transport global transport self.transport = TransportComponent() self.transport.name = 'Transport' loop_button = ButtonElement(1, MIDI_CC_TYPE, 1, 50) loop_button.name = 'loop_button' self.transport.set_loop_button(loop_button) stop_button = ButtonElement(1, MIDI_CC_TYPE, 1, 49) stop_button.name = 'stop_button' self.transport.set_stop_button(stop_button) play_button = ButtonElement(1, MIDI_CC_TYPE, 1, 48) play_button.name = 'play_button' self.transport.set_play_button(play_button) # button: track navigation right self.track_navigation_right = ButtonElement(1, MIDI_CC_TYPE, 3, 17) self.track_navigation_right.add_value_listener( self._track_navigation_right_track_nav, identify_sender=False) # button: track navigation left self.track_navigation_left = ButtonElement(1, MIDI_CC_TYPE, 3, 14) self.track_navigation_left.add_value_listener( self._track_navigation_left_track_nav, identify_sender=False) def _remove_mode1(self): # mixer global mixer self._remove_mode1_devices() self.remove_device_listeners() send0_controls = ( None, None, None, None, None, None, None, None, ) self.mixer.channel_strip(0).set_send_controls(tuple(send0_controls)) send1_controls = ( None, None, None, None, None, None, None, None, ) self.mixer.channel_strip(1).set_send_controls(tuple(send1_controls)) send2_controls = ( None, None, None, None, None, None, None, None, ) self.mixer.channel_strip(2).set_send_controls(tuple(send2_controls)) send3_controls = ( None, None, None, None, None, None, None, None, ) self.mixer.channel_strip(3).set_send_controls(tuple(send3_controls)) # session global _session self._session.set_clip_launch_buttons(None) self.set_highlighting_session_component(None) self._session.set_mixer(None) self._session.set_stop_all_clips_button(None) # session track stop self._track_stop_buttons = None self._session.set_stop_track_clip_buttons(None) # session scene launch self._scene_launch_buttons = None self._session.set_scene_launch_buttons(None) # session navigation self.session_left.remove_value_listener(self._reload_active_devices) self._session.set_page_left_button(None) self.session_right.remove_value_listener(self._reload_active_devices) self._session.set_page_right_button(None) self.session_up.remove_value_listener(self._reload_active_devices) self._session.set_page_up_button(None) self.session_down.remove_value_listener(self._reload_active_devices) self._session.set_page_down_button(None) self._session = None self.next_device.remove_value_listener(self._next_device_value) self.next_device = None self.previous_device.remove_value_listener(self._prev_device_value) self.previous_device = None # transport global transport self.transport.set_loop_button(None) self.transport.set_stop_button(None) self.transport.set_play_button(None) self.transport = None self.track_navigation_right.remove_value_listener( self._track_navigation_right_track_nav) self.track_navigation_right = None self.track_navigation_left.remove_value_listener( self._track_navigation_left_track_nav) self.track_navigation_left = None def _mode1_devices(self): global mixer global _session # device self.mixer.selected_strip().set_volume_control( SliderElement(MIDI_CC_TYPE, 0, 28)) self.mixer.selected_strip().set_pan_control( SliderElement(MIDI_CC_TYPE, 0, 29)) self.mixer.selected_strip().set_mute_button( ButtonElement(1, MIDI_CC_TYPE, 1, 28)) self.mixer.selected_strip().set_solo_button( ButtonElement(1, MIDI_CC_TYPE, 1, 29)) if (len(self.mixer.selected_strip()._track.devices) > 0): global device_tracktype_selected__chain_number_selected self.device_tracktype_selected__chain_number_selected = DeviceComponent( ) device_controls = ( SliderElement(MIDI_CC_TYPE, 0, 16), SliderElement(MIDI_CC_TYPE, 0, 17), SliderElement(MIDI_CC_TYPE, 0, 18), SliderElement(MIDI_CC_TYPE, 0, 19), SliderElement(MIDI_CC_TYPE, 0, 20), SliderElement(MIDI_CC_TYPE, 0, 21), SliderElement(MIDI_CC_TYPE, 0, 22), SliderElement(MIDI_CC_TYPE, 0, 23), ) self.device_tracktype_selected__chain_number_selected.set_parameter_controls( tuple(device_controls)) self.set_device_component( self.device_tracktype_selected__chain_number_selected) self.device_tracktype_selected__chain_number_selected.set_on_off_button( ButtonElement(1, MIDI_CC_TYPE, 1, 26)) self.device_tracktype_selected__chain_number_selected.set_bank_nav_buttons( ButtonElement(0, MIDI_CC_TYPE, 1, 31), ButtonElement(1, MIDI_CC_TYPE, 1, 33)) def _remove_mode1_devices(self): global mixer global _session # device if (hasattr(self, 'device_tracktype_selected__chain_number_selected')): global device_tracktype_selected__chain_number_selected device_controls = ( None, None, None, None, None, None, None, None, ) self.device_tracktype_selected__chain_number_selected.set_parameter_controls( tuple(device_controls)) self.device_tracktype_selected__chain_number_selected.set_on_off_button( None) self.device_tracktype_selected__chain_number_selected.set_bank_nav_buttons( None, None) self.set_device_component( self.device_tracktype_selected__chain_number_selected) def add_device_listeners(self): global mixer num_of_tracks = len(self.song().tracks) value = "add device listener" for index in range(num_of_tracks): self.song().tracks[index].add_devices_listener( self._reload_active_devices) def remove_device_listeners(self): global mixer num_of_tracks = len(self.song().tracks) value = "remove device listener" for index in range(num_of_tracks): self.song().tracks[index].remove_devices_listener( self._reload_active_devices) def _on_selected_track_changed(self): ControlSurface._on_selected_track_changed(self) self._display_reset_delay = 0 value = "selected track changed" self._reload_active_devices(value) def _reload_active_devices(self, value=None): self._remove_active_devices() self._set_active_devices() def _set_active_devices(self): global active_mode # activate mode if (active_mode == "_mode1") and (hasattr(self, '_mode1_devices')): self._mode1_devices() def _remove_active_devices(self): global active_mode # remove activate mode if (active_mode == "_mode1") and (hasattr(self, '_mode1_devices')): self._remove_mode1_devices() def _next_device_value(self, value): if value > 0: self._device = self.song().view.selected_track.view.selected_device if self._device is not None: self.song().view.select_device( self.song().view.selected_track.devices[ self.selected_device_idx() + 1]) def _prev_device_value(self, value): if value > 0: self._device = self.song().view.selected_track.view.selected_device if self._device is not None: self.song().view.select_device( self.song().view.selected_track.devices[ self.selected_device_idx() - 1]) def selected_device_idx(self): self._device = self.song().view.selected_track.view.selected_device return self.tuple_index(self.song().view.selected_track.devices, self._device) def _track_navigation_right_track_nav(self, value): if value > 0: self.song().view.selected_track = self.song().tracks[ self.selected_track_idx() + 1] def _track_navigation_left_track_nav(self, value): if value > 0: self.song().view.selected_track = self.song().tracks[ self.selected_track_idx() - 1] def selected_track_idx(self): return self.tuple_index(self.song().tracks, self.song().view.selected_track) def _set_active_mode(self): global active_mode # activate mode if active_mode == "_mode1": self._mode1() def _remove_active_mode(self): global active_mode # remove activate mode if active_mode == "_mode1": self._remove_mode1() def _activate_mode1(self, value): global active_mode if value > 0: self._remove_active_mode() active_mode = "_mode1" self._set_active_mode() def _activate_shift_mode1(self, value): global active_mode if value > 0: self._remove_active_mode() self._mode1() else: self._remove_mode1() self._set_active_mode() def tuple_index(self, tuple, obj): for i in xrange(0, len(tuple)): if (tuple[i] == obj): return i return (False) def disconnect(self): super(midi_twister_110, self).disconnect()
class MPK261MX(ControlSurface): def __init__(self, *a, **k): super(MPK261MX, self).__init__(*a, **k) self.show_message( "-----------------------= MPK261MX LOADING - maxcloutier13 says hi =----------------------------------------------------------" ) self.log_message( "-----------------------= MPK261MX LOADING - maxcloutier13 says hi =----------------------------------------------------------" ) with self.component_guard(): midimap = MidiMap() #Super crude manual init for the custom buttons and faders #Bank A - Channel 1 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- self._Encoder0 = EncoderElement( MIDI_CC_TYPE, 1, 22, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder0') self._Encoder1 = EncoderElement( MIDI_CC_TYPE, 1, 23, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder1') self._Encoder2 = EncoderElement( MIDI_CC_TYPE, 1, 24, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder2') self._Encoder3 = EncoderElement( MIDI_CC_TYPE, 1, 25, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder3') self._Encoder4 = EncoderElement( MIDI_CC_TYPE, 1, 26, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder4') self._Encoder5 = EncoderElement( MIDI_CC_TYPE, 1, 27, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder5') self._Encoder6 = EncoderElement( MIDI_CC_TYPE, 1, 28, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder6') self._Encoder7 = EncoderElement( MIDI_CC_TYPE, 1, 29, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder7') self._ArmButton0 = ButtonElement(False, MIDI_CC_TYPE, 0, 32, name='ArmButton0') self._ArmButton1 = ButtonElement(False, MIDI_CC_TYPE, 0, 33, name='ArmButton1') self._ArmButton2 = ButtonElement(False, MIDI_CC_TYPE, 0, 34, name='ArmButton2') self._ArmButton3 = ButtonElement(False, MIDI_CC_TYPE, 0, 35, name='ArmButton3') self._ArmButton4 = ButtonElement(False, MIDI_CC_TYPE, 0, 36, name='ArmButton4') self._ArmButton5 = ButtonElement(False, MIDI_CC_TYPE, 0, 37, name='ArmButton5') self._ArmButton6 = ButtonElement(False, MIDI_CC_TYPE, 0, 38, name='ArmButton6') self._ArmButton7 = ButtonElement(False, MIDI_CC_TYPE, 0, 39, name='ArmButton7') self._VolumeSlider0 = SliderElement(MIDI_CC_TYPE, 0, 12, name='VolumeSlider0') self._VolumeSlider1 = SliderElement(MIDI_CC_TYPE, 0, 13, name='VolumeSlider1') self._VolumeSlider2 = SliderElement(MIDI_CC_TYPE, 0, 14, name='VolumeSlider2') self._VolumeSlider3 = SliderElement(MIDI_CC_TYPE, 0, 15, name='VolumeSlider3') self._VolumeSlider4 = SliderElement(MIDI_CC_TYPE, 0, 16, name='VolumeSlider4') self._VolumeSlider5 = SliderElement(MIDI_CC_TYPE, 0, 17, name='VolumeSlider5') self._VolumeSlider6 = SliderElement(MIDI_CC_TYPE, 0, 18, name='VolumeSlider6') self._VolumeSlider7 = SliderElement(MIDI_CC_TYPE, 0, 19, name='VolumeSlider7') #Bank B - Channel 2 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- self._Encoder8 = EncoderElement( MIDI_CC_TYPE, 2, 22, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder8') self._Encoder9 = EncoderElement( MIDI_CC_TYPE, 2, 23, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder9') self._Encoder10 = EncoderElement( MIDI_CC_TYPE, 2, 24, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder10') self._Encoder11 = EncoderElement( MIDI_CC_TYPE, 2, 25, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder11') self._Encoder12 = EncoderElement( MIDI_CC_TYPE, 2, 26, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder12') self._Encoder13 = EncoderElement( MIDI_CC_TYPE, 2, 27, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder13') self._Encoder14 = EncoderElement( MIDI_CC_TYPE, 2, 28, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder14') self._Encoder15 = EncoderElement( MIDI_CC_TYPE, 2, 29, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder15') self._ArmButton8 = ButtonElement(False, MIDI_CC_TYPE, 1, 32, name='ArmButton8') self._ArmButton9 = ButtonElement(False, MIDI_CC_TYPE, 1, 33, name='ArmButton9') self._ArmButton10 = ButtonElement(False, MIDI_CC_TYPE, 1, 34, name='ArmButton10') self._ArmButton11 = ButtonElement(False, MIDI_CC_TYPE, 1, 35, name='ArmButton11') self._ArmButton12 = ButtonElement(False, MIDI_CC_TYPE, 1, 36, name='ArmButton12') self._ArmButton13 = ButtonElement(False, MIDI_CC_TYPE, 1, 37, name='ArmButton13') self._ArmButton14 = ButtonElement(False, MIDI_CC_TYPE, 1, 38, name='ArmButton14') self._ArmButton15 = ButtonElement(False, MIDI_CC_TYPE, 1, 39, name='ArmButton15') self._VolumeSlider8 = SliderElement(MIDI_CC_TYPE, 1, 12, name='VolumeSlider8') self._VolumeSlider9 = SliderElement(MIDI_CC_TYPE, 1, 13, name='VolumeSlider9') self._VolumeSlider10 = SliderElement(MIDI_CC_TYPE, 1, 14, name='VolumeSlider10') self._VolumeSlider11 = SliderElement(MIDI_CC_TYPE, 1, 15, name='VolumeSlider11') self._VolumeSlider12 = SliderElement(MIDI_CC_TYPE, 1, 16, name='VolumeSlider12') self._VolumeSlider13 = SliderElement(MIDI_CC_TYPE, 1, 17, name='VolumeSlider13') self._VolumeSlider14 = SliderElement(MIDI_CC_TYPE, 1, 18, name='VolumeSlider14') self._VolumeSlider15 = SliderElement(MIDI_CC_TYPE, 1, 19, name='VolumeSlider15') #Bank C - Channel 3 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- self._Encoder16 = EncoderElement( MIDI_CC_TYPE, 3, 22, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder16') self._Encoder17 = EncoderElement( MIDI_CC_TYPE, 3, 23, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder17') self._Encoder18 = EncoderElement( MIDI_CC_TYPE, 3, 24, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder18') self._Encoder19 = EncoderElement( MIDI_CC_TYPE, 3, 25, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder19') self._Encoder20 = EncoderElement( MIDI_CC_TYPE, 3, 26, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder20') self._Encoder21 = EncoderElement( MIDI_CC_TYPE, 3, 27, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder21') self._Encoder22 = EncoderElement( MIDI_CC_TYPE, 3, 28, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder22') self._Encoder23 = EncoderElement( MIDI_CC_TYPE, 3, 29, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder23') self._ArmButton16 = ButtonElement(False, MIDI_CC_TYPE, 2, 32, name='ArmButton16') self._ArmButton17 = ButtonElement(False, MIDI_CC_TYPE, 2, 33, name='ArmButton17') self._ArmButton18 = ButtonElement(False, MIDI_CC_TYPE, 2, 34, name='ArmButton18') self._ArmButton19 = ButtonElement(False, MIDI_CC_TYPE, 2, 35, name='ArmButton19') self._ArmButton20 = ButtonElement(False, MIDI_CC_TYPE, 2, 36, name='ArmButton20') self._ArmButton21 = ButtonElement(False, MIDI_CC_TYPE, 2, 37, name='ArmButton21') self._ArmButton22 = ButtonElement(False, MIDI_CC_TYPE, 2, 38, name='ArmButton22') self._ArmButton23 = ButtonElement(False, MIDI_CC_TYPE, 2, 39, name='ArmButton23') self._VolumeSlider16 = SliderElement(MIDI_CC_TYPE, 2, 12, name='VolumeSlider16') self._VolumeSlider17 = SliderElement(MIDI_CC_TYPE, 2, 13, name='VolumeSlider17') self._VolumeSlider18 = SliderElement(MIDI_CC_TYPE, 2, 14, name='VolumeSlider18') self._VolumeSlider19 = SliderElement(MIDI_CC_TYPE, 2, 15, name='VolumeSlider19') self._VolumeSlider20 = SliderElement(MIDI_CC_TYPE, 2, 16, name='VolumeSlider20') self._VolumeSlider21 = SliderElement(MIDI_CC_TYPE, 2, 17, name='VolumeSlider21') self._VolumeSlider22 = SliderElement(MIDI_CC_TYPE, 2, 18, name='VolumeSlider22') self._VolumeSlider23 = SliderElement(MIDI_CC_TYPE, 2, 19, name='VolumeSlider23') #Drum rack ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- drum_rack = DrumRackComponent( name='Drum_Rack', is_enabled=False, layer=Layer(pads=midimap['Drum_Pads'])) drum_rack.set_enabled(True) #Transport ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- transport = TransportComponent(name='Transport', is_enabled=False, layer=Layer( play_button=midimap['Play'], record_button=midimap['Record'], stop_button=midimap['Stop'], loop_button=midimap['Loop'])) #, seek_forward_button=midimap['Forward'], seek_backward_button=midimap['Backward'] transport.set_enabled(True) #Make the Back/Fwd button just normal mapable CC senders self._BackButton = ButtonElement(False, MIDI_CC_TYPE, 0, 116, name='BackButton') self._FwdButton = ButtonElement(False, MIDI_CC_TYPE, 0, 115, name='FwdButton') #Device ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- self._device = DeviceComponent( name='Device', is_enabled=False, layer=Layer(parameter_controls=midimap['Encoders']), device_selection_follows_track_selection=True) self._device.set_enabled(True) self.set_device_component(self._device) #Mixer ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- mixer_size = 24 self._mixer = MixerComponent(mixer_size, name='Mixer', is_enabled=False) #Super crude and repetitive mapping because after all this shit I'm not spending time learning how to loop this crap hehe #Bank A self._mixer.channel_strip(0).layer = Layer( volume_control=self._VolumeSlider0, arm_button=self._ArmButton0, pan_control=self._Encoder0) self._mixer.channel_strip(1).layer = Layer( volume_control=self._VolumeSlider1, arm_button=self._ArmButton1, pan_control=self._Encoder1) self._mixer.channel_strip(2).layer = Layer( volume_control=self._VolumeSlider2, arm_button=self._ArmButton2, pan_control=self._Encoder2) self._mixer.channel_strip(3).layer = Layer( volume_control=self._VolumeSlider3, arm_button=self._ArmButton3, pan_control=self._Encoder3) self._mixer.channel_strip(4).layer = Layer( volume_control=self._VolumeSlider4, arm_button=self._ArmButton4, pan_control=self._Encoder4) self._mixer.channel_strip(5).layer = Layer( volume_control=self._VolumeSlider5, arm_button=self._ArmButton5, pan_control=self._Encoder5) self._mixer.channel_strip(6).layer = Layer( volume_control=self._VolumeSlider6, arm_button=self._ArmButton6, pan_control=self._Encoder6) self._mixer.channel_strip(7).layer = Layer( volume_control=self._VolumeSlider7, arm_button=self._ArmButton7, pan_control=self._Encoder7) #Bank B self._mixer.channel_strip(8).layer = Layer( volume_control=self._VolumeSlider8, arm_button=self._ArmButton8, pan_control=self._Encoder8) self._mixer.channel_strip(9).layer = Layer( volume_control=self._VolumeSlider9, arm_button=self._ArmButton9, pan_control=self._Encoder9) self._mixer.channel_strip(10).layer = Layer( volume_control=self._VolumeSlider10, arm_button=self._ArmButton10, pan_control=self._Encoder10) self._mixer.channel_strip(11).layer = Layer( volume_control=self._VolumeSlider11, arm_button=self._ArmButton11, pan_control=self._Encoder11) self._mixer.channel_strip(12).layer = Layer( volume_control=self._VolumeSlider12, arm_button=self._ArmButton12, pan_control=self._Encoder12) self._mixer.channel_strip(13).layer = Layer( volume_control=self._VolumeSlider13, arm_button=self._ArmButton13, pan_control=self._Encoder13) self._mixer.channel_strip(14).layer = Layer( volume_control=self._VolumeSlider14, arm_button=self._ArmButton14, pan_control=self._Encoder14) self._mixer.channel_strip(15).layer = Layer( volume_control=self._VolumeSlider15, arm_button=self._ArmButton15, pan_control=self._Encoder15) #Bank C self._mixer.channel_strip(16).layer = Layer( volume_control=self._VolumeSlider16, arm_button=self._ArmButton16, pan_control=self._Encoder16) self._mixer.channel_strip(17).layer = Layer( volume_control=self._VolumeSlider17, arm_button=self._ArmButton17, pan_control=self._Encoder17) self._mixer.channel_strip(18).layer = Layer( volume_control=self._VolumeSlider18, arm_button=self._ArmButton18, pan_control=self._Encoder18) self._mixer.channel_strip(19).layer = Layer( volume_control=self._VolumeSlider19, arm_button=self._ArmButton19, pan_control=self._Encoder19) self._mixer.channel_strip(20).layer = Layer( volume_control=self._VolumeSlider20, arm_button=self._ArmButton20, pan_control=self._Encoder20) self._mixer.channel_strip(21).layer = Layer( volume_control=self._VolumeSlider21, arm_button=self._ArmButton21, pan_control=self._Encoder21) self._mixer.channel_strip(22).layer = Layer( volume_control=self._VolumeSlider22, arm_button=self._ArmButton22, pan_control=self._Encoder22) self._mixer.channel_strip(23).layer = Layer( volume_control=self._VolumeSlider23, arm_button=self._ArmButton23, pan_control=self._Encoder23) self._mixer.set_enabled(True) #-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
class Baseline_script_by_modern_dj_ch2(ControlSurface): __module__ = __name__ # Edie Brickell song __doc__ = " modern.dj baseline MRS controller script for live 9 http://modern.dj/app" #shamless self promotion # Getting issues on Channel switching via Livid Base. The log is clean - but is the issue fixed? please email em [email protected] if you know or can help. def handle_sysex(self, midi_bytes): return None # bootstrap method def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) # bootstrap into the API/_Framework ''' live 9 onlye with self.component_guard(): # live9 / new requirement ''' self.log_message(" - ") self.log_message("**************************************************") self.version_information() # log information from the readme.py file self.log_message(time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) + "..::|| Modern.DJ LIVE8 ch2 baseline MRS opened ||::..") self._suppress_session_highlight = True # stop the "Red box" for a second self._suppress_send_midi = True # sounds like a good idea #self.set_suppress_rebuild_requests(True) #deprecated for 9 !! Legacy note keep here for repository ref, remove later!! # Look for matrix option if enable_matrix == 1: # yes, matrix aka "red box" self.log_message("[matrix enabled]") self.volume_offset = volume_offset # see param info / offset for volume self.box_width = box_width # track width self.box_height = box_height # track height aka scene count self.session = None # local session object self._setup_session_control() # init the session via subclass pattern # Turn on volume is needed. Nested as Volume has session / matrix dependencies if enable_volume_control == 1: self.log_message("[volume control enabled]") self.volume_control = None # param container inside the obj self.mixer = None # holds the obj mixer object # should volume be static or not? if enable_static_volume == 1 : self.track_volume_static = track_volume_static # localize tuple of CCs for volume control self.mixer_custom = None self.custom_offset_mixer() else : self .track_volume = track_volume # localize tuple of CCs for volume control self._setup_mixer_control() self.session.set_mixer(self.mixer) # for the red box to move left/right w/session else: self.log_message("[volume control not enabled") else: self.log_message("[matrix not enabled]") # Check for tempo control option if enable_tempo_control == 1: self.log_message("[tempo enabled]") self._setup_transport_control() else: self.log_message("[tempo not enabled]") # turn on "red box" again -- drops mic, walks off stage ''' live 9 only self._suppress_session_highlight = False ''' ## tempo via @bitNomad / http://github.com/bitnomad # @todo : Move this off and pass the object along newer subclassing patterns def _setup_transport_control(self): transport = CustomTransportComponent() #Instantiate a Transport Component transport.set_tempo_bumpers(transport.button(tempo_button_up), transport.button(tempo_button_down)) # yells "DO IT!!" at tempo code # pass session component through a bunch of subclassing def _setup_session_control(self): self.session = CustomSessionComponent(self.box_width, self.box_height, self) # subclass from _Framework is_momentary = True # what exactly does this do in the _Framework? if up_button_note_number >= 0 and down_button_note_number >= 0: # opt in enable UP/DOWN nav up_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel, up_button_note_number) up_button.name = 'Bank_Select_Up_Button' # sure, why not down_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel, down_button_note_number) down_button.name = 'Bank_Select_Down_Button' #sure, why not self.session.set_scene_bank_buttons(down_button, up_button) if right_button_note_number >= 0 and left_button_note_number >= 0: # opt in enable LEFT/RIGHT nav right_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel, right_button_note_number) right_button.name = 'Bank_Select_Right_Button' #sure, why not left_button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel, left_button_note_number) left_button.name = 'Bank_Select_Left_Button' #sure, why not self.session.set_track_bank_buttons(right_button, left_button) self.session.name = 'Session_Control' #sure, why not matrix = ButtonMatrixElement() # @todo subclass this via established new patterns matrix.name = 'Button_Matrix' #sure, why not # I loop a little different. The goal is readbility, flexibility, and the web app...incase you did not notice yet if len(scene_launch_notes) > 0 and len(scene_launch_notes) == self.box_height: # logic check have launch notes and scene = box height for index in range(self.box_height): self.session.scene(index).set_launch_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel, scene_launch_notes[index])) else : self.log_message("..::|| Scene launch not in use or error on case of use. Modern.DJ ||::..") if len(stop_track_buttons) >0 and len(stop_track_buttons) == self.box_width: #logic check have track stop assignments and track_stop_buttons = [ ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel, stop_track_buttons[index]) for index in range(len(stop_track_buttons))] for index in range(len(track_stop_buttons)): track_stop_buttons[index].name = 'Track_' + str(index) + '_Stop_Button' # sure, why not self.session.set_stop_track_clip_buttons(tuple(track_stop_buttons)) else : self.log_message("..::|| Stop notes not in use or error found Modern.DJ ||::..") # Check for stop all clips option if stop_all_clips >=0 : self.session.set_stop_all_clips_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel, stop_all_clips)) # creating the matrix of buttons from the launch_button_list (tuple) launch_button_list_len = len(launch_button_list) # var used multiple times. This is a performance modification if (self.box_height*self.box_width) == launch_button_list_len : # check box size against number of button vars sent launch_ctr = launch_button_list_len -1 # decrement for zero offset in list/tuple launch_button_list.reverse() #reverse list from human readable for decrement use (performance tweak) ## check for use of RGB if use_velocity_for_RGB != 1: # if not enabled use these defaults self.log_message("..::|| RGB not in effect assigning defaults ||::..") self.clip_loaded_stopped = 1 self.clip_currently_playing = 127 self.clip_triggered_to_play = 64 else: # yes RGB in effect...assign per the parameters script self.clip_loaded_stopped = clip_loaded_stopped self.clip_currently_playing = clip_currently_playing self.clip_triggered_to_play = clip_triggered_to_play for scene_index in range(self.box_height): # loop on the notes matrix scene = self.session.scene(scene_index) # part of the martix built, think rows scene.name = 'Scene_' + str(scene_index) # sure, why not button_row = [] # create recepticle # loop across the tracks for track_index in range(self.box_width): button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, midi_channel, launch_button_list[launch_ctr]) # button instance for _Framework launch_ctr = launch_ctr -1# decrement is faster than increment button.name = str(track_index) + '_Clip_' + str(scene_index) + '_Button' # sure, why not button_row.append(button) # add to our growing list clip_slot = scene.clip_slot(track_index) # clips slot and buttons are not the same thing, this aligns these ideas in the red box clip_slot.name = str(track_index) + '_Clip_Slot_' + str(scene_index) # sure, why not # assign the button and and status in th refrech update clip_slot.set_stopped_value(self.clip_loaded_stopped ) # this number is sent back to the machine allowing diff colors for stopped clip_slot.set_started_value(self.clip_currently_playing) # this number is sent back to the machine allowing diff colors for started/is-playing clip_slot.set_triggered_to_play_value(self.clip_triggered_to_play) # this number is sent back to the machine allowing diff colors for cued, will play next clip_slot.set_launch_button(button) # part of the slit+button = go time paradigm matrix.add_row(tuple(button_row)) # close out the matrix build. @todo - possible subclass here? else : # log message self.log_message("..::|| Number of notes defined does not match box height and width Modern.DJ ||::..") ''' live 9 only self.set_highlighting_session_component(self.session) # new for live9 -- this is for the box. via aumhaa/bitnomad ''' return None # Volume control specific # Creation of a slider for volume. Not a small burger def slider(self, channel, value): if (value != -1): return SliderElement(MIDI_CC_TYPE, channel, value) # assign data to slider object else: return None # Static volume control offset via volume_offset param def custom_offset_mixer(self): # skipped the subclass # for some reason this pattern will allow the offset and static volume control. # looking for explaination and insight on this...Bueller? self.mixer_custom = MixerComponent(self.box_width) # get a local mixer object ready self.mixer_custom.name = 'Mixer Custom' # name self.mixer_custom.set_track_offset(self.volume_offset) # the offset # compare width with track vol count to qualify -- put somewhere else for index in range(self.box_width): # @marwei must kill this style and count self.mixer_custom.channel_strip(index).set_volume_control(self.slider(midi_channel, self.track_volume_static[index])) # volume control specific, will move with red box # Set up mixer locally / object def _setup_mixer_control(self): self.mixer = CustomMixerComponent(self.box_width, self) # essentially grab the super class self.mixer.name = 'Mixer' # sure, why not self.mixer.set_track_offset(0) # not sure if needed, seems not to hurt. # check box width and tuple size. Forward compatibility if len(self.track_volume) == self.box_width: # error checking per established app standard # loop on the CCs and create strip/volume control for index in range(self.box_width): # @todo kill this and count in reverse via decrement (performance) self.mixer.channel_strip(index).set_volume_control(self.slider(midi_channel, self.track_volume[index])) else: # bad math, error messAge, fail self.log_message(time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) + "..::|| volume param bad math message. box_width != len(track_volume) ||::..") def disconnect(self): self.log_message(time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) + "..::|| Modern.DJ LIVE8 ch2 baseline MRS opened ||::..") self.log_message("**************************************************") self.log_message(" - ") ControlSurface.disconnect(self) return None def version_information(self): baseline_version = str(baseline_script_version_major) baseline_version += '.'+str(baseline_script_version_minor) baseline_version += '.'+str(baseline_script_version_patch) self.log_message('Modern.Dj Baseline Script Version '+baseline_version) self.log_message('Modern.Dj Baseline Script Release Note : '+baseline_script_version_note)
def _setup_mixer_control(self): num_tracks = GRIDSIZE[ 1] # Here we define the mixer width in tracks (a mixer has only one dimension) global mixer # We want to instantiate the global mixer as a MixerComponent object (it was a global "None" type up until now...) mixer = MixerComponent( num_tracks) #(num_tracks, num_returns, with_eqs, with_filters) mixer.set_track_offset( 0) #Sets start point for mixer strip (offset from left) """set up the mixer buttons""" self.song().view.selected_track = mixer.channel_strip(0)._track #master_volume_control = SliderElement(MIDI_CC_TYPE, 1, 17) for index in range(GRIDSIZE[1]): mixer.channel_strip(index).set_volume_control( SliderElement(MIDI_CC_TYPE, CHANNEL, MIX_FADERS[index])) mixer.channel_strip(index).set_arm_button( ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, ARM_BUTTONS[index])) #sets the record arm button mixer.channel_strip(index).set_solo_button( ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, SOLO_BUTTONS[index])) mixer.channel_strip(index).set_mute_button( ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, MUTE_BUTTONS[index])) mixer.channel_strip(index).set_select_button( ButtonElement(True, MIDI_NOTE_TYPE, CHANNEL, TRACK_SELECTS[index])) """TRANSPORT CONTROLS""" stop_button = ButtonElement(False, MIDI_CC_TYPE, 0, STOP_BUTTON) play_button = ButtonElement(False, MIDI_CC_TYPE, 0, PLAY_BUTTON) record_button = ButtonElement(False, MIDI_CC_TYPE, 0, RECORD_BUTTON) transport = TransportComponent() transport.set_stop_button(stop_button) transport.set_play_button(play_button) transport.set_overdub_button(record_button) transport.set_overdub_button(record_button) transport.set_seek_buttons( ButtonElement(False, MIDI_CC_TYPE, 0, SEEK_LEFT), ButtonElement(False, MIDI_CC_TYPE, 0, SEEK_RIGHT))
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 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 KeyPad(ControlSurface): """ Reloop KeyPad controller script. """ _encoder_range = range(73, 81) _product_model_id = 101 def __init__(self, c_instance): super(KeyPad, self).__init__(c_instance) with self.component_guard(): self._create_controls() self._setup_mixer() self._setup_transport() self._setup_session() self._setup_cue_control() self.set_pad_translations(PAD_TRANSLATIONS) def _preset_message(self, send_byte): """ Sysex message for setting the preset to #2. """ return (240, 38, self._product_model_id, send_byte, 17, 2, 247) def refresh_state(self): super(KeyPad, self).refresh_state() self.schedule_message(2, self._send_midi, self._preset_message(1)) def handle_sysex(self, midi_bytes): if midi_bytes != self._preset_message(2): super(KeyPad, self).handle_sysex(midi_bytes) else: map(lambda x: x.set_enabled(True), (self._mixer, self._session, self._transport, self._cue_control)) def _create_controls(self): def make_controls_range(maker, label, cc_range): ccs = [(index + 1, cc) for index, cc in enumerate(cc_range)] return [maker(1, cc, label % index) for index, cc in ccs] + [ maker(2, cc, label % (index + len(ccs))) for index, cc in ccs ] def make_controls(maker, label, cc_offset): return make_controls_range(maker, label, xrange(cc_offset, cc_offset + 8)) make_non_momentary_button = partial(make_button, is_momentary=False) self._encoders = make_controls(make_encoder, 'Encoder_%d', 57) self._rotaries_a = make_controls(make_slider, 'Rotary_A%d', 89) self._rotaries_b = make_controls(make_slider, 'Rotary_B%d', 97) self._faders = make_controls(make_slider, 'Fader_%d', 0) self._mute_buttons = make_controls(make_non_momentary_button, 'Mute_%d_Button', 8) self._solo_buttons = make_controls(make_button, 'Solo_%d_Button', 24) self._arm_buttons = make_controls(make_button, 'Arm_%d_Button', 40) self._play_button = make_button(1, 105, 'Play_Button') self._stop_button = make_button(1, 106, 'Stop_Button') self._record_button = make_button(1, 107, 'Record_Button') self._encoder_pushes = make_controls_range( partial(make_button, is_momentary=False), 'Encoder_%d_Button', self._encoder_range) self._shifted_mute_buttons = make_controls(make_non_momentary_button, 'Shifted_Mute_%d_Button', 16) self._shifted_solo_buttons = make_controls(make_button, 'Shifted_Solo_%d_Button', 32) self._all_shifted_arm_buttons = make_controls(make_button, 'Shifted_Arm_%d_Button', 49) self._shifted_arm_buttons = [ CombinedButtonsElement( buttons=(self._all_shifted_arm_buttons[index], self._all_shifted_arm_buttons[index + 8])) for index in xrange(8) ] self._shifted_play_button = make_button(1, 108, 'Shifted_Play_Button') self._shifted_stop_button = make_button(1, 109, 'Shifted_Stop_Button') self._shifted_record_button = make_button(1, 110, 'Shifted_Record_Button') self._shifted_octave_down_button = make_button( 1, 111, 'Shifted_Octave_Down_Button') self._shifted_octave_up_button = make_button( 1, 112, 'Shifted_Octave_Up_Button') def _setup_mixer(self): self._mixer = MixerComponent(NUM_CHANNEL_STRIPS) self._mixer.name = 'Mixer' self._mixer.set_enabled(False) for index in xrange(NUM_CHANNEL_STRIPS): strip = self._mixer.channel_strip(index) strip.set_invert_mute_feedback(True) sends = ButtonMatrixElement(name='%d_Send_Controls' % (index + 1), rows=[(self._rotaries_a[index], self._rotaries_b[index])]) strip.layer = Layer(volume_control=self._faders[index], pan_control=self._encoders[index], send_controls=sends, mute_button=self._mute_buttons[index], solo_button=self._solo_buttons[index], arm_button=self._arm_buttons[index], select_button=self._encoder_pushes[index]) def _setup_transport(self): self._transport = TransportComponent(name='Transport') self._transport.set_enabled(False) self._transport.layer = Layer( play_button=self._play_button, stop_button=self._stop_button, record_button=self._record_button, overdub_button=self._shifted_record_button, loop_button=self._shifted_arm_buttons[3], tap_tempo_button=self._shifted_arm_buttons[4], metronome_button=self._shifted_arm_buttons[5], nudge_down_button=self._shifted_arm_buttons[6], nudge_up_button=self._shifted_arm_buttons[7]) def _setup_session(self): self._session = SessionComponent(NUM_CHANNEL_STRIPS, name='Session_Control') self._session.set_enabled(False) stop_buttons = ButtonMatrixElement(name='Track_Stop_Buttons', rows=[self._shifted_solo_buttons]) self._session.layer = Layer( stop_all_clips_button=self._shifted_stop_button, stop_track_clip_buttons=stop_buttons, select_prev_button=self._shifted_octave_down_button, select_next_button=self._shifted_octave_up_button) self._session.selected_scene().name = 'Selected_Scene_Control' self._session.selected_scene().layer = Layer( launch_button=self._shifted_play_button) for index in xrange(NUM_CHANNEL_STRIPS): slot = self._session.selected_scene().clip_slot(index) slot.layer = Layer(launch_button=self._shifted_mute_buttons[index]) def _setup_cue_control(self): self._cue_control = CuePointControlComponent(name='Cue_Point_Control') self._cue_control.set_enabled(False) self._cue_control.layer = Layer( toggle_cue_button=self._shifted_arm_buttons[0], prev_cue_button=self._shifted_arm_buttons[1], next_cue_button=self._shifted_arm_buttons[2])
class Codex(Codec): def __init__(self, c_instance, *a, **k): self._shifted = False super(Codex, self).__init__(c_instance, *a, **k) with self.component_guard(): self._setup_alt_mixer() self._setup_alt_device_selector() self._setup_alt_send_reset() self._setup_alt_device_control() self.log_message( '<<<<<<<<<<<<<<<<<<<<<<<<< Codex subclass log opened >>>>>>>>>>>>>>>>>>>>>>>>>' ) self.schedule_message(1, self._mode_update) def _setup_alt_device_selector(self): self._alt_device_selector = NewDeviceSelectorComponent(self) self._alt_device_selector.name = 'Alt_Device_Selector' def _setup_alt_send_reset(self): self._alt_send_reset = ResetSendsComponent(self) self._alt_send_reset.name = 'Alt_Reset_Sends' """these two secondary DeviceComponents are only set up if the MONOHM_LINK flag in Map is turned on""" def _setup_alt_device_control(self): self._device1 = NewDeviceComponent() self._device1.name = 'Device_Component1' self._device2 = NewDeviceComponent() self._device2.name = 'Device_Component2' def _setup_alt_mixer(self): is_momentary = True self._num_tracks = (8) #A mixer is one-dimensional self._mixer2 = MixerComponent(8, 4, False, False) self._mixer2.name = 'Mixer' #self._mixer2.set_track_offset(4) #Sets start point for mixer strip (offset from left) for index in range(8): self._mixer2.channel_strip( index).name = 'Mixer_ChannelStrip_' + str(index) self._mixer2.channel_strip(index)._invert_mute_feedback = True """Mode Functions""" def _enable_alt(self): if self._main_mode._mode_index == 0: for encoder, _ in self._encoder_matrix.submatrix[:, 0:2].iterbuttons( ): encoder.set_enabled(False) encoder.reset() self._alt_enabled = True self._mode_update() super(Codex, self)._enable_alt() def _disable_alt(self): if self._main_mode._mode_index == 0: self._button_matrix.submatrix[:, 0:2].reset() for encoder, _ in self._encoder_matrix.submatrix[:, 0:2].iterbuttons( ): encoder.set_enabled(True) super(Codex, self)._disable_alt() def _deassign_all(self): self._alt_send_reset.set_buttons(tuple([None for index in range(4)])) self._alt_send_reset.set_enabled(False) self._alt_device_selector.set_buttons(None) self._alt_device_selector.set_enabled(False) self._mixer2.selected_strip().set_send_controls(None) for index in range(8): self._mixer2.channel_strip(index).set_volume_control(None) self._mixer2.channel_strip(index).set_select_button(None) self._mixer2.channel_strip(index).set_mute_button(None) self._dial[index][2].release_parameter() for index in range(3): self._mixer2.return_strip(index).set_volume_control(None) self._device1.set_enabled(False) self._device1._parameter_controls = None self._device2.set_enabled(False) self._device2._parameter_controls = None self._mixer2.return_strip(0).set_send_controls(None) self._mixer2.return_strip(1).set_send_controls(None) self._mixer2.return_strip(2).set_send_controls(None) super(Codex, self)._deassign_all() def _assign_volume(self): if self._alt_enabled: inputs = self.find_inputs() if not inputs is None: for index in range(4): self._dial[index][2].connect_to(inputs.parameters[index + 1]) self._dial[6][2].connect_to(inputs.parameters[5]) xfade = self.find_perc_crossfader() if not xfade is None: self._dial[7][3].connect_to(xfade) self._alt_device_selector.set_matrix( self._button_matrix.submatrix[:, 0:2]) self._alt_device_selector.set_enabled(True) self._mixer2.return_strip(0).set_send_controls( [None, self._dial[4][2]]) self._mixer2.return_strip(1).set_send_controls( [self._dial[5][2], None]) else: self._alt_send_reset.set_buttons( tuple([ self._button[4][2], self._button[5][2], self._button[6][2], self._button[7][2] ])) self._alt_send_reset.set_enabled(True) self._mixer2.selected_strip().set_send_controls([ self._dial[0][2], self._dial[1][2], self._dial[2][2], self._dial[3][2] ]) for index in range(3): self._mixer2.return_strip(index).set_volume_control( self._dial[index + 4][2]) self._mixer2.set_crossfader_control(self._dial[7][2]) self._device1.set_parameter_controls( tuple([ self._dial[index % 4][int(index / 4)] for index in range(8) ])) self._device2.set_parameter_controls( tuple([ self._dial[(index % 4) + 4][int(index / 4)] for index in range(8) ])) self._device1.set_enabled(True) self._device2.set_enabled(True) self._find_devices() self._device1.update() self._device2.update() for index in range(8): self._mixer2.channel_strip(index).set_select_button( self._column_button[index]) for index in range(8): self._mixer2.channel_strip(index).set_volume_control( self._dial[index][3]) self._mixer2.channel_strip(index).set_mute_button( self._button[index][3]) self._mixer2.update() self.request_rebuild_midi_map() #self._mixer2.set_track_offset(TROLL_OFFSET) def find_inputs(self): found_device = None tracks = self.song().tracks for track in tracks: if track.name == 'Inputs': for device in track.devices: if bool(device.can_have_chains ) and device.name == 'Inputs': found_device = device return found_device def find_perc_crossfader(self): found_parameter = None tracks = self.song().tracks for track in tracks: if track.name == 'Perc': for device in track.devices: if bool(device.can_have_chains) and device.name == 'Perc': for parameter in device.parameters: if parameter.name == 'XFade': found_parameter = parameter return found_parameter """this method is used to find the devices the alt controls will latch to""" def _find_devices(self): if self._device1: if len(self.song().return_tracks) > 0: if len(self.song().return_tracks[0].devices) > 0: if self._device1._locked_to_device: self._device1.set_lock_to_device( False, self._device1._device) self._device1.set_lock_to_device( True, self.song().return_tracks[0].devices[0]) if self._device2: if len(self.song().return_tracks) > 1: if len(self.song().return_tracks[1].devices) > 0: if self._device2._locked_to_device: self._device2.set_lock_to_device( False, self._device2._device) self._device2.set_lock_to_device( True, self.song().return_tracks[1].devices[0])
class Codec(ControlSurface): __module__ = __name__ __doc__ = " MonoCode controller script " def __init__(self, c_instance, *a, **k): super(Codec, self).__init__(c_instance, *a, **k) self._monomod_version = 'b995' self._version_check = 'b995' self._host_name = 'Codec' self._color_type = 'Monochrome' self._link_mixer = LINK_MIXER self._hosts = [] self._linked_script = None self._local_ring_control = True self._last_device = None self._device_list = [None, None, None, None] self._device_select_buttons = None self._last_device_component = None self._timer = 0 self._touched = 0 self._locked = False self.flash_status = 1 self._shift_button = None self._shift_pressed = 0 self._shift_pressed_timer = 0 self._shift_thresh = SHIFT_THRESH self._use_device_selector = USE_DEVICE_SELECTOR self._device_selection_follows_track_selection=FOLLOW with self.component_guard(): #self.local_ring_control(True) #self.set_absolute_mode(True) self._setup_controls() self._setup_monobridge() self._setup_device_controls() self._setup_special_device_control() self._device.append(self._special_device) #necessary for device browsing to work with special device self._setup_device_chooser() self._setup_mixer_controls() self._setup_monomod() self._setup_modes() self._setup_device_selector() self._setup_send_reset() self._setup_default_buttons() self.set_local_ring_control(1) self.song().view.add_selected_track_listener(self._update_selected_device) self._initialize_code() #self._shift_mode.set_mode(0) #self._monomod_mode.set_mode(0) self.log_message('<<<<<<<<<<<<<<<<<<<<<<<<< Codec ' + str(self._monomod_version) + ' log opened >>>>>>>>>>>>>>>>>>>>>>>>>') self.show_message('Codec Control Surface Loaded') self.request_rebuild_midi_map() """script initialization methods""" def _initialize_code(self): self._send_midi(factoryreset) self._send_midi(btn_channels) self._send_midi(enc_channels) def _setup_monobridge(self): self._monobridge = MonoBridgeElement(self) self._monobridge.name = 'MonoBridge' def _setup_controls(self): is_momentary = True self._livid = CodecMonoButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, LIVID, 'Livid_Button', self) self._dial = [None for index in range(8)] for column in range(8): self._dial[column] = [None for index in range(4)] for row in range(4): self._dial[column][row] = CodecEncoderElement(MIDI_CC_TYPE, CHANNEL, CODE_DIALS[row][column], Live.MidiMap.MapMode.absolute, 'Dial_' + str(column) + '_' + str(row), (column + (row*8)), self) #CODE_DIALS[row][column] self._button = [None for index in range(8)] for column in range(8): self._button[column] = [None for index in range(4)] for row in range(4): self._button[column][row] = CodecMonoButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, CODE_BUTTONS[row][column], 'Button_' + str(column) + '_' + str(row), self) self._column_button = [None for index in range(8)] for index in range(8): self._column_button[index] = CodecMonoButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, CODE_COLUMN_BUTTONS[index], 'Column_Button_' + str(index), self) self._row_button = [None for index in range(4)] for index in range(4): self._row_button[index] = CodecMonoButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, CODE_ROW_BUTTONS[index], 'Row_Button_' + str(index), self) self._dial_matrix = EncoderMatrixElement(self) self._dial_matrix.name = 'Encoder_Matrix' for row in range(4): dial_row = tuple([self._dial[column][row] for column in range(8)]) self._dial_matrix.add_row(dial_row) self._button_matrix = ButtonMatrixElement() self._button_matrix.name = 'Button_Matrix' for row in range(4): button_row = [self._button[column][row] for column in range(8)] button_row.append(self._row_button[row]) self._button_matrix.add_row(tuple(button_row)) self._button_matrix.add_row(tuple(self._column_button + [self._livid])) def _setup_modes(self): self._monomod_mode = MonomodModeComponent(self._mod_mode_update, self) self._monomod_mode.name = 'Monomod_Mode' self.set_shift_button(self._livid) self._shift_mode = ShiftModeComponent(self._shift_update, self) self._shift_mode.name = 'Shift_Mode' self._shift_mode.set_mode_buttons(tuple([self._row_button[0], self._row_button[1], self._row_button[2], self._row_button[3]])) def _setup_transport_control(self): self._transport = TransportComponent() self._transport.name = 'Transport' def _setup_monomod(self): self._host = CodecMonomodComponent(self) self._host.name = 'Monomod_Host' self._host._set_dial_matrix(self._dial_matrix, self._button_matrix) self.hosts = [self._host] encs = [] for row in range(4): for col in range(8): encs.append(self._dial[col][row]) self._host._set_parameter_controls(encs) def _setup_mixer_controls(self): is_momentary = True self._num_tracks = (8) self._session = SessionComponent(self._num_tracks, 0) self._session.name = 'Session' self._mixer = MixerComponent(self._num_tracks, 0, False, False) self._mixer.name = 'Mixer' self._mixer._next_track_value = self._mixer_next_track_value(self._mixer) self._mixer._prev_track_value = self._mixer_prev_track_value(self._mixer) self._mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left) #for index in range(8): #use the bottom row of encoders for volume, so add 24 to offset the index # self._mixer.channel_strip(index).set_volume_control(self._dial[index+24]) for index in range(8): self._mixer.channel_strip(index).name = 'Mixer_ChannelStrip_' + str(index) self._mixer.channel_strip(index)._invert_mute_feedback = True self._mixer.channel_strip(index)._mute_value = self._channelstrip_mute_value(self._mixer.channel_strip(index)) self._mixer.channel_strip(index)._solo_value = self._channelstrip_solo_value(self._mixer.channel_strip(index)) #mixer.channel_strip(index).set_select_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CH, track_select_notes[index])) 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._session.set_mixer(self._mixer) def _setup_device_controls(self): self._device = [None for index in range(4)] for index in range(4): self._device[index] = CodecDeviceComponent(self) self._device[index].name = 'CodecDevice_Component_' + str(index) device_param_controls = [] for control in range(8): device_param_controls.append(self._dial[control][index]) self._device[index].set_on_off_button(self._button[1][index]) self._device[index].set_lock_button(self._button[2][index]) self._device[index].set_bank_nav_buttons(self._button[4][index], self._button[5][index]) self._device[index].set_nav_buttons(self._button[6][index], self._button[7][index]) self._device[index].set_parameter_controls(tuple(device_param_controls)) self.set_device_component(self._device[0]) self._last_device_component = self._device[0] def _setup_special_device_control(self): self._special_device = SpecialCodecDeviceComponent(self) self._special_device.name = 'SpecialCodecDeviceComponent' self._special_device.set_on_off_button(self._button[1][0]) self._special_device.set_lock_button(self._button[2][0]) self._special_device.set_bank_nav_buttons(self._button[4][0], self._button[5][0]) self._special_device.set_nav_buttons(self._button[6][0], self._button[7][0]) device_param_controls = [] for row in range(4): for column in range(8): device_param_controls.append(self._dial[column][row]) self._special_device.set_parameter_controls(tuple(device_param_controls)) def _setup_device_chooser(self): self._selected_device = self._device[0] self._last_selected_device = self._device[0] self._device_select_buttons = [self._button[0][index] for index in range(4)] for button in self._device_select_buttons: button.add_value_listener(self._device_select_value, True) def _setup_device_selector(self): self._device_selector = CodecDeviceSelectorComponent(self, 'c', self._device + [self._special_device]) self._device_selector.name = 'Device_Selector' self._device_selector.set_mode_buttons(self._column_button) #self._device_selector.set_mode_toggle(self._livid) def _setup_send_reset(self): self._send_reset = CodecResetSendsComponent(self) self._send_reset.set_buttons(self._button) def _setup_default_buttons(self): self._value_default = ParameterDefaultComponent(self) buttons = [] dials = [] for column in self._button: for button in column: buttons.append(button) for column in self._dial: for dial in column: dials.append(dial) self._value_default.set_buttons(buttons) self._value_default.set_dials(dials) """multiple device support""" def _device_select_value(self, value, sender): #self.log_message('device_select_value ' + str(value) + ' ' + str(self._device_select_buttons.index(sender))) if not self._shift_pressed: if sender.is_momentary or value > 0: if self._shift_mode._mode_index == 2: self.set_device_component(self._device[self._device_select_buttons.index(sender)]) self._last_device_component = self._device_component if self._device_component != None and isinstance(self._device_component._device, Live.Device.Device): if self._device_component.find_track(self._device_component._device) == self.song().view.selected_track: self._device_component.display_device() """livid double press mechanism""" def set_shift_button(self, button): assert ((button == None) or (isinstance(button, MonoButtonElement))) if self._shift_button != None: self._shift_button.remove_value_listener(self._shift_value) self._shift_button = button if self._shift_button != None: self._shift_button.add_value_listener(self._shift_value) def _shift_value(self, value): self._shift_pressed = int(value != 0) if self._shift_pressed > 0: self._send_midi(SLOWENCODER) if (self._shift_pressed_timer + self._shift_thresh) > self._timer: #if(self._host.is_enabled() != True) self.log_message('mod mode: ' + str(abs(self._monomod_mode._mode_index - 1))) self._monomod_mode.set_mode(max(0, min(1, abs(self._monomod_mode._mode_index - 1)))) #else: # self._monomod_mode.set_mode(0) self._shift_pressed_timer = self._timer % 256 else: self._send_midi(NORMALENCODER) def _mod_mode_update(self): if(self._monomod_mode._mode_index == 0): self._host._set_shift_button(None) self._host.set_enabled(False) self._dial_matrix.reset() self._shift_mode.set_enabled(True) self._shift_update() self.request_rebuild_midi_map() self._livid.turn_off() elif(self._monomod_mode._mode_index == 1): self._shift_mode.set_enabled(False) self._deassign_all() self._dial_matrix.reset() self._button_matrix.reset() self._livid.turn_on() if not self._host._active_client == None: self._host.set_enabled(True) self._host._set_shift_button(self._livid) else: self._assign_alternate_mappings(1) self.request_rebuild_midi_map() """Mode Functions""" def _shift_update(self): if(self._shift_mode.is_enabled()): with self.component_guard(): self.allow_updates(False) #if(not self._in_build_midi_map): # self.set_suppress_rebuild_requests(True) self._deassign_all() if(self._shift_mode._mode_index is 0): self._assign_volume() elif(self._shift_mode._mode_index is 1): self._assign_sends() elif(self._shift_mode._mode_index is 2): self._assign_devices() elif(self._shift_mode._mode_index is 3): self._assign_special_device() for index in range(self._shift_mode.number_of_modes()): if index == self._shift_mode._mode_index: self._shift_mode._modes_buttons[index].turn_on() else: self._shift_mode._modes_buttons[index].turn_off() self.allow_updates(True) #self.set_suppress_rebuild_requests(False) self.request_rebuild_midi_map() def _deassign_all(self): self._assign_alternate_mappings(0) self._device_selector.set_enabled(False) for index in range(8): self._mixer.channel_strip(index).set_volume_control(None) self._mixer.channel_strip(index).set_pan_control(None) self._mixer.channel_strip(index).set_send_controls(tuple([None, None, None, None])) for index in range(4): self._device[index].set_enabled(False) self._device[index]._parameter_controls = None #self._device_navigator[index].set_enabled(False) self._special_device.set_enabled(False) self._special_device._parameter_controls = None self._device_selector.set_enabled(False) self._deassign_buttons() for control in self.controls: control.reset() self.request_rebuild_midi_map() def _deassign_buttons(self): for index in range(8): self._mixer.channel_strip(index).set_select_button(None) self._mixer.channel_strip(index).set_solo_button(None) self._mixer.channel_strip(index).set_mute_button(None) self._mixer.set_select_buttons(None, None) self._send_reset.set_enabled(False) def _assign_volume(self): for index in range(8): self._mixer.channel_strip(index).set_volume_control(self._dial[index][3]) self._mixer.channel_strip(index).set_pan_control(self._dial[index][2]) self._mixer.channel_strip(index).set_send_controls(tuple([self._dial[index][0], self._dial[index][1]])) self._mixer.channel_strip(index).set_select_button(self._column_button[index]) self._mixer.channel_strip(index).set_solo_button(self._button[index][2]) self._mixer.channel_strip(index).set_mute_button(self._button[index][3]) self._mixer.set_select_buttons(self._button[7][0], self._button[6][0]) def _assign_sends(self): for index in range(8): self._mixer.channel_strip(index).set_send_controls(tuple([self._dial[index][0], self._dial[index][1], self._dial[index][2], self._dial[index][3]])) self._mixer.channel_strip(index).set_select_button(self._column_button[index]) self._send_reset.set_enabled(True) def _assign_devices(self): self.set_device_component(self._last_device_component) self._device_select_value(1, self._device_select_buttons[self._device.index(self._device_component)]) for index in range(4): device_param_controls = [] for control in range(8): device_param_controls.append(self._dial[control][index]) self._device[index].set_parameter_controls(tuple(device_param_controls)) self._device[index].set_enabled(True) self._device_selector.set_enabled(self._use_device_selector) if not self._use_device_selector: for index in range(8): self._mixer.channel_strip(index).set_select_button(self._column_button[index]) def _assign_special_device(self): self.set_device_component(self._special_device) device_param_controls = [] for row in range(4): for column in range(8): device_param_controls.append(self._dial[column][row]) self._special_device.set_parameter_controls(tuple(device_param_controls)) self._special_device.set_enabled(True) self._device_selector.set_enabled(self._use_device_selector) if not self._use_device_selector: for index in range(8): self._mixer.channel_strip(index).set_select_button(self._column_button[index]) def _assign_alternate_mappings(self, chan): for column in self._dial: for control in column: control.set_channel(chan) control.set_enabled(chan is 0) for column in self._button: for control in column: control.set_channel(chan) control.set_enabled(chan is 0) for control in self._column_button: control.set_channel(chan) control.set_enabled(chan is 0) for control in self._row_button: control.set_channel(chan) control.set_enabled(chan is 0) """general functionality""" def disconnect(self): """clean things up on disconnect""" if not self._shift_button is None: if self._shift_button.value_has_listener(self._shift_value): self._shift_button.remove_value_listener(self._shift_value) for button in self._device_select_buttons: if button.value_has_listener(self._device_select_value): button.remove_value_listener(self._device_select_value) if self._session._is_linked(): self._session._unlink() self.song().view.remove_selected_track_listener(self._update_selected_device) """for cs in self._control_surfaces(): for host in self._hosts: self.log_message('installed: ' + str(cs) + ' vs. ' + str(host)) if str(type(cs)) == str(type(host)): self.log_message('disconnecting: ' + str(type(cs))) cs.disconnect(cs)""" #self._host._set_parameter_controls(None) self._hosts = [] if self._linked_script != None: self._linked_script._update_linked_device_selection = None self._linked_script = None #self._disconnect_notifier.set_mode(0) self.log_message('<<<<<<<<<<<<<<<<<<<<<<<<< Codec log closed >>>>>>>>>>>>>>>>>>>>>>>>>') ControlSurface.disconnect(self) return None def connect_script_instances(self, instanciated_scripts): found = False for s in instanciated_scripts: if '_codec_version' in dir(s): if s._codec_version == self._version_check: if s._host_name == ('MonOhm'): self.log_message('found codec version ' + str(s._codec_version) + ' in script ' + str(s._host_name)) found = True self._linked_script = s self._linked_script._update_linked_device_selection = self._update_linked_device_selection if not self._session._is_linked() and self._link_mixer is True: self._session.set_offsets(LINK_OFFSET[0], LINK_OFFSET[1]) self._session._link() else: self.log_message('version mismatch: Monomod version ' + str(self._version_check) + ' vs. Host version ' + str(s._codec_version)) if found == False: for s in instanciated_scripts: if '_codec_version' in dir(s): if s._codec_version == self._version_check: if s._host_name == 'BlockMod': self.log_message('found codec version ' + str(s._codec_version) + ' in script ' + str(s._host_name)) self._linked_script = s self._linked_script._update_linked_device_selection = self._update_linked_device_selection if not self._session._is_linked() and self._link_mixer is True: self._session.set_offsets(LINK_OFFSET[0], LINK_OFFSET[1]) self._session._link() else: self.log_message('version mismatch: Monomod version ' + str(self._version_check) + ' vs. Host version ' + str(s._codec_version)) #self.log_message('hosts: ' + str(self._hosts))""" def update_display(self): ControlSurface.update_display(self) #since we are overriding this from the inherited method, we need to call the original routine as well self._timer = (self._timer + 1) % 256 if(self._timer == 0): self._shift_pressed_timer = -12 if(self._local_ring_control is False): self.send_ring_leds() self.flash() def handle_sysex(self, midi_bytes): #self._send_midi(tuple([240, 00, 01, 97, 04, 15, 01, 247])) #response = [long(0),long(0)] #self.log_message(response) pass def flash(self): if(self.flash_status > 0): for control in self.controls: if isinstance(control, MonoButtonElement): control.flash(self._timer) def send_ring_leds(self): leds = [240, 0, 1, 97, 4, 31] for column in range(8): for row in range(4): wheel = self._dial[column][row] bytes = wheel._get_ring() leds.append(bytes[0]) leds.append(int(bytes[1]) + int(bytes[2])) #if(row == 1 and column == 0): # self.log_message(str(leds) + ' ' + str(bytes[0]) + ' ' + str(bytes[1]) + ' ' + str(bytes[2])) leds.append(247) self._send_midi(tuple(leds)) def set_absolute_mode(self, val = 1): self._absolute_mode = (val!=0) if self._absolute_mode is True: self._send_midi(tuple([240, 0, 1, 97, 4, 17, 0, 0, 0, 0, 0, 0, 0, 0, 247])) else: self._send_midi(tuple([240, 0, 1, 97, 4, 17, 127, 127, 127, 127, 127, 127, 127, 127, 247])) def set_local_ring_control(self, val = 1): self._local_ring_control = (val!=0) if(self._local_ring_control is True): #self._send_midi(tuple([240, 0, 1, 97, 4, 32, 0, 247])) self._send_midi(tuple([240, 0, 1, 97, 4, 8, 72, 247])) else: #self._send_midi(tuple([240, 0, 1, 97, 4, 32, 1, 247])) self._send_midi(tuple([240, 0, 1, 97, 4, 8, 64, 247])) def device_follows_track(self, val): self._device_selection_follows_track_selection = (val == 1) return self """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 += ' ' assert (len(ret) == NUM_CHARS_PER_DISPLAY_STRIP) return ret def notification_to_bridge(self, name, value, sender): if(isinstance(sender, CodecEncoderElement)): 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 not self._host.is_enabled(): 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._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 get_clip_names(self): clip_names = [] for scene in self._session._scenes: for clip_slot in scene._clip_slots: if clip_slot.has_clip() is True: clip_names.append(clip_slot._clip_slot)##.clip.name) return clip_slot._clip_slot ##self.log_message(str(clip_slot._clip_slot.clip.name)) return clip_names """overrides""" def allow_updates(self, allow_updates): for component in self.components: component.set_allow_update(int(allow_updates!=0)) def set_device_component(self, device_component): if self._device_component != None: self._device_component._lock_callback = None assert (device_component != None) assert isinstance(device_component, DeviceComponent) self._device_component = device_component self._device_component._lock_callback = self._toggle_lock #old: self._device_component.set_lock_callback(self._toggle_lock) if self._device_select_buttons != None: for button in self._device_select_buttons: button.send_value(self._device_select_buttons.index(button) == self._device.index(self._device_component)) self._update_device_selection() return None def _update_selected_device(self): if self._device_selection_follows_track_selection is True: self._update_device_selection() return None def _update_linked_device_selection(self, device): #self.log_message('codec received ' + str(device.name)) if self._device_component != None and device != None: if not self._device_component.is_locked(): self._device_component.set_device(device) def _get_num_tracks(self): return self.num_tracks def _update_device_selection(self): #self.log_message('_update_device_selection') if self._device_component != None: if not self._device_component.is_locked(): track = self.song().view.selected_track device_to_select = track.view.selected_device if ((device_to_select == None) and (len(track.devices) > 0)): device_to_select = track.devices[0] if (device_to_select != None): self.song().view.select_device(device_to_select) self._device_component.set_device(device_to_select) def _channelstrip_mute_value(self, channelstrip): def _mute_value(value): if not self._shift_pressed: self.log_message('shift not pressed') ChannelStripComponent._mute_value(channelstrip, value) return _mute_value def _channelstrip_solo_value(self, channelstrip): def _solo_value(value): if not self._shift_pressed: ChannelStripComponent._solo_value(channelstrip, value) return _solo_value def _mixer_next_track_value(self, mixer): def _next_track_value(value): if not self._shift_pressed: MixerComponent._next_track_value(mixer, value) return _next_track_value def _mixer_prev_track_value(self, mixer): def _prev_track_value(value): if not self._shift_pressed: MixerComponent._prev_track_value(mixer, value) return _prev_track_value
def _setup_mixer_control(self): is_momentary = True num_tracks = 4 #A mixer is one-dimensional; here we define the width in tracks - seven columns, global mixer #We want to instantiate the global mixer as a MixerComponent object (it was a global "None" type up until now...) mixer = MixerComponent(num_tracks, 0, with_eqs=False, with_filters=False) #(num_tracks, num_returns, with_eqs, with_filters) mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left) self.song().view.selected_track = mixer.channel_strip(0)._track #set the selected strip to the first track, so that we don't, for example, try to assign a button to arm the master track, which would cause an assertion error #"""set up the mixer buttons""" #mixer.set_select_buttons(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 56),ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 54)) #left, right track select #mixer.master_strip().set_select_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 94)) #jump to the master track #mixer.selected_strip().set_mute_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 42)) #sets the mute ("activate") button #mixer.selected_strip().set_solo_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 44)) #sets the solo button #mixer.selected_strip().set_arm_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 46)) #sets the record arm button #"""set up the mixer sliders""" mixer.selected_strip().set_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL, 48)) #sets the continuous controller for volume #"""note that we have split the mixer functions across two scripts, in order to have two session highlight boxes (one red, one yellow), so there are a few things which we are not doing here...""" # this tells Live the filename in which to look for my code import wfK1 # this is the standardized function with which Live loads # any script. c_instance is the Control Surface slot in Live's # prefs, as far as I can tell def create_instance(c_instance): # this is what it should load # (the thing inside my file that's called 'K1') return wfK1.K1(c_instance) # this lets me use Live's own generic Control Surface code # to handle a bunch of background tasks in interfacing # with the app, so I will only have to customize the behavior # I want and not re-do all the plumbing from _Framework.ControlSurface import ControlSurface # this is the thing that'll be loaded in the __init__.py file. # it's going to be based on the generic Control Surface # (the slot that was called c_instance in __init__.py) class K1(ControlSurface): # this defines the function to construct what code # ('self', i.e. this very thing I wrote below) the slot # ('instance') will be assigned def __init__(self, instance): # this tells the compiler (which turns the script into # instructions Live can actually execute) to start with # the generic Control Surface initial setup. Super # means that we're executing a command in there # instead of code in here. super(K1, self).__init__(instance, False) # this is, as far as I can tell, a protection against crashes, # everything I do will be encapsulated in this guard. I # found a bunch of sources and scripts that # recommended to import the 'with' command, which # wasn't available in older versions of the script language, # but that turned out to not be necessary in Live 10 with self.component_guard(): # now we can do things! The first line shows a message # in Live's own status bar, the second adds a line to Log.txt self.show_message("Hello World") self.log_message("wayfinder K1 remote script loaded") # code snippet from The Rabbits at Ableton forum for RACKS def get_device_list(self, container): # add each device in order. if device is a rack, process each chain recursively # don't add racks that are not showing devices. lst = [] for dev in container: lst.append(dev) if dev.can_have_chains: # is a rack and it's open if dev.view.is_showing_chain_devices: for ch in dev.chains: lst += self.get_device_list(ch.devices) return lst # Called this way. device_list = self.get_device_list(current_track.devices) # for foldable groups if track.is_foldable: track.fold_state = not track.fold_state else: track.view.is_collapsed = not track.view.is_collapsed # fold_state refers to groups .is_foldable is true for Groups. # .is_collapsed refers to tracks that are collapsed in Arrangement view. # I combined the two because it means one less pad used and the two are never both true.
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 Codec(ControlSurface): __module__ = __name__ __doc__ = " MonoCode controller script " def __init__(self, c_instance): """everything except the '_on_selected_track_CHANNELged' override and 'disconnect' runs from here""" ControlSurface.__init__(self, c_instance) self.set_suppress_rebuild_requests( True ) # Turn off rebuild MIDI map until after we're done setting up self._monomod_version = 'b995' self._version_check = 'b995' self._host_name = 'Codec' self._color_type = 'Monochrome' self._link_mixer = LINK_MIXER self.log_message('<<<<<<<<<<<<<<<<<<<<<<<<< Codec ' + str(self._monomod_version) + ' log opened >>>>>>>>>>>>>>>>>>>>>>>>>') self._hosts = [] self._linked_script = None self._local_ring_control = True self.set_local_ring_control(1) self._setup_controls() self._last_device = None self._device_list = [None, None, None, None] self._device_select_buttons = None self._last_device_component = None self._timer = 0 self._touched = 0 self._locked = False self.flash_status = 1 self._shift_button = None self._shift_pressed = 0 self._shift_pressed_timer = 0 self._shift_thresh = SHIFT_THRESH self._use_device_selector = USE_DEVICE_SELECTOR self._device_selection_follows_track_selection = FOLLOW self.set_suppress_rebuild_requests( False) #Turn rebuild back on, now that we're done setting up self.song().view.add_selected_track_listener( self._update_selected_device) self.show_message('Codec Control Surface Loaded') #self.local_ring_control(True) #self.set_absolute_mode(True) self._setup_monobridge() self._setup_device_controls() self._setup_special_device_control() self._device.append( self._special_device ) #necessary for device browsing to work with special device self._setup_device_chooser() self._setup_mixer_controls() self._setup_monomod() self._setup_modes() self._setup_device_selector() self._setup_send_reset() self._setup_default_buttons() self._initialize_code() self.request_rebuild_midi_map() #Monomodular.create_instance(c_instance) #self._setup_disconnect() """script initialization methods""" def _initialize_code(self): self._send_midi(factoryreset) self._send_midi(btn_channels) self._send_midi(enc_channels) #pass def _setup_monobridge(self): self._monobridge = MonoBridgeElement(self) self._monobridge.name = 'MonoBridge' def _setup_controls(self): is_momentary = True self._livid = FlashingButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, LIVID, 'Livid_Button', self) self._dial = [None for index in range(8)] for column in range(8): self._dial[column] = [None for index in range(4)] for row in range(4): self._dial[column][row] = CodecEncoderElement( MIDI_CC_TYPE, CHANNEL, CODE_DIALS[row][column], Live.MidiMap.MapMode.absolute, 'Dial_' + str(column) + '_' + str(row), (column + (row * 8)), self) #CODE_DIALS[row][column] self._button = [None for index in range(8)] for column in range(8): self._button[column] = [None for index in range(4)] for row in range(4): self._button[column][row] = FlashingButtonElement( is_momentary, MIDI_NOTE_TYPE, CHANNEL, CODE_BUTTONS[row][column], 'Button_' + str(column) + '_' + str(row), self) self._column_button = [None for index in range(8)] for index in range(8): self._column_button[index] = FlashingButtonElement( is_momentary, MIDI_NOTE_TYPE, CHANNEL, CODE_COLUMN_BUTTONS[index], 'Column_Button_' + str(index), self) self._row_button = [None for index in range(4)] for index in range(4): self._row_button[index] = FlashingButtonElement( is_momentary, MIDI_NOTE_TYPE, CHANNEL, CODE_ROW_BUTTONS[index], 'Row_Button_' + str(index), self) self._dial_matrix = EncoderMatrixElement(self) self._dial_matrix.name = 'Encoder_Matrix' for row in range(4): dial_row = tuple([self._dial[column][row] for column in range(8)]) self._dial_matrix.add_row(dial_row) self._button_matrix = ButtonMatrixElement() self._button_matrix.name = 'Button_Matrix' for row in range(4): button_row = [self._button[column][row] for column in range(8)] button_row.append(self._row_button[row]) self._button_matrix.add_row(tuple(button_row)) self._button_matrix.add_row(tuple(self._column_button + [self._livid])) def _setup_modes(self): self._monomod_mode = MonomodModeComponent(self) self._monomod_mode.name = 'Monomod_Mode' self._monomod_mode.update = self._mod_mode_update #self._monomod_mode.set_mode_toggle(self._livid) self.set_shift_button(self._livid) self._shift_mode = ShiftModeComponent(self, self._shift_update) self._shift_mode.name = 'Shift_Mode' self._shift_mode.set_mode_buttons( tuple([ self._row_button[0], self._row_button[1], self._row_button[2], self._row_button[3] ])) def _setup_transport_control(self): self._transport = TransportComponent() self._transport.name = 'Transport' def _setup_monomod(self): self._host = MonomodComponent(self) self._host.name = 'Monomod_Host' self._host._set_dial_matrix(self._dial_matrix, self._button_matrix) self.hosts = [self._host] encs = [] for row in range(4): for col in range(8): encs.append(self._dial[col][row]) self._host._set_parameter_controls(encs) def _setup_mixer_controls(self): is_momentary = True self._num_tracks = (8) self._session = SessionComponent(self._num_tracks, 0) self._session.name = 'Session' self._mixer = MixerComponent(self._num_tracks, 0, False, False) self._mixer.name = 'Mixer' self._mixer._next_track_value = self._mixer_next_track_value( self._mixer) self._mixer._prev_track_value = self._mixer_prev_track_value( self._mixer) self._mixer.set_track_offset( 0) #Sets start point for mixer strip (offset from left) #for index in range(8): #use the bottom row of encoders for volume, so add 24 to offset the index # self._mixer.channel_strip(index).set_volume_control(self._dial[index+24]) for index in range(8): self._mixer.channel_strip( index).name = 'Mixer_ChannelStrip_' + str(index) self._mixer.channel_strip(index)._invert_mute_feedback = True self._mixer.channel_strip( index)._mute_value = self._channelstrip_mute_value( self._mixer.channel_strip(index)) self._mixer.channel_strip( index)._solo_value = self._channelstrip_solo_value( self._mixer.channel_strip(index)) #mixer.channel_strip(index).set_select_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CH, track_select_notes[index])) 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._session.set_mixer(self._mixer) def _setup_device_controls(self): self._device = [None for index in range(4)] for index in range(4): self._device[index] = CodecDeviceComponent(self) self._device[index].name = 'CodecDevice_Component_' + str(index) device_param_controls = [] for control in range(8): device_param_controls.append(self._dial[control][index]) self._device[index].set_on_off_button(self._button[1][index]) self._device[index].set_lock_button(self._button[2][index]) self._device[index].set_bank_nav_buttons(self._button[4][index], self._button[5][index]) self._device[index].set_nav_buttons(self._button[6][index], self._button[7][index]) self._device[index].set_parameter_controls( tuple(device_param_controls)) self.set_device_component(self._device[0]) self._last_device_component = self._device[0] def _setup_special_device_control(self): self._special_device = SpecialCodecDeviceComponent(self) self._special_device.name = 'SpecialCodecDeviceComponent' self._special_device.set_on_off_button(self._button[1][0]) self._special_device.set_lock_button(self._button[2][0]) self._special_device.set_bank_nav_buttons(self._button[4][0], self._button[5][0]) self._special_device.set_nav_buttons(self._button[6][0], self._button[7][0]) device_param_controls = [] for row in range(4): for column in range(8): device_param_controls.append(self._dial[column][row]) self._special_device.set_parameter_controls( tuple(device_param_controls)) def _setup_device_chooser(self): self._selected_device = self._device[0] self._last_selected_device = self._device[0] self._device_select_buttons = [ self._button[0][index] for index in range(4) ] for button in self._device_select_buttons: button.add_value_listener(self._device_select_value, True) def _setup_device_selector(self): self._device_selector = CodecDeviceSelectorComponent( self, 'c', self._device + [self._special_device]) self._device_selector.name = 'Device_Selector' self._device_selector.set_mode_buttons(self._column_button) #self._device_selector.set_mode_toggle(self._livid) def _setup_send_reset(self): self._send_reset = CodecResetSendsComponent(self) self._send_reset.set_buttons(self._button) def _setup_default_buttons(self): self._value_default = ParameterDefaultComponent(self) buttons = [] dials = [] for column in self._button: for button in column: buttons.append(button) for column in self._dial: for dial in column: dials.append(dial) self._value_default.set_buttons(buttons) self._value_default.set_dials(dials) """multiple device support""" def _device_select_value(self, value, sender): #self.log_message('device_select_value ' + str(value) + ' ' + str(self._device_select_buttons.index(sender))) if not self._shift_pressed: if sender.is_momentary or value > 0: if self._shift_mode._mode_index == 2: self.set_device_component(self._device[ self._device_select_buttons.index(sender)]) self._last_device_component = self._device_component if self._device_component != None and isinstance( self._device_component._device, Live.Device.Device): if self._device_component.find_track( self._device_component._device) == self.song( ).view.selected_track: self._device_component.display_device() """livid double press mechanism""" def set_shift_button(self, button): assert ((button == None) or (isinstance(button, FlashingButtonElement))) if self._shift_button != None: self._shift_button.remove_value_listener(self._shift_value) self._shift_button = button if self._shift_button != None: self._shift_button.add_value_listener(self._shift_value) def _shift_value(self, value): self._shift_pressed = int(value != 0) if self._shift_pressed > 0: self._send_midi(SLOWENCODER) if (self._shift_pressed_timer + self._shift_thresh) > self._timer: #if(self._host.is_enabled() != True) self._monomod_mode.set_mode( abs(self._monomod_mode._mode_index - 1)) #else: # self._monomod_mode.set_mode(0) self._shift_pressed_timer = self._timer % 256 else: self._send_midi(NORMALENCODER) def _mod_mode_update(self): if (self._monomod_mode._mode_index == 0): self._host._set_shift_button(None) self._host.set_enabled(False) self._dial_matrix.reset() self._shift_mode.set_enabled(True) self._shift_update() self.request_rebuild_midi_map() self._livid.turn_off() elif (self._monomod_mode._mode_index == 1): self._shift_mode.set_enabled(False) self._deassign_all() self._dial_matrix.reset() self._button_matrix.reset() self._livid.turn_on() if not self._host._active_client == None: self._host.set_enabled(True) self._host._set_shift_button(self._livid) else: self._assign_alternate_mappings(1) self.request_rebuild_midi_map() """Mode Functions""" def _shift_update(self): if (self._shift_mode.is_enabled()): self.allow_updates(False) if (not self._in_build_midi_map): self.set_suppress_rebuild_requests(True) self._deassign_all() if (self._shift_mode._mode_index is 0): self._assign_volume() elif (self._shift_mode._mode_index is 1): self._assign_sends() elif (self._shift_mode._mode_index is 2): self._assign_devices() elif (self._shift_mode._mode_index is 3): self._assign_special_device() for index in range(self._shift_mode.number_of_modes()): if index == self._shift_mode._mode_index: self._shift_mode._modes_buttons[index].turn_on() else: self._shift_mode._modes_buttons[index].turn_off() self.allow_updates(True) self.set_suppress_rebuild_requests(False) self.request_rebuild_midi_map() def _deassign_all(self): self._assign_alternate_mappings(0) self._device_selector.set_enabled(False) for index in range(8): self._mixer.channel_strip(index).set_volume_control(None) self._mixer.channel_strip(index).set_pan_control(None) self._mixer.channel_strip(index).set_send_controls( tuple([None, None, None, None])) for index in range(4): self._device[index].set_enabled(False) self._device[index]._parameter_controls = None #self._device_navigator[index].set_enabled(False) self._special_device.set_enabled(False) self._special_device._parameter_controls = None self._device_selector.set_enabled(False) self._deassign_buttons() for control in self.controls: control.reset() self.request_rebuild_midi_map() def _deassign_buttons(self): for index in range(8): self._mixer.channel_strip(index).set_select_button(None) self._mixer.channel_strip(index).set_solo_button(None) self._mixer.channel_strip(index).set_mute_button(None) self._mixer.set_select_buttons(None, None) self._send_reset.set_enabled(False) def _assign_volume(self): for index in range(8): self._mixer.channel_strip(index).set_volume_control( self._dial[index][3]) self._mixer.channel_strip(index).set_pan_control( self._dial[index][2]) self._mixer.channel_strip(index).set_send_controls( tuple([self._dial[index][0], self._dial[index][1]])) self._mixer.channel_strip(index).set_select_button( self._column_button[index]) self._mixer.channel_strip(index).set_solo_button( self._button[index][2]) self._mixer.channel_strip(index).set_mute_button( self._button[index][3]) self._mixer.set_select_buttons(self._button[7][0], self._button[6][0]) def _assign_sends(self): for index in range(8): self._mixer.channel_strip(index).set_send_controls( tuple([ self._dial[index][0], self._dial[index][1], self._dial[index][2], self._dial[index][3] ])) self._mixer.channel_strip(index).set_select_button( self._column_button[index]) self._send_reset.set_enabled(True) def _assign_devices(self): self.set_device_component(self._last_device_component) self._device_select_value( 1, self._device_select_buttons[self._device.index( self._device_component)]) for index in range(4): device_param_controls = [] for control in range(8): device_param_controls.append(self._dial[control][index]) self._device[index].set_parameter_controls( tuple(device_param_controls)) self._device[index].set_enabled(True) self._device_selector.set_enabled(self._use_device_selector) if not self._use_device_selector: for index in range(8): self._mixer.channel_strip(index).set_select_button( self._column_button[index]) def _assign_special_device(self): self.set_device_component(self._special_device) device_param_controls = [] for row in range(4): for column in range(8): device_param_controls.append(self._dial[column][row]) self._special_device.set_parameter_controls( tuple(device_param_controls)) self._special_device.set_enabled(True) self._device_selector.set_enabled(self._use_device_selector) if not self._use_device_selector: for index in range(8): self._mixer.channel_strip(index).set_select_button( self._column_button[index]) def _assign_alternate_mappings(self, chan): for column in self._dial: for control in column: control.set_channel(chan) control.set_enabled(chan is 0) for column in self._button: for control in column: control.set_channel(chan) control.set_enabled(chan is 0) for control in self._column_button: control.set_channel(chan) control.set_enabled(chan is 0) for control in self._row_button: control.set_channel(chan) control.set_enabled(chan is 0) """general functionality""" def disconnect(self): """clean things up on disconnect""" if not self._shift_button is None: if self._shift_button.value_has_listener(self._shift_value): self._shift_button.remove_value_listener(self._shift_value) for button in self._device_select_buttons: if button.value_has_listener(self._device_select_value): button.remove_value_listener(self._device_select_value) if self._session._is_linked(): self._session._unlink() self.song().view.remove_selected_track_listener( self._update_selected_device) """for cs in self._control_surfaces(): for host in self._hosts: self.log_message('installed: ' + str(cs) + ' vs. ' + str(host)) if str(type(cs)) == str(type(host)): self.log_message('disconnecting: ' + str(type(cs))) cs.disconnect(cs)""" #self._host._set_parameter_controls(None) self._hosts = [] if self._linked_script != None: self._linked_script._update_linked_device_selection = None self._linked_script = None #self._disconnect_notifier.set_mode(0) self.log_message( '<<<<<<<<<<<<<<<<<<<<<<<<< Codec log closed >>>>>>>>>>>>>>>>>>>>>>>>>' ) ControlSurface.disconnect(self) return None def connect_script_instances(self, instanciated_scripts): found = False for s in instanciated_scripts: if '_codec_version' in dir(s): if s._codec_version == self._version_check: if s._host_name == ('MonOhm'): self.log_message('found codec version ' + str(s._codec_version) + ' in script ' + str(s._host_name)) found = True self._linked_script = s self._linked_script._update_linked_device_selection = self._update_linked_device_selection if not self._session._is_linked( ) and self._link_mixer is True: self._session.set_offsets(LINK_OFFSET[0], LINK_OFFSET[1]) self._session._link() else: self.log_message('version mismatch: Monomod version ' + str(self._version_check) + ' vs. Host version ' + str(s._codec_version)) if found == False: for s in instanciated_scripts: if '_codec_version' in dir(s): if s._codec_version == self._version_check: if s._host_name == 'BlockMod': self.log_message('found codec version ' + str(s._codec_version) + ' in script ' + str(s._host_name)) self._linked_script = s self._linked_script._update_linked_device_selection = self._update_linked_device_selection if not self._session._is_linked( ) and self._link_mixer is True: self._session.set_offsets(LINK_OFFSET[0], LINK_OFFSET[1]) self._session._link() else: self.log_message('version mismatch: Monomod version ' + str(self._version_check) + ' vs. Host version ' + str(s._codec_version)) #self.log_message('hosts: ' + str(self._hosts))""" def update_display(self): ControlSurface.update_display( self ) #since we are overriding this from the inherited method, we need to call the original routine as well self._timer = (self._timer + 1) % 256 if (self._timer == 0): self._shift_pressed_timer = -12 if (self._local_ring_control is False): self.send_ring_leds() self.flash() def handle_sysex(self, midi_bytes): #self._send_midi(tuple([240, 00, 01, 97, 04, 15, 01, 247])) #response = [long(0),long(0)] #self.log_message(response) pass def flash(self): if (self.flash_status > 0): for control in self.controls: if isinstance(control, FlashingButtonElement): control.flash(self._timer) def send_ring_leds(self): leds = [240, 0, 1, 97, 4, 31] for column in range(8): for row in range(4): wheel = self._dial[column][row] bytes = wheel._get_ring() leds.append(bytes[0]) leds.append(int(bytes[1]) + int(bytes[2])) #if(row == 1 and column == 0): # self.log_message(str(leds) + ' ' + str(bytes[0]) + ' ' + str(bytes[1]) + ' ' + str(bytes[2])) leds.append(247) self._send_midi(tuple(leds)) def set_absolute_mode(self, val=1): self._absolute_mode = (val != 0) if self._absolute_mode is True: self._send_midi( tuple([240, 0, 1, 97, 4, 17, 0, 0, 0, 0, 0, 0, 0, 0, 247])) else: self._send_midi( tuple([ 240, 0, 1, 97, 4, 17, 127, 127, 127, 127, 127, 127, 127, 127, 247 ])) def set_local_ring_control(self, val=1): self._local_ring_control = (val != 0) if (self._local_ring_control is True): #self._send_midi(tuple([240, 0, 1, 97, 4, 32, 0, 247])) self._send_midi(tuple([240, 0, 1, 97, 4, 8, 72, 247])) else: #self._send_midi(tuple([240, 0, 1, 97, 4, 32, 1, 247])) self._send_midi(tuple([240, 0, 1, 97, 4, 8, 64, 247])) def device_follows_track(self, val): self._device_selection_follows_track_selection = (val == 1) return self """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 += ' ' assert (len(ret) == NUM_CHARS_PER_DISPLAY_STRIP) return ret def notification_to_bridge(self, name, value, sender): if (isinstance(sender, CodecEncoderElement)): 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 not self._host.is_enabled(): 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._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 get_clip_names(self): clip_names = [] for scene in self._session._scenes: for clip_slot in scene._clip_slots: if clip_slot.has_clip() is True: clip_names.append(clip_slot._clip_slot) ##.clip.name) return clip_slot._clip_slot ##self.log_message(str(clip_slot._clip_slot.clip.name)) return clip_names """overrides""" def allow_updates(self, allow_updates): for component in self.components: component.set_allow_update(int(allow_updates != 0)) def set_device_component(self, device_component): if self._device_component != None: self._device_component._lock_callback = None assert (device_component != None) assert isinstance(device_component, DeviceComponent) self._device_component = device_component self._device_component._lock_callback = self._toggle_lock #old: self._device_component.set_lock_callback(self._toggle_lock) if self._device_select_buttons != None: for button in self._device_select_buttons: button.send_value( self._device_select_buttons.index(button) == self._device.index(self._device_component)) self._update_device_selection() return None def _update_selected_device(self): if self._device_selection_follows_track_selection is True: self._update_device_selection() return None def _update_linked_device_selection(self, device): #self.log_message('codec received ' + str(device.name)) if self._device_component != None and device != None: if not self._device_component.is_locked(): self._device_component.set_device(device) def _get_num_tracks(self): return self.num_tracks def _update_device_selection(self): #new method: code to verify #self.log_message('_update_device_selection') if self._device_component != None: if not self._device_component.is_locked(): track = self.song().view.selected_track device_to_select = track.view.selected_device if ((device_to_select == None) and (len(track.devices) > 0)): device_to_select = track.devices[0] if (device_to_select != None): self.song().view.select_device(device_to_select) self._device_component.set_device(device_to_select) def _channelstrip_mute_value(self, channelstrip): def _mute_value(value): if not self._shift_pressed: self.log_message('shift not pressed') ChannelStripComponent._mute_value(channelstrip, value) return _mute_value def _channelstrip_solo_value(self, channelstrip): def _solo_value(value): if not self._shift_pressed: ChannelStripComponent._solo_value(channelstrip, value) return _solo_value def _mixer_next_track_value(self, mixer): def _next_track_value(value): if not self._shift_pressed: MixerComponent._next_track_value(mixer, value) return _next_track_value def _mixer_prev_track_value(self, mixer): def _prev_track_value(value): if not self._shift_pressed: MixerComponent._prev_track_value(mixer, value) return _prev_track_value
def _setup_mixer_control(self): num_tracks = GRIDSIZE[0] # Here we define the mixer width in tracks (a mixer has only one dimension) global mixer # We want to instantiate the global mixer as a MixerComponent object (it was a global "None" type up until now...) mixer = MixerComponent(num_tracks) #(num_tracks, num_returns, with_eqs, with_filters) mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left) """set up the mixer buttons""" self.song().view.selected_track = mixer.channel_strip(0)._track master = mixer.master_strip() master.set_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL_USER, MASTER_VOLUME)) mixer.set_prehear_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL_USER, PREHEAR)) for index in xrange(GRIDSIZE[0]): mixer.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL_MIXER, MIX_FADERS[index])) # mixer.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL_INST, MIX_FADERS[index])) mixer.channel_strip(index).set_pan_control(SliderElement(MIDI_CC_TYPE, CHANNEL_MIXER, PAN_CONTROLS[index])) mixer.channel_strip(index).set_arm_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL_INST, ARM_BUTTONS[index])) #sets the record arm button mixer.channel_strip(index).set_solo_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL_INST, SOLO_BUTTONS[index])) mixer.channel_strip(index).set_mute_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL_INST, MUTE_BUTTONS[index])) mixer.channel_strip(index).set_select_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL_INST, TRACK_SELECTS[index])) mixer.channel_strip(index).set_send_controls([SliderElement(MIDI_CC_TYPE, CHANNEL_MIXER, SEND_CONTROLS[index][0]), SliderElement(MIDI_CC_TYPE, CHANNEL_MIXER, SEND_CONTROLS[index][1]), SliderElement(MIDI_CC_TYPE, CHANNEL_MIXER, SEND_CONTROLS[index][2]), SliderElement(MIDI_CC_TYPE, CHANNEL_MIXER, SEND_CONTROLS[index][3])]) """TRANSPORT CONTROLS""" stop_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL_MIXER, STOP_BUTTON) play_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL_MIXER, PLAY_BUTTON) record_button = ButtonElement(False,MIDI_CC_TYPE,CHANNEL_MIXER,RECORD_BUTTON) overdub_button = ButtonElement(False,MIDI_CC_TYPE,CHANNEL_MIXER,OVERDUB_BUTTON) transport = TransportComponent() transport.TEMPO_TOP = 188 transport.set_stop_button(stop_button) transport.set_play_button(play_button) transport.set_overdub_button(overdub_button) transport.set_record_button(record_button) transport.set_seek_buttons(ButtonElement(False,MIDI_CC_TYPE,0,SEEK_LEFT),ButtonElement(False,MIDI_CC_TYPE,0,SEEK_RIGHT)) transport.set_tempo_control(SliderElement(MIDI_CC_TYPE, CHANNEL_USER, TEMPO)) transport.set_metronome_button(ButtonElement(False,MIDI_CC_TYPE,CHANNEL_USER, METRONOME)) transport.set_tap_tempo_button(ButtonElement(False,MIDI_CC_TYPE,CHANNEL_USER,TAP_TEMPO))
class QuNexus_Basic(ControlSurface): __module__ = __name__ __doc__ = "QuNexus Keyboard controller script" def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) #Turn off rebuild MIDI map until after we're done setting up self.set_suppress_rebuild_requests(True) #set up some variables I want to use in multiple functions self.mixer = None self.session = None #Setup the mixer and session object self._setup_session_control() self._setup_mixer_control() self._setup_device_control() self._setup_transport_control() self.set_suppress_rebuild_requests(False) def _setup_transport_control(self): self._transport = TransportComponent() self._transport.set_stop_button(ButtonElement(is_momentary,MIDI_NOTE_TYPE,CHANNEL,68)) self._transport.set_record_button(ButtonElement(is_momentary,MIDI_NOTE_TYPE,CHANNEL,66)) self._transport.set_play_button(ButtonElement(is_momentary,MIDI_NOTE_TYPE,CHANNEL,70)) #note that we have split the mixer functions across two scripts, in order to have two session highlight boxes (one red, one yellow), so there are a few things which we are not doing here... def _setup_session_control(self): num_tracks = 1 #one column (track) num_scenes = 8 #eight rows, which will be mapped to eight "white" notes #(num_tracks, num_scenes) a session highlight ("red box") will appear with any two non-zero values self.session = QuNexusSessionComponent(num_tracks,num_scenes) #(track_offset, scene_offset) Sets the initial offset of the "red box" from top left self.session.set_offsets(0,0) self.session.set_select_buttons(ButtonElement(is_momentary,MIDI_NOTE_TYPE,CHANNEL,63), ButtonElement(is_momentary,MIDI_NOTE_TYPE,CHANNEL,61)) self.session.set_scene_bank_buttons(ButtonElement(is_momentary,MIDI_NOTE_TYPE,CHANNEL,51), ButtonElement(is_momentary,MIDI_NOTE_TYPE,CHANNEL,49)) self.session.set_track_bank_buttons(ButtonElement(is_momentary,MIDI_NOTE_TYPE,CHANNEL,56), ButtonElement(is_momentary,MIDI_NOTE_TYPE,CHANNEL,54)) self.session.selected_scene().set_launch_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 62)) self.session.set_stop_all_clips_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 58)) for row in range(8): for col in range(1): self.session.scene(row).clip_slot(col).set_started_value(127) self.session.scene(row).clip_slot(col).set_stopped_value(0) #here we set up the clip launch assignments for the session clip_launch_notes = [48,50,52,53,55,57,59,60] #set of eight white notes starting at C3/C4 for index in range(num_scenes): #step though scenes and assign a note to first slot of each self.session.scene(index).clip_slot(0).set_started_value(127) self.session.scene(index).clip_slot(0).set_stopped_value(3) #self.session.scene(index).clip_slot(0).set_recording_value(64) self.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.session.set_mixer(self.mixer) #bind the mixer to the session so that they move together def _setup_mixer_control(self): is_momentary = True #A mixer is one-dimensional; here we define the width in tracks - seven columns, which we will map to the seven "white" notes num_tracks = 1 #set up the mixer self.mixer = MixerComponent(num_tracks, 2, with_eqs=True, with_filters=True) #(num_tracks, num_returns, with_eqs, with_filters) self.mixer.set_track_offset(0) #sets start point for mixer strip (offset from left) #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.song().view.selected_track = self.mixer.channel_strip(0)._track #set up the mixer buttons #self.mixer.set_select_buttons() #left, right track select def _setup_device_control(self): sliders = [] pressures = [92,94,98,102,106,108] for index in range(6): sliders.append(SliderElement(MIDI_CC_TYPE, CHANNEL, pressures[index])) self._sliders = tuple(sliders) device = DeviceComponent() device.name = 'Device_Component' self.set_device_component(device) device.set_parameter_controls(self._sliders) def disconnect(self): #clean things up on disconnect #create entry in log file self.log_message(time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) + "----------QuNexus Basic log closed----------") ControlSurface.disconnect(self) return None
class ControlMI(ControlSurface): __module__ = __name__ __doc__ = " ControlMI controller script" def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) self._suppress_session_highlight = True self._suppress_send_midi = True # Turn off rebuild MIDI map until after we're done setting up self.log("--------------= ControlMI log opened =--------------") with self.component_guard(): # OBJECTS self.session = None self.mixer = None self.view = None self.device = None self.transport = None # INITIALIZE MIXER, SESSIONS self._setup_session_control() # Setup the session object self._setup_mixer_control() # Setup the mixer object self.session.set_mixer(self.mixer) # Bind mixer to session self._setup_device_control() # Setup the device object self._setup_transport_control() # Setup transport object self._set_initial_mode() self.set_device_component( self.device) # Bind device to control surface- self.set_highlighting_session_component(self.session) for component in self.components: component.set_enabled(True) self._suppress_session_highlight = True self._suppress_send_midi = True # Turn rebuild back on, once we're done setting up def _setup_session_control(self): self.show_message( "#################### SESSION: ON ##############################") self.session = SessionComponent(num_tracks, num_scenes) self.session.set_offsets(0, 0) self.session.set_track_bank_buttons( ButtonElement(False, MIDI_CC_TYPE, data_channel, session_right), ButtonElement(False, MIDI_CC_TYPE, data_channel, session_left)) def _setup_mixer_control(self): self.mixer = MixerComponent(num_tracks, 0, False, False) self.mixer.name = 'Mixer' self.mixer.set_track_offset(0) def _setup_device_control(self): self.device = DeviceComponent() self.device.name = 'Device_Component' def _setup_transport_control(self): self.transport = TransportComponent(self) def _clear_controls(self): self.mixer._set_send_nav(None, None) for track_index in range(num_tracks): strip = self.mixer.channel_strip(track_index) strip.set_solo_button(None) strip.set_mute_button(None) strip.set_arm_button(None) strip.set_select_button(None) # TRANSPORT self.transport.set_stop_button(None) self.transport.set_play_button(None) self.transport.set_record_button(None) self.log_message("Controls Cleared") def _set_initial_mode(self): is_momentary = True ### MIXER for index in range(num_tracks): strip = self.mixer.channel_strip(index) strip.name = 'Mixer_ChannelStrip_' + str(index) strip.set_volume_control( SliderElement(MIDI_CC_TYPE, data_channel, mixer_volume_cc[index])) strip._invert_mute_feedback = True self.mixer.master_strip().set_volume_control( SliderElement(MIDI_CC_TYPE, data_channel, mixer_master_cc)) self.transport.set_stop_button( ButtonElement(False, MIDI_CC_TYPE, data_channel, transport_stop_cc)) self.transport.set_play_button( ButtonElement(False, MIDI_CC_TYPE, data_channel, transport_play_cc)) self.transport.set_record_button( ButtonElement(False, MIDI_CC_TYPE, data_channel, transport_record_cc)) self.log("color: " + str(self.session.tracks_to_use()[0].color)) self.log("color: " + str(self.session.tracks_to_use()[1].color)) self.log("color: " + str(self.session.tracks_to_use()[2].color)) self.log("color: " + str(self.session.tracks_to_use()[3].color)) self._send_midi([0x09, 0x09, 0x09, 0x09]) def disconnect(self): """clean things up on disconnect""" self.log("--------------= ControlMI log closed =--------------") self._clear_controls() self.session = None self.mixer = None self.view = None self.device = None self.transport = None self.set_device_component(None) ControlSurface.disconnect(self) return None def log(self, message): self.log_message( time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) + message)
class Codex(Codec): def __init__(self, c_instance, *a, **k): self._shifted = False super(Codex, self).__init__(c_instance, *a, **k) with self.component_guard(): self._setup_alt_mixer() self._setup_alt_device_selector() self._setup_alt_send_reset() self._setup_alt_device_control() self.log_message('<<<<<<<<<<<<<<<<<<<<<<<<< Codex subclass log opened >>>>>>>>>>>>>>>>>>>>>>>>>') self.schedule_message(1, self._mode_update) def _setup_alt_device_selector(self): self._alt_device_selector = NewDeviceSelectorComponent(self) self._alt_device_selector.name = 'Alt_Device_Selector' def _setup_alt_send_reset(self): self._alt_send_reset = ResetSendsComponent(self) self._alt_send_reset.name = 'Alt_Reset_Sends' """these two secondary DeviceComponents are only set up if the MONOHM_LINK flag in Map is turned on""" def _setup_alt_device_control(self): self._device1 = NewDeviceComponent() self._device1.name = 'Device_Component1' self._device2 = NewDeviceComponent() self._device2.name = 'Device_Component2' def _setup_alt_mixer(self): is_momentary = True self._num_tracks = (8) #A mixer is one-dimensional self._mixer2 = MixerComponent(8, 4, False, False) self._mixer2.name = 'Mixer' #self._mixer2.set_track_offset(4) #Sets start point for mixer strip (offset from left) for index in range(8): self._mixer2.channel_strip(index).name = 'Mixer_ChannelStrip_' + str(index) self._mixer2.channel_strip(index)._invert_mute_feedback = True """Mode Functions""" def _enable_alt(self): if self._main_mode._mode_index == 0: for encoder, _ in self._encoder_matrix.submatrix[:, 0:2].iterbuttons(): encoder.set_enabled(False) encoder.reset() self._alt_enabled = True self._mode_update() super(Codex, self)._enable_alt() def _disable_alt(self): if self._main_mode._mode_index == 0: self._button_matrix.submatrix[:, 0:2].reset() for encoder, _ in self._encoder_matrix.submatrix[:, 0:2].iterbuttons(): encoder.set_enabled(True) super(Codex, self)._disable_alt() def _deassign_all(self): self._alt_send_reset.set_buttons(None) self._alt_send_reset.set_enabled(False) self._alt_device_selector.set_buttons(None) self._alt_device_selector.set_enabled(False) self._mixer2.selected_strip().set_send_controls(None) for index in range(8): self._mixer2.channel_strip(index).set_volume_control(None) self._mixer2.channel_strip(index).set_select_button(None) self._mixer2.channel_strip(index).set_mute_button(None) self._dial[index][2].release_parameter() for index in range(3): self._mixer2.return_strip(index).set_volume_control(None) self._device1.set_enabled(False) self._device1._parameter_controls = None self._device2.set_enabled(False) self._device2._parameter_controls = None self._mixer2.return_strip(0).set_send_controls(None) self._mixer2.return_strip(1).set_send_controls(None) self._mixer2.return_strip(2).set_send_controls(None) super(Codex, self)._deassign_all() def _assign_volume(self): if self._alt_enabled: inputs = self.find_inputs() if not inputs is None: for index in range(4): self._dial[index][2].connect_to(inputs.parameters[index+1]) self._dial[6][2].connect_to(inputs.parameters[5]) xfade = self.find_perc_crossfader() if not xfade is None: self._dial[7][3].connect_to(xfade) self._alt_device_selector.set_matrix(self._button_matrix.submatrix[:, 0:2]) self._alt_device_selector.set_enabled(True) self._mixer2.return_strip(0).set_send_controls([None, self._dial[4][2]]) self._mixer2.return_strip(1).set_send_controls([self._dial[5][2], None]) else: self._alt_send_reset.set_buttons(self._button_matrix.submatrix[4:, 2]) self._alt_send_reset.set_enabled(True) self._mixer2.selected_strip().set_send_controls([self._dial[0][2], self._dial[1][2], self._dial[2][2], self._dial[3][2]]) for index in range(3): self._mixer2.return_strip(index).set_volume_control(self._dial[index+4][2]) self._mixer2.set_crossfader_control(self._dial[7][2]) self._device1.set_parameter_controls(tuple([self._dial[index%4][int(index/4)] for index in range(8)])) self._device2.set_parameter_controls(tuple([self._dial[(index%4)+4][int(index/4)] for index in range(8)])) self._device1.set_enabled(True) self._device2.set_enabled(True) self._find_devices() self._device1.update() self._device2.update() for index in range(8): self._mixer2.channel_strip(index).set_select_button(self._column_button[index]) for index in range(8): self._mixer2.channel_strip(index).set_volume_control(self._dial[index][3]) self._mixer2.channel_strip(index).set_mute_button(self._button[index][3]) self._mixer2.update() self.request_rebuild_midi_map() #self._mixer2.set_track_offset(TROLL_OFFSET) def find_inputs(self): found_device = None tracks = self.song().tracks for track in tracks: if track.name == 'Inputs': for device in track.devices: if bool(device.can_have_chains) and device.name.endswith('Inputs'): found_device = device return found_device def find_perc_crossfader(self): found_parameter = None tracks = self.song().tracks for track in tracks: if track.name == 'Perc': for device in track.devices: if bool(device.can_have_chains) and device.name == 'Perc': for parameter in device.parameters: if parameter.name == 'XFade': found_parameter = parameter return found_parameter """this method is used to find the devices the alt controls will latch to""" def _find_devices(self): if self._device1: if len(self.song().return_tracks) > 0: if len(self.song().return_tracks[0].devices) > 0: if self._device1._locked_to_device: self._device1.set_lock_to_device(False, self._device1._device) self._device1.set_lock_to_device(True, self.song().return_tracks[0].devices[0]) if self._device2: if len(self.song().return_tracks) > 1: if len(self.song().return_tracks[1].devices) > 0: if self._device2._locked_to_device: self._device2.set_lock_to_device(False, self._device2._device) self._device2.set_lock_to_device(True, self.song().return_tracks[1].devices[0]) # #
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 MPK261MXLOOP(ControlSurface): def __init__(self, *a, **k): super(MPK261MXLOOP, self).__init__(*a, **k) self.show_message("-----------------------= MPK261MXLOOP LOADING - maxcloutier13 says hi =----------------------------------------------------------") self.log_message("-----------------------= MPK261MXLOOP LOADING - maxcloutier13 says hi =----------------------------------------------------------") with self.component_guard(): midimap = MidiMap() #Sustain pedal 1 = Play/Record/Overdub switch for live looping self._LoopRecordButton = ButtonElement(True, MIDI_CC_TYPE, 0, 64) self._LoopRecordButton.add_value_listener(self._launch_clip, False) #Sustain pedal 2 = Sustain pour l'instant ;o) #self._LoopRecordButton = ButtonElement(True, MIDI_CC_TYPE, 0, 65) #Control up/down/left/right using the daw controls self._UpButton = ButtonElement(False, MIDI_CC_TYPE, 0, 88, name='UpButton') self._DownButton = ButtonElement(False, MIDI_CC_TYPE, 0, 89, name='DownButton') self._LeftButton = ButtonElement(False, MIDI_CC_TYPE, 0, 20, name='LeftButton') self._RightButton = ButtonElement(False, MIDI_CC_TYPE, 0, 21, name='RightButton') #Listeners for the functions self._UpButton.add_value_listener(self._move_up, False) self._DownButton.add_value_listener(self._move_down, False) self._LeftButton.add_value_listener(self._move_left, False) self._RightButton.add_value_listener(self._move_right, False) #Super crude manual init for the custom buttons and faders #Control Bank A - Channel 1 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- self._Encoder0 = EncoderElement(MIDI_CC_TYPE,1,22, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder0') self._Encoder1 = EncoderElement(MIDI_CC_TYPE,1,23, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder1') self._Encoder2 = EncoderElement(MIDI_CC_TYPE,1,24, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder2') self._Encoder3 = EncoderElement(MIDI_CC_TYPE,1,25, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder3') self._Encoder4 = EncoderElement(MIDI_CC_TYPE,1,26, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder4') self._Encoder5 = EncoderElement(MIDI_CC_TYPE,1,27, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder5') self._Encoder6 = EncoderElement(MIDI_CC_TYPE,1,28, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder6') self._Encoder7 = EncoderElement(MIDI_CC_TYPE,1,29, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder7') self._ArmButton0 = ButtonElement(False, MIDI_CC_TYPE, 0, 32, name='ArmButton0') self._ArmButton1 = ButtonElement(False, MIDI_CC_TYPE, 0, 33, name='ArmButton1') self._ArmButton2 = ButtonElement(False, MIDI_CC_TYPE, 0, 34, name='ArmButton2') self._ArmButton3 = ButtonElement(False, MIDI_CC_TYPE, 0, 35, name='ArmButton3') self._ArmButton4 = ButtonElement(False, MIDI_CC_TYPE, 0, 36, name='ArmButton4') self._ArmButton5 = ButtonElement(False, MIDI_CC_TYPE, 0, 37, name='ArmButton5') self._ArmButton6 = ButtonElement(False, MIDI_CC_TYPE, 0, 38, name='ArmButton6') self._ArmButton7 = ButtonElement(False, MIDI_CC_TYPE, 0, 39, name='ArmButton7') self._VolumeSlider0 = SliderElement(MIDI_CC_TYPE, 0, 12, name='VolumeSlider0') self._VolumeSlider1 = SliderElement(MIDI_CC_TYPE, 0, 13, name='VolumeSlider1') self._VolumeSlider2 = SliderElement(MIDI_CC_TYPE, 0, 14, name='VolumeSlider2') self._VolumeSlider3 = SliderElement(MIDI_CC_TYPE, 0, 15, name='VolumeSlider3') self._VolumeSlider4 = SliderElement(MIDI_CC_TYPE, 0, 16, name='VolumeSlider4') self._VolumeSlider5 = SliderElement(MIDI_CC_TYPE, 0, 17, name='VolumeSlider5') self._VolumeSlider6 = SliderElement(MIDI_CC_TYPE, 0, 18, name='VolumeSlider6') self._VolumeSlider7 = SliderElement(MIDI_CC_TYPE, 0, 19, name='VolumeSlider7') #Control Bank B - Channel 2 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- self._Encoder8 = EncoderElement(MIDI_CC_TYPE,2,22, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder8') self._Encoder9 = EncoderElement(MIDI_CC_TYPE,2,23, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder9') self._Encoder10 = EncoderElement(MIDI_CC_TYPE,2,24, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder10') self._Encoder11 = EncoderElement(MIDI_CC_TYPE,2,25, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder11') self._Encoder12 = EncoderElement(MIDI_CC_TYPE,2,26, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder12') self._Encoder13 = EncoderElement(MIDI_CC_TYPE,2,27, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder13') self._Encoder14 = EncoderElement(MIDI_CC_TYPE,2,28, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder14') self._Encoder15 = EncoderElement(MIDI_CC_TYPE,2,29, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder15') self._ArmButton8 = ButtonElement(False, MIDI_CC_TYPE, 1, 32, name='ArmButton8') self._ArmButton9 = ButtonElement(False, MIDI_CC_TYPE, 1, 33, name='ArmButton9') self._ArmButton10 = ButtonElement(False, MIDI_CC_TYPE, 1, 34, name='ArmButton10') self._ArmButton11 = ButtonElement(False, MIDI_CC_TYPE, 1, 35, name='ArmButton11') self._ArmButton12 = ButtonElement(False, MIDI_CC_TYPE, 1, 36, name='ArmButton12') self._ArmButton13 = ButtonElement(False, MIDI_CC_TYPE, 1, 37, name='ArmButton13') self._ArmButton14 = ButtonElement(False, MIDI_CC_TYPE, 1, 38, name='ArmButton14') self._ArmButton15 = ButtonElement(False, MIDI_CC_TYPE, 1, 39, name='ArmButton15') self._VolumeSlider8 = SliderElement(MIDI_CC_TYPE, 1, 12, name='VolumeSlider8') self._VolumeSlider9 = SliderElement(MIDI_CC_TYPE, 1, 13, name='VolumeSlider9') self._VolumeSlider10 = SliderElement(MIDI_CC_TYPE, 1, 14, name='VolumeSlider10') self._VolumeSlider11 = SliderElement(MIDI_CC_TYPE, 1, 15, name='VolumeSlider11') self._VolumeSlider12 = SliderElement(MIDI_CC_TYPE, 1, 16, name='VolumeSlider12') self._VolumeSlider13 = SliderElement(MIDI_CC_TYPE, 1, 17, name='VolumeSlider13') self._VolumeSlider14 = SliderElement(MIDI_CC_TYPE, 1, 18, name='VolumeSlider14') self._VolumeSlider15 = SliderElement(MIDI_CC_TYPE, 1, 19, name='VolumeSlider15') #Control Bank C - Channel 3 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- self._Encoder16 = EncoderElement(MIDI_CC_TYPE,3,22, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder16') self._Encoder17 = EncoderElement(MIDI_CC_TYPE,3,23, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder17') self._Encoder18 = EncoderElement(MIDI_CC_TYPE,3,24, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder18') self._Encoder19 = EncoderElement(MIDI_CC_TYPE,3,25, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder19') self._Encoder20 = EncoderElement(MIDI_CC_TYPE,3,26, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder20') self._Encoder21 = EncoderElement(MIDI_CC_TYPE,3,27, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder21') self._Encoder22 = EncoderElement(MIDI_CC_TYPE,3,28, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder22') self._Encoder23 = EncoderElement(MIDI_CC_TYPE,3,29, Live.MidiMap.MapMode.relative_two_compliment, name='Encoder23') self._ArmButton16 = ButtonElement(False, MIDI_CC_TYPE, 2, 32, name='ArmButton16') self._ArmButton17 = ButtonElement(False, MIDI_CC_TYPE, 2, 33, name='ArmButton17') self._ArmButton18 = ButtonElement(False, MIDI_CC_TYPE, 2, 34, name='ArmButton18') self._ArmButton19 = ButtonElement(False, MIDI_CC_TYPE, 2, 35, name='ArmButton19') self._ArmButton20 = ButtonElement(False, MIDI_CC_TYPE, 2, 36, name='ArmButton20') self._ArmButton21 = ButtonElement(False, MIDI_CC_TYPE, 2, 37, name='ArmButton21') self._ArmButton22 = ButtonElement(False, MIDI_CC_TYPE, 2, 38, name='ArmButton22') self._ArmButton23 = ButtonElement(False, MIDI_CC_TYPE, 2, 39, name='ArmButton23') self._VolumeSlider16 = SliderElement(MIDI_CC_TYPE, 2, 12, name='VolumeSlider16') self._VolumeSlider17 = SliderElement(MIDI_CC_TYPE, 2, 13, name='VolumeSlider17') self._VolumeSlider18 = SliderElement(MIDI_CC_TYPE, 2, 14, name='VolumeSlider18') self._VolumeSlider19 = SliderElement(MIDI_CC_TYPE, 2, 15, name='VolumeSlider19') self._VolumeSlider20 = SliderElement(MIDI_CC_TYPE, 2, 16, name='VolumeSlider20') self._VolumeSlider21 = SliderElement(MIDI_CC_TYPE, 2, 17, name='VolumeSlider21') self._VolumeSlider22 = SliderElement(MIDI_CC_TYPE, 2, 18, name='VolumeSlider22') self._VolumeSlider23 = SliderElement(MIDI_CC_TYPE, 2, 19, name='VolumeSlider23') #Drum Bank A - Channel 4-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- self._Pad0 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 81, name='Pad0') self._Pad1 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 83, name='Pad1') self._Pad2 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 84, name='Pad2') self._Pad3 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 86, name='Pad3') self._Pad4 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 74, name='Pad4') self._Pad5 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 76, name='Pad5') self._Pad6 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 77, name='Pad6') self._Pad7 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 79, name='Pad7') self._Pad8 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 67, name='Pad8') self._Pad9 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 69, name='Pad9') self._Pad10 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 71, name='Pad10') self._Pad11 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 72, name='Pad11') self._Pad12 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 60, name='Pad12') self._Pad13 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 62, name='Pad13') self._Pad14 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 64, name='Pad14') self._Pad15 = ButtonElement(True, MIDI_NOTE_TYPE, 3, 65, name='Pad15') self._Pads = ButtonMatrixElement(rows=[[self._Pad0, self._Pad1, self._Pad2, self._Pad3], [self._Pad4, self._Pad5, self._Pad6, self._Pad7], [self._Pad8, self._Pad9, self._Pad10, self._Pad11], [self._Pad12, self._Pad13, self._Pad14, self._Pad15]]) #Drum Bank B ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- #Drum Bank C ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- #Drum Bank D ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- # #Drum rack ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- drum_rack = DrumRackComponent(name='Drum_Rack', is_enabled=False, layer=Layer(pads=self._Pads)) drum_rack.set_enabled(True) #Transport ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- transport = TransportComponent(name='Transport', is_enabled=False, layer=Layer(play_button=midimap['Play'], record_button=midimap['Record'], stop_button=midimap['Stop'], loop_button=midimap['Loop'])) #, seek_forward_button=midimap['Forward'], seek_backward_button=midimap['Backward'] transport.set_enabled(True) #Make the Back/Fwd button just normal mapable CC senders self._BackButton = ButtonElement(False, MIDI_CC_TYPE, 0, 116, name='BackButton') self._FwdButton = ButtonElement(False, MIDI_CC_TYPE, 0, 115, name='FwdButton') #Device ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- self._device = DeviceComponent(name='Device', is_enabled=False, layer=Layer(parameter_controls=midimap['Encoders']), device_selection_follows_track_selection=True) self._device.set_enabled(True) self.set_device_component(self._device) #Mixer ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- mixer_size = 24 self._mixer = MixerComponent(mixer_size, name='Mixer', is_enabled=False) #Super crude and repetitive mapping because after all this shit I'm not spending time learning how to loop this crap hehe #Bank A self._mixer.channel_strip(0).layer = Layer(volume_control = self._VolumeSlider0, arm_button=self._ArmButton0, pan_control=self._Encoder0) self._mixer.channel_strip(1).layer = Layer(volume_control = self._VolumeSlider1, arm_button=self._ArmButton1, pan_control=self._Encoder1) self._mixer.channel_strip(2).layer = Layer(volume_control = self._VolumeSlider2, arm_button=self._ArmButton2, pan_control=self._Encoder2) self._mixer.channel_strip(3).layer = Layer(volume_control = self._VolumeSlider3, arm_button=self._ArmButton3, pan_control=self._Encoder3) self._mixer.channel_strip(4).layer = Layer(volume_control = self._VolumeSlider4, arm_button=self._ArmButton4, pan_control=self._Encoder4) self._mixer.channel_strip(5).layer = Layer(volume_control = self._VolumeSlider5, arm_button=self._ArmButton5, pan_control=self._Encoder5) self._mixer.channel_strip(6).layer = Layer(volume_control = self._VolumeSlider6, arm_button=self._ArmButton6, pan_control=self._Encoder6) self._mixer.channel_strip(7).layer = Layer(volume_control = self._VolumeSlider7, arm_button=self._ArmButton7, pan_control=self._Encoder7) #Bank B self._mixer.channel_strip(8).layer = Layer(volume_control = self._VolumeSlider8, arm_button=self._ArmButton8, pan_control=self._Encoder8) self._mixer.channel_strip(9).layer = Layer(volume_control = self._VolumeSlider9, arm_button=self._ArmButton9, pan_control=self._Encoder9) self._mixer.channel_strip(10).layer = Layer(volume_control = self._VolumeSlider10, arm_button=self._ArmButton10, pan_control=self._Encoder10) self._mixer.channel_strip(11).layer = Layer(volume_control = self._VolumeSlider11, arm_button=self._ArmButton11, pan_control=self._Encoder11) self._mixer.channel_strip(12).layer = Layer(volume_control = self._VolumeSlider12, arm_button=self._ArmButton12, pan_control=self._Encoder12) self._mixer.channel_strip(13).layer = Layer(volume_control = self._VolumeSlider13, arm_button=self._ArmButton13, pan_control=self._Encoder13) self._mixer.channel_strip(14).layer = Layer(volume_control = self._VolumeSlider14, arm_button=self._ArmButton14, pan_control=self._Encoder14) self._mixer.channel_strip(15).layer = Layer(volume_control = self._VolumeSlider15, arm_button=self._ArmButton15, pan_control=self._Encoder15) #Bank C self._mixer.channel_strip(16).layer = Layer(volume_control = self._VolumeSlider16, arm_button=self._ArmButton16, pan_control=self._Encoder16) self._mixer.channel_strip(17).layer = Layer(volume_control = self._VolumeSlider17, arm_button=self._ArmButton17, pan_control=self._Encoder17) self._mixer.channel_strip(18).layer = Layer(volume_control = self._VolumeSlider18, arm_button=self._ArmButton18, pan_control=self._Encoder18) self._mixer.channel_strip(19).layer = Layer(volume_control = self._VolumeSlider19, arm_button=self._ArmButton19, pan_control=self._Encoder19) self._mixer.channel_strip(20).layer = Layer(volume_control = self._VolumeSlider20, arm_button=self._ArmButton20, pan_control=self._Encoder20) self._mixer.channel_strip(21).layer = Layer(volume_control = self._VolumeSlider21, arm_button=self._ArmButton21, pan_control=self._Encoder21) self._mixer.channel_strip(22).layer = Layer(volume_control = self._VolumeSlider22, arm_button=self._ArmButton22, pan_control=self._Encoder22) self._mixer.channel_strip(23).layer = Layer(volume_control = self._VolumeSlider23, arm_button=self._ArmButton23, pan_control=self._Encoder23) self._mixer.set_enabled(True) #Track change listener self.song().view.add_selected_track_listener(self._update_selected_device) #Track changed def _update_selected_device(self): track = self.song().view.selected_track #self.show_message("----- Track changed! -----") #Launch/Record/Overdub def _launch_clip(self, value): global _overdub_flag #self.log_message("--> Track launch! -----") #self.song().view.highlighted_clip_slot.set_fire_button_state(True) _current_slot = self.song().view.highlighted_clip_slot if _current_slot.is_playing == 0 and _current_slot.is_recording == 0: self.song().view.highlighted_clip_slot.set_fire_button_state(True) elif _current_slot.is_playing == 1 and _current_slot.is_recording == 0: self.song().overdub = 1 _overdub_flag = 1 elif _current_slot.is_playing == 1 and _current_slot.is_recording == 1 and _overdub_flag == 1: self.song().overdub = 0 _overdub_flag = 0 else: self.song().view.highlighted_clip_slot.set_fire_button_state(True) #Move up/down def _move_clipslot(self, up): scene = self.song().view.selected_scene scenes = self.song().scenes max_scenes = len(scenes) for i in range(max_scenes): if scene == scenes[i]: #Found our guy if up == 1: self.song().view.selected_scene = scenes[i-1] self.show_message("TFMX Debug: Up!") else: if scene == scenes[max_scenes-1]: self.song().view.selected_scene = scenes[0] else: self.song().view.selected_scene = scenes[i+1] self.show_message("TFMX Debug: Down!") #Move left/right def _move_track(self, left): #Get track and tracks track = self.song().view.selected_track tracks = self.get_all_tracks(only_visible = True) max_tracks = len(tracks) #Iterate to find current track's index. for i in range(max_tracks): if track == tracks[i]: #Found our track if left == 1: self.song().view.selected_track = tracks[i-1] else: if track == tracks[max_tracks-1]: self.song().view.selected_track = tracks[0] else: self.song().view.selected_track = tracks[i+1] def get_all_tracks(self, only_visible = False): tracks = [] for track in self.song().tracks: if not only_visible or track.is_visible: tracks.append(track) #Include the master track? #NOPE tracks.append(self.song().master_track) return tracks def _move_up(self, value): if value > 0: self._move_clipslot(1) def _move_down(self, value): if value > 0: self._move_clipslot(0) def _move_left(self, value): if value > 0: self._move_track(1) def _move_right(self, value): if value > 0: self._move_track(0) #-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------