Esempio n. 1
0
    def _setup_mixer_control(self):
        num_tracks = GRIDSIZE[0] # Here we define the mixer width in tracks (a mixer has only one dimension)
        global mixer # We want to instantiate the global mixer as a MixerComponent object (it was a global "None" type up until now...)
        mixer = MixerComponent(num_tracks) #(num_tracks, num_returns, with_eqs, with_filters)
        mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left)
        """set up the mixer buttons"""
        self.song().view.selected_track = mixer.channel_strip(0)._track
        master = mixer.master_strip()
        master.set_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL_USER, MASTER_VOLUME))
        mixer.set_prehear_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL_USER, PREHEAR))

        for index in xrange(GRIDSIZE[0]):
            mixer.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL_MIXER, MIX_FADERS[index]))
            # mixer.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL_INST, MIX_FADERS[index]))
            mixer.channel_strip(index).set_pan_control(SliderElement(MIDI_CC_TYPE, CHANNEL_MIXER, PAN_CONTROLS[index]))
            mixer.channel_strip(index).set_arm_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL_INST, ARM_BUTTONS[index])) #sets the record arm button
            mixer.channel_strip(index).set_solo_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL_INST, SOLO_BUTTONS[index]))
            mixer.channel_strip(index).set_mute_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL_INST, MUTE_BUTTONS[index]))
            mixer.channel_strip(index).set_select_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL_INST, TRACK_SELECTS[index]))
            mixer.channel_strip(index).set_send_controls([SliderElement(MIDI_CC_TYPE, CHANNEL_MIXER, SEND_CONTROLS[index][0]),
                                                              SliderElement(MIDI_CC_TYPE, CHANNEL_MIXER, SEND_CONTROLS[index][1]),
                                                              SliderElement(MIDI_CC_TYPE, CHANNEL_MIXER, SEND_CONTROLS[index][2]),
                                                              SliderElement(MIDI_CC_TYPE, CHANNEL_MIXER, SEND_CONTROLS[index][3])])




        """TRANSPORT CONTROLS"""
        stop_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL_MIXER, STOP_BUTTON)
        play_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL_MIXER, PLAY_BUTTON)
        record_button = ButtonElement(False,MIDI_CC_TYPE,CHANNEL_MIXER,RECORD_BUTTON)
        overdub_button = ButtonElement(False,MIDI_CC_TYPE,CHANNEL_MIXER,OVERDUB_BUTTON)
        transport = TransportComponent()
        transport.TEMPO_TOP = 188
        transport.set_stop_button(stop_button)
        transport.set_play_button(play_button)
        transport.set_overdub_button(overdub_button)
        transport.set_record_button(record_button)
        transport.set_seek_buttons(ButtonElement(False,MIDI_CC_TYPE,0,SEEK_LEFT),ButtonElement(False,MIDI_CC_TYPE,0,SEEK_RIGHT))
        transport.set_tempo_control(SliderElement(MIDI_CC_TYPE, CHANNEL_USER, TEMPO))
        transport.set_metronome_button(ButtonElement(False,MIDI_CC_TYPE,CHANNEL_USER, METRONOME))
        transport.set_tap_tempo_button(ButtonElement(False,MIDI_CC_TYPE,CHANNEL_USER,TAP_TEMPO))
Esempio n. 2
0
 def _setup_transport_control(self):
     is_momentary = True  # We'll only be using momentary buttons here
     transport = TransportComponent()  #Instantiate a Transport Component
     return
     """set up the buttons"""
     transport.set_play_button(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 61)
     )  #ButtonElement(is_momentary, msg_type, channel, identifier) Note that the MIDI_NOTE_TYPE constant is defined in the InputControlElement module
     transport.set_stop_button(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 63))
     transport.set_record_button(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 66))
     transport.set_overdub_button(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 68))
     transport.set_nudge_buttons(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 75),
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                       73))  #(up_button, down_button)
     transport.set_tap_tempo_button(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 78))
     transport.set_metronome_button(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 80)
     )  #For some reason, in Ver 7.x.x this method's name has no trailing "e" , and must be called as "set_metronom_button()"...
     transport.set_loop_button(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 82))
     transport.set_punch_buttons(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 85),
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                       87))  #(in_button, out_button)
     transport.set_seek_buttons(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 90),
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                       92))  # (ffwd_button, rwd_button)
     """set up the sliders"""
     transport.set_tempo_control(
         SliderElement(MIDI_CC_TYPE, CHANNEL, 26),
         SliderElement(MIDI_CC_TYPE, CHANNEL, 25))  #(control, fine_control)
     transport.set_song_position_control(
         SliderElement(MIDI_CC_TYPE, CHANNEL, 24))
