示例#1
0
 def _setup_transport(self):
     is_momentary = True
     transport = TransportComponent()
     studiotransport = MaschineTransport()
     playButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 108)
     stopButton = StateButton(not is_momentary, MIDI_CC_TYPE, 0, 110)
     recordButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 109)
     overdubButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 107)
     metrononmeButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 104)
     eventRecButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 98)
     playButton.name = 'Play'
     stopButton.name = 'Stop'
     recordButton.name = 'Record'
     overdubButton.name = 'Overdub'
     metrononmeButton.name = 'Metronome'
     transport.set_play_button(playButton)
     transport.set_stop_button(stopButton)
     transport.set_record_button(recordButton)
     transport.set_overdub_button(overdubButton)
     transport.set_metronome_button(metrononmeButton)
     studiotransport.set_session_auto_button(eventRecButton)
     studiotransport.set_arrangement_overdub_button(
         StateButton(is_momentary, MIDI_CC_TYPE, 0, 106))
     studiotransport.set_back_arrange_button(
         StateButton(is_momentary, MIDI_CC_TYPE, 0, 105))
     transport.set_nudge_buttons(
         StateButton(is_momentary, MIDI_CC_TYPE, 1, 51),
         StateButton(is_momentary, MIDI_CC_TYPE, 1, 50))
     punchinbutton = ToggleButton(MIDI_CC_TYPE, 1, 52)
     punchoutbutton = ToggleButton(MIDI_CC_TYPE, 1, 53)
     punchinbutton.name = 'Punch In'
     punchoutbutton.name = 'Punch Out'
     transport.set_punch_buttons(punchinbutton, punchoutbutton)
     transport.set_loop_button(
         StateButton(is_momentary, MIDI_CC_TYPE, 1, 54))
     self.song_follow_button = ButtonElement(True, MIDI_CC_TYPE, 2, 98)
     self._do_song_follow.subject = self.song_follow_button
     self._song_follow_changed.subject = self.song().view
     self._song_follow_changed()
     self.transp_ff_button = ButtonElement(True, MIDI_CC_TYPE, 1, 59)
     self.transp_rw_button = ButtonElement(True, MIDI_CC_TYPE, 1, 58)
     transport.set_seek_buttons(self.transp_ff_button,
                                self.transp_rw_button)
     self.xfadeKnob = SliderElement(MIDI_CC_TYPE, 1, 105)
     self.xfadeKnob.connect_to(
         self.song().master_track.mixer_device.crossfader)
     self.master_knob = SliderElement(MIDI_CC_TYPE, 0, 99)
     self.master_knob.connect_to(
         self.song().master_track.mixer_device.volume)
     self.tap_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 88)
     self._do_tap_tempo.subject = self.tap_button
     self.cue_add_delete_button = StateButton(is_momentary, MIDI_CC_TYPE, 1,
                                              55)
     self.cue_prev_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 56)
     self.cue_next_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 57)
     self._do_toggle_cue.subject = self.cue_add_delete_button
     self._do_toggle_prev_cue.subject = self.cue_prev_button
     self._do_toggle_next_cue.subject = self.cue_next_button
