예제 #1
0
class Launchpad_X(InstrumentControlMixin, NovationBase):
    model_family_code = ids.LP_X_FAMILY_CODE
    element_class = Elements
    channel_strip_class = ChannelStripComponent
    session_recording_class = mixin(SessionRecordingMixin,
                                    SessionRecordingComponent)
    track_recording_class = mixin(SessionRecordingMixin,
                                  TrackRecordingComponent)
    target_track_class = ArmedTargetTrackComponent
    skin = skin

    def __init__(self, *a, **k):
        self._last_layout_byte = sysex.SESSION_LAYOUT_BYTE
        (super(Launchpad_X, self).__init__)(*a, **k)

    def on_identified(self, midi_bytes):
        self._elements.firmware_mode_switch.send_value(sysex.DAW_MODE_BYTE)
        self._elements.layout_switch.send_value(self._last_layout_byte)
        self._target_track_changed()
        self._drum_group_changed()
        self.set_feedback_channels(
            [DRUM_FEEDBACK_CHANNEL, SCALE_FEEDBACK_CHANNEL])
        super(Launchpad_X, self).on_identified(midi_bytes)

    def _create_components(self):
        super(Launchpad_X, self)._create_components()
        self._background = BackgroundComponent(name='Background',
                                               add_nop_listeners=True)
        self._session_layout_mode = partial(
            self._elements.layout_switch.send_value, sysex.SESSION_LAYOUT_BYTE)
        self._create_recording_modes()
        self._create_mixer_modes()
        self._create_session_modes()
        self._create_note_modes()
        self._create_main_modes()
        self._mixer.set_send_controls = nop
        self._Launchpad_X__on_layout_switch_value.subject = self._elements.layout_switch

    def _create_mixer_modes(self):
        self._mixer_modes = ModesComponent(
            name='Mixer_Modes',
            is_enabled=False,
            enable_skinning=True,
            layer=Layer(
                volume_button=(self._elements.scene_launch_buttons_raw[0]),
                pan_button=(self._elements.scene_launch_buttons_raw[1]),
                send_a_button=(self._elements.scene_launch_buttons_raw[2]),
                send_b_button=(self._elements.scene_launch_buttons_raw[3]),
                stop_button=(self._elements.scene_launch_buttons_raw[4]),
                mute_button=(self._elements.scene_launch_buttons_raw[5]),
                solo_button=(self._elements.scene_launch_buttons_raw[6]),
                arm_button=(self._elements.scene_launch_buttons_raw[7])))
        bottom_row = self._elements.clip_launch_matrix.submatrix[:, 7:8]
        select_none_mode = partial(setattr, self._mixer_modes, 'selected_mode',
                                   'none')
        self._mixer_modes.add_mode('none', self._session_layout_mode)
        button_fader_layout_mode = partial(
            self._elements.layout_switch.send_value, sysex.FADERS_LAYOUT_BYTE)

        def add_fader_mode(name, color, is_pan=False):
            control_dict = {'{}_controls'.format(name): 'button_faders'}
            if is_pan:
                control_dict[
                    'track_color_controls'] = 'button_fader_color_elements'
            else:
                control_dict[
                    'static_color_controls'] = 'button_fader_color_elements'
            self._mixer_modes.add_mode(
                name, (partial(
                    self._elements.button_fader_setup_element.send_value,
                    sysex.FADER_HORIZONTAL_ORIENTATION
                    if is_pan else sysex.FADER_VERTICAL_ORIENTATION,
                    sysex.FADER_BIPOLAR if is_pan else sysex.FADER_UNIPOLAR),
                       partial(self._mixer.set_static_color_value, color),
                       self._clear_send_cache_of_button_fader_color_elements,
                       AddLayerMode(self._mixer, Layer(**control_dict)),
                       button_fader_layout_mode),
                behaviour=ReenterBehaviour(on_reenter=select_none_mode))

        add_fader_mode('volume', Rgb.GREEN.midi_value)
        add_fader_mode('pan', 0, True)
        add_fader_mode('send_a', Rgb.VIOLET.midi_value)
        add_fader_mode('send_b', Rgb.DARK_BLUE.midi_value)
        self._mixer_modes.add_mode(
            'stop', (self._session_layout_mode,
                     AddLayerMode(self._session,
                                  Layer(stop_track_clip_buttons=bottom_row))),
            behaviour=ReenterBehaviour(on_reenter=select_none_mode))
        self._mixer_modes.add_mode(
            'mute',
            (self._session_layout_mode,
             AddLayerMode(self._mixer, Layer(mute_buttons=bottom_row))),
            behaviour=ReenterBehaviour(on_reenter=select_none_mode))
        self._mixer_modes.add_mode(
            'solo',
            (self._session_layout_mode,
             AddLayerMode(self._mixer, Layer(solo_buttons=bottom_row))),
            behaviour=ReenterBehaviour(on_reenter=select_none_mode))
        self._mixer_modes.add_mode(
            'arm', (self._session_layout_mode,
                    AddLayerMode(self._mixer, Layer(arm_buttons=bottom_row))),
            behaviour=ReenterBehaviour(on_reenter=select_none_mode))
        self._mixer_modes.selected_mode = 'none'

    def _clear_send_cache_of_button_fader_color_elements(self):
        for element in self._elements.button_fader_color_elements_raw:
            element.clear_send_cache()

    def _create_session_modes(self):
        self._session_overview = SessionOverviewComponent(
            name='Session_Overview',
            is_enabled=False,
            session_ring=(self._session_ring),
            enable_skinning=True,
            layer=Layer(button_matrix='clip_launch_matrix'))
        self._session_modes = SessionModesComponent(
            name='Session_Modes',
            is_enabled=False,
            layer=Layer(
                cycle_mode_button='session_mode_button',
                mode_button_color_control='session_button_color_element'))
        self._session_modes.add_mode(
            'launch',
            AddLayerMode(self._session,
                         Layer(scene_launch_buttons='scene_launch_buttons')))
        self._session_modes.add_mode(
            'mixer', DelayMode(self._mixer_modes, SESSION_MODES_SWITCH_DELAY))
        (self._session_modes.add_mode(
            'overview',
            (self._session_layout_mode, self._session_overview,
             AddLayerMode(
                 self._session_navigation,
                 Layer(page_up_button='up_button',
                       page_down_button='down_button',
                       page_left_button='left_button',
                       page_right_button='right_button')),
             AddLayerMode(
                 self._background,
                 Layer(scene_launch_buttons='scene_launch_buttons')))), )
        self._session_modes.selected_mode = 'launch'

    def _create_note_modes(self):
        self._drum_group = DrumGroupComponent(
            name='Drum_Group',
            is_enabled=False,
            translation_channel=DRUM_FEEDBACK_CHANNEL,
            layer=Layer(matrix='drum_pads',
                        scroll_up_button='left_button',
                        scroll_down_button='right_button',
                        scroll_page_up_button='up_button',
                        scroll_page_down_button='down_button'))
        self._scale_pad_translator = ConfigurablePlayableComponent(
            SCALE_FEEDBACK_CHANNEL,
            name='Scale_Pads',
            is_enabled=False,
            layer=Layer(matrix='scale_pads'))
        self._note_modes = ModesComponent(name='Note_Modes', is_enabled=False)
        self._note_modes.add_mode(
            'scale', (self._scale_pad_translator,
                      AddLayerMode((self._background),
                                   layer=Layer(up_button='up_button',
                                               down_button='down_button',
                                               left_button='left_button',
                                               right_button='right_button'))))
        self._note_modes.add_mode('drum', self._drum_group)
        self._note_modes.selected_mode = 'scale'
        self._Launchpad_X__on_note_mode_changed.subject = self._note_modes

    def _create_main_modes(self):
        self._main_modes = ModesComponent(
            name='Main_Modes',
            is_enabled=False,
            layer=Layer(session_button='session_mode_button',
                        note_button='note_mode_button',
                        custom_button='custom_mode_button'))
        self._main_modes.add_mode('session', (self._session_modes),
                                  behaviour=(ImmediateBehaviour()))
        self._main_modes.add_mode('note', (self._note_modes),
                                  behaviour=(ImmediateBehaviour()))
        self._main_modes.add_mode('custom',
                                  None,
                                  behaviour=(ImmediateBehaviour()))
        self._main_modes.selected_mode = 'session'
        self._main_modes.set_enabled(True)
        self._Launchpad_X__on_main_mode_changed.subject = self._main_modes

    @listens('selected_mode')
    def __on_main_mode_changed(self, mode):
        self._recording_modes.selected_mode = 'track' if mode == 'note' else 'session'
        if mode == 'session':
            self._session_modes.revert_to_main_mode()
        self._update_controlled_track()
        self._elements.layout_switch.enquire_value()

    @listens('selected_mode')
    def __on_note_mode_changed(self, mode):
        if self._note_modes.is_enabled():
            self._update_controlled_track()

    @listens('value')
    def __on_layout_switch_value(self, value):
        self._last_layout_byte = value

    def _drum_group_changed(self):
        drum_group = self._drum_group_finder.drum_group
        drum_groud_valid = liveobj_valid(drum_group)
        self._drum_group.set_drum_group_device(drum_group)
        self._elements.note_layout_switch.send_value(
            sysex.DRUM_LAYOUT_BYTE if drum_groud_valid else sysex.
            SCALE_LAYOUT_BYTE)
        self._note_modes.selected_mode = 'drum' if drum_groud_valid else 'scale'

    def _is_instrument_mode(self):
        return self._main_modes.selected_mode == 'note'

    def _feedback_velocity_changed(self, feedback_velocity):
        self._elements.scale_feedback_switch.send_value(feedback_velocity)