Esempio n. 3
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")
Esempio n. 4
0
class OhmModesHH(ControlSurface):
	__module__ = __name__
	__doc__ = " OhmModes controller script, custom script for Herbie Hancock by amounra "


	def __init__(self, c_instance):
		ControlSurface.__init__(self, c_instance)
		with self.component_guard():
			self.log_message(time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) + "--------------= OhmModesHH2 log opened =--------------") # Writes message into Live's main log file. This is a ControlSurface method.
			#self.set_suppress_rebuild_requests(True) # Turn off rebuild MIDI map until after we're done setting up
			self.revision = 'HH'
			self.flash_status = 1
			self._backlight = 127
			self._backlight_type = 'static'
			self._ohm = 127
			self._ohm_type = 'static'
			self._pad_translations = PAD_TRANSLATION
			self._rgb = 1
			self._keys_octave = 5
			self._keys_scale = 0
			self._tempo_buttons = None
			self._scene_indexes = [[[0,0],  [8, 0], [16, 0], [24, 0], [32, 0],  [40, 0]], 
									[[0,0],  [8, 0], [16, 0], [24, 0], [32, 0],  [40, 0]], 
									[[0,0],  [8, 0], [16, 0], [24, 0], [32, 0],  [40, 0]], 
									[[0,0],  [8, 0], [16, 0], [24, 0], [32, 0],  [40, 0]], 
									[[0,0],  [8, 0], [16, 0], [24, 0], [32, 0],  [40, 0]]]
			self._scene_bank = 0
			self._bank_is_on = False
			self._setup_monobridge()
			self._setup_controls()
			self._setup_transport_control() # Run the transport setup part of the script
			self._setup_mixer_control() # Setup the mixer object
			self._setup_session_control()  # Setup the session object 
			self._setup_device_control() # Setup the device object
			self._setup_crossfader()
			self._setup_looper()
			#self._setup_scene_selector()
			#self._setup_modes() 
			self._assign_page_constants()
			self.assign_page_0()
			self._setup_hilight_knobs()
			self._last_device = None
			self._timer = 0
			#self.set_suppress_rebuild_requests(False) #Turn rebuild back on, now that we're done setting up
			self.song().view.add_selected_track_listener(self._update_selected_device)
			self._on_selected_scene_changed()
			self.show_message('OhmModes Control Surface Loaded')
			self._send_midi(tuple(switchxfader))
			#self.schedule_message(10, self.query_ohm, None)
			#self.song().view.selected_scene = self.song().scenes[0]
			self._assign_session_colors()
		
	def query_ohm(self):
		#self.log_message('querying Ohm')
		self._send_midi(tuple(check_model))

	

	def _setup_monobridge(self):
		self._monobridge = MonoBridgeElement(self)
		self._monobridge.name = 'MonoBridge'
	



	def update_display(self):
		ControlSurface.update_display(self)
		self._timer = (self._timer + 1) % 256
		self.flash()

	def get_device_bank(self):
		return self._device._bank_index
	

	def _setup_controls(self):
		is_momentary = True
		self._fader = [None for index in range(8)]
		self._dial = [None for index in range(16)]
		self._button = [None for index in range(8)]
		self._menu = [None for index in range(6)]
		for index in range(8):
			self._fader[index] = EncoderElement(MIDI_CC_TYPE, CHANNEL, OHM_FADERS[index], Live.MidiMap.MapMode.absolute)
			self._fader[index].name = 'Fader_' + str(index), self
		for index in range(8):
			self._button[index] = MonoButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, OHM_BUTTONS[index], 'Button_' + str(index), self)
		for index in range(16):
			self._dial[index] = EncoderElement(MIDI_CC_TYPE, CHANNEL, OHM_DIALS[index], Live.MidiMap.MapMode.absolute)
			self._dial[index].name = 'Dial_' + str(index)
		for index in range(6):
			self._menu[index] = MonoButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, OHM_MENU[index], 'Menu_' + str(index), self)	
		self._crossfader = EncoderElement(MIDI_CC_TYPE, CHANNEL, CROSSFADER, Live.MidiMap.MapMode.absolute)
		self._crossfader.name = "Crossfader"
		self._livid = MonoButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, LIVID, 'Livid_Button', self)
		self._shift_l = MonoButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, SHIFT_L, 'Page_Button_Left', self)
		self._shift_r = MonoButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, SHIFT_R, 'Page_Button_Right', self)
		self._matrix = ButtonMatrixElement()
		self._matrix.name = 'Matrix'
		self._grid = [None for index in range(8)]
		for column in range(8):
			self._grid[column] = [None for index in range(8)]
			for row in range(8):
				self._grid[column][row] = MonoButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, (column * 8) + row, 'Grid_' + str(column) + '_' + str(row), self)
		for row in range(6):
			button_row = []
			for column in range(7):
				button_row.append(self._grid[column][row])
			self._matrix.add_row(tuple(button_row)) 
	
		
	def _setup_modes(self):
		self._shift_mode = ShiftModeComponent(self) 
		self._shift_mode.name = 'Shift_Mode'
		#self._shift_mode.set_mode_toggle(self._shift_l, self._shift_r)
		#self._select_mode = ModeSelectorComponent(self)
		#self._select_mode.name = 'Select_Mode'
		#self._select_mode.set_mode_toggle(self._menu[5])
		#self._select_mode.update = self.select_mode_update(self._select_mode)
		#self._menu[5].add_value_listener(self._select_mode)
		#self._scale_mode = ScaleModeComponent(self)
		#self._scale_mode.name = "Scale_Mode"
		#self._octave_mode = OctaveModeComponent(self)
		#self._octave_mode.name = "Octave_Mode"
	

			
		
	

	def select_mode_update(self, mode_selector):
		def update():
			if mode_selector._mode_index>0:
				pass
		return update
		
	

	def _setup_looper(self):
		self._looper = [None for index in range(2)]
		for index in range(2):
			self._looper[index] = LooperListenerComponent(self, index + 1)
			self._looper[index].assign_buttons(self._button[index*4], self._button[(index*4)+1], self._button[(index*4)+2], self._button[(index*4)+3])
	

	def _setup_transport_control(self):
		self._transport = TransportComponent() 
		self._transport.name = 'Transport'

	def _setup_mixer_control(self):
		is_momentary = True
		self._num_tracks = (7) #A mixer is one-dimensional; 
		global mixer
		mixer = SpecialMixerComponent(7, 0, True, False)
		mixer.name = 'Mixer'
		self._mixer = mixer
		mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left)
		for index in range(7):
			mixer.channel_strip(index).set_volume_control(self._fader[index])
		for index in range(7):
			mixer.channel_strip(index).name = 'Mixer_ChannelStrip_' + str(index)
			mixer.track_eq(index).name = 'Mixer_EQ_' + str(index)
			mixer.channel_strip(index)._invert_mute_feedback = True
		self.song().view.selected_track = mixer.channel_strip(0)._track #set the selected strip to the first track, so that we don't, for example, try to assign a button to arm the master track, which would cause an assertion error


	def _setup_session_control(self):
		is_momentary = True
		num_tracks = 7
		num_scenes = 7  ###changed from 5 for HH 
		global session
		session = SessionComponent(num_tracks, num_scenes)
		session.name = "Session"
		session.set_offsets(0, 0)
		self._session = session		 
		self._scene = [None for index in range(num_scenes)]
		for row in range(num_scenes):
			self._scene[row] = session.scene(row)
			self._scene[row].name = 'Scene_' + str(row)
			for column in range(num_tracks):
				clip_slot = self._scene[row].clip_slot(column)
				clip_slot.name = str(column) + '_Clip_Slot_' + str(row)		
		session.set_mixer(mixer)
		self._session_zoom = SessionZoomingComponent(session)	 
		self._session_zoom.name = 'Session_Overview'
		#self._session_zoom.set_enabled(False)
		self.set_highlighting_session_component(self._session)

		
	def _assign_session_colors(self):
		num_tracks = 7
		num_scenes = 7 
		self._session.set_stop_clip_value(STOP_CLIP_COLOR[self._rgb])
		for row in range(num_scenes): 
			for column in range(num_tracks):
				self._scene[row].clip_slot(column).set_triggered_to_play_value(CLIP_TRIGD_TO_PLAY_COLOR[self._rgb])
				self._scene[row].clip_slot(column).set_triggered_to_record_value(CLIP_TRIGD_TO_RECORD_COLOR[self._rgb])
				self._scene[row].clip_slot(column).set_stopped_value(CLIP_STOPPED_COLOR[self._rgb])
				self._scene[row].clip_slot(column).set_started_value(CLIP_STARTED_COLOR[self._rgb])
				self._scene[row].clip_slot(column).set_recording_value(CLIP_RECORDING_COLOR[self._rgb])		
		self._session_zoom.set_stopped_value(ZOOM_STOPPED_COLOR[self._rgb])
		self._session_zoom.set_playing_value(ZOOM_PLAYING_COLOR[self._rgb])
		self._session_zoom.set_selected_value(ZOOM_SELECTED_COLOR[self._rgb])
		

	def _setup_device_control(self):
		self._device = DeviceComponent()
		self._device.name = 'Device_Component'
		self.set_device_component(self._device)
		self._device_navigator = DetailViewControllerComponent()
		self._device_navigator.name = 'Device_Navigator'
		self._device_selection_follows_track_selection = FOLLOW
		
	def device_follows_track(self, val):
		self._device_selection_follows_track_selection = (val == 1)
		return self
		
	def _setup_crossfader(self):
		self._mixer.set_crossfader_control(self._crossfader)
	

	def _setup_scene_selector(self):
		for index in range(5):
			self._menu[index].add_value_listener(self._select_new_scene, True)
	

	def set_bank(self, val):
		self._scene_bank = int(val)
		self._monobridge._send('bank', self._scene_bank)
		self._display_bank()
	

	def _select_mode(self, value):
		self.log_message('select mode update' + str(value))
		self._bank_is_on = value!=0
		if self._bank_is_on is True:
			self._display_bank()
		else:
			self._on_selected_scene_changed()
	

	def _select_new_scene(self, value, sender):
		if self._bank_is_on is False:
			if value > 0:
				new_scene = int(self._scene_indexes[self._scene_bank][self._menu.index(sender)][0])
				new_track = int(self._scene_indexes[self._scene_bank][self._menu.index(sender)][1])
				self.log_message('select new scene ' + str(new_scene) + ' and track ' + str(new_track))
				all_scenes = self.song().scenes
				all_tracks = self.song().tracks
				if (new_scene < len(all_scenes)) and (new_track < len(all_tracks)):
					self.song().view.selected_scene = all_scenes[(new_scene)]
					self.song().view.selected_track = all_tracks[(new_track)]
					self._session.set_offsets(self._scene_indexes[self._scene_bank][self._menu.index(sender)][1], self._scene_indexes[self._scene_bank][self._menu.index(sender)][0])
		else:
			if value > 0:
				self._scene_bank = int(self._menu.index(sender))
				self._monobridge._send('bank', self._scene_bank)
				self._display_bank()
	

	def _display_bank(self):
		if(self._bank_is_on):
			for index in range(5):
				if index == self._scene_bank:
					self._menu[index].send_value(11)
				else:
					self._menu[index].send_value(0)
	



	def _on_selected_scene_changed(self):
		ControlSurface._on_selected_scene_changed(self)
		#self.log_message('scene offset: ' + str(self._session._scene_offset))
		for index in range(6):
			if self._session._scene_offset == self._scene_indexes[self._scene_bank][index][0]:  ## and self._session._scene_offset < self._scene_indexes[index + 1]:
				self._menu[index].turn_on()
			else:
				self._menu[index].turn_off()
		#if self._session._scene_offset >= self._scene_indexes[5]:
		#	self._menu[5].turn_on
		#else:
		#	self._menu[5].turn_off
			
	
	def _setup_hilight_knobs(self):
		self._dial[15].add_value_listener(self._knob_set_scene, True)
		self._dial[14].add_value_listener(self._knob_set_track, True)
	

	def _knob_set_scene(self, value, sender):
		all_scenes = self.song().scenes
		num_scenes = len(all_scenes)
		new_scene = float(value/127.0) * float(num_scenes - 1)
		self.song().view.selected_scene = all_scenes[int(new_scene)]
		self._session.set_offsets(self._session._track_offset, int(new_scene))
	

	def _knob_set_track(self, value, sender):
		#self.log_message(str(value))
		all_tracks = self.song().visible_tracks  #self.song().tracks
		num_tracks = len(self.song().visible_tracks)
		new_track = float(value/127.0) * float(num_tracks - 1)
		#self.log_message(str(int(new_track)))
		#self.log_message(str(value) + str(float(value/127.0)))
		self.song().view.selected_track = all_tracks[int(new_track)]
		self._session.set_offsets(int(new_track), self._session._scene_offset)
	

	def disconnect(self):
		"""clean things up on disconnect"""
		for index in range(5):
			if self._menu[index].value_has_listener(self._select_new_scene):
				self._menu[index].remove_value_listener(self._select_new_scene)
		if self._menu[5].value_has_listener(self._select_mode):
			self._menu[5].remove_value_listener(self._select_mode)
		if self._dial[15].value_has_listener(self._knob_set_scene):
			self._dial[15].remove_value_listener(self._knob_set_scene)
		if self._dial[15].value_has_listener(self._knob_set_scene):		
			self._dial[15].remove_value_listener(self._knob_set_scene)
		self.song().view.remove_selected_track_listener(self._update_selected_device)
		ControlSurface.disconnect(self)
		self.log_message(time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) + "--------------= OhmModes log closed =--------------") #Create entry in log file
		return None

	def _get_num_tracks(self):
		return self.num_tracks

	def flash(self):
		#if(self.flash_status > 0):
		for index in range(6):
			if(self._menu[index]._flash_state>0):
				self._menu[index].flash(self._timer)
		for row in range(8):
			if(self._button[row]._flash_state > 0):
				self._button[row].flash(self._timer)
			for column in range(8):
				button = self._grid[column][row]
				if(button._flash_state > 0):
					button.flash(self._timer)


	def strobe(self):
		if(self._backlight_type != 'static'):
			if(self._backlight_type is 'pulse'):
				self._backlight = int(math.fabs(((self._timer * 16) % 64) -32) +32)
			if(self._backlight_type is 'up'):
				self._backlight = int(((self._timer * 8) % 64) + 16)
			if(self._backlight_type is 'down'):
				self._backlight = int(math.fabs(int(((self._timer * 8) % 64) - 64)) + 16)
		self._send_midi(tuple([176, 27, int(self._backlight)]))
		if(self._ohm_type != 'static'):
			if(self._ohm_type is 'pulse'):
				self._ohm = int(math.fabs(((self._timer * 16) % 64) -32) +32)
			if(self._ohm_type is 'up'):
				self._ohm = int(((self._timer * 8) % 64) + 16)
			if(self._ohm_type is 'down'):
				self._ohm = int(math.fabs(int(((self._timer * 8) % 64) - 64)) + 16)
		self._send_midi(tuple([176, 63, int(self._ohm)]))
		self._send_midi(tuple([176, 31, int(self._ohm)]))	

	def deassign_matrix(self):
		#self._scale_mode.set_mode_buttons(None)
		#self._scale_mode.set_enabled(False)
		#self._octave_mode.set_mode_buttons(None)
		#self._octave_mode.set_enabled(False)
		#self._session_zoom.set_button_matrix(None)
		#if self._dial[15].has_value_listener(self._knob_set_scene):
		#	self._dial[15].remove_value_listener(self._knob_set_scene)
		#if self._dial[14].has_value_listener(self._knob_set_track):
		#	self._dial[14].remove_value_listener(self._knob_set_track)
		self._session_zoom.set_enabled(False)
		self._session_zoom.set_nav_buttons(None, None, None, None)
		self._session.set_track_bank_buttons(None, None)
		self._session.set_scene_bank_buttons(None, None)
		for column in range(7):
			self._mixer.channel_strip(column).set_crossfade_toggle(None)
			self._mixer.channel_strip(column).set_mute_button(None)
			self._mixer.channel_strip(column).set_solo_button(None)
			self._mixer.channel_strip(column).set_arm_button(None)
			self._mixer.channel_strip(column).set_send_controls(None)
			self._mixer.channel_strip(column).set_pan_control(None)
			self._mixer.track_eq(column).set_enabled(False)
			for row in range(7):
				self._scene[row].clip_slot(column).set_launch_button(None)
		for column in range(8):
			#self._button[column]._on_value = SELECT_COLOR[self._rgb]
			for row in range(8):
				self._grid[column][row].set_channel(0)
				self._grid[column][row].release_parameter()
				self._grid[column][row].use_default_message()
				self._grid[column][row].set_enabled(True)
				self._grid[column][row].send_value(0, True)
				self._grid[column][row]._on_value = 127
				self._grid[column][row]._off_value = 0
		#for index in range(8):
		#	self._button[index].set_channel(0)
		#	self._button[index].use_default_message()
		#	self._button[index].set_enabled(True)
		#	self._button[index].reset()
		#for index in range(6):
		#	self._menu[index]._on_value = 127
		#	self._menu[index]._off_value = 0
		#	self._menu[index].reset()
		#for index in range(16):
		#	self._dial[index].use_default_message()
		#	self._dial[index].release_parameter()
			#self._dial[index].set_enabled(True)
		if(self._device._parameter_controls != None):
			for control in self._device._parameter_controls:
				control.release_parameter()
			self._device._parameter_controls = None
		self._device_navigator.set_enabled(False)
		self._mixer.update()
		self._matrix.reset()

		"""HH Specific"""
		#self._mixer.master_strip().set_select_button(None)
		#for column in range(7):
		#	self._mixer.channel_strip(column).set_select_button(None)
		self._session_zoom.set_zoom_button(None)
		self._transport.set_play_button(None)
		self._transport.set_stop_button(None)
		self._device_navigator.set_device_nav_buttons(None, None)
		
		#for index in range(2):
		#	self._looper[index].find_looper()
		
	def _assign_page_constants(self):
		#self._session_zoom.set_zoom_button(self._button[7]) #commented out pn 070111
		#self._session_zoom.set_zoom_button(self._grid[7][7]) #added pn 070111
		#self._session_zoom.set_button_matrix(self._matrix)
		#self._session_zoom.set_enabled(True)
		#for column in range(7):
			#self._mixer.channel_strip(column).set_select_button(self._button[column])
		#	self._mixer.channel_strip(column).set_volume_control(self._fader[column])
		#self._mixer.master_strip().set_volume_control(self._fader[7])
		#for column in range(8):
		#	self._button[column]._on_value = SELECT_COLOR[self._rgb]
		#self._mixer.master_strip().set_select_button(self._button[7]) #added pn 070111
		#self._mixer.set_prehear_volume_control(self._dial[15])
		#self._transport.set_play_button(self._menu[0])
		#self._menu[0].send_value(PLAY_COLOR[self._rgb], True)	
		#self._menu[0]._on_value = PLAY_COLOR[self._rgb]
		#self._transport.set_stop_button(self._menu[1])
		#self._menu[1]._off_value = STOP_COLOR[self._rgb]
		#self._menu[1]._on_value = STOP_COLOR[self._rgb]
		#self._menu[1].send_value(STOP_COLOR[self._rgb], True)	
		self._livid._on_value = TAP_COLOR[self._rgb]
		self._transport.set_tap_tempo_button(self._livid)
		#self._livid.send_value(TAP_COLOR, True)
		#self._device_navigator.set_device_nav_buttons(self._menu[3], self._menu[4])
		for index in range(2):
			self._menu[index + 4]._on_value = SESSION_NAV[self._rgb]
			self._menu[index * 3]._on_value = SESSION_NAV[self._rgb]
		self._session.set_track_bank_buttons(self._menu[5], self._menu[4])
		self._session.set_scene_bank_buttons(self._menu[3], self._menu[0])


	def assign_page_0(self):
		self._backlight_type = 'static'
		#self._session_zoom.set_button_matrix(self._matrix)
		self._session_zoom.set_enabled(True)
		for column in range(7):
			#self._grid[column][5]._on_value = MUTE_COLOR[self._rgb]
			#self._mixer.channel_strip(column).set_mute_button(self._grid[column][5])
			#self._grid[column][6]._on_value = SOLO_COLOR[self._rgb]
			#self._mixer.channel_strip(column).set_solo_button(self._grid[column][6])
			#self._grid[column][7]._on_value = ARM_COLOR[self._rgb]
			#self._mixer.channel_strip(column).set_arm_button(self._grid[column][7])
			#self._mixer.channel_strip(column).set_pan_control(self._dial[column + 8])
			for row in range(7):
				self._scene[row].clip_slot(column).set_launch_button(self._grid[column][row])
		#for column in range(4):
		#	self._mixer.channel_strip(column).set_send_controls(tuple([self._dial[column], self._dial[column + 4]]))
		track_stop_buttons = []
		for index in range(7):
			self._grid[7][index]._off_value = SCENE_LAUNCH_COLOR[self._rgb]
			self._scene[index].set_launch_button(self._grid[7][index])
			self._grid[index][7]._on_value = TRACK_STOP[self._rgb]
			self._grid[index][7]._off_value = TRACK_STOP[self._rgb]
			track_stop_buttons.append(self._grid[index][7])
		self._session.set_stop_track_clip_buttons(tuple(track_stop_buttons))
		self._session.set_stop_all_clips_button(self._grid[7][7])
		#for index in range(4):
		#	self._menu[2 + index]._on_value = NAV_BUTTON_COLOR[self._rgb]
		#self._session.set_track_bank_buttons(self._menu[4], self._menu[3])
		#self._session.set_scene_bank_buttons(self._menu[5], self._menu[2])
		#for index in range(6):
		#	self._menu[index]._on_value = HHMENU[index][1]
		#	self._menu[index]._off_value = HHMENU[index][0]
		for index in range(8):
			self._button[index].set_channel(2)
			self._button[index].set_identifier(index)
			#self._button[index].reset()
			self._button[index].set_enabled(False)
		self.request_rebuild_midi_map()
		for index in range(7):
			self._grid[index][7].turn_on()
		for index in range(2):
			self._looper[index]._state_change()
			self._button[1 + (index * 4)].send_value(3)
			self._button[2 + (index * 4)].send_value(6)
			self._button[3 + (index * 4)].send_value(1)

	def assign_page_1(self):
		self._backlight_type = 'pulse'
		self._session_zoom.set_enabled(False)
		for column in range(4):
			for row in range(4):
				self._grid[column][row].set_channel(PAGE1_DRUM_CHANNEL)
				self._grid[column][row].set_identifier(PAGE1_DRUM_MAP[column][row])
				self._grid[column][row].send_value(DRUM_COLOR[self._rgb], True)
				self._grid[column][row].set_enabled(False)
				self._grid[column + 4][row].set_channel(PAGE1_BASS_CHANNEL)
				self._grid[column + 4][row].set_identifier(PAGE1_BASS_MAP[column][row])
				self._grid[column + 4][row].send_value(BASS_COLOR[self._rgb], True)
				self._grid[column + 4][row].set_enabled(False)
		scale_mode_buttons = []
		for column in range(8):
			for row in range(3):
				self._grid[column][row + 4].set_enabled(False)
				self._grid[column][row + 4].set_channel(PAGE1_KEYS_CHANNEL)
				self._grid[column][row + 4].set_identifier(int(PAGE1_KEYS_MAP[column][row]) + int(PAGE1_MODES_MAP[self._scale_mode._mode_index][column]) + int(self._octave_mode._mode_index * 12))
				self._grid[column][row + 4].send_value(KEYS_COLOR[self._rgb], True)
			for row in range(1):
				scale_mode_buttons.append(self._grid[column][7])
		self._scale_mode.set_mode_buttons(tuple(scale_mode_buttons))
		self._scale_mode.set_enabled(True)
		#self._octave_mode.set_mode_buttons(tuple([self._menu[5], self._menu[2]]))
		#self._octave_mode.set_enabled(True)
		for column in range(7):
			self._mixer.channel_strip(column).set_send_controls(tuple([self._dial[column + 8]]))
			#self._button[column].set_on_off_values(REC_ARM, 0)
			#self._mixer.channel_strip(column).set_arm_button(self._button[column])
		self._device.set_enabled(True)
		device_param_controls = []
		for index in range(8):
			device_param_controls.append(self._dial[index])
		self._device.set_parameter_controls(tuple(device_param_controls))
		#for index in range(4):
		#	self._menu[2 + index]._on_value = (DEVICE_NAV_COLOR[self._rgb])
		#self._device_navigator.set_enabled(True)

		"""HH Specific from Constants"""
		#self._mixer.master_strip().set_select_button(self._button[7])
		#for column in range(7):
		#	self._button[column].set_on_off_values(REC_ARM, 0)
		#self._session_zoom.set_zoom_button(self._grid[7][7])
		#self._transport.set_play_button(self._menu[0])
		#self._menu[0].send_value(PLAY_COLOR[self._rgb], True)	
		#self._menu[0]._on_value = PLAY_COLOR[self._rgb]
		#self._transport.set_stop_button(self._menu[1])
		#self._menu[1]._off_value = STOP_COLOR[self._rgb]
		#self._menu[1]._on_value = STOP_COLOR[self._rgb]
		#self._menu[1].send_value(STOP_COLOR[self._rgb], True)
		#self._device_navigator.set_device_nav_buttons(self._menu[3], self._menu[4])
		for index in range(8):
			self._button[index].set_channel(2)
			self._button[index].set_identifier(index)
			#self._button[index].reset()
			self._button[index].set_enabled(False)
		self.request_rebuild_midi_map()
		#for index in range(8):
		#	self._grid[index][7].send(self.
		for index in range(2):
			self._looper[index]._state_change()
			self._button[1 + (index * 4)].send_value(3)
			self._button[2 + (index * 4)].send_value(6)
			self._button[3 + (index * 4)].send_value(1)
	
	def assign_page_2(self):
		self._backlight_type = 'up'
		#self._session_zoom.set_button_matrix(self._matrix)
		self._session_zoom.set_enabled(False)
		for column in range(7):
			self._grid[column][5]._on_value = MUTE_COLOR[self._rgb]
			self._mixer.channel_strip(column).set_mute_button(self._grid[column][5])
			self._grid[column][6]._on_value = CROSSFADE_ASSIGN_COLOR[self._rgb]
			self._mixer.channel_strip(column).set_crossfade_toggle(self._grid[column][6])
			self._grid[column][7].set_channel(2)
			self._grid[column][7].set_identifier(column)
			self._grid[column][7].reset()
			self._grid[column][7].set_enabled(False)
			self._grid[column][7].send_value(4, True)
			for row in range(5):
				self._scene[row].clip_slot(column).set_launch_button(self._grid[column][row])
		for row in range(5):
			self._grid[7][row]._off_value = SCENE_LAUNCH_COLOR[self._rgb]
			self._scene[row].set_launch_button(self._grid[7][row])
		for column in range(4):
			self._mixer.track_eq(column).set_gain_controls(tuple([self._dial[column + 8], self._dial[column + 4], self._dial[column]]))
			self._mixer.track_eq(column).set_enabled(True)	
		for column in range(3):
			self._mixer.channel_strip(column+4).set_pan_control(self._dial[column + 12])
		#for index in range(4):
		#	self._menu[2 + index]._on_value = NAV_BUTTON_COLOR[self._rgb]
		#self._session.set_track_bank_buttons(self._menu[4], self._menu[3])
		#self._session.set_scene_bank_buttons(self._menu[5], self._menu[2])
		self._set_tempo_buttons([self._grid[7][5], self._grid[7][6]])
		
		"""HH Specific from Constants"""
		#self._mixer.master_strip().set_select_button(self._button[7])
		#for column in range(7):
		#	self._mixer.channel_strip(column).set_select_button(self._button[column])
		#for index in range(8):
		#	self._button[index].set_on_off_values(SELECT_COLOR[self._rgb], 0)
		self._session_zoom.set_zoom_button(self._grid[7][7])
		#self._transport.set_play_button(self._menu[0])
		#self._menu[0].send_value(PLAY_COLOR[self._rgb], True)	
		#self._menu[0]._on_value = PLAY_COLOR[self._rgb]
		#self._transport.set_stop_button(self._menu[1])
		#self._menu[1]._off_value = STOP_COLOR[self._rgb]
		#self._menu[1]._on_value = STOP_COLOR[self._rgb]
		#self._menu[1].send_value(STOP_COLOR[self._rgb], True)
		#self._device_navigator.set_device_nav_buttons(self._menu[3], self._menu[4])
		for index in range(8):
			self._button[index].set_channel(2)
			self._button[index].set_identifier(index)
			#self._button[index].reset()
			self._button[index].set_enabled(False)
		self.request_rebuild_midi_map()
		for index in range(2):
			self._looper[index]._state_change()
			self._button[1 + (index * 4)].send_value(3)
			self._button[2 + (index * 4)].send_value(6)
			self._button[3 + (index * 4)].send_value(1)
		
	
	def _update_selected_device(self):
		if self._device_selection_follows_track_selection is True:
			track = self.song().view.selected_track
			device_to_select = track.view.selected_device
			if device_to_select == None and len(track.devices) > 0:
				device_to_select = track.devices[0]
			if device_to_select != None:
				self.song().view.select_device(device_to_select)
			#self._device.set_device(device_to_select)
			self.set_appointed_device(device_to_select)
			#self._device_selector.set_enabled(True)
			self.request_rebuild_midi_map()
		return None
	
	def handle_sysex(self, midi_bytes):
		#self.log_message(str('>>sysexIN') + str(midi_bytes))
		if len(midi_bytes) > 10:
			#self.log_message(str('>>sysex>10') + str(midi_bytes[:11]))
			if midi_bytes[:11] == tuple([240, 126, 0, 6, 2, 0, 1, 97, 1, 0, 7]):
				self.log_message(str('>>>color detected'))
				self._rgb = 1
			elif midi_bytes[:11] == tuple([240, 126, 0, 6, 2, 0, 1, 97, 1, 0, 2]):
				self.log_message(str('>>>mono detected'))
				self._rgb = 0
		self._assign_session_colors()
		#self._shift_mode.update()
		self.deassign_matrix()
		self._assign_page_constants()
		self.assign_page_0()
		#self._setup_hilight_knobs()
		for index in range(8):
			self._grid[7][index].send_value(SCENE_LAUNCH_COLOR[self._rgb])
		for index in range(7):
			self._grid[index][7].turn_on()