示例#2
0
 def _setup_transport(self):
     is_momentary = True
     transport = TransportComponent()
     self.__play_button = StateButton(is_momentary,
                                      MIDI_CC_TYPE,
                                      BASE_CONTROL_CHANNEL,
                                      CC_PLAY_BUTTON,
                                      name='Play_Button')
     self.__restart_button = StateButton(True, MIDI_CC_TYPE,
                                         BASE_CONTROL_CHANNEL,
                                         CC_RESTART_BUTTON)
     stop_button = StateButton(not is_momentary,
                               MIDI_CC_TYPE,
                               BASE_CONTROL_CHANNEL,
                               CC_STOP_BUTTON,
                               name='Stop_Button')
     self._rec_button = StateButton(is_momentary,
                                    MIDI_CC_TYPE,
                                    BASE_CONTROL_CHANNEL,
                                    CC_RECORD_BUTTON,
                                    name='Record_Button')
     metrononme_button = StateButton(is_momentary,
                                     MIDI_CC_TYPE,
                                     BASE_CONTROL_CHANNEL,
                                     CC_METRONOME_BUTTON,
                                     name='Metronome_Button')
     self._song_follow_button = StateButton(is_momentary,
                                            MIDI_CC_TYPE,
                                            BASE_CONTROL_CHANNEL,
                                            CC_FOLLOW_BUTTON,
                                            name='Follow_Button')
     self._do_rec_button.subject = self._rec_button
     if self._has_stop_button:
         transport.set_play_button(self.__play_button)
         transport.set_stop_button(stop_button)
     else:
         self._hand_play_pressed.subject = self.__play_button
         self._listen_playing.subject = self.song()
     self._stopall_button = StateButton(True, MIDI_CC_TYPE, 0,
                                        CC_ALL_BUTTON)
     self._do_stop_all.subject = self._stopall_button
     self._auto_button = StateButton(True,
                                     MIDI_CC_TYPE,
                                     0,
                                     CC_AUTO_BUTTON,
                                     name='Auto_Button')
     self._handle_automation_record.subject = self._auto_button
     self._listen_automation_record.subject = self.song()
     self._handle_restart_button.subject = self.__restart_button
     self._handle_follows_button.subject = self._song_follow_button
     self._follow_song_changed.subject = self.song().view
     transport.set_metronome_button(metrononme_button)
     self._listen_overdub.subject = self.song()
 def _setup_transport(self):
     is_momentary = True
     transport = TransportComponent()
     studiotransport = MaschineTransport()
     playButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 108)
     stopButton = StateButton(not is_momentary, MIDI_CC_TYPE, 0, 110)
     recordButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 109)
     overdubButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 107)
     metrononmeButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 104)
     eventRecButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 98)
     playButton.name = 'Play'
     stopButton.name = 'Stop'
     recordButton.name = 'Record'
     overdubButton.name = 'Overdub'
     metrononmeButton.name = 'Metronome'
     transport.set_play_button(playButton)
     transport.set_stop_button(stopButton)
     transport.set_record_button(recordButton)
     transport.set_overdub_button(overdubButton)
     transport.set_metronome_button(metrononmeButton)
     studiotransport.set_session_auto_button(eventRecButton)
     studiotransport.set_arrangement_overdub_button(StateButton(is_momentary, MIDI_CC_TYPE, 0, 106))
     studiotransport.set_back_arrange_button(StateButton(is_momentary, MIDI_CC_TYPE, 0, 105))
     transport.set_nudge_buttons(StateButton(is_momentary, MIDI_CC_TYPE, 1, 51), StateButton(is_momentary, MIDI_CC_TYPE, 1, 50))
     punchinbutton = ToggleButton(MIDI_CC_TYPE, 1, 52)
     punchoutbutton = ToggleButton(MIDI_CC_TYPE, 1, 53)
     punchinbutton.name = 'Punch In'
     punchoutbutton.name = 'Punch Out'
     transport.set_punch_buttons(punchinbutton, punchoutbutton)
     transport.set_loop_button(StateButton(is_momentary, MIDI_CC_TYPE, 1, 54))
     self.song_follow_button = ButtonElement(True, MIDI_CC_TYPE, 2, 98)
     self._do_song_follow.subject = self.song_follow_button
     self._song_follow_changed.subject = self.song().view
     self._song_follow_changed()
     self.prehear_knob = SliderElement(MIDI_CC_TYPE, 0, 41)
     self.prehear_knob.connect_to(self.song().master_track.mixer_device.cue_volume)
     self.transp_ff_button = ButtonElement(True, MIDI_CC_TYPE, 1, 59)
     self.transp_rw_button = ButtonElement(True, MIDI_CC_TYPE, 1, 58)
     transport.set_seek_buttons(self.transp_ff_button, self.transp_rw_button)
     self.xfadeKnob = SliderElement(MIDI_CC_TYPE, 1, 105)
     self.xfadeKnob.connect_to(self.song().master_track.mixer_device.crossfader)
     self.master_knob = SliderElement(MIDI_CC_TYPE, 0, 99)
     self.master_knob.connect_to(self.song().master_track.mixer_device.volume)
     self.tap_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 88)
     self._do_tap_tempo.subject = self.tap_button
     self.cue_add_delete_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 55)
     self.cue_prev_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 56)
     self.cue_next_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 57)
     self._do_toggle_cue.subject = self.cue_add_delete_button
     self._do_toggle_prev_cue.subject = self.cue_prev_button
     self._do_toggle_next_cue.subject = self.cue_next_button