예제 #2
0
class Launchpad(ControlSurface):
	u""" Script for Novation's Launchpad Controller """

	def __init__(self, c_instance):
		ControlSurface.__init__(self, c_instance)
		is_momentary = True
		self._suppress_send_midi = False
		with self.component_guard():
			self._skin = make_default_skin()
			#with inject(skin=const(self._skin)).everywhere():
			#	self._midimap = MidiMap()
			self._suggested_input_port = u'Launchpad'
			self._suggested_output_port = u'Launchpad'
			self._control_is_with_automap = False
			self._user_byte_write_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 16)
			self._user_byte_write_button.name = u'User_Byte_Button'
			self._user_byte_write_button.send_value(1)
			self._user_byte_write_button.add_value_listener(self._user_byte_value)
			self._wrote_user_byte = False
			self._challenge = Live.Application.get_random_int(0, 400000000) & 2139062143
			self._matrix = ButtonMatrixElement()
			self._matrix.name = u'Button_Matrix'
			#with inject(skin=const(self._skin)).everywhere():
			for row in range(8):
				button_row = []
				for column in range(8):
					button = ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, row * 16 + column, skin = self._skin)
					button.name = str(column) + u'_Clip_' + str(row) + u'_Button'
					button_row.append(button)

				self._matrix.add_row(tuple(button_row))
			self._top_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_CC_TYPE, 0, 104 + index, skin = self._skin) for index in range(8) ]
			self._side_buttons = [ ConfigurableButtonElement(is_momentary, MIDI_NOTE_TYPE, 0, SIDE_NOTES[index], skin = self._skin) for index in range(8) ]
			self._top_matrix = ButtonMatrixElement(name = u'Top_Button_Matrix', rows = [self._top_buttons])
			self._side_matrix = ButtonMatrixElement(name = u'Side_Button_Matrix', rows = [self._side_buttons])

			self._config_button = ButtonElement(is_momentary, MIDI_CC_TYPE, 0, 0, optimized_send_midi=False)
			self._config_button.add_value_listener(self._config_value)

			self._top_buttons[0].name = u'Bank_Select_Up_Button'
			self._top_buttons[1].name = u'Bank_Select_Down_Button'
			self._top_buttons[2].name = u'Bank_Select_Left_Button'
			self._top_buttons[3].name = u'Bank_Select_Right_Button'
			self._top_buttons[4].name = u'Session_Button'
			self._top_buttons[5].name = u'User1_Button'
			self._top_buttons[6].name = u'User2_Button'
			self._top_buttons[7].name = u'Mixer_Button'
			self._side_buttons[0].name = u'Vol_Button'
			self._side_buttons[1].name = u'Pan_Button'
			self._side_buttons[2].name = u'SndA_Button'
			self._side_buttons[3].name = u'SndB_Button'
			self._side_buttons[4].name = u'Stop_Button'
			self._side_buttons[5].name = u'Trk_On_Button'
			self._side_buttons[6].name = u'Solo_Button'
			self._side_buttons[7].name = u'Arm_Button'

			self._create_background()
			self._create_translations()
			self._create_session()
			self._create_mixer()
			self._create_modes()
	

	def _create_background(self):
		self._background = BackgroundComponent(name = 'Background')
		self._background.layer = Layer(priority = 5, matrix = self._matrix, side_buttons = self._side_matrix, top_buttons = self._top_matrix)
		self._background.set_enabled(True)
	

	def _create_translations(self):
		self._translations1 = TranslationComponent(name = 'User1Translation', translated_channel=2, should_enable=True, should_reset=True, is_enabled=False, layer=Layer(matrix = self._matrix, top_buttons = self._top_matrix.submatrix[:4,1], side_buttons = self._side_matrix))
		self._translations2 = TranslationComponent(name = 'User2Translation', translated_channel=3, should_enable=True, should_reset=True, is_enabled=False, layer=Layer(matrix = self._matrix, top_buttons = self._top_matrix.submatrix[:4,1], side_buttons = self._side_matrix))
	

	def _create_session(self):
		self._session_ring = SessionRingComponent(8,  8, name = u'Session_Ring')
		self._session = SpecialSessionComponent(session_ring = self._session_ring, name = u'Session', is_enabled = False, auto_name = True)
		self._session_navigation = SessionNavigationComponent(session_ring = self._session_ring, name = u'SessionNavigation', is_enabled = False)
		self._session_navigation._vertical_banking.scroll_up_button.color = 'Session.NavigationButtonOn'
		self._session_navigation._vertical_banking.scroll_up_button.disabled_color = 'Session.NavigationButtonOff'
		self._session_navigation._vertical_banking.scroll_down_button.color = 'Session.NavigationButtonOn'
		self._session_navigation._vertical_banking.scroll_down_button.disabled_color = 'Session.NavigationButtonOff'
		self._session_navigation._horizontal_banking.scroll_up_button.color = 'Session.NavigationButtonOn'
		self._session_navigation._horizontal_banking.scroll_up_button.disabled_color = 'Session.NavigationButtonOff'
		self._session_navigation._horizontal_banking.scroll_down_button.color = 'Session.NavigationButtonOn'
		self._session_navigation._horizontal_banking.scroll_down_button.disabled_color = 'Session.NavigationButtonOff'
		self._session_navigation._vertical_paginator.scroll_up_button.color = 'Session.PageNavigationButtonOn'
		self._session_navigation._vertical_paginator.scroll_up_button.disabled_color = 'Session.PageNavigationButtonOff'
		self._session_navigation._vertical_paginator.scroll_down_button.color = 'Session.PageNavigationButtonOn'
		self._session_navigation._vertical_paginator.scroll_down_button.disabled_color = 'Session.PageNavigationButtonOff'
		self._session_navigation._horizontal_paginator.scroll_up_button.color = 'Session.PageNavigationButtonOn'
		self._session_navigation._horizontal_paginator.scroll_up_button.disabled_color = 'Session.PageNavigationButtonOff'
		self._session_navigation._horizontal_paginator.scroll_down_button.color = 'Session.PageNavigationButtonOn'
		self._session_navigation._horizontal_paginator.scroll_down_button.disabled_color = 'Session.PageNavigationButtonOff'
		self._zooming = SessionOverviewComponent(session_ring = self._session_ring, enable_skinning = True, name = u'Session_Zooming', is_enabled = False)
		self._zooming.layer = Layer(button_matrix = self._matrix)

		self._session_navigation.nav_layer = AddLayerMode(self._session_navigation, Layer(up_button = self._top_buttons[0], down_button = self._top_buttons[1], left_button = self._top_buttons[2], right_button = self._top_buttons[3]))
		self._session_navigation.page_layer = AddLayerMode(self._session_navigation, Layer(page_up_button = self._top_buttons[0], page_down_button = self._top_buttons[1], page_left_button = self._top_buttons[2], page_right_button = self._top_buttons[3]))
		self._session.cliplaunch_layer = AddLayerMode(self._session, Layer(priority = 1, clip_launch_buttons = self._matrix, scene_launch_buttons = self._side_matrix))
		self._session.clipstop_layer = AddLayerMode(self._session, Layer(priority = 1, stop_all_clips_button = self._side_buttons[4], stop_track_clip_buttons = self._matrix.submatrix[:, 4:5]))

	def _create_mixer(self):
		self._mixer = SpecialMixerComponent(tracks_provider = self._session_ring, auto_name=True, is_enabled=True, invert_mute_feedback=True)
		self._mixer.name = u'Mixer'
		self._mixer.master_strip().name = u'Master_Channel_strip'
		self._mixer.selected_strip().name = u'Selected_Channel_strip'
		self._sliders = []
		self._slider_volume_modes = []
		self._slider_pan_modes = []
		self._slider_single_modes = []
		for column in range(8):
			self._mixer.channel_strip(column).name = u'Channel_Strip_' + str(column)
			self._sliders.append(PreciseButtonSliderElement(buttons = tuple([ self._matrix._orig_buttons[7-row][column]for row in range(8) ])))
			self._sliders[-1].name = u'Button_Slider_' + str(column)
		self._slider_matrix = ButtonMatrixElement(name = u'SliderMatrix', rows = [self._sliders])
		self._mixer.overview_layer = AddLayerMode(self._mixer, Layer(priority = 1, default_volume_buttons = self._matrix.submatrix[:, :1],
																					default_panning_buttons = self._matrix.submatrix[:, 1:2],
																					default_send1_buttons = self._matrix.submatrix[:, 2:3],
																					default_send2_buttons = self._matrix.submatrix[:, 3:4],
																					mute_buttons = self._matrix.submatrix[:, 5:6],
																					solo_buttons = self._matrix.submatrix[:, 6:7],
																					arm_buttons = self._matrix.submatrix[:, 7:8],
																					unarm_all_button = self._side_buttons[7],
																					unsolo_all_button = self._side_buttons[6],
																					unmute_all_button = self._side_buttons[5]))
		self._mixer.volume_layer = AddLayerMode(self._mixer, Layer(priority = 1, volume_controls = self._slider_matrix))
		self._mixer.pan_layer = AddLayerMode(self._mixer, Layer(priority = 1, pan_controls = self._slider_matrix))
		self._mixer.send1_layer = AddLayerMode(self._mixer, Layer(priority = 1, send_controls = self._slider_matrix))
		self._mixer.send2_layer = AddLayerMode(self._mixer, Layer(priority = 1, send_controls = self._slider_matrix))
	

	def _create_modes(self):
		self._session_modes = ModesComponent(name = u'SessionModes')
		self._session_modes.add_mode(u'Session', [self._session, self._session.cliplaunch_layer, self._session_navigation, self._session_navigation.nav_layer], cycle_mode_button_color = u'MainModes.SelectedOn')
		self._session_modes.add_mode(u'Zoom', [self._zooming, self._session_navigation, self._session_navigation.page_layer], cycle_mode_button_color = u'MainModes.SelectedPressed')
		self._session_modes.selected_mode = u'Session'
		self._session_modes.layer = Layer(priority = 1, cycle_mode_button = self._top_buttons[4])
		self._session_modes.set_enabled(False)

		self._mixer_modes = ModesComponent(name = u'MixerModes')
		self._mixer_modes.add_mode(u'Overview', [self._session_navigation, self._session_navigation.nav_layer, self._session, self._session.clipstop_layer, self._mixer, self._mixer.overview_layer])
		self._mixer_modes.add_mode(u'TrackVolume', [self._session_navigation, self._session_navigation.nav_layer, self._mixer, self._mixer.volume_layer, tuple([self.set_slider_volume_mode, self.set_slider_single_mode])])
		self._mixer_modes.add_mode(u'TrackPan', [self._session_navigation, self._session_navigation.nav_layer, self._mixer, self._mixer.pan_layer, tuple([self.set_slider_pan_mode, self.set_slider_single_mode])])
		self._mixer_modes.add_mode(u'TrackSend1', [self._session_navigation, self._session_navigation.nav_layer, self._mixer, self._mixer.send1_layer, SetAttributeMode(obj=self._mixer, attribute=u'send_index', value=0), tuple([self.set_slider_send_mode, self.set_slider_single_mode])])
		self._mixer_modes.add_mode(u'TrackSend2', [self._session_navigation, self._session_navigation.nav_layer, self._mixer, self._mixer.send2_layer, SetAttributeMode(obj=self._mixer, attribute=u'send_index', value=1), tuple([self.set_slider_send_mode, self.set_slider_single_mode])])
		for mode in self._mixer_modes._mode_list:
			if mode == 'Overview':
				self._mixer_modes.get_mode_button(mode).mode_selected_color = u'MainModes.SelectedOn'
				self._mixer_modes.get_mode_button(mode).mode_unselected_color = u'MainModes.SelectedOn'
			else:
				self._mixer_modes.get_mode_button(mode).mode_selected_color = u'SubModes.SelectedOn'
				self._mixer_modes.get_mode_button(mode).mode_unselected_color = u'SubModes.SelectedOff'
		self._mixer_modes.selected_mode = 'Overview'
		self._mixer_modes.layer = Layer(priority = 1, Overview_button = self._top_buttons[7], TrackVolume_button = self._side_buttons[0], TrackPan_button = self._side_buttons[1], TrackSend1_button = self._side_buttons[2], TrackSend2_button = self._side_buttons[3])
		self._mixer_modes.set_enabled(False)

		self._selector = ModesComponent(name = u'Selector')
		self._selector.add_mode(u'disabled', [self._background])
		self._selector.add_mode(u'Session', [self._session_modes])
		self._selector.add_mode(u'User1', [self._translations1])
		self._selector.add_mode(u'User2', [self._translations2])
		self._selector.add_mode(u'Mixer', [tuple([self.enable_sliders, self.disable_sliders]), self._mixer_modes])
		for mode in self._selector._mode_list:
			self._selector.get_mode_button(mode).mode_selected_color = u'MainModes.SelectedOn'
			self._selector.get_mode_button(mode).mode_unselected_color = u'MainModes.SelectedOff'
		self._selector.layer = Layer(priority = 1, Session_button = self._top_buttons[4], User1_button = self._top_buttons[5], User2_button = self._top_buttons[6], Mixer_button = self._top_buttons[7])
		self._selector.set_enabled(True)
		self._selector.selected_mode = u'disabled'

	def enable_sliders(self):
		for slider in self._sliders:
			slider._disabled = False
	

	def disable_sliders(self):
		for slider in self._sliders:
			slider._disabled = True
	

	def set_slider_single_mode(self):
		for slider in self._sliders:
			slider.set_mode(0)
	

	def set_slider_volume_mode(self):
		for slider in self._sliders:
			slider.set_mode(1)
	

	def set_slider_pan_mode(self):
		for slider in self._sliders:
			slider.set_mode(2)
	

	def set_slider_send_mode(self):
		for slider in self._sliders:
			slider.set_mode(1)
	

	def disconnect(self):
		self._suppress_send_midi = True
		for control in self.controls:
			if isinstance(control, ConfigurableButtonElement):
				control.remove_value_listener(self._button_value)

		self._selector = None
		self._user_byte_write_button.remove_value_listener(self._user_byte_value)
		self._config_button.remove_value_listener(self._config_value)
		super(Launchpad, self).disconnect()
		self._suppress_send_midi = False
		self._config_button.send_value(32)
		self._config_button.send_value(0)
		self._config_button = None
		self._user_byte_write_button.send_value(0)
		self._user_byte_write_button = None
	

	def refresh_state(self):
		super(Launchpad, self).refresh_state()
		self.schedule_message(5, self._update_hardware)
	

	def process_midi_bytes(self, midi_bytes, midi_processor):
		#def handle_sysex(self, midi_bytes):
		if len(midi_bytes) == 8:
			if midi_bytes[1:5] == (0, 32, 41, 6):
				response = long(midi_bytes[5])
				response += long(midi_bytes[6]) << 8
				if response == Live.Application.encrypt_challenge2(self._challenge):
					self._on_handshake_successful()
		else:
			super(Launchpad, self).process_midi_bytes(midi_bytes, midi_processor)
	

	def _on_handshake_successful(self):
		debug('Launchpad._on_handshake_successful')
		self._suppress_send_midi = False
		self.set_enabled(True)
		self._selector.selected_mode = 'Session'
		self._selector.set_enabled(True)
		debug(self._selector.selected_mode)
	
	"""
	def build_midi_map(self, midi_map_handle):
		ControlSurface.build_midi_map(self, midi_map_handle)
		#if self._selector.mode_index == 1:
		#	new_channel = self._selector.channel_for_current_mode()
		#	for note in DRUM_NOTES:
		#		self._translate_message(MIDI_NOTE_TYPE, note, 0, note, new_channel)
	"""
	"""
	def _send_midi(self, midi_bytes, optimized = None):
		sent_successfully = False
		if not self._suppress_send_midi:
			sent_successfully = ControlSurface._send_midi(self, midi_bytes, optimized=optimized)
		return sent_successfully
	"""

	def _update_hardware(self):
		self._suppress_send_midi = False
		self._wrote_user_byte = True
		self._user_byte_write_button.send_value(1)
		self._suppress_send_midi = True
		self.set_enabled(False)
		self._suppress_send_midi = False
		self._send_challenge()
	

	def _send_challenge(self):
		for index in range(4):
			challenge_byte = self._challenge >> 8 * index & 127
			self._send_midi((176, 17 + index, challenge_byte))
	

	def _user_byte_value(self, value):
		if not value in range(128):
			raise AssertionError
			enabled = self._wrote_user_byte or value == 1
			self._control_is_with_automap = not enabled
			self._suppress_send_midi = self._control_is_with_automap
			if not self._control_is_with_automap:
				for control in self.controls:
					if isinstance(control, ConfigurableButtonElement):
						control.set_force_next_value()

			#self._selector.set_mode(0)
			self._selector.selected_mode = u'Session'
			self.set_enabled(enabled)
			self._suppress_send_midi = False
		else:
			self._wrote_user_byte = False
	

	def _button_value(self, value):
		debug('_button_value', value, self._selector.selected_mode, self._selector.is_enabled())
		#self._top_buttons[0].send_value(127)
		#assert value in range(128)
	

	def _config_value(self, value):
		assert value in range(128)
	
	"""