# 	def handle_sysex(self, midi_bytes):
# 		#assert(isinstance (midi_bytes, tuple))
# 		##self.log_message(str('sysex') + str(midi_bytes))
# 		if midi_bytes == tuple([240, 126, 0, 6, 2, 0, 1, 97, 1, 0, 7, 0, 15, 10, 0, 0, 247]):
# 			self.log_message(str('color detected'))
# 			self._rgb = 1
# 		elif midi_bytes == tuple([240, 126, 0, 6, 2, 0, 1, 97, 1, 0, 2, 0, 0, 1, 1, 0, 247]):
# 			self.log_message(str('mono detected'))
# 			self._rgb = 0
# 		self._assign_session_colors()

	def receive_midi(self, midi_bytes):
		""" Live -> Script
		MIDI messages are only received through this function, when explicitly 
		forwarded in 'build_midi_map'.
	"""
		assert (midi_bytes != None)
		assert isinstance(midi_bytes, tuple)
		##self.log_message('got message' + str(midi_bytes))
		#self.set_suppress_rebuild_requests(True)
		with self.component_guard():
			if (len(midi_bytes) is 3):
				msg_type = (midi_bytes[0] & 240)
				forwarding_key = [midi_bytes[0]]
				if (msg_type is not MIDI_PB_TYPE):
					forwarding_key.append(midi_bytes[1])
				if (tuple(forwarding_key) in self._forwarding_registry.keys()):
					recipient = self._forwarding_registry[tuple(forwarding_key)]
					if (recipient != None):
						recipient.receive_value(midi_bytes[2])
				else:
					self.log_message(('Got unknown message: ' + str(midi_bytes)))
			else:
				self.handle_sysex(midi_bytes)
		#self.set_suppress_rebuild_requests(False)		 

	def _set_tempo_buttons(self, buttons):
		if self._tempo_buttons != None:
			self._tempo_buttons[0].remove_value_listener(self._tempo_value)
			self._tempo_buttons[1].remove_value_listener(self._tempo_value)
		self._tempo_buttons = buttons
		if buttons != None:
			for button in buttons:
				assert isinstance(button, FlashingButtonElement)
			self._tempo_buttons[0].set_on_off_values(4, 0)
			self._tempo_buttons[0].add_value_listener(self._tempo_value, True)
			self._tempo_buttons[1].set_on_off_values(4, 0)
			self._tempo_buttons[1].add_value_listener(self._tempo_value, True)
			self._tempo_buttons[0].turn_on()
			self._tempo_buttons[1].turn_on()

	def _tempo_value(self, value, sender):
		if (value > 0) and (self._tempo_buttons.index(sender) == 0):
			self.song().tempo = round(min((self.song().tempo + 1), 999))
		elif (value > 0) and (self._tempo_buttons.index(sender) == 1):
			self.song().tempo = round(max((self.song().tempo - 1), 20))
			
		

	def set_scene_index_value(self, bank_index, scene, track):
		bank = int(bank_index)/5
		index = int(bank_index)%5
		self.log_message('set_scene_index_value' + str(bank) + str(index) + str(scene) + str(track))
		#self.log_message( str(type(index)) + str(type(scene)) + str(type(track)))
		self._scene_indexes[bank][index][0] = scene
		self._scene_indexes[bank][index][1] = track
		#self._on_selected_scene_changed()
	

	def connect_script_instances(self, instanciated_scripts):
		#link = False
		#offsets = [0, 0]
		#new_channel = CHAN
		for s in instanciated_scripts:
			if isinstance(s, APC) or s is self:
				#link = True
				if not s._session._is_linked():
					s._session._link()
					#self.log_message('found other linked instance')
					#offsets[0] += (int(self._link_offset[0]) * 8)
					#offsets[1] += (int(self._link_offset[1]) * 4)
					#new_channel += 1
		#if link and not self._session._is_linked():
			#self._session.set_offsets(offsets[0], offsets[1])
			#self._session._link()
		#self._set_code_channels(new_channel)
	
	