示例#4
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))
示例#5
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))
 def _setup_transport(self):
     is_momentary = True
     transport = TransportComponent()
     playButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 108)
     stopButton = StateButton(not is_momentary, MIDI_CC_TYPE, 0, 110)
     recordButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 109)
     overdubButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 107)
     metrononmeButton = StateButton(is_momentary, MIDI_CC_TYPE, 0, 104)
     playButton.name = 'Play'
     stopButton.name = 'Stop'
     recordButton.name = 'Record'
     overdubButton.name = 'Overdub'
     metrononmeButton.name = 'Metronome'
     transport.set_play_button(playButton)
     transport.set_stop_button(stopButton)
     transport.set_record_button(recordButton)
     transport.set_overdub_button(overdubButton)
     transport.set_metronome_button(metrononmeButton)
     transport.set_nudge_buttons(StateButton(is_momentary, MIDI_CC_TYPE, 1, 51), StateButton(is_momentary, MIDI_CC_TYPE, 1, 50))
     punchinbutton = ToggleButton(MIDI_CC_TYPE, 1, 52)
     punchoutbutton = ToggleButton(MIDI_CC_TYPE, 1, 53)
     punchinbutton.name = 'Punch In'
     punchoutbutton.name = 'Punch Out'
     transport.set_punch_buttons(punchinbutton, punchoutbutton)
     transport.set_loop_button(StateButton(is_momentary, MIDI_CC_TYPE, 1, 54))
     self.transp_ff_button = ButtonElement(True, MIDI_CC_TYPE, 1, 59)
     self.transp_rw_button = ButtonElement(True, MIDI_CC_TYPE, 1, 58)
     transport.set_seek_buttons(self.transp_ff_button, self.transp_rw_button)
     self.xfadeKnob = SliderElement(MIDI_CC_TYPE, 1, 100)
     self.xfadeKnob.connect_to(self.song().master_track.mixer_device.crossfader)
     self.tap_button = StateButton(is_momentary, MIDI_CC_TYPE, 0, 88)
     self.tap_button.add_value_listener(self._do_tap_tempo)
     self.cue_add_delete_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 55)
     self.cue_prev_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 56)
     self.cue_next_button = StateButton(is_momentary, MIDI_CC_TYPE, 1, 57)
     self.cue_add_delete_button.add_value_listener(self._do_toggle_cue)
     self.cue_prev_button.add_value_listener(self._do_toggle_prev_cue)
     self.cue_next_button.add_value_listener(self._do_toggle_next_cue)
