Exemple #1
0
	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 = [23, 22, 15, 14, 5, 7, 6, 4]
		pan_select_notes = [21, 20, 13, 12, 3, 1, 0, 2]
		master_volume_control = SliderElement(MIDI_CC_TYPE, 0, 4)
		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)
		mixer.master_strip().set_select_button(master_select_button)
Exemple #2
0
 def _setup_mixer_control(self):
     is_momentary = True
     mixer = MixerComponent(1)
     mixer.selected_strip().set_mute_button(
         SysexButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                            KMK_PAD[9]))
     mixer.selected_strip().set_solo_button(
         SysexButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                            KMK_PAD[13]))
     mixer.set_select_buttons(
         SysexButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                            KMK_PAD[15]),
         SysexButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                            KMK_PAD[14]))
     send_faders = []
     NUM_CONTROLLABLE_SENDS = 4
     for index in range(NUM_CONTROLLABLE_SENDS):
         send_faders.append(
             SliderElement(MIDI_CC_TYPE, CHANNEL, KMK_FADER[index + 2]))
     mixer.selected_strip().set_volume_control(
         SliderElement(MIDI_CC_TYPE, CHANNEL, KMK_FADER[0]))
     mixer.selected_strip().set_pan_control(
         SliderElement(MIDI_CC_TYPE, CHANNEL, KMK_FADER[1]))
     mixer.selected_strip().set_send_controls(tuple(send_faders))
     mixer.set_prehear_volume_control(
         EncoderElement(MIDI_CC_TYPE, CHANNEL, KMK_FADER[6],
                        Live.MidiMap.MapMode.absolute))
     mixer.master_strip().set_volume_control(
         SliderElement(MIDI_CC_TYPE, CHANNEL, KMK_FADER[7]))
     return mixer