#
#
Esempio n. 5
0
class ProjectX(ControlSurface):
    __module__ = __name__
    __doc__ = " ProjectX keyboard controller script "

    def __init__(self, c_instance):
        """everything except the '_on_selected_track_changed' override and 'disconnect' runs from here"""
        ControlSurface.__init__(self, c_instance)

        self.log_message(
            time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) +
            "--------------= ProjectX log opened =--------------")

        with self.component_guard():
            self._create_transport_control()
            self._create_mixer_control()
            self._create_session_control()

        self.request_rebuild_midi_map()
        self.log_message("Captain's last log stardate ****")

    def _create_transport_control(self):
        is_momentary = True

        self._transport = TransportComponent(is_enabled=True, name='Transport')
        """set up the buttons"""
        self._transport.set_play_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 61))
        self._transport.set_stop_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 63))
        self._transport.set_record_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 66))
        self._transport.set_overdub_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 68))
        self._transport.set_nudge_buttons(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 75),
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 73))
        self._transport.set_tap_tempo_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 78))
        self._transport.set_metronome_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 80))
        self._transport.set_loop_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 82))
        self._transport.set_punch_buttons(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 85),
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 87))
        self._transport.set_seek_buttons(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 90),
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 92))
        """set up the sliders"""
        self._transport.set_tempo_control(
            SliderElement(MIDI_CC_TYPE, CHANNEL, 26),
            SliderElement(MIDI_CC_TYPE, CHANNEL, 25))
        self._transport.set_song_position_control(
            SliderElement(MIDI_CC_TYPE, CHANNEL, 24))

        self.log_message("Captain's log stardate 1")

    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")

    def _create_session_control(self):
        is_momentary = True
        num_tracks = 1
        num_scenes = 7
        global session
        session = SessionComponent(num_tracks, num_scenes)
        session.set_offsets(0, 0)
        """set up the session navigation buttons"""
        session.set_select_buttons(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 25),
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 27))
        session.set_scene_bank_buttons(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 51),
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 49))
        session.set_stop_all_clips_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 70))
        session.selected_scene().set_launch_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 30))
        """Here we set up the scene launch assignments for the session"""
        launch_notes = [60, 62, 64, 65, 67, 69, 71]
        for index in range(num_scenes):
            session.scene(index).set_launch_button(
                ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                              launch_notes[index]))
        """Here we set up the track stop launch assignment(s) for the session"""
        stop_track_buttons = []
        for index in range(num_tracks):
            stop_track_buttons.append(
                ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                              58 + index))
        session.set_stop_track_clip_buttons(tuple(stop_track_buttons))
        """Here we set up the clip launch assignments for the session"""
        clip_launch_notes = [48, 50, 52, 53, 55, 57, 59]
        for index in range(num_scenes):
            session.scene(index).clip_slot(0).set_launch_button(
                ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                              clip_launch_notes[index]))
        """Here we set up a mixer and channel strip(s) which move with the session"""

        self.log_message("Captain's log stardate 3")

    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)
        """here we set the mixer and session to the selected track, when the selected track changes"""
        selected_track = self.song().view.selected_track
        mixer.channel_strip(0).set_track(selected_track)
        all_tracks = ((self.song().tracks + self.song().return_tracks) +
                      (self.song().master_track, ))
        index = list(all_tracks).index(selected_track)
        session.set_offsets(index, session._scene_offset)

    def disconnect(self):
        """clean things up on disconnect"""
        self.log_message(
            time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) +
            "--------------= ProjectX log closed =--------------")
        ControlSurface.disconnect(self)
        return None
