def set_control(self, control): """ Sets the control to use for controlling this property. """ self._remove_property_listener() self._on_takeover_control_value_changed.subject = None self._on_relative_control_value_changed.subject = None release_parameters((self._control, )) self._control = control self._can_set_value_directly = True self._use_full_range = False if control: if isinstance(control, SpecialButtonSliderElement): self._can_set_value_directly = False control.set_property_to_map_to( self if live_object_is_valid(self._parent) else None) elif isinstance(control, SpecialEncoderElement): control.set_property_to_map_to( self if live_object_is_valid(self._parent) else None) self._can_suppress_feedback = control.should_suppress_feedback_for_property_controls( ) if control.message_map_mode() in ABS_MODES: self._can_enforce_takeover = self._can_enforce_takeover and control.needs_takeover( ) if self._can_set_value_directly: self._on_takeover_control_value_changed.subject = control else: self._on_relative_control_value_changed.subject = control self._use_full_range = True self._add_property_listener() return
def update(self): """ Extends standard to set enabled state of ButtonControls, update 0db property and set up implicit listener. """ super(SpecialChannelStripComponent, self).update() can_mute_or_solo = live_object_is_valid( self._track) and self._track != self.song().master_track self.alt_mute_button.enabled = can_mute_or_solo self.alt_solo_button.enabled = can_mute_or_solo self.alt_select_button.enabled = live_object_is_valid(self._track) self._on_implicit_arm_changed.subject = self._track if self.is_enabled(): self._0_db_volume_property.update() self._on_arm_changed()
def _on_takeover_control_value_changed(self, control_value): if live_object_is_valid(self._parent): param_value = self.get_property_value() scaled_value = self._absolute_factor * control_value last_control_value = self._control._last_received_value control_diff = control_value - last_control_value if self._enforce_takeover: if self._awaiting_control_value: self._on_property_value_changed() return if control_diff > 0 and last_control_value < 127: if param_value > self._absolute_range[1]: return step_factor = (self._absolute_range[1] - param_value ) / float(127 - last_control_value) scaled_value = step_factor + step_factor * control_diff + param_value - self._absolute_range[ 0] elif control_diff < 0 and last_control_value > 0: step_factor = (param_value - self._absolute_range[0] ) / float(last_control_value) scaled_value = control_value * step_factor scaled_value += self._absolute_range[0] if self._is_quantized: scaled_value = int(scaled_value) new_param_value = max(self._absolute_range[0], min(self._absolute_range[1], scaled_value)) self._suppress_feedback = self._can_suppress_feedback self.set_property_value(param_value, new_param_value)
def set_property_value(self, current_value, new_value): """ Sets the property value and calls the display callback if there is one. This is broken out so that it can be overridden. """ if live_object_is_valid(self._parent) and current_value != new_value: setattr(self._parent, self._property_name, new_value) if self._display_callback: self._display_callback(new_value)
def get_property_value(self): """ Returns the value of the property. This is broken out so that it can be overridden. """ if live_object_is_valid(self._parent): return getattr(self._parent, self._property_name) else: return
def _update_track_name_data_source(self): """ Extends standard to notify track name subjects. """ if self.track_name_data_source(): super(SpecialChannelStripComponent, self)._update_track_name_data_source() self.notify_track_name( self._track.name if live_object_is_valid(self._track) else '', self.is_selected)
def set_track(self, track): """ Sets the track this component will operate on. """ assert track is None or isinstance(track, Live.Track.Track) self._track = track if live_object_is_valid(track) else None if self._wrapper: self._wrapper.set_track(track) self.update(True) return
def _remove_property_listener(self): if live_object_is_valid(self._parent): remove_method = getattr(self._parent, 'remove_%s_listener' % self._property_name) try: remove_method(self._on_property_value_changed) except: pass
def _select_value(self, value): """ Overrides standard to handle reselecting last selected track for master track selection. """ if self.is_enabled() and live_object_is_valid(self._track) and value: if self._track == self.song().master_track: if self.song().view.selected_track == self._track: self.song().view.selected_track = self._last_selected_track return self.song().view.selected_track = self._track
def _on_matrix_value(self, value, x, y, _): if self._is_enabled and value: if self._is_velocity_sensitive: s = get_smoothing_speed_for_velocity(value) self._x_smoother.set_smoothing_speed(s) self._y_smoother.set_smoothing_speed(s) y = self._height - 1 - y if live_object_is_valid(self._x_parameter): target = self._get_target_value(self._x_parameter, self._width, x) self._x_smoother.set_parameter_value(target) else: self._update_matrix(update_x=True) if live_object_is_valid(self._y_parameter): target = self._get_target_value(self._y_parameter, self._height, y) self._y_smoother.set_parameter_value(target) else: self._update_matrix(update_y=True)
def set_drum_rack(self, drum_rack, _=None): """ Sets the drum rack to control. """ self._drum_rack = drum_rack if live_object_is_valid( drum_rack) else None view = drum_rack.view if drum_rack else None self._on_selected_drum_pad_changed.subject = view self._select_property.set_parent(view) self._scroll_property.set_parent(view) self._on_selected_drum_pad_changed() self._update_macro_connections() return
def set_clip(self, clip): """ Used when prefer_playing_clip to set the clip of sub-components. """ if clip != self._clip or not live_object_is_valid(self._clip): self._clip = clip if clip and clip.is_midi_clip else None self._page_component.set_clip(clip) self._playhead_component.set_clip(clip) for n in self._note_lane_components: n.set_clip(clip) self.on_clip_changed() return
def set_property_value(self, current_value, new_value): """ Overrides standard to utilize different levels of quantization for controlling markers. """ if self._enabled: current_value *= self.marker_factor new_value *= self.marker_factor if live_object_is_valid(self._parent) and current_value != new_value: new_param_value = max(self._absolute_range[0] * self.marker_factor, min(self._absolute_range[1] * self.marker_factor, new_value)) setattr(self._parent, self._property_name, new_param_value) if self._should_zoom: self._parent.view.show_loop() self._parent.view.show_loop()
def parameter_is_quantized(param): """ Returns whether or not the given parameter is quantized. This is needed for cases where parameters are quantized, but are not listed that way. """ if live_object_is_valid(param): if param.is_quantized: return True parent = param.canonical_parent if isinstance(parent, Live.Device.Device): parent = parent.class_name return parent in UNLISTED_QUANTIZED_PARAMETERS and param.name in UNLISTED_QUANTIZED_PARAMETERS[ parent] return False
def _on_selected_parameter_changed(self, display=True): if self._selected_parameter_control: release_parameters((self._selected_parameter_control, )) if self.is_enabled(): is_locked = False if self._selected_parameter_is_locked: if live_object_is_valid(self._current_selected_parameter): is_locked = True else: self._selected_parameter_is_locked = False self._update_selected_parameter_lock_button() param = self._current_selected_parameter if is_locked else self.song( ).view.selected_parameter if live_object_is_valid(param): self._current_selected_parameter = param self._selected_parameter_control.connect_to(param) if display and not is_locked: p_info = resolve_path_name_for_parameter( self.song(), param) self.component_message( 'Selected Parameter Control assigned to', p_info)
def _toggle_solo(self, is_release=False): if self.is_enabled() and live_object_is_valid(self._track): if self._track != self.song().master_track: if not is_release or self._track.solo: exclusive = self.song( ).exclusive_solo != is_button_pressed(self._shift_button) if exclusive: for track in chain(self.song().tracks, self.song().return_tracks): if track != self._track: track.solo = False self._track.solo = not self._track.solo
def _on_arm_changed(self): """ Overrides standard to allow for skinning, implicit arm handling and update alt_select. """ self._update_alt_select_button() if self.is_enabled() and self._arm_button is not None: if live_object_is_valid(self._track) and self._track in self.song( ).tracks and self._track.can_be_armed: is_armed = self._track.arm or self._track.implicit_arm self._arm_button.set_light( 'Track.Armed' if is_armed else 'Track.NotArmed') else: self._arm_button.set_light('Track.Empty') return
def _on_relative_control_value_changed(self, value): if live_object_is_valid(self._parent): param_value = self.get_property_value() factor = self._control.get_adjustment_factor( value, self._relative_threshold) if factor: factor = factor * self._relative_step if self._is_quantized: factor = int(factor) new_param_value = max( self._full_range[0], min(self._full_range[1], param_value + factor)) self.set_property_value(param_value, new_param_value)
def _update_matrix(self, update_x=False, update_y=False): if self._is_enabled and self._matrix: if live_object_is_valid(self._x_parameter) or live_object_is_valid( self._y_parameter): should_update = False x_value = self._last_x_value y_value = self._last_y_value if live_object_is_valid(self._x_parameter) and update_x: x_value = self._get_scaled_parameter_value( self._x_parameter, self._width) if x_value != self._last_x_value: self._last_x_value = x_value should_update = True if live_object_is_valid(self._y_parameter) and update_y: y_value = self._height - 1 - self._get_scaled_parameter_value( self._y_parameter, self._height) if y_value != self._last_y_value: self._last_y_value = y_value should_update = True if should_update: self._handle_matrix_update(x_value, y_value) else: set_group_button_lights(self._matrix, 'DefaultButton.Off')
def set_parent(self, parent): """ Sets the parent of this property. """ self._remove_property_listener() self._parent = parent if live_object_is_valid(parent) else None if self._control: self._add_property_listener() if isinstance(self._control, SpecialButtonSliderElement): self._control.set_property_to_map_to( self if self._parent else None) elif isinstance(self._control, SpecialEncoderElement): self._control.set_property_to_map_to( self if self._parent else None) self._update_control() return
def _update_assignment_and_notify(self): """ Updates/verifies this encoder's assignment, notifies listeners and sets up value and name listeners. """ param = self.mapped_parameter() if self._property_to_map_to: param = self._property_to_map_to if self.is_mapped_manually() or not live_object_is_valid(param): param = None self.notify_parameter(param) self.notify_parameter_name(self.parameter_name) self.notify_parameter_value(self.parameter_value) self._on_parameter_value_changed.subject = param self._on_parameter_name_changed.subject = param return
def _on_solo_changed(self): """ Overrides standard to update alt_solo_button and allow for skinning. """ if self.is_enabled(): has_track = live_object_is_valid( self._track) and self._track != self.song().master_track if has_track: self.alt_solo_button.is_on = self._track.solo if self._solo_button is not None: if has_track: self._solo_button.set_light('Track.Soloed' if self._track. solo else 'Track.NotSoloed') else: self._solo_button.set_light('Track.Empty') return
def get_assigned_track_parameter(self, a): """ Returns the track-based parameter for the given assignment. """ if a: dev = self.get_device_by_class_name(a['class_name'], a['instance_name']) if live_object_is_valid(dev): if a['chain'] is not None: return get_mixer_parameter(dev.chains[a['chain']], a['parameter']) if a['return_chain'] is not None: return get_mixer_parameter( dev.return_chains[a['return_chain']], a['parameter']) return get_device_parameter(dev, a['parameter']) return
def _on_selected_parameter_lock_button_value(self, value): if value and self._selected_parameter_control: if self._selected_parameter_is_locked: self._selected_parameter_is_locked = False self._on_selected_parameter_changed() elif live_object_is_valid(self._current_selected_parameter): self._selected_parameter_is_locked = True p_info = resolve_path_name_for_parameter( self.song(), self._current_selected_parameter) self.component_message('Selected Parameter Control locked to', p_info) else: self._on_selected_parameter_changed() self._update_selected_parameter_lock_button()
def _update_control_connections(self, track_changed=False): if self.is_enabled(): release_parameters(self._controls) for slot in self._control_slots: self.disconnect_disconnectable(slot) del self._control_slots[:] if self._controls: self._on_update_connections_method() for i, control in enumerate(self._controls): if control: param = self._get_parameter(i) if live_object_is_valid(param): control.connect_to(param) else: self._register_slot_for_control(control)
def on_selected_track_changed(self): """ Overrides standard to allow for skinning, update alt_select and track name and store last selected track. """ self._update_alt_select_button() self._update_track_name_data_source() if self.is_enabled(): if self._select_button is not None: if live_object_is_valid(self._track): self._select_button.set_light( 'Track.Selected' if self._track == self.song( ).view.selected_track else 'Track.NotSelected') else: self._select_button.set_light('Track.Empty') if self.song().view.selected_track != self.song().master_track: self._last_selected_track = self.song().view.selected_track return
def _update_control(self): if self._control and not self._suppress_feedback: if live_object_is_valid(self._parent): prop_value = self.get_property_value() if prop_value == self._absolute_range[1]: self._control.send_value(127) elif prop_value > self._absolute_range[0]: scaled_value = parameter_value_to_midi_value( prop_value, self._absolute_range[0], self._absolute_range[1]) self._control.send_value(scaled_value) else: self._control.send_value(0) else: self._control.send_value(0) self._suppress_feedback = False
def _update_alt_select_button(self): """ Updates alt_select on arm and select changes. """ if self.is_enabled(): value = 'Track.Empty' if live_object_is_valid(self._track): t = self._track value = 'Track.NotSelected' is_selected = t and t == self.song().view.selected_track is_armed = self._alt_select_should_arm and t.can_be_armed and ( t.arm or t.implicit_arm) if is_selected and is_armed: value = 'Track.SelectedAndArmed' elif is_selected: value = 'Track.Selected' elif is_armed: value = 'Track.NotSelectedAndArmed' self.alt_select_button.color = value
def set_clip(self, clip): """ Sets the clip for the component to control, adds listeners and calls on_clip_changed, which sub-classes should override. """ assert clip is None or isinstance(clip, Live.Clip.Clip) if clip != self._clip or not live_object_is_valid(self._clip): self._clip = clip self._on_looping_status_changed.subject = self._clip self._on_playing_status_changed.subject = self._clip self.on_clip_name_changed.subject = self._clip self.on_clip_changed() self.on_clip_name_changed() self._on_looping_status_changed() self._on_playing_status_changed() self._update_delete_button() self._update_double_button() self._update_duplicate_button() self._update_quantize_button() return
def _on_property_value_changed(self): if live_object_is_valid(self._parent) and self._control: if self._control.message_map_mode() in ABS_MODES: last_control_value = self._control._last_received_value self._awaiting_control_value = last_control_value == -1 value = self.get_property_value() if self._awaiting_control_value or value < self._absolute_range[ 0] or value > self._absolute_range[1]: self._enforce_takeover = self._can_enforce_takeover else: scaled_value = self._absolute_factor * last_control_value if self._is_quantized: scaled_value = int(scaled_value) if self._can_enforce_takeover: self._enforce_takeover = abs( scaled_value - value) > self._absolute_factor * 2 self.notify_value() self._update_control()