Exemple #3
0
	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 _setup_mixer_control(self):
     is_momentary = True
     #mixer = MixerComponent(8)
     mixer = MixerComponent(1)
     #for track in range(8):
     #    strip = mixer.channel_strip(track)
     #    strip.set_volume_control(SliderElement(MIDI_CC_TYPE, track, 7))
     #    strip.set_arm_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, track, 48))
     #    strip.set_solo_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, track, 49))
     #    strip.set_mute_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, track, 50))
     #    #strip.set_select_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, track, 51))
     #    strip.set_shift_button(self._shift_button)
     #    strip.set_invert_mute_feedback(True)
     """ WAC addition...................................."""
     mixer.selected_strip().set_mute_button(SysexButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, KMK_PAD[9]))
     mixer.selected_strip().set_solo_button(SysexButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, KMK_PAD[13]))
     mixer.set_select_buttons(SysexButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, KMK_PAD[15]),
                              SysexButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, KMK_PAD[14]))
     send_faders = []
     NUM_CONTROLLABLE_SENDS = 4
     for index in range(NUM_CONTROLLABLE_SENDS):
         send_faders.append(SliderElement(MIDI_CC_TYPE, CHANNEL, KMK_FADER[index + 2]))
     mixer.selected_strip().set_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL, KMK_FADER[0]))
     mixer.selected_strip().set_pan_control(SliderElement(MIDI_CC_TYPE, CHANNEL, KMK_FADER[1]))
     mixer.selected_strip().set_send_controls(tuple(send_faders))
     """------------------------------------------------"""
     #mixer.set_crossfader_control(SliderElement(MIDI_CC_TYPE, 0, 15))
     #mixer.set_prehear_volume_control(EncoderElement(MIDI_CC_TYPE, 0, 47, Live.MidiMap.MapMode.relative_two_compliment))
     mixer.set_prehear_volume_control(EncoderElement(MIDI_CC_TYPE, CHANNEL, KMK_FADER[6], Live.MidiMap.MapMode.absolute))
     #mixer.master_strip().set_volume_control(SliderElement(MIDI_CC_TYPE, 0, 14))
     mixer.master_strip().set_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL, KMK_FADER[7]))
     #mixer.master_strip().set_select_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, 80))
     return mixer
 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..."""
Exemple #6
0
    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")
Exemple #7
0
 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
     mixer = MixerComponent(1)
     mixer.selected_strip().set_mute_button(SysexButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, KMK_PAD[9]))
     mixer.selected_strip().set_solo_button(SysexButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, KMK_PAD[13]))
     mixer.set_select_buttons(SysexButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, KMK_PAD[15]),
                              SysexButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, KMK_PAD[14]))
     send_faders = []
     NUM_CONTROLLABLE_SENDS = 4
     for index in range(NUM_CONTROLLABLE_SENDS):
         send_faders.append(SliderElement(MIDI_CC_TYPE, CHANNEL, KMK_FADER[index + 2]))
     mixer.selected_strip().set_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL, KMK_FADER[0]))
     mixer.selected_strip().set_pan_control(SliderElement(MIDI_CC_TYPE, CHANNEL, KMK_FADER[1]))
     mixer.selected_strip().set_send_controls(tuple(send_faders))
     mixer.set_prehear_volume_control(EncoderElement(MIDI_CC_TYPE, CHANNEL, KMK_FADER[6], Live.MidiMap.MapMode.absolute))
     mixer.master_strip().set_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL, KMK_FADER[7]))
     return mixer
Exemple #9
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")
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.
Exemple #11
0
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])
Exemple #12
0
class xtouch(ControlSurface):
    def __init__(self, c_instance):
        super(xtouch, self).__init__(c_instance)
        with self.component_guard():
            self.__c_instance = c_instance

            self._highlighting_session_component = None
            self._device_selection_follows_track_selection = False
            self._device_component = None

            self._pad_control_device = None
            self._track_control_device = None

            self._should_update_tracks = 0

            self._map_modes = Live.MidiMap.MapMode
            self.current_track_offset = 0
            self.current_scene_offset = 0

            self.mixer = MixerComponent(128, 24)

            num_of_tracks = len(self.song().tracks)
            for index in range(num_of_tracks):
                self.song().tracks[index].view.add_selected_device_listener(
                    self._reload_track_control)

            self._reload_track_control()

    def best_of_parameter_bank(self):
        return []

    def _do_deactivate_pad_control(self):
        with self.component_guard():
            if (self._pad_control_device is not None):
                device_controls = (None, None, None, None, None, None, None,
                                   None)

                self._pad_control_device.set_parameter_controls(
                    tuple(device_controls))
                self._pad_control_device.set_lock_to_device(
                    "", self.actual_device)
                self._pad_control_device.set_device(None)

                self._pad_control_device = None

    def activate_pad_control(self, track, pad):
        self._do_deactivate_pad_control()

        with self.component_guard():
            self._deactivate_track_control()

            track_id = track + 8
            tracks = self.mixer.song().tracks

            if track_id < len(tracks):
                track = tracks[track_id]

                if (len(track.devices) > 0):
                    drumpad = track.devices[0].drum_pads[36 + pad]
                    if len(drumpad.chains) > 0:
                        if len(drumpad.chains[0].devices) > 0:
                            self.actual_device = drumpad.chains[0].devices[0]

                            def log(msg):
                                self.log_message(msg)

                            self._pad_control_device = CustomDeviceComponent(
                                log)
                            device_controls = (
                                EncoderElement(MIDI_CC_TYPE, 10, 1,
                                               self._map_modes.absolute),
                                EncoderElement(MIDI_CC_TYPE, 10, 2,
                                               self._map_modes.absolute),
                                EncoderElement(MIDI_CC_TYPE, 10, 3,
                                               self._map_modes.absolute),
                                EncoderElement(MIDI_CC_TYPE, 10, 4,
                                               self._map_modes.absolute),
                                EncoderElement(MIDI_CC_TYPE, 10, 5,
                                               self._map_modes.absolute),
                                EncoderElement(MIDI_CC_TYPE, 10, 6,
                                               self._map_modes.absolute),
                                EncoderElement(MIDI_CC_TYPE, 10, 7,
                                               self._map_modes.absolute),
                                EncoderElement(MIDI_CC_TYPE, 10, 8,
                                               self._map_modes.absolute),
                            )

                            self.actual_device.playback_mode = 0
                            self.actual_device.parameters[31].value = 1.0

                            self._pad_control_device.set_device(
                                self.actual_device)
                            self._pad_control_device.set_parameter_controls(
                                tuple(device_controls))
                            self._pad_control_device.set_lock_to_device(
                                "lock", self.actual_device)
                            self.log_message("AA " +
                                             str(self._pad_control_device.
                                                 _current_bank_details()))

    def deactivate_pad_control(self):
        with self.component_guard():
            self._do_deactivate_pad_control()
            self._reload_track_control()

    def _activate_track_control(self):
        if self._pad_control_device is not None:
            return

        if (len(self.mixer.selected_strip()._track.devices) > 0):
            devices = self.mixer.selected_strip()._track.devices
            self.actual_device = devices[0]

            self._track_control_device = DeviceComponent()
            device_controls = (
                EncoderElement(MIDI_CC_TYPE, 10, 1, self._map_modes.absolute),
                EncoderElement(MIDI_CC_TYPE, 10, 2, self._map_modes.absolute),
                EncoderElement(MIDI_CC_TYPE, 10, 3, self._map_modes.absolute),
                EncoderElement(MIDI_CC_TYPE, 10, 4, self._map_modes.absolute),
                EncoderElement(MIDI_CC_TYPE, 10, 5, self._map_modes.absolute),
                EncoderElement(MIDI_CC_TYPE, 10, 6, self._map_modes.absolute),
                EncoderElement(MIDI_CC_TYPE, 10, 7, self._map_modes.absolute),
                EncoderElement(MIDI_CC_TYPE, 10, 8, self._map_modes.absolute),
            )

            self._track_control_device.set_device(self.actual_device)
            self._track_control_device.set_parameter_controls(
                tuple(device_controls))
            self._track_control_device.set_lock_to_device(
                "lock", self.actual_device)

    def _deactivate_track_control(self):
        if (self._track_control_device is not None):
            device_controls = (None, None, None, None, None, None, None, None)

            self._track_control_device.set_parameter_controls(
                tuple(device_controls))
            self._track_control_device.set_lock_to_device(
                "", self.actual_device)
            self._track_control_device.set_device(None)

            self._track_control_device = None

    def _reload_track_control(self, value=None):
        self._deactivate_track_control()
        self._activate_track_control()

    def _highlight_tracks(self):
        j = [0]

        def update_next_track(selected):
            if selected:
                self.__c_instance.send_midi((10 | 0x90, 8 + j[0], 127))
            else:
                self.__c_instance.send_midi((10 | 0x80, 8 + j[0], 0))
            j[0] += 1

        selected_track = self.song().view.selected_track
        for i in [0, 1, 2, 3, 4, 5, 6, 7, 17, 18]:
            track_selected = False
            if i < len(self.song().tracks):
                if self.song().tracks[i] == selected_track:
                    track_selected = True

            update_next_track(track_selected)

        update_next_track(self.song().return_tracks[0] == selected_track)
        update_next_track(self.song().return_tracks[1] == selected_track)
        update_next_track(self.song().master_track == selected_track)

    def _on_selected_track_changed(self):
        ControlSurface._on_selected_track_changed(self)
        self._display_reset_delay = 0
        self._reload_track_control()
        self._should_update_tracks = 3

    def build_midi_map(self, midi_map_handle):
        ControlSurface.build_midi_map(self, midi_map_handle)
        for i in range(0, 16):
            Live.MidiMap.forward_midi_note(self.__c_instance.handle(),
                                           midi_map_handle, 10, 8 + i)

    def receive_midi(self, midi_bytes):
        ControlSurface.receive_midi(self, midi_bytes)
        if (midi_bytes[0] == 10 | 0x90) or (midi_bytes[0] == 10 | 0x80):
            if midi_bytes[1] >= 8 and midi_bytes[1] <= 24:
                track_id = midi_bytes[1] - 8
                if (track_id < 8):
                    self.song().view.selected_track = self.song(
                    ).tracks[track_id]
                elif (track_id < 10):
                    self.song().view.selected_track = self.song().tracks[
                        9 + track_id]
                elif (track_id < 12):
                    self.song().view.selected_track = self.song(
                    ).return_tracks[track_id - 10]
                else:
                    self.song().view.selected_track = self.song().master_track

                self._should_update_tracks = 2

    def update_display(self):
        ControlSurface.update_display(self)
        if self._should_update_tracks == 1:
            self._highlight_tracks()
            self._should_update_tracks = 0

        if self._should_update_tracks > 1:
            self._should_update_tracks -= 1

    def disconnect(self):
        super(xtouch, self).disconnect()
Exemple #13
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")
Exemple #14
0
class MPK_SessionControl(ControlSurface):
    __module__ = __name__
    __doc__ = "MPK Session Control Script"

    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
            self._setup_mixer_control()
            self._setup_transport_control()
            self._setup_session_control()
            self._setup_channel_strip_control()
            self.set_highlighting_session_component(self.session)

    # Sets up the control surface ('colored box')
    def _setup_session_control(self):
        num_tracks = 3  # 3 columns (tracks)
        num_scenes = 1  # 1 row (scenes)

        # a session highlight ("red box") will appear with any two non-zero values
        self.session = SessionComponent(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,
                          KEYBOARD_HIGH_C - 7),
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                          KEYBOARD_HIGH_C - 6))

        # These calls control the actual movement of the box; however, we're just
        # using scene and track select to move around
        # self.session.set_scene_bank_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, 86), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, 85))
        # self.session.set_track_bank_buttons(ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, 15), ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, 14))

        # Launch current scene with top right pad
        self.session.selected_scene().set_launch_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, BANK_B[3]))
        # Stop all clips with bottom right pad
        self.session.set_stop_all_clips_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, BANK_B[7]))

        # First three pads launch clips in box
        clip_launch_notes = [BANK_B[0], BANK_B[1], BANK_B[2]]
        clip_select_notes = [
            KEYBOARD_MID_C - 6, KEYBOARD_MID_C - 4, KEYBOARD_MID_C - 2
        ]

        for tracks in range(num_tracks):
            self.session.scene(0).clip_slot(tracks).set_launch_button(
                ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                              clip_launch_notes[tracks]))
            self.session.scene(0).clip_slot(tracks).set_select_button(
                ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                              clip_select_notes[tracks]))
            self.session.scene(0).clip_slot(tracks).set_started_value(1)
            self.session.scene(0).clip_slot(tracks).set_stopped_value(0)

        # Bottom three pads stop current tracks in box
        track_stop_notes = [BANK_B[4], BANK_B[5], BANK_B[6]]
        # This looks unnecessary but I don't know the actual API call to to set the stop track button for the selected track
        stop_track_buttons = []
        for tracks in range(num_tracks):
            stop_track_buttons.append(
                ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                              track_stop_notes[tracks]))

        self.session.set_stop_track_clip_buttons(tuple(stop_track_buttons))

        #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
        selected_scene = self.song(
        ).view.selected_scene  #this is from the Live API
        all_scenes = self.song().scenes
        index = list(all_scenes).index(selected_scene)
        self.session.set_offsets(0, index)  #(track_offset, scene_offset)

    def _setup_transport_control(self):
        self.transport = TransportComponent()
        self.transport.set_stop_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                          KEYBOARD_LOW_C))
        self.transport.set_play_button(
            ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, 113))
        self.transport.set_metronome_button(
            ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, 114))
        self.transport.set_tap_tempo_button(
            ButtonElement(is_momentary, MIDI_CC_TYPE, CHANNEL, 81))

    def _setup_mixer_control(self):
        #set up the mixer
        self.mixer = MixerComponent(
            NUM_TRACKS, 2)  #(num_tracks, num_returns, with_eqs, with_filters)
        self.mixer.set_track_offset(
            0)  #sets start point for mixer strip (offset from left)
        self.mixer.selected_strip().set_arm_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                          KEYBOARD_HIGH_C))
        self.mixer.set_select_buttons(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                          KEYBOARD_HIGH_C - 2),
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                          KEYBOARD_HIGH_C - 4))
        self.mixer.master_strip().set_volume_control(
            SliderElement(MIDI_CC_TYPE, CHANNEL, KNOBS[3]))
        #self.mixer.master_strip().set_pan_control(SliderElement(MIDI_CC_TYPE, CHANNEL, KNOBS[7]))
        #set the selected strip to the first track, so that we don't 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
        self.mixer.selected_strip().set_volume_control(
            SliderElement(MIDI_CC_TYPE, CHANNEL, KNOBS[0]))
        #self.mixer.selected_strip().set_pan_control(SliderElement(MIDI_CC_TYPE, CHANNEL, KNOBS[4]))

        selected_track = self.song().view.selected_track
        all_tracks = ((self.song().tracks + self.song().return_tracks) +
                      (self.song().master_track, ))
        currentTrackIndex = list(all_tracks).index(selected_track)
        if currentTrackIndex < len(all_tracks) - 1:
            self.mixer.channel_strip(currentTrackIndex + 1).set_volume_control(
                SliderElement(MIDI_CC_TYPE, CHANNEL, KNOBS[1]))
            #self.mixer.channel_strip(currentTrackIndex + 1).set_pan_control(SliderElement(MIDI_CC_TYPE, CHANNEL, KNOBS[5]))
        if currentTrackIndex < len(all_tracks) - 2:
            self.mixer.channel_strip(currentTrackIndex + 2).set_volume_control(
                SliderElement(MIDI_CC_TYPE, CHANNEL, KNOBS[2]))
            #self.mixer.channel_strip(currentTrackIndex + 2).set_pan_control(SliderElement(MIDI_CC_TYPE, CHANNEL, KNOBS[6]))

    def _setup_channel_strip_control(self):
        self.channelstrip = ChannelStripComponent()
        self.channelstrip.set_track(self.mixer.channel_strip(0)._track)

    def _on_selected_track_changed(self):
        """This is an override, to add special functionality (we want to move the session to the selected track, when it changes)
    Note that it is sometimes necessary to reload Live (not just the script) when making changes to this function"""
        ControlSurface._on_selected_track_changed(
            self
        )  # This will run component.on_selected_track_changed() for all components
        """here we set the mixer and session to the selected track, when the selected track changes"""
        selected_track = self.song(
        ).view.selected_track  #this is how to get the currently selected track, using the Live API
        self.mixer.channel_strip(0).set_track(selected_track)
        all_tracks = (
            (self.song().tracks + self.song().return_tracks) +
            (self.song().master_track, )
        )  #this is from the MixerComponent's _next_track_value method
        index = list(all_tracks).index(selected_track)  #and so is this

        self.session.set_offsets(
            index, self.session._scene_offset
        )  #(track_offset, scene_offset); we leave scene_offset unchanged, but set track_offset to the selected track. This allows us to jump the red box to the selected track.

    def _on_selected_scene_changed(self):
        """This is an override, to add special functionality (we want to move the session to the selected scene, when it changes)"""
        """When making changes to this function on the fly, it is sometimes necessary to reload Live (not just the script)..."""
        ControlSurface._on_selected_scene_changed(
            self
        )  # This will run component.on_selected_scene_changed() for all components
        """Here we set the mixer and session to the selected track, when the selected track changes"""
        selected_scene = self.song(
        ).view.selected_scene  #this is how we get the currently selected scene, using the Live API
        all_scenes = self.song().scenes  #then get all of the scenes
        index = list(all_scenes).index(
            selected_scene
        )  #then identify where the selected scene sits in relation to the full list
        self.session.set_offsets(
            self.session._track_offset, index
        )  #(track_offset, scene_offset) Set the session's scene offset to match the selected track (but make no change to the track offset)

    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()) +
            "----------MPK SessionControl log closed----------")

        ControlSurface.disconnect(self)
        return None
Exemple #15
0
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])
	


#
#
Exemple #16
0
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()
Exemple #17
0
class joyMIDI(ControlSurface):
    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
            self.setup_transport()
            self.setup_mixer()
            self.setup_session()

    def setup_transport(self):
        # elements
        self.play_button = ButtonElement(True, MIDI_NOTE_TYPE, 0, 93)
        self.stop_button = ButtonElement(True, MIDI_NOTE_TYPE, 0, 94)
        self.record_button = ButtonElement(True, MIDI_NOTE_TYPE, 0, 95)
        # transport
        self.transport = TransportComponent()
        self.transport.set_play_button(self.play_button)
        self.transport.set_stop_button(self.stop_button)
        self.transport.set_record_button(self.record_button)

    def setup_mixer(self):
        # elements
        self.mute_button = ButtonElement(True, MIDI_NOTE_TYPE, 0,
                                         92)  # tracks, return_tracks
        self.solo_button = ButtonElement(True, MIDI_NOTE_TYPE, 0,
                                         84)  # tracks, return_tracks
        self.arm_button = ButtonElement(True, MIDI_NOTE_TYPE, 0, 85)  # tracks
        self.senda_up_button = ButtonElement(True, MIDI_NOTE_TYPE, 0,
                                             96)  # tracks, return_tracks
        self.senda_down_button = ButtonElement(True, MIDI_NOTE_TYPE, 0,
                                               88)  # tracks, return_tracks
        self.sendb_up_button = ButtonElement(True, MIDI_NOTE_TYPE, 0,
                                             97)  # tracks, return_tracks
        self.sendb_down_button = ButtonElement(True, MIDI_NOTE_TYPE, 0,
                                               89)  # tracks, return_tracks
        self.pan_up_button = ButtonElement(
            True, MIDI_NOTE_TYPE, 0, 98)  # tracks, return_tracks, master_track
        self.pan_down_button = ButtonElement(
            True, MIDI_NOTE_TYPE, 0, 90)  # tracks, return_tracks, master_track
        self.volume_up_button = ButtonElement(
            True, MIDI_NOTE_TYPE, 0, 99)  # tracks, return_tracks, master_track
        self.volume_down_button = ButtonElement(
            True, MIDI_NOTE_TYPE, 0, 91)  # tracks, return_tracks, master_track
        self.track_nav_encoder = EncoderElement(
            MIDI_CC_TYPE, 0, 14, Live.MidiMap.MapMode.relative_binary_offset)
        # mixer
        self.mixer = MixerComponent(7, 2)
        self.mixer.selected_strip().set_mute_button(self.mute_button)
        self.mixer.selected_strip().set_solo_button(self.solo_button)
        self.mixer.selected_strip().set_arm_button(self.arm_button)
        # send A/B, pan, volume
        self.senda_up_button.add_value_listener(self.on_senda_up_changed)
        self.senda_down_button.add_value_listener(self.on_senda_down_changed)
        self.sendb_up_button.add_value_listener(self.on_sendb_up_changed)
        self.sendb_down_button.add_value_listener(self.on_sendb_down_changed)
        self.pan_up_button.add_value_listener(self.on_pan_up_changed)
        self.pan_down_button.add_value_listener(self.on_pan_down_changed)
        self.volume_up_button.add_value_listener(self.on_volume_up_changed)
        self.volume_down_button.add_value_listener(self.on_volume_down_changed)
        # nav
        self.track_nav_encoder.add_value_listener(self.on_mixer_track_nav)

    def on_senda_up_changed(self, value):
        if value > 0:
            param = self.song().view.selected_track.mixer_device.sends[0]
            param.value = max(
                param.min,
                min(param.max,
                    param.value + ((param.max - param.min) / SEND_STEPS)))

    def on_senda_down_changed(self, value):
        if value > 0:
            param = self.song().view.selected_track.mixer_device.sends[0]
            param.value = max(
                param.min,
                min(param.max,
                    param.value - ((param.max - param.min) / SEND_STEPS)))

    def on_sendb_up_changed(self, value):
        if value > 0:
            param = self.song().view.selected_track.mixer_device.sends[1]
            param.value = max(
                param.min,
                min(param.max,
                    param.value + ((param.max - param.min) / SEND_STEPS)))

    def on_sendb_down_changed(self, value):
        if value > 0:
            param = self.song().view.selected_track.mixer_device.sends[1]
            param.value = max(
                param.min,
                min(param.max,
                    param.value - ((param.max - param.min) / SEND_STEPS)))

    def on_pan_up_changed(self, value):
        if value > 0:
            param = self.song().view.selected_track.mixer_device.panning
            param.value = max(
                param.min,
                min(param.max,
                    param.value + ((param.max - param.min) / PAN_STEPS)))

    def on_pan_down_changed(self, value):
        if value > 0:
            param = self.song().view.selected_track.mixer_device.panning
            param.value = max(
                param.min,
                min(param.max,
                    param.value - ((param.max - param.min) / PAN_STEPS)))

    def on_volume_up_changed(self, value):
        if value > 0:
            param = self.song().view.selected_track.mixer_device.volume
            param.value = max(
                param.min,
                min(param.max,
                    param.value + ((param.max - param.min) / VOLUME_STEPS)))

    def on_volume_down_changed(self, value):
        if value > 0:
            param = self.song().view.selected_track.mixer_device.volume
            param.value = max(
                param.min,
                min(param.max,
                    param.value - ((param.max - param.min) / VOLUME_STEPS)))

    def on_mixer_track_nav(self, value):
        move = -1 if value > 64 else +1
        # get tracks-info
        tracks = self.song().tracks
        return_tracks = self.song().return_tracks
        master_track = self.song().master_track
        all_tracks = list(chain(tracks, return_tracks))
        all_tracks.append(master_track)
        num_tracks = len(tracks)
        num_return_tracks = len(return_tracks)
        num_master_track = 1
        num_all_tracks = num_tracks + num_return_tracks + num_master_track
        # update selected-track
        index = index_if(lambda t: t == self.song().view.selected_track,
                         all_tracks)
        index += move
        index = min(max(index, 0), num_all_tracks - 1)
        self.song().view.selected_track = all_tracks[index]

    def setup_session(self):
        num_tracks = 7
        num_scenes = 1
        track_offset = 0
        scene_offset = 0
        # elements
        self.clip_launch_buttons = ButtonMatrixElement(rows=[[
            ButtonElement(True, MIDI_NOTE_TYPE, 0, 76 + i)
            for i in range(num_tracks)
        ]])
        self.clip_stop_buttons = [
            ButtonElement(True, MIDI_NOTE_TYPE, 0, 68 + i)
            for i in range(num_tracks)
        ]
        self.scene_launch_buttons = ButtonMatrixElement(rows=[[
            ButtonElement(True, MIDI_NOTE_TYPE, 0, 83 + i)
            for i in range(num_scenes)
        ]])
        self.scene_stop_button = ButtonElement(True, MIDI_NOTE_TYPE, 0, 75)
        self.session_scene_nav_encoder = EncoderElement(
            MIDI_CC_TYPE, 0, 15, Live.MidiMap.MapMode.relative_binary_offset)
        # session
        self.session = SessionComponent(num_tracks, num_scenes)
        self.session.set_offsets(track_offset, scene_offset)
        self.session.add_offset_listener(self.on_session_offset_changed)
        self.set_highlighting_session_component(self.session)
        # clips
        self.session.set_clip_launch_buttons(self.clip_launch_buttons)
        self.session.set_stop_track_clip_buttons(self.clip_stop_buttons)
        self.session.set_scene_launch_buttons(self.scene_launch_buttons)
        self.session.set_stop_all_clips_button(self.scene_stop_button)
        # nav
        self.session_scene_nav_encoder.add_value_listener(
            self.on_session_scene_nav)

    def on_session_offset_changed(self):
        pass

    def on_session_scene_nav(self, value):
        value -= 64
        value = -value
        track_offset = self.session.track_offset()
        scene_offset = max(0, self.session.scene_offset() + value)
        self.session.set_offsets(track_offset, scene_offset)

    def disconnect(self):
        u"""Live -> Script
        Called right before we get disconnected from Live.
        """
        self.log_message('disconnect')
        self.show_message('disconnect')
class StackControlSurface(ControlSurface):
    __doc__ = "Script for Stack"

    _active_instances = []
    def _combine_active_instances():
        track_offset = 0
        scene_offset = 0
        for instance in StackControlSurface._active_instances:
            instance._activate_combination_mode(track_offset, scene_offset)
            track_offset += instance._session.width()
    _combine_active_instances = staticmethod(_combine_active_instances)


    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        #self.set_suppress_rebuild_requests(True)
        with self.component_guard():
            self._note_map = []
            self._ctrl_map = []
            self._load_MIDI_map()
            self._mixer = None
            self._setup_mixer_control()
            self._session = None
            self._setup_session_control()
            self._session.set_mixer(self._mixer)
            self.set_highlighting_session_component(self._session)
            #self.set_suppress_rebuild_requests(False)
        self._do_combine()


    def disconnect(self):
        self._note_map = None
        self._ctrl_map = None
        self._do_uncombine()
        self._session = None
        self._mixer = None
        ControlSurface.disconnect(self)


    def _do_combine(self):
        if self not in StackControlSurface._active_instances:
            StackControlSurface._active_instances.append(self)
            StackControlSurface._combine_active_instances()


    def _do_uncombine(self):
        if ((self in StackControlSurface._active_instances) and StackControlSurface._active_instances.remove(self)):
            StackControlSurface._session.unlink()
            StackControlSurface._combine_active_instances()


    def _activate_combination_mode(self, track_offset, scene_offset):
        if TRACK_OFFSET != -1:
            track_offset = TRACK_OFFSET
        if SCENE_OFFSET != -1:
            scene_offset = SCENE_OFFSET
        self._session.link_with_track_offset(track_offset, scene_offset)


    def _setup_session_control(self):
        is_momentary = True
        self._session = StackSessionComponent(self, 1, 8)
        self._session.name = 'Session_Control'
        self._session.set_select_buttons(self._ctrl_map[SCENEDN], self._ctrl_map[SCENEUP])
        self._session.selected_scene().name = 'Selected_Scene'
        self._session.set_slot_launch_button(self._ctrl_map[SELCLIPLAUNCH])
        self._session.set_slot_gen_button(self._ctrl_map[SELCLIPGEN])
        for scene_index in range(8):
            for track_index in range(8):
                button = self._note_map[CLIPNOTEMAP[scene_index][track_index]]
                self._session.set_pad_button(button)


    def _setup_mixer_control(self):
        is_momentary = True
        self._mixer = MixerComponent(8)
        self._mixer.name = 'Mixer'
        self._mixer.selected_strip().name = 'Selected_Channel_Strip'
        self._mixer.set_select_buttons(self._ctrl_map[TRACKRIGHT], self._ctrl_map[TRACKLEFT])


    def _load_MIDI_map(self):
        is_momentary = True
        for note in range(128):
            button = ButtonElement(is_momentary, MIDI_NOTE_TYPE, BUTTONCHANNEL, note)
            button.name = 'Note_' + str(note)
            self._note_map.append(button)
        self._note_map.append(None) #add None to the end of the list, selectable with [-1]

        for cc in range(128):
            button = ButtonElement(is_momentary, MIDI_CC_TYPE, BUTTONCHANNEL, cc)
            button.name = 'Ctrl_' + str(cc)
            self._ctrl_map.append(button)
        self._ctrl_map.append(None) #add None to the end of the list, selectable with [-1]
        '''

        for ctrl in range(128):
            control = SliderElement(MIDI_CC_TYPE, SLIDERCHANNEL, ctrl)
            control.name = 'Ctrl_' + str(ctrl)
            self._ctrl_map.append(control)
        self._ctrl_map.append(None)
        '''

    #SysEx Functions TO DO: replace them with functions from framework
    def snapshot(self):
        for i in range(1, 5):
            self.fill_screen(rnd=True)
            time.sleep(1/60)
        self.clear_screen()


    def fill_screen(self, char=29, rnd=False):
        for offset in range(0, 136):
            for row in range(0, 4):
                if rnd:
                    char = random.randint(33, 96)
                self._send_midi(SYSEX_START + (24+row, 0, 2, offset, char) + SYSEX_END)


    def print_text(self, text, row=0, offset=0):
        int_letters = tuple([ord(i) for i in list(text)])
        self._send_midi(SYSEX_START + (24+row, offset, len(text)+1, 0) + int_letters + SYSEX_END)


    def clear_screen(self):
        for row in range(0, 4):
            self._send_midi(SYSEX_START + (28 + row, 0, 0) + SYSEX_END)


    def set_pad(self, column, row, color):
        if color == "white":
            PAD_COLOR = (0, 127, 127, 127, 127, 127, 127)
        if color == "red":
            PAD_COLOR = (0, 127, 127, 0, 0, 0, 0)
        self._send_midi(SYSEX_START + (4, 0, 8, column + row*8) + PAD_COLOR + SYSEX_END)