class VoidMaschine(ControlSurface):
  """
  Originally Created on Nov 7, 2010  :: Matt Howell
  Thanks to Hanz Petrov, Native Instruments, Ableton, Liine
  """
  

      
  def __init__(self, c_instance):
    """
    Constructor
    """
    ControlSurface.__init__(self, c_instance)
    self.name = 'VoidMaschine'
    self.log_message(self.name + " opened =-- @ "+ time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()))
    self.set_suppress_rebuild_requests(True)
    self._suppress_session_highlight = False
    self._suppress_send_midi = True
    self._suggested_input_port = MASCHINE_DEVICE_PORT_NAME
    self._suggested_output_port = MASCHINE_DEVICE_PORT_NAME
    self._shift_button = None
    self.transport = TransportComponent()
    self.transport.name = 'Transport'
    self.session = None
    self.session_zoom = None
    self.mixer = None
    self.back_to_arranger_button = None
    self.is_momentary = True
    self.bpmBeatTime = 0
    self.lastBeat = 0
    
    self._setup_transport_control()
    self._session = VoidSessionComponent(c_instance)
    self._session.name = 'Session_Control'
    
    self._setup_mixer_control()
    
    #self._session_zoom = SessionZoomingComponent(self._session)
    #self._session_zoom.name = 'Session_Overview'
    #self._session_zoom.set_button_matrix(self._session._matrix)
    
    self._set_back_to_arranger_button(ButtonElement(True, MIDI_NOTE_TYPE, TRANSPORT_CHANNEL, TRANSPORT_BACK_TO_ARRANGER))
    self.set_suppress_rebuild_requests(False)
    self._display = PhysicalDisplayElement(56, 8)
    self._void_message()
    self._register_timer_callback(self.update_controller)
    self._register_timer_callback(self.updateTempo)
    self._register_timer_callback(self.onTempoChange)
    
  def _void_message(self):
    self.sendScreenSysex(self.translateString((SYSEX_SCREEN_BUFFER_15 + 'VoidMaschine' + SYSEX_SCREEN_BUFFER_15)), 1)
    self.sendScreenSysex(self.translateString(('Voidrunner.com' + SYSEX_SCREEN_BUFFER_15 + '    maschine/ableton')), 2)

  def _setup_mixer_control(self):
    self.mixer = MixerComponent(0, 0, with_eqs=False, with_filters=False)
    master_volume_control = EncoderElement(MIDI_CC_TYPE, MIXER_CHANNEL, MASTER_VOLUME, Live.MidiMap.MapMode.absolute)
    booth_volume_control = EncoderElement(MIDI_CC_TYPE, MIXER_CHANNEL, MASTER_BOOTH, Live.MidiMap.MapMode.absolute)
    self.mixer.set_prehear_volume_control(booth_volume_control)
    self.mixer.master_strip().set_volume_control(master_volume_control)

  def _setup_transport_control(self):
    play_button = ButtonElement(self.is_momentary, MIDI_NOTE_TYPE, TRANSPORT_CHANNEL, TRANSPORT_PLAY)
    stop_button = ButtonElement(self.is_momentary, MIDI_NOTE_TYPE, TRANSPORT_CHANNEL, TRANSPORT_STOP)
    record_button = ButtonElement(self.is_momentary, MIDI_NOTE_TYPE, TRANSPORT_CHANNEL, TRANSPORT_RECORD)
    seek_ffwd_button = ButtonElement(self.is_momentary, MIDI_NOTE_TYPE, TRANSPORT_CHANNEL, TRANSPORT_SEEK_FFWD)
    seek_rwd_button = ButtonElement(self.is_momentary, MIDI_NOTE_TYPE, TRANSPORT_CHANNEL, TRANSPORT_SEEK_RWD)
    tap_tempo_button = ButtonElement(self.is_momentary, MIDI_NOTE_TYPE, TRANSPORT_CHANNEL, TRANSPORT_TAP_TEMPO)
    tempo_control = EncoderElement(MIDI_CC_TYPE, TRANSPORT_CHANNEL, TRANSPORT_COARSE_TEMPO, Live.MidiMap.MapMode.absolute)
    play_button.name = 'Play_Button'
    stop_button.name = 'Stop_Button'
    record_button.name = 'Record_Button'
    seek_ffwd_button.name = 'Seek_FFWD_Button'
    seek_rwd_button.name = 'Seek_RWD_Button'
    tap_tempo_button.name = 'Tap_Tempo_Button'
    self.transport.set_play_button(play_button)
    self.transport.set_stop_button(stop_button)
    self.transport.set_record_button(record_button)
    self.transport.set_tap_tempo_button(tap_tempo_button)
    self.transport.set_tempo_control(tempo_control)
    self.transport.set_seek_buttons(seek_ffwd_button, seek_rwd_button)

  def _set_back_to_arranger_button(self, button):
    button.add_value_listener(self.back_to_arranger)
    self.back_to_arranger_button = button

  def disconnect(self):
    self.send_midi((240, 0, 66, 89, 69, 247)) #goodbye message in sysex stream
  
  def send_midi(self, midi_event_bytes):
    """
    Use this function to send MIDI events through Live to the _real_ MIDI devices
    that this script is assigned to.
    """
    assert isinstance(midi_event_bytes, tuple)
    self._send_midi(midi_event_bytes)
    return True

  def translateString(self, text):
    """
    Convert a string into a sysex safe string
    """
    result = ()
    length = len(text)
    for i in range(0, length):
      charCode = ord(text[i])
      if (charCode < 32):
        charCode = 32
      elif (charCode > 127):
        charCode = 127
      result = (result + (charCode,))
    
    return result
  
  def sendScreenSysex(self, data, line=1):
    """
    Data must be a tuple of bytes, remember only 7-bit data is allowed for sysex
    """
    if not data:
      pass
    if(line==1):
        self._send_midi(((SYSEX_SCREEN_BEGIN_LINE_1 + data) + SYSEX_SCREEN_END))
    else:
        if(line==2):
            self._send_midi(((SYSEX_SCREEN_BEGIN_LINE_2 + data) + SYSEX_SCREEN_END))
  
  def send_value(self, msg_type, channel, id, value, force_send = False):
    assert (value != None)
    assert isinstance(value, int)
    assert (value in range(128))
    
    data_byte1 = id
    data_byte2 = value
    status_byte = channel
    if (msg_type == MIDI_NOTE_TYPE):
      status_byte += MIDI_NOTE_ON_STATUS
    elif (msg_type == MIDI_CC_TYPE):
      status_byte += MIDI_CC_STATUS
    else:
        assert False
    self._send_midi((status_byte, data_byte1, data_byte2))
  
  def back_to_arranger(self, *args, **kwargs):
    self.song().back_to_arranger = False
  
  def update_controller(self):
    """
    controller event loop
    this may also update every 100 miliseconds.
    decoupling the data updates from live and the controller communication
    may help keep latency to a minimum.
    """
    
  def onTempoChange(self):      
    self.bpmBeatTime = self.song().get_current_beats_song_time()
  
  def updateTempo(self):                          
    if self.song().is_playing:
      if (self.bpmBeatTime.beats > self.lastBeat):
        self.updateBPMLightOff()
      else:
        self.updateBPMLightOn()
  
  def updateBPMLightOn(self):  
    self.transport._play_button.turn_on()
    #self.send_value(MIDI_NOTE_TYPE, TRANSPORT_CHANNEL, TRANSPORT_TEMPO, MASCHINE_DISPLAY_BPM)

  def updateBPMLightOff(self): 
    self.transport._play_button.turn_off()
    #self.send_value(MIDI_NOTE_TYPE, TRANSPORT_CHANNEL, TRANSPORT_TEMPO, 0)
    
