class FixedLengthSettingComponent(Component): length_option_buttons = control_list(RadioButtonControl, checked_color='Option.Selected', unchecked_color='Option.Unselected', control_count=len(LENGTH_OPTIONS)) fixed_length_toggle_button = ToggleButtonControl( toggled_color='Option.On', untoggled_color='Option.Off') label_display_line = TextDisplayControl(LENGTH_LABELS) option_display_line = TextDisplayControl(LENGTH_OPTION_NAMES) def __init__(self, fixed_length_setting=None, *a, **k): raise fixed_length_setting is not None or AssertionError super(FixedLengthSettingComponent, self).__init__(*a, **k) self._fixed_length_setting = fixed_length_setting self.length_option_buttons.connect_property(fixed_length_setting, 'selected_index') self.fixed_length_toggle_button.connect_property( fixed_length_setting, 'enabled') self.__on_setting_selected_index_changes.subject = fixed_length_setting self.__on_setting_selected_index_changes( fixed_length_setting.selected_index) @listens('selected_index') def __on_setting_selected_index_changes(self, index): self._update_option_display() def _update_option_display(self): for index, option_name in enumerate(LENGTH_OPTION_NAMES): prefix = consts.CHAR_SELECT if index == self._fixed_length_setting.selected_index else ' ' self.option_display_line[index] = prefix + option_name
class QuantizationSettingsComponent(QuantizationSettingsComponentBase): display_line1 = TextDisplayControl(segments=(u'', u'', u'', u'', u'', u'', u'', u'')) display_line2 = TextDisplayControl(segments=(u'Swing', u'Quantize', u'Quantize', u'', u'', u'', u'', u'Record')) display_line3 = TextDisplayControl(segments=(u'Amount', u'To', u'Amount', u'', u'', u'', u'', u'Quantize')) display_line4 = TextDisplayControl(segments=(u'', u'', u'', u'', u'', u'', u'', u'')) def __init__(self, *a, **k): super(QuantizationSettingsComponent, self).__init__(*a, **k) self._update_swing_amount_display() self._update_quantize_to_display() self._update_quantize_amount_display() self._update_record_quantization_display() self.__on_swing_amount_changed.subject = self.song self.__on_record_quantization_index_changed.subject = self self.__on_record_quantization_enabled_changed.subject = self self.__on_quantize_to_index_changed.subject = self self.__on_quantize_amount_changed.subject = self def _update_swing_amount_display(self): self.display_line1[0] = str(int(self.song.swing_amount * 200.0)) + '%' def _update_record_quantization_display(self): record_quantization_on = self.record_quantization_toggle_button.is_toggled self.display_line1[-1] = QUANTIZATION_NAMES[ self.record_quantization_index] self.display_line4[ -1] = '[ On ]' if record_quantization_on else '[ Off ]' def _update_quantize_to_display(self): self.display_line1[1] = QUANTIZATION_NAMES[self.quantize_to_index] def _update_quantize_amount_display(self): self.display_line1[2] = quantize_amount_to_string(self.quantize_amount) @listens('quantize_to_index') def __on_quantize_to_index_changed(self, _): self._update_quantize_to_display() @listens('quantize_amount') def __on_quantize_amount_changed(self, _): self._update_quantize_amount_display() @listens('swing_amount') def __on_swing_amount_changed(self): self._update_swing_amount_display() @listens('record_quantization_index') def __on_record_quantization_index_changed(self, _): self._update_record_quantization_display() @listens('record_quantization_enabled') def __on_record_quantization_enabled_changed(self, _): self._update_record_quantization_display()
class DisplayingSkinableModesComponent(SkinableModesComponent): mode_display = TextDisplayControl(segments=(u'', ) * MAX_MODE_NUMBER) mode_color_fields = control_list(ColorSysexControl, MAX_MODE_NUMBER) mode_selection_fields = control_list(BinaryControl, MAX_MODE_NUMBER) selected_mode_color_field = ColorSysexControl() def __init__(self, *a, **k): super(DisplayingSkinableModesComponent, self).__init__(*a, **k) self.__on_selected_mode_changed.subject = self def add_mode_button_control(self, mode_name, behaviour): super(DisplayingSkinableModesComponent, self).add_mode_button_control(mode_name, behaviour) self.mode_display[len(self._mode_list) - 1] = to_camel_case_name(mode_name, separator=' ') self.mode_color_fields[(len(self._mode_list) - 1)].color = 'Mode.' + to_camel_case_name(mode_name) + '.On' @listens('selected_mode') def __on_selected_mode_changed(self, _): self._update_selection_fields() self._update_selected_mode_color_field() def _update_selection_fields(self): for field, mode in izip(self.mode_selection_fields, self._mode_list): field.is_on = mode == self.selected_mode def _update_selected_mode_color_field(self): self.selected_mode_color_field.color = ('Mode.{}.On').format(to_camel_case_name(self.selected_mode)) if self.selected_mode else 'DefaultButton.Disabled'
class DisplayingNavigatableModesComponent(NavigatableModesComponent): display_1 = TextDisplayControl(segments=(u'', )) display_2 = TextDisplayControl(segments=(u'', )) color_field_1 = ColorSysexControl() color_field_2 = ColorSysexControl() def _update_selected_mode(self): super(DisplayingNavigatableModesComponent, self)._update_selected_mode() self._update_mode_displays() def _update_mode_displays(self): if self.selected_mode: for display, color_field, name in izip_longest((self.display_1, self.display_2), ( self.color_field_1, self.color_field_2), self.selected_mode.split('_')[:2]): display[0] = name.capitalize() if name else '' color_field.color = ('Mode.{}.On').format(name.capitalize()) if name else 'DefaultButton.Disabled'
class DeviceComponent(DeviceComponentBase): prev_bank_button = ButtonControl(color=u'Action.Off', pressed_color=u'Action.On') next_bank_button = ButtonControl(color=u'Action.Off', pressed_color=u'Action.On') bank_name_display = TextDisplayControl() device_lock_button = ToggleButtonControl() def __init__(self, toggle_lock=None, *a, **k): super(DeviceComponent, self).__init__(*a, **k) assert toggle_lock is not None self._toggle_lock = toggle_lock self.__on_is_locked_to_device_changed.subject = self._device_provider self.__on_is_locked_to_device_changed() @prev_bank_button.pressed def prev_bank_button(self, _): self._scroll_bank(-1) @next_bank_button.pressed def next_bank_button(self, _): self._scroll_bank(1) @device_lock_button.toggled def device_lock_button(self, toggled, _): self._toggle_lock() self._update_device_lock_button() def _create_parameter_info(self, parameter, name): return ParameterInfo(parameter=parameter, name=name, default_encoder_sensitivity=1.0) def _set_bank_index(self, index): super(DeviceComponent, self)._set_bank_index(index) self._update_bank_name_display() def _scroll_bank(self, offset): bank = self._bank if bank: new_index = clamp(bank.index + offset, 0, bank.bank_count() - 1) self._device_bank_registry.set_device_bank(self.device(), new_index) def _update_bank_name_display(self): bank_name = u'' device = self.device() if liveobj_valid(device): device_bank_names = self._banking_info.device_bank_names(device) if device_bank_names: bank_name = device_bank_names[ self._device_bank_registry.get_device_bank(device)] self.bank_name_display[0] = bank_name def _update_device_lock_button(self): self.device_lock_button.is_toggled = self._device_provider.is_locked_to_device @listens(u'is_locked_to_device') def __on_is_locked_to_device_changed(self): self._update_device_lock_button()
class SceneComponent(SceneComponentBase): clip_slot_component_type = ClipSlotComponent scene_name_display = TextDisplayControl(segments=('', )) scene_color_control = ButtonControl() scene_selection_control = SendValueControl() force_launch_button = ButtonControl(color='Session.SceneOff', pressed_color='Session.SceneOn') _default_scene_color = 'DefaultButton.Off' def __init__(self, *a, **k): (super(SceneComponent, self).__init__)(*a, **k) @force_launch_button.pressed def force_launch_button(self, value): self._on_launch_button_pressed() @force_launch_button.released def force_launch_button(self, value): self._on_launch_button_released() def set_scene(self, scene): super(SceneComponent, self).set_scene(scene) self._SceneComponent__on_scene_name_changed.subject = self._scene self._SceneComponent__on_scene_name_changed() self._SceneComponent__on_scene_color_changed.subject = self._scene self._SceneComponent__on_scene_color_changed() self._SceneComponent__on_selected_scene_changed.subject = self.song.view self._SceneComponent__on_selected_scene_changed() @listens('name') def __on_scene_name_changed(self): self._update_scene_name_display() @listens('color_index') def __on_scene_color_changed(self): self._update_scene_color_control() @listens('selected_scene') def __on_selected_scene_changed(self): self.scene_selection_control.value = int(self.song.view.selected_scene == self._scene) def _update_scene_color_control(self): color = 'DefaultButton.Off' scene = self._scene if liveobj_valid(scene): color = scene.color_index + LIVE_COLOR_TABLE_INDEX_OFFSET if scene.color_index != None else self._default_scene_color self.scene_color_control.color = color def _update_scene_name_display(self): scene = self._scene self.scene_name_display[0] = scene.name if liveobj_valid(scene) else '' def _update_launch_button(self): value_to_send = self._no_scene_color if liveobj_valid(self._scene): value_to_send = self._scene_color if self._scene.is_triggered: value_to_send = self._triggered_color self.launch_button.color = value_to_send
class ScrollingDeviceNavigationComponent(DeviceNavigationComponent): prev_device_button = ButtonControl(color=b'Action.Off', pressed_color=b'Action.On') next_device_button = ButtonControl(color=b'Action.Off', pressed_color=b'Action.On') num_devices_control = SendValueControl() device_index_control = SendValueControl() device_name_display = TextDisplayControl() def __init__(self, *a, **k): super(ScrollingDeviceNavigationComponent, self).__init__(item_provider=ScrollableDeviceChain(), *a, **k) @prev_device_button.pressed def prev_device_button(self, value): self.item_provider.scroll_left() @next_device_button.pressed def next_device_button(self, value): self.item_provider.scroll_right() def _on_selection_changed(self): selected_item = self.item_provider.selected_item self._select_item(selected_item) self._update_device_index_control() def _on_items_changed(self): self.num_devices_control.value = len(self.item_provider.items) self._update_device_index_control() def _update_device(self): device = self._device_component.device() live_device = getattr(device, b'proxied_object', device) self._update_item_provider( live_device if liveobj_valid(live_device) else None) self.__on_appointed_device_name_changed.subject = device self.__on_appointed_device_name_changed() return @listens(b'name') def __on_appointed_device_name_changed(self): self._update_device_name_display() def _update_device_index_control(self): selected_index = self.item_provider.selected_index if selected_index is not None: self.device_index_control.value = selected_index return def _update_device_name_display(self): device = self._device_component.device() self.device_name_display[0] = device.name if liveobj_valid( device) else b'No Device'
class ChannelStripComponent(ChannelStripComponentBase): track_name_display = TextDisplayControl(' ') def set_track_name_display(self, display): self.track_name_display.set_control_element(display) self._update_track_name_display() def set_track(self, track): super(ChannelStripComponent, self).set_track(track) self._update_track_name_display() def _update_track_name_display(self): track = self._track self.track_name_display[0] = track.name if liveobj_valid(track) else ''
class MixerComponent(MixerComponentBase): send_up_button = ButtonControl(color='Mixer.Send') send_down_button = ButtonControl(color='Mixer.Send') pan_value_display = ConfigurableTextDisplayControl(segments=(u'', ) * SESSION_WIDTH) send_value_display = ConfigurableTextDisplayControl(segments=(u'', ) * SESSION_WIDTH) mixer_display = TextDisplayControl(segments=(u'Mixer', )) pan_display = TextDisplayControl(segments=(u'Pan', )) send_index_display = ConfigurableTextDisplayControl(segments=(u'', )) send_encoder_color_fields = control_list(ColorSysexControl, SESSION_WIDTH) selected_track_color_field = ColorSysexControl() def __init__(self, *a, **k): super(MixerComponent, self).__init__( channel_strip_component_type=ChannelStripComponent, *a, **k) self.__on_selected_track_changed.subject = self.song.view self.__on_selected_track_changed() self.pan_value_display.set_data_sources([ strip.pan_value_display_data_source for strip in self._channel_strips ]) self.on_send_index_changed() @property def controlled_tracks(self): return self._track_assigner.tracks(self._provider) @property def controlled_sends(self): tracks = self.controlled_tracks controlled_sends = [None] * len(tracks) send_index = self.send_index for index, track in enumerate(tracks): if liveobj_valid(track): sends = track.mixer_device.sends if send_index != None and send_index < len(sends): controlled_sends[index] = sends[send_index] return controlled_sends @send_up_button.pressed def send_up_button(self, _): self.send_index -= 1 @send_down_button.pressed def send_down_button(self, _): self.send_index += 1 def set_track_names_display(self, display): if display: display.set_data_sources([ strip.track_name_data_source() for strip in self._channel_strips ]) def set_selected_track_name_display(self, display): if display: display.set_data_sources( [self._selected_strip.track_name_data_source()]) def set_pan_encoder_color_fields(self, controls): for strip, control in izip_longest(self._channel_strips, controls or []): strip.pan_encoder_color_field.set_control_element(control) def set_track_color_fields(self, controls): for strip, control in izip_longest(self._channel_strips, controls or []): strip.track_color_field.set_control_element(control) def set_track_selection_fields(self, controls): for strip, control in izip_longest(self._channel_strips, controls or []): strip.track_selection_field.set_control_element(control) def set_volume_leds(self, controls): for strip, control in izip_longest(self._channel_strips, controls or []): strip.volume_led.set_control_element(control) def set_monitoring_state_buttons(self, controls): for strip, control in izip_longest(self._channel_strips, controls or []): strip.monitoring_state_button.set_control_element(control) def on_send_index_changed(self): self._update_send_value_subjects() self._update_send_navigation_buttons() self._update_send_index_display() self._update_send_value_display() def on_num_sends_changed(self): self._update_send_navigation_buttons() self._update_send_value_display() def _update_send_navigation_buttons(self): send_index = self.send_index self.send_up_button.enabled = send_index != None and send_index > 0 self.send_down_button.enabled = send_index != None and send_index < self.num_sends - 1 return def _update_send_index_display(self): send_index = self.send_index self.send_index_display[0] = 'Send ' + chr( send_index + 65) if send_index != None else '' return def _update_send_value_display(self): for index, send in enumerate(self.controlled_sends): self.send_value_display[index] = str(send) if send else '' def _update_send_encoder_color_fields(self): for index, send in enumerate(self.controlled_sends): self.send_encoder_color_fields[ index].color = 'Mixer.Send' if send else 'DefaultButton.Disabled' def _update_selected_track_color_field(self): self.selected_track_color_field.color = color_for_track( self.song.view.selected_track) def _update_send_value_subjects(self): self.__on_send_value_changed.replace_subjects(self.controlled_sends) @listens('selected_track') def __on_selected_track_changed(self): self._update_selected_strip() self._update_selected_track_color_field() self.__on_selected_track_color_changed.subject = self.song.view.selected_track @listens('color') def __on_selected_track_color_changed(self): self._update_selected_track_color_field() @listens_group('value') def __on_send_value_changed(self, _): self._update_send_value_display() def _reassign_tracks(self): super(MixerComponent, self)._reassign_tracks() self._update_send_value_subjects() self._update_send_value_display() self._update_send_encoder_color_fields()
class MessageComponent(Component): display = TextDisplayControl(segments=(u'', ) * NUM_MESSAGE_SEGMENTS) def __call__(self, *messages): for index, message in izip(xrange(NUM_MESSAGE_SEGMENTS), messages): self.display[index] = message if message else ''
class ClipSlotComponent(ClipSlotComponentBase): clip_name_display = TextDisplayControl(segments=(u'', )) clip_color_control = ButtonControl() def __init__(self, *a, **k): super(ClipSlotComponent, self).__init__(*a, **k) self._empty_slot_with_stop_button_color = 'Session.ClipEmptyWithStopButton' view = self.song.view self.__on_selected_scene_changed.subject = view self.__on_selected_track_changed.subject = view self.__on_selected_track_changed() @property def select_button_is_pressed(self): return self._select_button is not None and self._select_button.is_pressed( ) def set_select_button(self, button): super(ClipSlotComponent, self).set_select_button(button) self.__on_select_button_value.subject = button @listens('value') def __on_select_button_value(self, value): self._update_clip_color_control() def _update_clip_property_slots(self): super(ClipSlotComponent, self)._update_clip_property_slots() clip = self._clip_slot.clip if liveobj_valid(self._clip_slot) else None self.__on_clip_name_changed.subject = clip self.__on_clip_name_changed() return def _update_launch_button_color(self): super(ClipSlotComponent, self)._update_launch_button_color() self._update_clip_color_control() def _feedback_value(self, track, slot_or_clip): if slot_or_clip.is_triggered: if slot_or_clip.will_record_on_start: return self._triggered_to_record_color return self._triggered_to_play_color else: if slot_or_clip.is_playing: if slot_or_clip.is_recording: return self._recording_color return self._started_value if slot_or_clip.color != None or getattr( slot_or_clip, 'controls_other_clips', True): return self._stopped_value if self._track_is_armed(track) and self._clip_slot.has_stop_button: return self._record_button_color if self._clip_slot.has_stop_button: return self._empty_slot_with_stop_button_color return self._empty_slot_color @listens('name') def __on_clip_name_changed(self): self._update_clip_name_display() @listens('selected_scene') def __on_selected_scene_changed(self): self._update_clip_color_control() @listens('selected_track') def __on_selected_track_changed(self): self._update_clip_color_control() def _update_clip_name_display(self): clip_slot = self._clip_slot self.clip_name_display[0] = clip_slot.clip.name if liveobj_valid( clip_slot) and self.has_clip() else '' def _update_clip_color_control(self): color_to_send = 'DefaultButton.Off' clip_slot = self._clip_slot if liveobj_valid(clip_slot): if self.has_clip(): color_to_send = 'Session.ClipSelected' if self.select_button_is_pressed and clip_slot == self.song.view.highlighted_clip_slot else clip_slot.clip.color_index + LIVE_COLOR_TABLE_INDEX_OFFSET elif clip_slot.color != None: color_to_send = clip_slot.color_index + LIVE_COLOR_TABLE_INDEX_OFFSET self.clip_color_control.color = color_to_send return
class ChannelStripComponent(ChannelStripComponentBase): track_type_control = SendValueControl() oled_display_style_control = SendValueControl() arm_color_control = ButtonControl() mute_color_control = ButtonControl() solo_color_control = ButtonControl() output_meter_left_control = SendValueControl() output_meter_right_control = SendValueControl() track_color_control = ButtonControl() physical_track_color_control = ButtonControl() volume_touch_control = ButtonControl() solo_mute_button = ButtonControl() crossfade_assign_control = SendReceiveValueControl() assign_a_button = ButtonControl() assign_b_button = ButtonControl() assign_a_color_control = ButtonControl() assign_b_color_control = ButtonControl() volume_value_display = TextDisplayControl() pan_value_display = TextDisplayControl() send_value_displays = control_list(TextDisplayControl, MAX_NUM_SENDS) mpc_mute_button = ButtonControl() def __init__(self, *a, **k): self._oled_display_track_name_data_source = DisplayDataSource() self._oled_display_volume_value_data_source = DisplayDataSource() self._track_name_or_volume_value_display = None self._drum_group_finder = None super(ChannelStripComponent, self).__init__(*a, **k) self.__on_selected_track_changed.subject = self.song.view self.__on_selected_track_changed() self._drum_group_finder = self.register_disconnectable(PercussionInstrumentFinder(device_parent=self.track)) def set_track(self, track): super(ChannelStripComponent, self).set_track(track) self._drum_group_finder.device_parent = track self.__on_drum_group_found.subject = self._drum_group_finder self.__on_drum_group_found() self._update_listeners() self._update_controls() def set_volume_control(self, control): super(ChannelStripComponent, self).set_volume_control(control) self.volume_touch_control.set_control_element(control.touch_element if control else None) def set_track_name_display(self, display): if display: display.set_data_sources([self.track_name_data_source()]) def set_track_name_or_volume_value_display(self, display): self._track_name_or_volume_value_display = display self._update_track_name_or_volume_value_display() def set_send_value_displays(self, displays): self.send_value_displays.set_control_element(displays) @volume_touch_control.pressed def volume_touch_control(self, _): self._update_track_name_or_volume_value_display() @volume_touch_control.released def volume_touch_control(self, _): self._update_track_name_or_volume_value_display() @crossfade_assign_control.value def crossfade_assign_control(self, value, _): value_to_set = force_to_live_crossfade_assign_value(value) if value_to_set < len(LIVE_CROSSFADE_ASSIGN_VALUES) and self._track_has_visible_crossfade_assignment_buttons(): self.track.mixer_device.crossfade_assign = value_to_set @assign_a_button.pressed def assign_a_button(self, _): self._toggle_crossfade_assign(force_to_live_crossfade_assign_value(CROSSFADE_ASSIGN_A)) @assign_b_button.pressed def assign_b_button(self, _): self._toggle_crossfade_assign(force_to_live_crossfade_assign_value(CROSSFADE_ASSIGN_B)) @mpc_mute_button.pressed def mpc_mute_button(self, _): track = self.track if liveobj_valid(track) and track != self.song.master_track: track.mute = not track.mute def _on_select_button_pressed_delayed(self, _): if self.track.is_foldable: self.track.fold_state = not self.track.fold_state @listens(u'has_audio_output') def __on_has_audio_output_changed(self): self._update_output_meter_listeners() self._update_track_type_control() self._update_oled_display_style_control() self._update_crossfade_assignment_control() self._update_crossfade_assign_color_controls() def _update_output_meter_listeners(self): track = self.track subject = track if liveobj_valid(track) and track.has_audio_output else None self.__on_output_meter_left_changed.subject = subject self.__on_output_meter_right_changed.subject = subject if liveobj_valid(subject): self.__on_output_meter_left_changed() self.__on_output_meter_right_changed() else: self._reset_output_meter_controls() def _on_arm_changed(self): super(ChannelStripComponent, self)._on_arm_changed() self._update_arm_color_control() def _on_mute_changed(self): self._update_mute_color_controls() def _on_solo_changed(self): super(ChannelStripComponent, self)._on_solo_changed() self._update_solo_color_control() def _on_cf_assign_changed(self): super(ChannelStripComponent, self)._on_cf_assign_changed() self._update_crossfade_assignment_control() self._update_crossfade_assign_color_controls() def _on_sends_changed(self): super(ChannelStripComponent, self)._on_sends_changed() self._update_listeners() self._update_controls() @listens(u'output_meter_left') def __on_output_meter_left_changed(self): self.output_meter_left_control.value = meter_value_to_midi_value(self.track.output_meter_left) @listens(u'output_meter_right') def __on_output_meter_right_changed(self): self.output_meter_right_control.value = meter_value_to_midi_value(self.track.output_meter_right) @listens(u'color') def __on_track_color_changed(self): self._update_track_color_control() @listens(u'value') def __on_volume_changed(self): track = self.track value_string = format_volume_value_string(str(track.mixer_device.volume) if liveobj_valid(track) and track.has_audio_output else u'') self._oled_display_volume_value_data_source.set_display_string(value_string) self.volume_value_display[0] = value_string @listens(u'value') def __on_pan_changed(self): track = self.track self.pan_value_display[0] = str(track.mixer_device.panning) if liveobj_valid(track) and track.has_audio_output else u'' @listens_group(u'value') def __on_send_value_changed(self, send_index): self._update_send_value_display(send_index) @listens(u'selected_track') def __on_selected_track_changed(self): self._update_select_button() self._update_track_color_control() @listens(u'muted_via_solo') def __on_muted_via_solo_changed(self): self.solo_mute_button.color = u'DefaultButton.On' if liveobj_valid(self.track) and self.track != self.song.master_track and self.track.muted_via_solo else u'DefaultButton.Off' @listens(u'instrument') def __on_drum_group_found(self): self._update_track_type_control() def _update_listeners(self): track = self.track self.__on_has_audio_output_changed.subject = track self.__on_has_audio_output_changed() self.__on_track_color_changed.subject = track self.__on_track_color_changed() self.__on_volume_changed.subject = track.mixer_device.volume if liveobj_valid(track) else None self.__on_volume_changed() self.__on_muted_via_solo_changed.subject = track self.__on_muted_via_solo_changed() self.__on_pan_changed.subject = track.mixer_device.panning if liveobj_valid(track) else None self.__on_pan_changed() track = self.track self.__on_send_value_changed.replace_subjects(track.mixer_device.sends if liveobj_valid(track) else [], count()) def _update_controls(self): self._update_track_type_control() self._update_oled_display_style_control() for send_index in range(MAX_NUM_SENDS): self._update_send_value_display(send_index) def _update_track_type_control(self): track_type = NO_TRACK track = self.track if liveobj_valid(track): if track == self.song.master_track: track_type = MASTER_TRACK elif track in self.song.return_tracks: track_type = RETURN_TRACK elif track.is_foldable: track_type = GROUP_TRACK elif track.has_midi_input: if self._drum_group_finder is not None and liveobj_valid(self._drum_group_finder.drum_group): track_type = DRUM_TRACK elif track.has_audio_output: track_type = MELODIC_TRACK else: track_type = EMPTY_MIDI_TRACK elif track.has_audio_output: track_type = AUDIO_TRACK self.track_type_control.value = track_type def _update_crossfade_assignment_control(self): self.crossfade_assign_control.value = LIVE_CROSSFADE_ASSIGN_VALUES[self.track.mixer_device.crossfade_assign] if self._track_has_visible_crossfade_assignment_buttons() else CROSSFADE_ASSIGN_OFF def _update_crossfade_assign_color_controls(self): off_color = u'DefaultButton.Off' track = self.track assign_a_control_color = off_color assign_b_control_color = off_color if self._track_has_visible_crossfade_assignment_buttons(): mixer_device = track.mixer_device assign_a_control_color = u'Mixer.CrossfadeAssignA' if mixer_device.crossfade_assign == force_to_live_crossfade_assign_value(CROSSFADE_ASSIGN_A) else off_color assign_b_control_color = u'Mixer.CrossfadeAssignB' if mixer_device.crossfade_assign == force_to_live_crossfade_assign_value(CROSSFADE_ASSIGN_B) else off_color self.assign_a_color_control.color = assign_a_control_color self.assign_b_color_control.color = assign_b_control_color def _update_track_name_data_source(self): super(ChannelStripComponent, self)._update_track_name_data_source() self._oled_display_track_name_data_source.set_display_string(self._track.name if liveobj_valid(self._track) else u' - ') def _update_arm_color_control(self): color = u'Mixer.ArmOff' track = self.track if liveobj_valid(track) and track in self.song.tracks and track.can_be_armed and track.arm: color = u'Mixer.ArmOn' self.arm_color_control.color = color def _update_mute_color_controls(self): mute_color_control_color = u'Mixer.MuteOff' mute_button_color = u'Mixer.MuteOn' track = self.track if liveobj_valid(track) and (track == self.song.master_track or not track.mute): mute_color_control_color = u'Mixer.MuteOn' mute_button_color = u'Mixer.MuteOff' self.mute_color_control.color = mute_color_control_color self.mpc_mute_button.color = mute_color_control_color if self._mute_button: self._mute_button.set_light(mute_button_color) def _update_solo_color_control(self): color = u'Mixer.SoloOff' track = self.track if liveobj_valid(track) and track != self.song.master_track and track.solo: color = u'Mixer.SoloOn' self.solo_color_control.color = color def _update_track_color_control(self): color_to_send = u'DefaultButton.Off' selected_color_to_send = None track = self.track if liveobj_valid(track) and track.color_index != None: color_to_send = track.color_index + LIVE_COLOR_TABLE_INDEX_OFFSET if track == self.song.view.selected_track: selected_color_to_send = u'DefaultButton.On' self.track_color_control.color = color_to_send self.physical_track_color_control.color = selected_color_to_send or color_to_send def _update_oled_display_style_control(self): value_to_send = OLED_DISPLAY_OFF track = self.track if liveobj_valid(track) and track.has_audio_output: value_to_send = OLED_DISPLAY_UNIPOLAR self.oled_display_style_control.value = value_to_send def _update_track_name_or_volume_value_display(self): if self._track_name_or_volume_value_display: self._track_name_or_volume_value_display.set_data_sources([self._oled_display_volume_value_data_source if self.volume_touch_control.is_pressed else self._oled_display_track_name_data_source]) def _update_send_value_display(self, index): if index < MAX_NUM_SENDS: value_to_send = u'' track = self.track if liveobj_valid(track): sends = track.mixer_device.sends if index < len(sends): value_to_send = str(sends[index]) self.send_value_displays[index][0] = value_to_send def _reset_output_meter_controls(self): self.output_meter_left_control.value = 0 self.output_meter_right_control.value = 0 def _track_has_visible_crossfade_assignment_buttons(self): track = self.track return liveobj_valid(track) and track != self.song.master_track and track.has_audio_output def _toggle_crossfade_assign(self, value): track = self.track if self._track_has_visible_crossfade_assignment_buttons(): mixer_device = track.mixer_device mixer_device.crossfade_assign = force_to_live_crossfade_assign_value(CROSSFADE_ASSIGN_OFF) if mixer_device.crossfade_assign == value else value
class TransportComponent(TransportComponentBase): tempo_control = InputControl() tempo_display = TextDisplayControl() play_button = ButtonControl() stop_button = ButtonControl() shift_button = ButtonControl() tui_metronome_button = ToggleButtonControl() metronome_color_control = ButtonControl() follow_song_button = ButtonControl() clip_trigger_quantization_control = SendReceiveValueControl() clip_trigger_quantization_button_row = control_list( RadioButtonControl, len(RADIO_BUTTON_GROUP_QUANTIZATION_VALUES)) clip_trigger_quantization_color_controls = control_list( ColorSysexControl, len(RADIO_BUTTON_GROUP_QUANTIZATION_VALUES)) jump_backward_button = ButtonControl() jump_forward_button = ButtonControl() loop_start_display = TextDisplayControl() loop_length_display = TextDisplayControl() arrangement_position_display = TextDisplayControl() arrangement_position_control = EncoderControl() loop_start_control = EncoderControl() loop_length_control = EncoderControl() tui_arrangement_record_button = ToggleButtonControl() def __init__(self, *a, **k): super(TransportComponent, self).__init__(*a, **k) song = self.song self._cached_num_beats_in_bar = num_beats_in_bar(song) self.__on_song_tempo_changed.subject = song self.__on_song_tempo_changed() self.__on_metronome_changed.subject = song self.__on_metronome_changed() self.__on_clip_trigger_quantization_changed.subject = song self.__on_clip_trigger_quantization_changed() self.__on_follow_song_changed.subject = song.view self.__on_follow_song_changed() self.__on_signature_numerator_changed.subject = song self.__on_signature_denominator_changed.subject = song self.__on_loop_start_changed.subject = song self.__on_loop_start_changed() self.__on_loop_length_changed.subject = song self.__on_loop_length_changed() self.__on_arrangement_position_changed.subject = song self.__on_arrangement_position_changed() self.__on_record_mode_changed.subject = song self.__on_record_mode_changed() def set_tempo_control(self, control): self.tempo_control.set_control_element(control) @listens(b'tempo') def __on_song_tempo_changed(self): self.tempo_display[0] = (b'{0:.2f}').format(self.song.tempo) @tempo_control.value def tempo_control(self, value, _): self.song.tempo = clamp(float((b'').join(imap(chr, value[2:]))), TEMPO_MIN, TEMPO_MAX) @play_button.pressed def play_button(self, _): song = self.song song.is_playing = not song.is_playing @stop_button.pressed def stop_button(self, _): self.song.stop_playing() if self.shift_button.is_pressed: self.song.current_song_time = 0.0 @tui_metronome_button.toggled def tui_metronome_button(self, toggled, _): self.song.metronome = toggled @follow_song_button.pressed def follow_song_button(self, _): view = self.song.view view.follow_song = not view.follow_song @clip_trigger_quantization_control.value def clip_trigger_quantization_control(self, value, _): if is_valid_launch_quantize_value(value): self.song.clip_trigger_quantization = value @clip_trigger_quantization_button_row.checked def clip_trigger_quantization_button_row(self, button): self.song.clip_trigger_quantization = RADIO_BUTTON_GROUP_QUANTIZATION_VALUES[ button.index] def _apply_value_to_arrangement_property(self, property_name, value): factor = 0.25 if self.shift_button.is_pressed else 1.0 delta = factor * sign(value) old_value = getattr(self.song, property_name) setattr(self.song, property_name, max(0.0, old_value + delta)) @arrangement_position_control.value def arrangement_position_control(self, value, _): self._apply_value_to_arrangement_property(b'current_song_time', value) @loop_start_control.value def loop_start_control(self, value, _): self._apply_value_to_arrangement_property(b'loop_start', value) @loop_length_control.value def loop_length_control(self, value, _): self._apply_value_to_arrangement_property(b'loop_length', value) @jump_backward_button.pressed def jump_backward_button(self, _): self.song.jump_by(self._cached_num_beats_in_bar * -1) @jump_forward_button.pressed def jump_forward_button(self, _): self.song.jump_by(self._cached_num_beats_in_bar) @tui_arrangement_record_button.toggled def tui_arrangement_record_button(self, toggled, _): self.song.record_mode = toggled def _update_button_states(self): self._update_play_button_color() self._update_continue_playing_button_color() self._update_stop_button_color() def _update_play_button_color(self): raise NotImplementedError def _update_continue_playing_button_color(self): self.continue_playing_button.color = b'Transport.PlayOn' if self.song.is_playing else b'Transport.PlayOff' def _update_stop_button_color(self): self.stop_button.color = b'Transport.StopOff' if self.song.is_playing else b'Transport.StopOn' @listens(b'metronome') def __on_metronome_changed(self): self._update_tui_metronome_button() self._update_metronome_color_control() @listens(b'follow_song') def __on_follow_song_changed(self): self.follow_song_button.color = b'DefaultButton.On' if self.song.view.follow_song else b'DefaultButton.Off' @listens(b'clip_trigger_quantization') def __on_clip_trigger_quantization_changed(self): self._update_clip_trigger_quantization_control() self._update_clip_trigger_quantization_color_controls() @listens(b'signature_numerator') def __on_signature_numerator_changed(self): self._cached_num_beats_in_bar = num_beats_in_bar(self.song) @listens(b'signature_denominator') def __on_signature_denominator_changed(self): self._cached_num_beats_in_bar = num_beats_in_bar(self.song) def _update_clip_trigger_quantization_control(self): self.clip_trigger_quantization_control.value = int( self.song.clip_trigger_quantization) def _update_clip_trigger_quantization_color_controls(self): quantization = self.song.clip_trigger_quantization for index, control in enumerate( self.clip_trigger_quantization_color_controls): control.color = b'DefaultButton.On' if RADIO_BUTTON_GROUP_QUANTIZATION_VALUES[ index] == quantization else b'DefaultButton.Off' def _update_tui_metronome_button(self): self.tui_metronome_button.is_toggled = self.song.metronome def _update_metronome_color_control(self): self.metronome_color_control.color = b'Transport.MetronomeOn' if self.song.metronome else b'Transport.MetronomeOff' def _update_tui_arrangement_record_button(self): self.tui_arrangement_record_button.is_toggled = self.song.record_mode @listens(b'loop_start') def __on_loop_start_changed(self): loop_start_time = self.song.get_beats_loop_start() self.loop_start_display[0] = format_beat_time(loop_start_time) @listens(b'loop_length') def __on_loop_length_changed(self): loop_length_time = self.song.get_beats_loop_length() self.loop_length_display[0] = format_beat_time(loop_length_time) @listens(b'current_song_time') def __on_arrangement_position_changed(self): song_time = self.song.get_current_beats_song_time() self.arrangement_position_display[0] = format_beat_time(song_time) @listens(b'record_mode') def __on_record_mode_changed(self): self._update_tui_arrangement_record_button()
class ActionsComponent(Component): actions_display = TextDisplayControl(segments=ACTION_NAMES) actions_color_fields = control_list(ColorSysexControl, len(ACTION_NAMES)) actions_selection_fields = control_list(BinaryControl, len(ACTION_NAMES)) undo_button = ButtonControl(color='Action.Available') redo_button = ButtonControl(color='Action.Available') capture_midi_button = ButtonControl() metronome_button = ToggleButtonControl( toggled_color='Transport.MetronomeOn', untoggled_color='Transport.MetronomeOff') def __init__(self, *a, **k): super(ActionsComponent, self).__init__(*a, **k) self.__on_can_capture_midi_changed.subject = self.song self.__on_can_capture_midi_changed() self.actions_color_fields[ METRONOME_DISPLAY_INDEX].color = 'Transport.MetronomeOn' self.actions_color_fields[ UNDO_DISPLAY_INDEX].color = 'Action.Available' self.actions_color_fields[ REDO_DISPLAY_INDEX].color = 'Action.Available' self.__on_metronome_changed.subject = self.song self.__on_metronome_changed() @property def capture_midi_display(self): return self.actions_display[CAPTURE_DISPLAY_INDEX] @capture_midi_display.setter def capture_midi_display(self, string): self.actions_display[CAPTURE_DISPLAY_INDEX] = string @property def capture_midi_color_field(self): return self.actions_color_fields[CAPTURE_DISPLAY_INDEX] @property def capture_midi_selection_field(self): return self.actions_selection_fields[CAPTURE_DISPLAY_INDEX] @undo_button.pressed def undo_button(self, _): if self.song.can_undo: self.song.undo() @redo_button.pressed def redo_button(self, _): if self.song.can_redo: self.song.redo() @capture_midi_button.pressed def capture_midi_button(self, _): try: self.song.capture_midi() except RuntimeError: pass @metronome_button.toggled def metronome_button(self, toggled, _): self.song.metronome = toggled @listens('can_capture_midi') def __on_can_capture_midi_changed(self): self._update_capture_midi_controls() @listens('metronome') def __on_metronome_changed(self): self._update_metronome_controls() def _update_capture_midi_controls(self): can_capture_midi = self.song.can_capture_midi self.capture_midi_button.enabled = can_capture_midi self.capture_midi_display = 'capture' if can_capture_midi else '' self.capture_midi_color_field.color = 'DefaultButton.On' if can_capture_midi else 'DefaultButton.Disabled' self.capture_midi_selection_field.is_on = can_capture_midi def _update_metronome_controls(self): metronome = self.song.metronome self.metronome_button.is_toggled = metronome self.actions_selection_fields[ METRONOME_DISPLAY_INDEX].is_on = metronome
class DisplayingDeviceNavigationComponent(DeviceNavigationComponent): device_name_display_1 = TextDisplayControl(segments=(u'', ) * NUM_DISPLAY_SEGMENTS) device_name_display_2 = TextDisplayControl(segments=(u'', ) * NUM_DISPLAY_SEGMENTS) device_bank_name_display_1 = TextDisplayControl(segments=(u'', ) * NUM_DISPLAY_SEGMENTS) device_bank_name_display_2 = TextDisplayControl(segments=(u'', ) * NUM_DISPLAY_SEGMENTS) selected_device_name_display = TextDisplayControl(segments=(u'', )) selected_device_bank_name_display = TextDisplayControl(segments=(u'', )) device_color_fields = control_list(ColorSysexControl, NUM_VISIBLE_ITEMS) device_selection_fields = control_list(BinaryControl, NUM_VISIBLE_ITEMS) def __init__(self, banking_info=None, device_bank_registry=None, *a, **k): super(DisplayingDeviceNavigationComponent, self).__init__(*a, **k) self.select_buttons.control_count = NUM_VISIBLE_ITEMS assert banking_info is not None assert device_bank_registry is not None self._banking_info = banking_info self._device_bank_registry = device_bank_registry self.__on_items_changed.subject = self self.__on_items_changed() self.__on_selection_changed.subject = self._item_provider self.__on_selection_changed() self.__on_device_bank_changed.subject = self._device_bank_registry return @listens('items') def __on_items_changed(self): for index, control in enumerate(self.select_buttons): control.enabled = index < len(self.items) self._update_button_colors() self._update_device_color_fields() self._update_device_names() self._update_device_bank_names() self._update_selection_display() self._scroll_overlay.update_scroll_buttons() self.__on_item_names_changed.replace_subjects(self.items) @listens('selected_item') def __on_selection_changed(self): self._update_button_colors() self._update_selection_display() self._update_selected_device_name_display() self._update_selected_device_bank_name_display() self.__on_selected_item_name_changed.subject = self._item_provider.selected_item @listens_group('name') def __on_item_names_changed(self, something): self._update_device_names() @listens('device_bank') def __on_device_bank_changed(self, *a): self._update_device_bank_names() self._update_selected_device_bank_name_display() @listens('name') def __on_selected_item_name_changed(self): self._update_selected_device_name_display() def _update_device_color_fields(self): for color_field, item in izip_longest(self.device_color_fields, self.items): color_field.color = 'Device.On' if item else 'DefaultButton.Disabled' def _update_selection_display(self): selected_item = self._item_provider.selected_item for selection_field, item in izip_longest(self.device_selection_fields, self.items): selection_field.is_on = bool(item) and self._items_equal( item, selected_item) def _update_device_names(self): for index, item in izip_longest(xrange(NUM_VISIBLE_ITEMS), self.items): display = getattr(self, ( 'device_name_display_{}').format(index / NUM_DISPLAY_SEGMENTS + 1)) display[index % NUM_DISPLAY_SEGMENTS] = item.item.name if item else '' def _update_device_bank_names(self): for index, item in izip_longest(xrange(NUM_VISIBLE_ITEMS), self.items): display = getattr(self, ('device_bank_name_display_{}' ).format(index / NUM_DISPLAY_SEGMENTS + 1)) display[index % NUM_DISPLAY_SEGMENTS] = self._bank_name_for_item( item.item if item else None) return def _update_selected_device_name_display(self): item = self._item_provider.selected_item self.selected_device_name_display[ 0] = item.name if item else 'No Device' def _update_selected_device_bank_name_display(self): self.selected_device_bank_name_display[0] = self._bank_name_for_item( self._item_provider.selected_item) def _bank_name_for_item(self, item): bank_name = '' if item: item_bank_names = self._banking_info.device_bank_names(item) if item_bank_names: bank = self._device_bank_registry.get_device_bank(item) bank_name = item_bank_names[bank] return bank_name