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))
class BCR2000(ControlSurface, AbletonPlus): __doc__ = "BCR2000 Custom Script" def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) AbletonPlus.__init__(self, options) self._main_encoders = [] self._main_buttons = [] self._effects_encoders = [] self._extra_buttons = [] self._mixer = None for index in range(0, 24): encoder = EncoderElement(MIDI_CC_TYPE, 0, 81 + index, Live.MidiMap.MapMode.absolute) self._main_encoders.append(encoder) for index in range(0, 16): button = ButtonElement(False, MIDI_CC_TYPE, 0, 76 + index) self._main_buttons.append(button) self._mixer = MixerComponent(8) self._remap_track_mixer_controls() self._enable_abletonplus() return None def _enable_abletonplus(self): if (self not in AbletonPlus._enabled_devices): AbletonPlus._enabled_devices.append(self) AbletonPlus._connect_active_instances(self) def disconnect(self): self._disconnect_instance() def _remap_track_mixer_controls(self): self._mixer.set_track_offset(AbletonPlus.get_track_offset()) for index in range(8): strip = self._mixer.channel_strip(index) strip.name = 'Channel_Strip_' + str(index) strip.set_volume_control(self._main_encoders[(index * 3) + 2]) strip.set_pan_control(self._main_encoders[(index * 3) + 1]) strip.set_mute_button(self._main_buttons[index * 2]) strip.set_arm_button(self._main_buttons[(index * 2) + 1]) strip.set_send_controls((self._main_encoders[index * 3], )) return None def offset_update(self): self._remap_track_mixer_controls() return None def selected_change(self): self._remap_selected_track_devices() return None
class BCR2000(ControlSurface, AbletonPlus): __doc__ = "BCR2000 Custom Script" def __init__(self,c_instance): ControlSurface.__init__(self, c_instance) AbletonPlus.__init__(self, options) self._main_encoders = [] self._main_buttons = [] self._effects_encoders = [] self._extra_buttons = [] self._mixer = None for index in range(0, 24): encoder = EncoderElement(MIDI_CC_TYPE,0,92 + index,Live.MidiMap.MapMode.absolute) self._main_encoders.append(encoder) for index in range(0,16): button = ButtonElement(False, MIDI_CC_TYPE,0, 76 + index) self._main_buttons.append(button) self._mixer = MixerComponent(8) self._remap_track_mixer_controls() self._enable_abletonplus() return None def _enable_abletonplus(self): if(self not in AbletonPlus._enabled_devices): AbletonPlus._enabled_devices.append(self) AbletonPlus._connect_active_instances(self) def disconnect(self): self._disconnect_instance() def _remap_track_mixer_controls(self): self._mixer.set_track_offset(AbletonPlus.get_track_offset()) for index in range(8): strip = self._mixer.channel_strip(index) strip.name = 'Channel_Strip_' + str(index) strip.set_volume_control(self._main_encoders[(index * 3) + 2]) strip.set_pan_control(self._main_encoders[(index * 3) + 1]) strip.set_mute_button(self._main_buttons[index * 2]) strip.set_arm_button(self._main_buttons[(index * 2)+ 1]) strip.set_send_controls((self._main_encoders[index * 3],)) return None def offset_update(self): self._remap_track_mixer_controls() return None def selected_change(self): self._remap_selected_track_devices() return None
class KeyPad(ControlSurface): _encoder_range = list(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): 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: list(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, range(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 range(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 range(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 range(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 BCFR2000(ControlSurface): """BCFR Control Surface Class""" ####PRIVATE METHODS def __init__(self, c_instance): """Initalization function for the BCFR2000 object""" ControlSurface.__init__(self, c_instance) self._bcf = BCF2000() self._bcr = BCR2000() self._master_coords = (0,0) self._ap = AbletonPlus(self,options['abletonplus']) self._setup_ap_options() #initalize the live objects needed self._mixer = MixerComponent(8,3) self._fx_strip = None #placeholder for the efx stuff self._enable_abletonplus() self._remap_track_mixer_controls() def _remap_track_mixer_controls(self): """this function is called to remap the mixer controls to the new offsets""" self._mixer.set_track_offset(self._master_coords[0]) for index in range(8): strip = self._mixer.channel_strip(index) strip.set_volume_control(self._bcf.main_faders[index]) strip.set_pan_control(self._bcf.encoder_groups[0][index]) strip.set_mute_button(self._bcf.buttons[0][index]) strip.set_arm_button(self._bcf.buttons[1][index]) strip.set_send_controls((self._bcf.encoder_groups[1][index],self._bcf.encoder_groups[2][index],self._bcf.encoder_groups[3][index])) def __remap_sfx_controls(self): """remaps the sfx controls when the controls are changed""" pass def _get_coords(self): """get the coordinates from the master grid controller. master-grid-coords returns a tuple to be treated like an x-y coordinate""" return self._ap.getter("master_grid_offset") def _ape_add(self, sender, event, **kwargs): """this event handler is fired when a controller gets added""" pass def _ape_rem(self, sender, event, **kwargs): pass def _ape_ena(self, sender, event, **kwargs): pass def _ape_dis(self, sender, event, **kwargs): pass def _ape_update_master_grid_coords(self,event,**kwargs): """recieves an event from the master controller changing the coordinates, forces update""" write_log(event) if event == 'update_master_grid_coords': if "coords" in kwargs: self._master_coords = kwargs['coords'] self._remap_track_mixer_controls() def _ape_update_master_selected_track(self,event,**kwargs): """receives an event from the master controller changing the selected track""" if event == 'update_master_selected_track': if 'track' in kwargs: #do track getting stuff here, from the track in kwargs #remap the track controls pass def _ape_update_bcf2000_mappings(self,event,**kwargs): """recieves a message to force re-updating the control mappings""" if event == 'update_bcf2000_mappings': self._remap_track_mixer_controls(-1,-1) def _setup_ap_options(self): ap_options = options['abletonplus'] #EVENTS #listeners ##always need to add a handler for controller add, remove, enable, disable... so we use the helper function to do that ap_add_default_options(self, ap_options['callbacks'][0]) ap_options['callbacks'][0].update({'update_master_grid_coords':self._ape_update_master_grid_coords, 'update_master_selected_track':self._ape_update_master_selected_track, 'update_bcf2000_mappings':self._ape_update_bcf2000_mappings}) #ap_options['callbacks'][0].update('ap_add':self._ape_add,'ap_remove':self._ape_rem,'ap_enable':self._ape_ena,'ap_disable':self._ape_dis def _enable_abletonplus(self): self._ap.enable_abletonplus() def selcted_track_changed(self,event, **kwargs): """recieves and event from the master controller that a new track has been selected""" pass def update_master_coords(self,coords = None): if coords == None: master_coords = self._get_coords() if (master_coords[0] != self._master_coords[0]) or (master_coords[1] != self._master_coords[1]): self._master_coords = master_coords update def disconnect(self): """disconnect the instance""" self._ap.disable_abletonplus() self._disconnect_instance()
class BCFR2000(ControlSurface): """BCFR Control Surface Class""" ####PRIVATE METHODS def __init__(self, c_instance): """Initalization function for the BCFR2000 object""" ControlSurface.__init__(self, c_instance) self._bcf = BCF2000() self._bcr = BCR2000() self._master_coords = (0, 0) self._ap = AbletonPlus(self, options['abletonplus']) self._setup_ap_options() #initalize the live objects needed self._mixer = MixerComponent(8, 3) self._fx_strip = None #placeholder for the efx stuff self._enable_abletonplus() self._remap_track_mixer_controls() def _remap_track_mixer_controls(self): """this function is called to remap the mixer controls to the new offsets""" self._mixer.set_track_offset(self._master_coords[0]) for index in range(8): strip = self._mixer.channel_strip(index) strip.set_volume_control(self._bcf.main_faders[index]) strip.set_pan_control(self._bcf.encoder_groups[0][index]) strip.set_mute_button(self._bcf.buttons[0][index]) strip.set_arm_button(self._bcf.buttons[1][index]) strip.set_send_controls((self._bcf.encoder_groups[1][index], self._bcf.encoder_groups[2][index], self._bcf.encoder_groups[3][index])) def __remap_sfx_controls(self): """remaps the sfx controls when the controls are changed""" pass def _get_coords(self): """get the coordinates from the master grid controller. master-grid-coords returns a tuple to be treated like an x-y coordinate""" return self._ap.getter("master_grid_offset") def _ape_add(self, sender, event, **kwargs): """this event handler is fired when a controller gets added""" pass def _ape_rem(self, sender, event, **kwargs): pass def _ape_ena(self, sender, event, **kwargs): pass def _ape_dis(self, sender, event, **kwargs): pass def _ape_update_master_grid_coords(self, event, **kwargs): """recieves an event from the master controller changing the coordinates, forces update""" write_log(event) if event == 'update_master_grid_coords': if "coords" in kwargs: self._master_coords = kwargs['coords'] self._remap_track_mixer_controls() def _ape_update_master_selected_track(self, event, **kwargs): """receives an event from the master controller changing the selected track""" if event == 'update_master_selected_track': if 'track' in kwargs: #do track getting stuff here, from the track in kwargs #remap the track controls pass def _ape_update_bcf2000_mappings(self, event, **kwargs): """recieves a message to force re-updating the control mappings""" if event == 'update_bcf2000_mappings': self._remap_track_mixer_controls(-1, -1) def _setup_ap_options(self): ap_options = options['abletonplus'] #EVENTS #listeners ##always need to add a handler for controller add, remove, enable, disable... so we use the helper function to do that ap_add_default_options(self, ap_options['callbacks'][0]) ap_options['callbacks'][0].update({ 'update_master_grid_coords': self._ape_update_master_grid_coords, 'update_master_selected_track': self._ape_update_master_selected_track, 'update_bcf2000_mappings': self._ape_update_bcf2000_mappings }) #ap_options['callbacks'][0].update('ap_add':self._ape_add,'ap_remove':self._ape_rem,'ap_enable':self._ape_ena,'ap_disable':self._ape_dis def _enable_abletonplus(self): self._ap.enable_abletonplus() def selcted_track_changed(self, event, **kwargs): """recieves and event from the master controller that a new track has been selected""" pass def update_master_coords(self, coords=None): if coords == None: master_coords = self._get_coords() if (master_coords[0] != self._master_coords[0]) or ( master_coords[1] != self._master_coords[1]): self._master_coords = master_coords update def disconnect(self): """disconnect the instance""" self._ap.disable_abletonplus() self._disconnect_instance()