Esempio n. 7
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")
Esempio n. 8
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
Esempio n. 9
0
class OhmModesHH(ControlSurface):
    __module__ = __name__
    __doc__ = " OhmModes controller script, custom script for Herbie Hancock by amounra "

    def __init__(self, c_instance):
        ControlSurface.__init__(self, c_instance)
        with self.component_guard():
            self.log_message(
                time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) +
                "--------------= OhmModesHH2 log opened =--------------"
            )  # Writes message into Live's main log file. This is a ControlSurface method.
            #self.set_suppress_rebuild_requests(True) # Turn off rebuild MIDI map until after we're done setting up
            self.revision = 'HH'
            self.flash_status = 1
            self._backlight = 127
            self._backlight_type = 'static'
            self._ohm = 127
            self._ohm_type = 'static'
            self._pad_translations = PAD_TRANSLATION
            self._rgb = 1
            self._keys_octave = 5
            self._keys_scale = 0
            self._tempo_buttons = None
            self._scene_indexes = [[[0, 0], [8, 0], [16, 0], [24, 0], [32, 0],
                                    [40, 0]],
                                   [[0, 0], [8, 0], [16, 0], [24, 0], [32, 0],
                                    [40, 0]],
                                   [[0, 0], [8, 0], [16, 0], [24, 0], [32, 0],
                                    [40, 0]],
                                   [[0, 0], [8, 0], [16, 0], [24, 0], [32, 0],
                                    [40, 0]],
                                   [[0, 0], [8, 0], [16, 0], [24, 0], [32, 0],
                                    [40, 0]]]
            self._scene_bank = 0
            self._bank_is_on = False
            self._setup_monobridge()
            self._setup_controls()
            self._setup_transport_control(
            )  # Run the transport setup part of the script
            self._setup_mixer_control()  # Setup the mixer object
            self._setup_session_control()  # Setup the session object
            self._setup_device_control()  # Setup the device object
            self._setup_crossfader()
            self._setup_looper()
            #self._setup_scene_selector()
            #self._setup_modes()
            self._assign_page_constants()
            self.assign_page_0()
            self._setup_hilight_knobs()
            self._last_device = None
            self._timer = 0
            #self.set_suppress_rebuild_requests(False) #Turn rebuild back on, now that we're done setting up
            self.song().view.add_selected_track_listener(
                self._update_selected_device)
            self._on_selected_scene_changed()
            self.show_message('OhmModes Control Surface Loaded')
            self._send_midi(tuple(switchxfader))
            #self.schedule_message(10, self.query_ohm, None)
            #self.song().view.selected_scene = self.song().scenes[0]
            self._assign_session_colors()

    def query_ohm(self):
        #self.log_message('querying Ohm')
        self._send_midi(tuple(check_model))

    def _setup_monobridge(self):
        self._monobridge = MonoBridgeElement(self)
        self._monobridge.name = 'MonoBridge'

    def update_display(self):
        ControlSurface.update_display(self)
        self._timer = (self._timer + 1) % 256
        self.flash()

    def get_device_bank(self):
        return self._device._bank_index

    def _setup_controls(self):
        is_momentary = True
        self._fader = [None for index in range(8)]
        self._dial = [None for index in range(16)]
        self._button = [None for index in range(8)]
        self._menu = [None for index in range(6)]
        for index in range(8):
            self._fader[index] = EncoderElement(MIDI_CC_TYPE, CHANNEL,
                                                OHM_FADERS[index],
                                                Live.MidiMap.MapMode.absolute)
            self._fader[index].name = 'Fader_' + str(index), self
        for index in range(8):
            self._button[index] = MonoButtonElement(is_momentary,
                                                    MIDI_NOTE_TYPE, CHANNEL,
                                                    OHM_BUTTONS[index],
                                                    'Button_' + str(index),
                                                    self)
        for index in range(16):
            self._dial[index] = EncoderElement(MIDI_CC_TYPE, CHANNEL,
                                               OHM_DIALS[index],
                                               Live.MidiMap.MapMode.absolute)
            self._dial[index].name = 'Dial_' + str(index)
        for index in range(6):
            self._menu[index] = MonoButtonElement(is_momentary, MIDI_NOTE_TYPE,
                                                  CHANNEL, OHM_MENU[index],
                                                  'Menu_' + str(index), self)
        self._crossfader = EncoderElement(MIDI_CC_TYPE, CHANNEL, CROSSFADER,
                                          Live.MidiMap.MapMode.absolute)
        self._crossfader.name = "Crossfader"
        self._livid = MonoButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                                        LIVID, 'Livid_Button', self)
        self._shift_l = MonoButtonElement(is_momentary, MIDI_NOTE_TYPE,
                                          CHANNEL, SHIFT_L, 'Page_Button_Left',
                                          self)
        self._shift_r = MonoButtonElement(is_momentary, MIDI_NOTE_TYPE,
                                          CHANNEL, SHIFT_R,
                                          'Page_Button_Right', self)
        self._matrix = ButtonMatrixElement()
        self._matrix.name = 'Matrix'
        self._grid = [None for index in range(8)]
        for column in range(8):
            self._grid[column] = [None for index in range(8)]
            for row in range(8):
                self._grid[column][row] = MonoButtonElement(
                    is_momentary, MIDI_NOTE_TYPE, CHANNEL, (column * 8) + row,
                    'Grid_' + str(column) + '_' + str(row), self)
        for row in range(6):
            button_row = []
            for column in range(7):
                button_row.append(self._grid[column][row])
            self._matrix.add_row(tuple(button_row))

    def _setup_modes(self):
        self._shift_mode = ShiftModeComponent(self)
        self._shift_mode.name = 'Shift_Mode'
        #self._shift_mode.set_mode_toggle(self._shift_l, self._shift_r)
        #self._select_mode = ModeSelectorComponent(self)
        #self._select_mode.name = 'Select_Mode'
        #self._select_mode.set_mode_toggle(self._menu[5])
        #self._select_mode.update = self.select_mode_update(self._select_mode)
        #self._menu[5].add_value_listener(self._select_mode)
        #self._scale_mode = ScaleModeComponent(self)
        #self._scale_mode.name = "Scale_Mode"
        #self._octave_mode = OctaveModeComponent(self)
        #self._octave_mode.name = "Octave_Mode"

    def select_mode_update(self, mode_selector):
        def update():
            if mode_selector._mode_index > 0:
                pass

        return update

    def _setup_looper(self):
        self._looper = [None for index in range(2)]
        for index in range(2):
            self._looper[index] = LooperListenerComponent(self, index + 1)
            self._looper[index].assign_buttons(self._button[index * 4],
                                               self._button[(index * 4) + 1],
                                               self._button[(index * 4) + 2],
                                               self._button[(index * 4) + 3])

    def _setup_transport_control(self):
        self._transport = TransportComponent()
        self._transport.name = 'Transport'

    def _setup_mixer_control(self):
        is_momentary = True
        self._num_tracks = (7)  #A mixer is one-dimensional;
        global mixer
        mixer = SpecialMixerComponent(7, 0, True, False)
        mixer.name = 'Mixer'
        self._mixer = mixer
        mixer.set_track_offset(
            0)  #Sets start point for mixer strip (offset from left)
        for index in range(7):
            mixer.channel_strip(index).set_volume_control(self._fader[index])
        for index in range(7):
            mixer.channel_strip(
                index).name = 'Mixer_ChannelStrip_' + str(index)
            mixer.track_eq(index).name = 'Mixer_EQ_' + str(index)
            mixer.channel_strip(index)._invert_mute_feedback = True
        self.song().view.selected_track = mixer.channel_strip(
            0
        )._track  #set the selected strip to the first track, so that we don't, for example, try to assign a button to arm the master track, which would cause an assertion error

    def _setup_session_control(self):
        is_momentary = True
        num_tracks = 7
        num_scenes = 7  ###changed from 5 for HH
        global session
        session = SessionComponent(num_tracks, num_scenes)
        session.name = "Session"
        session.set_offsets(0, 0)
        self._session = session
        self._scene = [None for index in range(num_scenes)]
        for row in range(num_scenes):
            self._scene[row] = session.scene(row)
            self._scene[row].name = 'Scene_' + str(row)
            for column in range(num_tracks):
                clip_slot = self._scene[row].clip_slot(column)
                clip_slot.name = str(column) + '_Clip_Slot_' + str(row)
        session.set_mixer(mixer)
        self._session_zoom = SessionZoomingComponent(session)
        self._session_zoom.name = 'Session_Overview'
        #self._session_zoom.set_enabled(False)
        self.set_highlighting_session_component(self._session)

    def _assign_session_colors(self):
        num_tracks = 7
        num_scenes = 7
        self._session.set_stop_clip_value(STOP_CLIP_COLOR[self._rgb])
        for row in range(num_scenes):
            for column in range(num_tracks):
                self._scene[row].clip_slot(column).set_triggered_to_play_value(
                    CLIP_TRIGD_TO_PLAY_COLOR[self._rgb])
                self._scene[row].clip_slot(
                    column).set_triggered_to_record_value(
                        CLIP_TRIGD_TO_RECORD_COLOR[self._rgb])
                self._scene[row].clip_slot(column).set_stopped_value(
                    CLIP_STOPPED_COLOR[self._rgb])
                self._scene[row].clip_slot(column).set_started_value(
                    CLIP_STARTED_COLOR[self._rgb])
                self._scene[row].clip_slot(column).set_recording_value(
                    CLIP_RECORDING_COLOR[self._rgb])
        self._session_zoom.set_stopped_value(ZOOM_STOPPED_COLOR[self._rgb])
        self._session_zoom.set_playing_value(ZOOM_PLAYING_COLOR[self._rgb])
        self._session_zoom.set_selected_value(ZOOM_SELECTED_COLOR[self._rgb])

    def _setup_device_control(self):
        self._device = DeviceComponent()
        self._device.name = 'Device_Component'
        self.set_device_component(self._device)
        self._device_navigator = DetailViewControllerComponent()
        self._device_navigator.name = 'Device_Navigator'
        self._device_selection_follows_track_selection = FOLLOW

    def device_follows_track(self, val):
        self._device_selection_follows_track_selection = (val == 1)
        return self

    def _setup_crossfader(self):
        self._mixer.set_crossfader_control(self._crossfader)

    def _setup_scene_selector(self):
        for index in range(5):
            self._menu[index].add_value_listener(self._select_new_scene, True)

    def set_bank(self, val):
        self._scene_bank = int(val)
        self._monobridge._send('bank', self._scene_bank)
        self._display_bank()

    def _select_mode(self, value):
        self.log_message('select mode update' + str(value))
        self._bank_is_on = value != 0
        if self._bank_is_on is True:
            self._display_bank()
        else:
            self._on_selected_scene_changed()

    def _select_new_scene(self, value, sender):
        if self._bank_is_on is False:
            if value > 0:
                new_scene = int(self._scene_indexes[self._scene_bank][
                    self._menu.index(sender)][0])
                new_track = int(self._scene_indexes[self._scene_bank][
                    self._menu.index(sender)][1])
                self.log_message('select new scene ' + str(new_scene) +
                                 ' and track ' + str(new_track))
                all_scenes = self.song().scenes
                all_tracks = self.song().tracks
                if (new_scene < len(all_scenes)) and (new_track <
                                                      len(all_tracks)):
                    self.song().view.selected_scene = all_scenes[(new_scene)]
                    self.song().view.selected_track = all_tracks[(new_track)]
                    self._session.set_offsets(
                        self._scene_indexes[self._scene_bank][self._menu.index(
                            sender)][1], self._scene_indexes[self._scene_bank][
                                self._menu.index(sender)][0])
        else:
            if value > 0:
                self._scene_bank = int(self._menu.index(sender))
                self._monobridge._send('bank', self._scene_bank)
                self._display_bank()

    def _display_bank(self):
        if (self._bank_is_on):
            for index in range(5):
                if index == self._scene_bank:
                    self._menu[index].send_value(11)
                else:
                    self._menu[index].send_value(0)

    def _on_selected_scene_changed(self):
        ControlSurface._on_selected_scene_changed(self)
        #self.log_message('scene offset: ' + str(self._session._scene_offset))
        for index in range(6):
            if self._session._scene_offset == self._scene_indexes[
                    self._scene_bank][index][
                        0]:  ## and self._session._scene_offset < self._scene_indexes[index + 1]:
                self._menu[index].turn_on()
            else:
                self._menu[index].turn_off()
        #if self._session._scene_offset >= self._scene_indexes[5]:
        #	self._menu[5].turn_on
        #else:
        #	self._menu[5].turn_off

    def _setup_hilight_knobs(self):
        self._dial[15].add_value_listener(self._knob_set_scene, True)
        self._dial[14].add_value_listener(self._knob_set_track, True)

    def _knob_set_scene(self, value, sender):
        all_scenes = self.song().scenes
        num_scenes = len(all_scenes)
        new_scene = float(value / 127.0) * float(num_scenes - 1)
        self.song().view.selected_scene = all_scenes[int(new_scene)]
        self._session.set_offsets(self._session._track_offset, int(new_scene))

    def _knob_set_track(self, value, sender):
        #self.log_message(str(value))
        all_tracks = self.song().visible_tracks  #self.song().tracks
        num_tracks = len(self.song().visible_tracks)
        new_track = float(value / 127.0) * float(num_tracks - 1)
        #self.log_message(str(int(new_track)))
        #self.log_message(str(value) + str(float(value/127.0)))
        self.song().view.selected_track = all_tracks[int(new_track)]
        self._session.set_offsets(int(new_track), self._session._scene_offset)

    def disconnect(self):
        """clean things up on disconnect"""
        for index in range(5):
            if self._menu[index].value_has_listener(self._select_new_scene):
                self._menu[index].remove_value_listener(self._select_new_scene)
        if self._menu[5].value_has_listener(self._select_mode):
            self._menu[5].remove_value_listener(self._select_mode)
        if self._dial[15].value_has_listener(self._knob_set_scene):
            self._dial[15].remove_value_listener(self._knob_set_scene)
        if self._dial[15].value_has_listener(self._knob_set_scene):
            self._dial[15].remove_value_listener(self._knob_set_scene)
        self.song().view.remove_selected_track_listener(
            self._update_selected_device)
        ControlSurface.disconnect(self)
        self.log_message(
            time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) +
            "--------------= OhmModes log closed =--------------"
        )  #Create entry in log file
        return None

    def _get_num_tracks(self):
        return self.num_tracks

    def flash(self):
        #if(self.flash_status > 0):
        for index in range(6):
            if (self._menu[index]._flash_state > 0):
                self._menu[index].flash(self._timer)
        for row in range(8):
            if (self._button[row]._flash_state > 0):
                self._button[row].flash(self._timer)
            for column in range(8):
                button = self._grid[column][row]
                if (button._flash_state > 0):
                    button.flash(self._timer)

    def strobe(self):
        if (self._backlight_type != 'static'):
            if (self._backlight_type is 'pulse'):
                self._backlight = int(
                    math.fabs(((self._timer * 16) % 64) - 32) + 32)
            if (self._backlight_type is 'up'):
                self._backlight = int(((self._timer * 8) % 64) + 16)
            if (self._backlight_type is 'down'):
                self._backlight = int(
                    math.fabs(int(((self._timer * 8) % 64) - 64)) + 16)
        self._send_midi(tuple([176, 27, int(self._backlight)]))
        if (self._ohm_type != 'static'):
            if (self._ohm_type is 'pulse'):
                self._ohm = int(math.fabs(((self._timer * 16) % 64) - 32) + 32)
            if (self._ohm_type is 'up'):
                self._ohm = int(((self._timer * 8) % 64) + 16)
            if (self._ohm_type is 'down'):
                self._ohm = int(
                    math.fabs(int(((self._timer * 8) % 64) - 64)) + 16)
        self._send_midi(tuple([176, 63, int(self._ohm)]))
        self._send_midi(tuple([176, 31, int(self._ohm)]))

    def deassign_matrix(self):
        #self._scale_mode.set_mode_buttons(None)
        #self._scale_mode.set_enabled(False)
        #self._octave_mode.set_mode_buttons(None)
        #self._octave_mode.set_enabled(False)
        #self._session_zoom.set_button_matrix(None)
        #if self._dial[15].has_value_listener(self._knob_set_scene):
        #	self._dial[15].remove_value_listener(self._knob_set_scene)
        #if self._dial[14].has_value_listener(self._knob_set_track):
        #	self._dial[14].remove_value_listener(self._knob_set_track)
        self._session_zoom.set_enabled(False)
        self._session_zoom.set_nav_buttons(None, None, None, None)
        self._session.set_track_bank_buttons(None, None)
        self._session.set_scene_bank_buttons(None, None)
        for column in range(7):
            self._mixer.channel_strip(column).set_crossfade_toggle(None)
            self._mixer.channel_strip(column).set_mute_button(None)
            self._mixer.channel_strip(column).set_solo_button(None)
            self._mixer.channel_strip(column).set_arm_button(None)
            self._mixer.channel_strip(column).set_send_controls(None)
            self._mixer.channel_strip(column).set_pan_control(None)
            self._mixer.track_eq(column).set_enabled(False)
            for row in range(7):
                self._scene[row].clip_slot(column).set_launch_button(None)
        for column in range(8):
            #self._button[column]._on_value = SELECT_COLOR[self._rgb]
            for row in range(8):
                self._grid[column][row].set_channel(0)
                self._grid[column][row].release_parameter()
                self._grid[column][row].use_default_message()
                self._grid[column][row].set_enabled(True)
                self._grid[column][row].send_value(0, True)
                self._grid[column][row]._on_value = 127
                self._grid[column][row]._off_value = 0
        #for index in range(8):
        #	self._button[index].set_channel(0)
        #	self._button[index].use_default_message()
        #	self._button[index].set_enabled(True)
        #	self._button[index].reset()
        #for index in range(6):
        #	self._menu[index]._on_value = 127
        #	self._menu[index]._off_value = 0
        #	self._menu[index].reset()
        #for index in range(16):
        #	self._dial[index].use_default_message()
        #	self._dial[index].release_parameter()
        #self._dial[index].set_enabled(True)
        if (self._device._parameter_controls != None):
            for control in self._device._parameter_controls:
                control.release_parameter()
            self._device._parameter_controls = None
        self._device_navigator.set_enabled(False)
        self._mixer.update()
        self._matrix.reset()
        """HH Specific"""
        #self._mixer.master_strip().set_select_button(None)
        #for column in range(7):
        #	self._mixer.channel_strip(column).set_select_button(None)
        self._session_zoom.set_zoom_button(None)
        self._transport.set_play_button(None)
        self._transport.set_stop_button(None)
        self._device_navigator.set_device_nav_buttons(None, None)

        #for index in range(2):
        #	self._looper[index].find_looper()

    def _assign_page_constants(self):
        #self._session_zoom.set_zoom_button(self._button[7]) #commented out pn 070111
        #self._session_zoom.set_zoom_button(self._grid[7][7]) #added pn 070111
        #self._session_zoom.set_button_matrix(self._matrix)
        #self._session_zoom.set_enabled(True)
        #for column in range(7):
        #self._mixer.channel_strip(column).set_select_button(self._button[column])
        #	self._mixer.channel_strip(column).set_volume_control(self._fader[column])
        #self._mixer.master_strip().set_volume_control(self._fader[7])
        #for column in range(8):
        #	self._button[column]._on_value = SELECT_COLOR[self._rgb]
        #self._mixer.master_strip().set_select_button(self._button[7]) #added pn 070111
        #self._mixer.set_prehear_volume_control(self._dial[15])
        #self._transport.set_play_button(self._menu[0])
        #self._menu[0].send_value(PLAY_COLOR[self._rgb], True)
        #self._menu[0]._on_value = PLAY_COLOR[self._rgb]
        #self._transport.set_stop_button(self._menu[1])
        #self._menu[1]._off_value = STOP_COLOR[self._rgb]
        #self._menu[1]._on_value = STOP_COLOR[self._rgb]
        #self._menu[1].send_value(STOP_COLOR[self._rgb], True)
        self._livid._on_value = TAP_COLOR[self._rgb]
        self._transport.set_tap_tempo_button(self._livid)
        #self._livid.send_value(TAP_COLOR, True)
        #self._device_navigator.set_device_nav_buttons(self._menu[3], self._menu[4])
        for index in range(2):
            self._menu[index + 4]._on_value = SESSION_NAV[self._rgb]
            self._menu[index * 3]._on_value = SESSION_NAV[self._rgb]
        self._session.set_track_bank_buttons(self._menu[5], self._menu[4])
        self._session.set_scene_bank_buttons(self._menu[3], self._menu[0])

    def assign_page_0(self):
        self._backlight_type = 'static'
        #self._session_zoom.set_button_matrix(self._matrix)
        self._session_zoom.set_enabled(True)
        for column in range(7):
            #self._grid[column][5]._on_value = MUTE_COLOR[self._rgb]
            #self._mixer.channel_strip(column).set_mute_button(self._grid[column][5])
            #self._grid[column][6]._on_value = SOLO_COLOR[self._rgb]
            #self._mixer.channel_strip(column).set_solo_button(self._grid[column][6])
            #self._grid[column][7]._on_value = ARM_COLOR[self._rgb]
            #self._mixer.channel_strip(column).set_arm_button(self._grid[column][7])
            #self._mixer.channel_strip(column).set_pan_control(self._dial[column + 8])
            for row in range(7):
                self._scene[row].clip_slot(column).set_launch_button(
                    self._grid[column][row])
        #for column in range(4):
        #	self._mixer.channel_strip(column).set_send_controls(tuple([self._dial[column], self._dial[column + 4]]))
        track_stop_buttons = []
        for index in range(7):
            self._grid[7][index]._off_value = SCENE_LAUNCH_COLOR[self._rgb]
            self._scene[index].set_launch_button(self._grid[7][index])
            self._grid[index][7]._on_value = TRACK_STOP[self._rgb]
            self._grid[index][7]._off_value = TRACK_STOP[self._rgb]
            track_stop_buttons.append(self._grid[index][7])
        self._session.set_stop_track_clip_buttons(tuple(track_stop_buttons))
        self._session.set_stop_all_clips_button(self._grid[7][7])
        #for index in range(4):
        #	self._menu[2 + index]._on_value = NAV_BUTTON_COLOR[self._rgb]
        #self._session.set_track_bank_buttons(self._menu[4], self._menu[3])
        #self._session.set_scene_bank_buttons(self._menu[5], self._menu[2])
        #for index in range(6):
        #	self._menu[index]._on_value = HHMENU[index][1]
        #	self._menu[index]._off_value = HHMENU[index][0]
        for index in range(8):
            self._button[index].set_channel(2)
            self._button[index].set_identifier(index)
            #self._button[index].reset()
            self._button[index].set_enabled(False)
        self.request_rebuild_midi_map()
        for index in range(7):
            self._grid[index][7].turn_on()
        for index in range(2):
            self._looper[index]._state_change()
            self._button[1 + (index * 4)].send_value(3)
            self._button[2 + (index * 4)].send_value(6)
            self._button[3 + (index * 4)].send_value(1)

    def assign_page_1(self):
        self._backlight_type = 'pulse'
        self._session_zoom.set_enabled(False)
        for column in range(4):
            for row in range(4):
                self._grid[column][row].set_channel(PAGE1_DRUM_CHANNEL)
                self._grid[column][row].set_identifier(
                    PAGE1_DRUM_MAP[column][row])
                self._grid[column][row].send_value(DRUM_COLOR[self._rgb], True)
                self._grid[column][row].set_enabled(False)
                self._grid[column + 4][row].set_channel(PAGE1_BASS_CHANNEL)
                self._grid[column + 4][row].set_identifier(
                    PAGE1_BASS_MAP[column][row])
                self._grid[column + 4][row].send_value(BASS_COLOR[self._rgb],
                                                       True)
                self._grid[column + 4][row].set_enabled(False)
        scale_mode_buttons = []
        for column in range(8):
            for row in range(3):
                self._grid[column][row + 4].set_enabled(False)
                self._grid[column][row + 4].set_channel(PAGE1_KEYS_CHANNEL)
                self._grid[column][row + 4].set_identifier(
                    int(PAGE1_KEYS_MAP[column][row]) + int(PAGE1_MODES_MAP[
                        self._scale_mode._mode_index][column]) +
                    int(self._octave_mode._mode_index * 12))
                self._grid[column][row + 4].send_value(KEYS_COLOR[self._rgb],
                                                       True)
            for row in range(1):
                scale_mode_buttons.append(self._grid[column][7])
        self._scale_mode.set_mode_buttons(tuple(scale_mode_buttons))
        self._scale_mode.set_enabled(True)
        #self._octave_mode.set_mode_buttons(tuple([self._menu[5], self._menu[2]]))
        #self._octave_mode.set_enabled(True)
        for column in range(7):
            self._mixer.channel_strip(column).set_send_controls(
                tuple([self._dial[column + 8]]))
            #self._button[column].set_on_off_values(REC_ARM, 0)
            #self._mixer.channel_strip(column).set_arm_button(self._button[column])
        self._device.set_enabled(True)
        device_param_controls = []
        for index in range(8):
            device_param_controls.append(self._dial[index])
        self._device.set_parameter_controls(tuple(device_param_controls))
        #for index in range(4):
        #	self._menu[2 + index]._on_value = (DEVICE_NAV_COLOR[self._rgb])
        #self._device_navigator.set_enabled(True)
        """HH Specific from Constants"""
        #self._mixer.master_strip().set_select_button(self._button[7])
        #for column in range(7):
        #	self._button[column].set_on_off_values(REC_ARM, 0)
        #self._session_zoom.set_zoom_button(self._grid[7][7])
        #self._transport.set_play_button(self._menu[0])
        #self._menu[0].send_value(PLAY_COLOR[self._rgb], True)
        #self._menu[0]._on_value = PLAY_COLOR[self._rgb]
        #self._transport.set_stop_button(self._menu[1])
        #self._menu[1]._off_value = STOP_COLOR[self._rgb]
        #self._menu[1]._on_value = STOP_COLOR[self._rgb]
        #self._menu[1].send_value(STOP_COLOR[self._rgb], True)
        #self._device_navigator.set_device_nav_buttons(self._menu[3], self._menu[4])
        for index in range(8):
            self._button[index].set_channel(2)
            self._button[index].set_identifier(index)
            #self._button[index].reset()
            self._button[index].set_enabled(False)
        self.request_rebuild_midi_map()
        #for index in range(8):
        #	self._grid[index][7].send(self.
        for index in range(2):
            self._looper[index]._state_change()
            self._button[1 + (index * 4)].send_value(3)
            self._button[2 + (index * 4)].send_value(6)
            self._button[3 + (index * 4)].send_value(1)

    def assign_page_2(self):
        self._backlight_type = 'up'
        #self._session_zoom.set_button_matrix(self._matrix)
        self._session_zoom.set_enabled(False)
        for column in range(7):
            self._grid[column][5]._on_value = MUTE_COLOR[self._rgb]
            self._mixer.channel_strip(column).set_mute_button(
                self._grid[column][5])
            self._grid[column][6]._on_value = CROSSFADE_ASSIGN_COLOR[self._rgb]
            self._mixer.channel_strip(column).set_crossfade_toggle(
                self._grid[column][6])
            self._grid[column][7].set_channel(2)
            self._grid[column][7].set_identifier(column)
            self._grid[column][7].reset()
            self._grid[column][7].set_enabled(False)
            self._grid[column][7].send_value(4, True)
            for row in range(5):
                self._scene[row].clip_slot(column).set_launch_button(
                    self._grid[column][row])
        for row in range(5):
            self._grid[7][row]._off_value = SCENE_LAUNCH_COLOR[self._rgb]
            self._scene[row].set_launch_button(self._grid[7][row])
        for column in range(4):
            self._mixer.track_eq(column).set_gain_controls(
                tuple([
                    self._dial[column + 8], self._dial[column + 4],
                    self._dial[column]
                ]))
            self._mixer.track_eq(column).set_enabled(True)
        for column in range(3):
            self._mixer.channel_strip(column + 4).set_pan_control(
                self._dial[column + 12])
        #for index in range(4):
        #	self._menu[2 + index]._on_value = NAV_BUTTON_COLOR[self._rgb]
        #self._session.set_track_bank_buttons(self._menu[4], self._menu[3])
        #self._session.set_scene_bank_buttons(self._menu[5], self._menu[2])
        self._set_tempo_buttons([self._grid[7][5], self._grid[7][6]])
        """HH Specific from Constants"""
        #self._mixer.master_strip().set_select_button(self._button[7])
        #for column in range(7):
        #	self._mixer.channel_strip(column).set_select_button(self._button[column])
        #for index in range(8):
        #	self._button[index].set_on_off_values(SELECT_COLOR[self._rgb], 0)
        self._session_zoom.set_zoom_button(self._grid[7][7])
        #self._transport.set_play_button(self._menu[0])
        #self._menu[0].send_value(PLAY_COLOR[self._rgb], True)
        #self._menu[0]._on_value = PLAY_COLOR[self._rgb]
        #self._transport.set_stop_button(self._menu[1])
        #self._menu[1]._off_value = STOP_COLOR[self._rgb]
        #self._menu[1]._on_value = STOP_COLOR[self._rgb]
        #self._menu[1].send_value(STOP_COLOR[self._rgb], True)
        #self._device_navigator.set_device_nav_buttons(self._menu[3], self._menu[4])
        for index in range(8):
            self._button[index].set_channel(2)
            self._button[index].set_identifier(index)
            #self._button[index].reset()
            self._button[index].set_enabled(False)
        self.request_rebuild_midi_map()
        for index in range(2):
            self._looper[index]._state_change()
            self._button[1 + (index * 4)].send_value(3)
            self._button[2 + (index * 4)].send_value(6)
            self._button[3 + (index * 4)].send_value(1)

    def _update_selected_device(self):
        if self._device_selection_follows_track_selection is True:
            track = self.song().view.selected_track
            device_to_select = track.view.selected_device
            if device_to_select == None and len(track.devices) > 0:
                device_to_select = track.devices[0]
            if device_to_select != None:
                self.song().view.select_device(device_to_select)
            #self._device.set_device(device_to_select)
            self.set_appointed_device(device_to_select)
            #self._device_selector.set_enabled(True)
            self.request_rebuild_midi_map()
        return None

    def handle_sysex(self, midi_bytes):
        #self.log_message(str('>>sysexIN') + str(midi_bytes))
        if len(midi_bytes) > 10:
            #self.log_message(str('>>sysex>10') + str(midi_bytes[:11]))
            if midi_bytes[:11] == tuple([240, 126, 0, 6, 2, 0, 1, 97, 1, 0,
                                         7]):
                self.log_message(str('>>>color detected'))
                self._rgb = 1
            elif midi_bytes[:11] == tuple(
                [240, 126, 0, 6, 2, 0, 1, 97, 1, 0, 2]):
                self.log_message(str('>>>mono detected'))
                self._rgb = 0
        self._assign_session_colors()
        #self._shift_mode.update()
        self.deassign_matrix()
        self._assign_page_constants()
        self.assign_page_0()
        #self._setup_hilight_knobs()
        for index in range(8):
            self._grid[7][index].send_value(SCENE_LAUNCH_COLOR[self._rgb])
        for index in range(7):
            self._grid[index][7].turn_on()