示例#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")
示例#8
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
示例#9
0
class OP1(ControlSurface):
    def __init__(self, *args, **kwargs):
        ControlSurface.__init__(self, *args, **kwargs)

        self.log_message('__init__()')
        self.show_message("Version: " + VERSION)

        # Data for tracking connection attempts
        self.device_connected = False
        self.next_retry_delay = 1
        self.next_retry_ts = None
        self.retries_count = 0
        self._current_midi_map = None

        # State of display text
        self.text_top = ''
        self.text_bottom = ''

        # State of display key slots
        self.display_color_by_slot_num = {}
        for i in range(NUM_DISPLAY_CLIP_SLOTS):
            self.display_color_by_slot_num[i] = COLOR_BLACK_BYTES

        with self.component_guard():
            self._build_components()
            self.init_modes()

    #
    # Ableton Helpers
    #

    @property
    def num_tracks(self):
        return min(NUM_TRACKS, len(self.song().tracks))

    @property
    def num_scenes(self):
        return min(NUM_SCENES, len(self.song().scenes))

    @property
    def selected_track(self):
        return self.song().view.selected_track

    @property
    def selected_track_num(self):
        return list(self.song().tracks).index(self.selected_track)

    @property
    def selected_scene(self):
        return self.song().view.selected_scene

    @property
    def selected_scene_num(self):
        return list(self.song().scenes).index(self.selected_scene)

    @property
    def selected_clip_slot(self):
        return self.selected_track.clip_slots[self.selected_scene_num]

    @property
    def selected_device(self):
        return self.selected_track.view.selected_device

    def get_selected_track_devices(self, class_name):
        return [
            device for device in self.selected_track.devices
            if device.class_name == class_name
        ]

    #
    # Connected Components
    #

    def _with_shift(self, control):
        return ComboElement(control, modifiers=[self._button_shift])

    def _build_components(self):

        self._buttons = {}
        for identifier in range(5, 53) + range(64, 68):
            # We create the shift button in a special way
            if identifier == OP1_SHIFT_BUTTON:
                continue
            # Encoders present as buttons when values are changed
            button = APCUtils.make_pedal_button(identifier)
            button.add_value_listener(self.debug_button_handler)
            self._buttons[identifier] = button

        # Encoder buttons
        # See notes below for explanation of exclusion of first button
        # for identifier in [OP1_ENCODER_2_BUTTON, OP1_ENCODER_3_BUTTON, OP1_ENCODER_4_BUTTON]:
        # 	button = APCUtils.make_pedal_button(identifier)
        # 	button.add_value_listener(self.debug_button_handler)
        # 	APCUtils.make_pedal_button(identifier] = butto)

        self._notes = {}
        for identifier in range(OP1_MIN_NOTE, OP1_MAX_NOTE + 1):
            note = APCUtils.make_button(CHANNEL, identifier)
            note.add_value_listener(self.debug_note_handler)
            self._notes[identifier] = note

        # Buttons
        self._button_shift = ButtonElement(
            is_momentary=True,
            msg_type=MIDI_CC_TYPE,
            channel=0,
            identifier=OP1_SHIFT_BUTTON,
            # Required for modifier buttons
            resource_type=PrioritizedResource,
            name='ShiftButton',
        )
        # self._button_shift.add_value_listener(self.on_shift_button)

        self._button_mode_synth = self._buttons[OP1_MODE_1_BUTTON]
        self._button_mode_drum = self._buttons[OP1_MODE_2_BUTTON]
        self._button_mode_tape = self._buttons[OP1_MODE_3_BUTTON]
        self._button_mode_mixer = self._buttons[OP1_MODE_4_BUTTON]

        self._button_mode_1 = self._buttons[OP1_T1_BUTTON]
        self._button_mode_2 = self._buttons[OP1_T2_BUTTON]
        self._button_mode_3 = self._buttons[OP1_T3_BUTTON]
        self._button_mode_4 = self._buttons[OP1_T4_BUTTON]

        self._button_down = self._buttons[OP1_ARROW_DOWN_BUTTON]
        self._button_up = self._buttons[OP1_ARROW_UP_BUTTON]
        self._button_left = self._buttons[OP1_LEFT_ARROW]
        self._button_right = self._buttons[OP1_RIGHT_ARROW]

        self._button_metronome = self._buttons[OP1_METRONOME_BUTTON]
        self._button_scissors = self._buttons[OP1_SCISSOR_BUTTON]

        self._button_ss1 = self._buttons[OP1_SS1_BUTTON]
        self._button_ss2 = self._buttons[OP1_SS2_BUTTON]
        self._button_ss3 = self._buttons[OP1_SS3_BUTTON]
        self._button_ss4 = self._buttons[OP1_SS4_BUTTON]
        self._button_ss5 = self._buttons[OP1_SS5_BUTTON]
        self._button_ss6 = self._buttons[OP1_SS6_BUTTON]
        self._button_ss7 = self._buttons[OP1_SS7_BUTTON]
        self._button_ss8 = self._buttons[OP1_SS8_BUTTON]

        self._button_record = self._buttons[OP1_REC_BUTTON]
        self._button_play = self._buttons[OP1_PLAY_BUTTON]
        self._button_stop = self._buttons[OP1_STOP_BUTTON]

        self._button_microphone = self._buttons[OP1_MICROPHONE]
        self._button_com = self._buttons[OP1_COM]
        self._button_sequencer = self._buttons[OP1_SEQUENCER]

        # Encoders
        self._encoder_1 = EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_1,
                                         ENCODER_MODE)
        self._encoder_2 = EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_2,
                                         ENCODER_MODE)
        self._encoder_3 = EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_3,
                                         ENCODER_MODE)
        self._encoder_4 = EncoderElement(MIDI_CC_TYPE, CHANNEL, OP1_ENCODER_4,
                                         ENCODER_MODE)

        self._unshift_encoder_1 = ShiftEnabledControl(self._encoder_1,
                                                      self._button_shift,
                                                      False, self)
        self._unshift_encoder_2 = ShiftEnabledControl(self._encoder_2,
                                                      self._button_shift,
                                                      False, self)
        self._unshift_encoder_3 = ShiftEnabledControl(self._encoder_3,
                                                      self._button_shift,
                                                      False, self)
        self._unshift_encoder_4 = ShiftEnabledControl(self._encoder_4,
                                                      self._button_shift,
                                                      False, self)
        self._shift_encoder_1 = ShiftEnabledControl(self._encoder_1,
                                                    self._button_shift, True,
                                                    self)
        self._shift_encoder_2 = ShiftEnabledControl(self._encoder_2,
                                                    self._button_shift, True,
                                                    self)
        self._shift_encoder_3 = ShiftEnabledControl(self._encoder_3,
                                                    self._button_shift, True,
                                                    self)
        self._shift_encoder_4 = ShiftEnabledControl(self._encoder_4,
                                                    self._button_shift, True,
                                                    self)

        self._encoder_u01_1 = EncoderElement(MIDI_CC_TYPE, CHANNEL,
                                             OP1_U01_ENCODER_1, ENCODER_MODE)
        self._encoder_u01_2 = EncoderElement(MIDI_CC_TYPE, CHANNEL,
                                             OP1_U01_ENCODER_2, ENCODER_MODE)
        self._encoder_u01_3 = EncoderElement(MIDI_CC_TYPE, CHANNEL,
                                             OP1_U01_ENCODER_3, ENCODER_MODE)
        self._encoder_u01_4 = EncoderElement(MIDI_CC_TYPE, CHANNEL,
                                             OP1_U01_ENCODER_4, ENCODER_MODE)

        self._unshift_encoder_u01_1 = ShiftEnabledControl(
            self._encoder_u01_1, self._button_shift, False, self)
        self._unshift_encoder_u01_2 = ShiftEnabledControl(
            self._encoder_u01_2, self._button_shift, False, self)
        self._unshift_encoder_u01_3 = ShiftEnabledControl(
            self._encoder_u01_3, self._button_shift, False, self)
        self._unshift_encoder_u01_4 = ShiftEnabledControl(
            self._encoder_u01_4, self._button_shift, False, self)
        self._shift_encoder_u01_1 = ShiftEnabledControl(
            self._encoder_u01_1, self._button_shift, True, self)
        self._shift_encoder_u01_2 = ShiftEnabledControl(
            self._encoder_u01_2, self._button_shift, True, self)
        self._shift_encoder_u01_3 = ShiftEnabledControl(
            self._encoder_u01_3, self._button_shift, True, self)
        self._shift_encoder_u01_4 = ShiftEnabledControl(
            self._encoder_u01_4, self._button_shift, True, self)

        self._encoder_u02_1 = EncoderElement(MIDI_CC_TYPE, CHANNEL,
                                             OP1_U02_ENCODER_1, ENCODER_MODE)
        self._encoder_u02_2 = EncoderElement(MIDI_CC_TYPE, CHANNEL,
                                             OP1_U02_ENCODER_2, ENCODER_MODE)
        self._encoder_u02_3 = EncoderElement(MIDI_CC_TYPE, CHANNEL,
                                             OP1_U02_ENCODER_3, ENCODER_MODE)
        self._encoder_u02_4 = EncoderElement(MIDI_CC_TYPE, CHANNEL,
                                             OP1_U02_ENCODER_4, ENCODER_MODE)

        # NOTE: encoder_1_button conflicts with encoder_U03_4
        self._encoder_button_1 = self._buttons[OP1_ENCODER_1_BUTTON]
        self._encoder_button_2 = self._buttons[OP1_ENCODER_2_BUTTON]
        self._encoder_button_3 = self._buttons[OP1_ENCODER_3_BUTTON]
        self._encoder_button_4 = self._buttons[OP1_ENCODER_4_BUTTON]

        self._mixer = MixerComponent(
            num_tracks=NUM_TRACKS,
            num_returns=2,
        )

        # self._mixer.set_select_buttons(
        # 	prev_button=self._button_up,
        # 	next_button=self._button_down,
        # )
        # self.map_mixer_controls_for_current_track()

        def on_down_button(value):
            if value == BUTTON_ON:
                self.set_selected_scene(self.scene_offset + 1)

        def on_up_button(value):
            if value == BUTTON_ON:
                self.set_selected_scene(self.scene_offset - 1)

        self.scene_offset = 0
        self.song().view.add_selected_scene_listener(
            self.selected_scene_changed)
        self._button_right.add_value_listener(on_down_button)
        self._button_left.add_value_listener(on_up_button)

        self._transport = TransportComponent()
        self._transport.set_metronome_button(self._button_metronome)

        #
        # Controls for navigating the bottom detail pane
        #
        self._device_navigation = DetailViewCntrlComponent()

        # Toggle hide/show of bottom detail pane
        self._device_navigation.set_detail_toggle_button(self._button_ss1)

        # Toggle between clip detail and effects detail in bottom detail pane
        self._device_navigation.set_device_clip_toggle_button(self._button_ss2)

        # Nav left/right in the device chain detail view in bottom pane
        self._device_navigation.device_nav_left_button.set_control_element(
            self._button_ss7)
        self._device_navigation.device_nav_right_button.set_control_element(
            self._button_ss8)

        # Clip firing
        self._notes[OP1_F3_NOTE].add_value_listener(partial(
            self.clip_fired, 0))
        self._notes[OP1_G3_NOTE].add_value_listener(partial(
            self.clip_fired, 1))
        self._notes[OP1_A3_NOTE].add_value_listener(partial(
            self.clip_fired, 2))
        self._notes[OP1_B3_NOTE].add_value_listener(partial(
            self.clip_fired, 3))
        self._notes[OP1_C4_NOTE].add_value_listener(partial(
            self.clip_fired, 4))
        self._notes[OP1_D4_NOTE].add_value_listener(partial(
            self.clip_fired, 5))
        self._notes[OP1_E4_NOTE].add_value_listener(partial(
            self.clip_fired, 6))
        self._notes[OP1_F4_NOTE].add_value_listener(partial(
            self.clip_fired, 7))

        self._button_scissors.add_value_listener(self.selected_clip_deleted)

        #
        # Device Controls
        #

        # self._device = DeviceComponent(
        # 	name='Device_Component',
        # 	is_enabled=False,
        # 	layer=Layer(
        # 		parameter_controls=ButtonMatrixElement(rows=[[
        #    				self._encoder_u01_1,
        # 			self._encoder_u01_2,
        # 			self._encoder_u01_3,
        # 			self._encoder_u01_4,
        # 			self._encoder_u02_1,
        # 			self._encoder_u02_2,
        # 			self._encoder_u02_3,
        # 			self._encoder_u02_4,
        #        		]]),
        # 		# bank_buttons=ButtonMatrixElement(rows=[[
        # 		# 	self._encoder_button_1,
        # 		# 	self._encoder_button_2,
        # 		# 	self._encoder_button_3,
        # 		# 	self._encoder_button_4,
        # 		# ]]),
        # 		bank_prev_button=self._button_ss5,
        # 		bank_next_button=self._button_ss6,
        # 		on_off_button=self._button_record,
        # 	),
        # 	device_selection_follows_track_selection=True
        # )
        # self._device.set_enabled(True)
        # self.set_device_component(self._device)

    #
    # Mode configuration
    #

    def init_modes(self):
        self.tracks_mode = modes.TracksMode(self)
        self.effects_mode = modes.EffectsMode(self)

        self.current_mode = None

        self._button_mode_synth.add_value_listener(
            partial(self.on_mode_button, self.tracks_mode))
        self._button_mode_drum.add_value_listener(
            partial(self.on_mode_button, self.effects_mode))
        # self._button_mode_3.add_value_listener(
        # 	partial(self.on_mode_button, ))
        # self._button_mode_4.add_value_listener(
        # 	partial(self.on_mode_button, ))

        self.set_mode(self.tracks_mode)

    def set_mode(self, mode):
        self.log_message('set_mode()')
        if self.current_mode is not None:
            self.current_mode.deactivate()
        self.current_mode = mode
        self.current_mode.activate()

    def on_mode_button(self, mode, value):
        if value:
            self.set_mode(mode)

    #
    # Shift Button Alternative modes
    #

    def on_shift_button(self, value):
        if value == BUTTON_ON:
            self.log_message('shift on')
            pass
        else:
            self.log_message('shift off')
            pass

    #
    # Scene selection
    #

    def selected_scene_changed(self):
        self.log_message('selected_scene_changed()')
        self.scene_offset = self.selected_scene_num
        self.map_clip_controls_for_current_scene()

    def set_selected_scene(self, scene_offset):
        scene_offset = max(0, scene_offset)
        scene_offset = min(scene_offset, self.num_scenes - 1)

        next_scene = self.song().scenes[scene_offset]
        next_scene = self.song().view.selected_scene = next_scene

        self.scene_offset = scene_offset

    def clear_key_assignments(self):
        pass

    def map_clip_controls_for_current_scene(self):
        for clip_slot in self.selected_scene.clip_slots:
            pass

    #
    # Clip triggers
    #

    def clip_fired(self, clip_num, value):
        if value == NOTE_ON:

            self.log_message('clip_fired(clip_num=%s, value=%s)' %
                             (clip_num, value))
            clip_slot = self.selected_track.clip_slots[clip_num]

            # if clip_slot.is_playing:
            # 	self.log_message('stoping clip')
            # 	clip_slot.stop()
            # else:
            # 	self.log_message('firing clip. has_clip=%s has_stop=%s, playing_status=%s' % (
            # 		clip_slot.has_clip,
            # 		clip_slot.has_stop_button,
            # 		clip_slot.playing_status,
            # 	))
            # 	clip_slot.fire()

            self.log_message(
                'firing clip. has_clip=%s has_stop=%s, playing_status=%s' % (
                    clip_slot.has_clip,
                    clip_slot.has_stop_button,
                    clip_slot.playing_status,
                ))
            clip_slot.fire()

            # Update scene selection to fired clip's row.
            self.set_selected_scene(clip_num)

    def selected_clip_deleted(self, value):
        if value == BUTTON_ON:
            self.log_message('deleting clip')
            self.selected_clip_slot.delete_clip()

    #
    # Looper triggers
    #

    def looper_fired(looper_device):
        fire_param = [
            param for param in looper_device.parameters
            if param.name == 'State'
        ]
        self.log_message(fire_param)

    #
    # Refresh handling
    #

    def handle_sysex(self, midi_bytes):
        super(OP1, self).handle_sysex(midi_bytes)
        if (len(midi_bytes) >= 8 and (midi_bytes[6] == 32)
                and (midi_bytes[7] == 118)):
            self.handle_device_connection_success()
        else:
            self.log_message("sysex: %s" % (midi_bytes, ))

    def refresh_state(self):
        super(OP1, self).refresh_state()

        self.log_message("refresh_state()")
        self.retries_count = 0
        self.next_retry_ts = None
        self.next_retry_delay = 1
        self.device_connected = False

    def update_display(self):
        super(OP1, self).update_display()

        if not (self.device_connected):
            if self.next_retry_ts is None or time.time() >= self.next_retry_ts:
                self.attempt_connection_with_device()
            return

        # Render the currently active view
        self.current_mode.view.render()

    #
    # Connection Management
    #

    def build_midi_map(self, midi_map_handle):
        super(OP1, self).build_midi_map(midi_map_handle)

        # map mixer controls to currently selected track
        # self.map_mixer_controls_for_current_track()

    def attempt_connection_with_device(self):
        self.log_message("Attempting to connect to OP-1... (num_retries: %s)" %
                         self.retries_count)
        self.retries_count += 1
        self.next_retry_ts = time.time() + self.next_retry_delay
        self.next_retry_delay *= 2
        self._send_midi(ID_SEQUENCE)

    def handle_device_connection_success(self):
        self.device_connected = True
        self.retries_count = 0
        self.log_message("OP-1 Connected")
        self._send_midi(ENABLE_SEQUENCE)

    def disconnect(self):
        self.log_message("disconnect()")
        self.retries_count = 0
        self.device_connected = False
        self._send_midi(DISABLE_SEQUENCE)
        super(OP1, self).disconnect()

    def suggest_input_port(self):
        return "OP-1 Midi Device"

    def suggest_output_port(self):
        return "OP-1 Midi Device"

    #
    # Debug utils
    #

    def param_value_updated(self, param):
        self.log_message('Param update: %s(%s)' % (param.name, param.value))
        self.log_message('    value_items: %s' % (list(param.value_items), ))

    def debug_button_handler(self, value, *args, **kwargs):
        self.log_message('button: %s' % value)

    def debug_note_handler(self, value, *args, **kwargs):
        self.log_message('note: %s' % value)

    def handle_nonsysex(self, midi_bytes):
        super(OP1, self).handle_nonsysex(midi_bytes)
        channel, identifier, value, is_pitchbend = midi_bytes_to_values(
            midi_bytes)
        if not is_pitchbend:
            self.log_message('midi ch:%s value:%s(%s)' %
                             (channel, identifier, value))
示例#10
0
文件: OP1.py 项目: imaginando/op1
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")
示例#11
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