# 	def handle_sysex(self, midi_bytes):
# 		#assert(isinstance (midi_bytes, tuple))
# 		##self.log_message(str('sysex') + str(midi_bytes))
# 		if midi_bytes == tuple([240, 126, 0, 6, 2, 0, 1, 97, 1, 0, 7, 0, 15, 10, 0, 0, 247]):
# 			self.log_message(str('color detected'))
# 			self._rgb = 1
# 		elif midi_bytes == tuple([240, 126, 0, 6, 2, 0, 1, 97, 1, 0, 2, 0, 0, 1, 1, 0, 247]):
# 			self.log_message(str('mono detected'))
# 			self._rgb = 0
# 		self._assign_session_colors()

    def receive_midi(self, midi_bytes):
        """ Live -> Script
		MIDI messages are only received through this function, when explicitly 
		forwarded in 'build_midi_map'.
	"""
        assert (midi_bytes != None)
        assert isinstance(midi_bytes, tuple)
        ##self.log_message('got message' + str(midi_bytes))
        #self.set_suppress_rebuild_requests(True)
        with self.component_guard():
            if (len(midi_bytes) is 3):
                msg_type = (midi_bytes[0] & 240)
                forwarding_key = [midi_bytes[0]]
                if (msg_type is not MIDI_PB_TYPE):
                    forwarding_key.append(midi_bytes[1])
                if (tuple(forwarding_key) in self._forwarding_registry.keys()):
                    recipient = self._forwarding_registry[tuple(
                        forwarding_key)]
                    if (recipient != None):
                        recipient.receive_value(midi_bytes[2])
                else:
                    self.log_message(
                        ('Got unknown message: ' + str(midi_bytes)))
            else:
                self.handle_sysex(midi_bytes)
        #self.set_suppress_rebuild_requests(False)

    def _set_tempo_buttons(self, buttons):
        if self._tempo_buttons != None:
            self._tempo_buttons[0].remove_value_listener(self._tempo_value)
            self._tempo_buttons[1].remove_value_listener(self._tempo_value)
        self._tempo_buttons = buttons
        if buttons != None:
            for button in buttons:
                assert isinstance(button, FlashingButtonElement)
            self._tempo_buttons[0].set_on_off_values(4, 0)
            self._tempo_buttons[0].add_value_listener(self._tempo_value, True)
            self._tempo_buttons[1].set_on_off_values(4, 0)
            self._tempo_buttons[1].add_value_listener(self._tempo_value, True)
            self._tempo_buttons[0].turn_on()
            self._tempo_buttons[1].turn_on()

    def _tempo_value(self, value, sender):
        if (value > 0) and (self._tempo_buttons.index(sender) == 0):
            self.song().tempo = round(min((self.song().tempo + 1), 999))
        elif (value > 0) and (self._tempo_buttons.index(sender) == 1):
            self.song().tempo = round(max((self.song().tempo - 1), 20))

    def set_scene_index_value(self, bank_index, scene, track):
        bank = int(bank_index) / 5
        index = int(bank_index) % 5
        self.log_message('set_scene_index_value' + str(bank) + str(index) +
                         str(scene) + str(track))
        #self.log_message( str(type(index)) + str(type(scene)) + str(type(track)))
        self._scene_indexes[bank][index][0] = scene
        self._scene_indexes[bank][index][1] = track
        #self._on_selected_scene_changed()

    def connect_script_instances(self, instanciated_scripts):
        #link = False
        #offsets = [0, 0]
        #new_channel = CHAN
        for s in instanciated_scripts:
            if isinstance(s, APC) or s is self:
                #link = True
                if not s._session._is_linked():
                    s._session._link()