def _add_margin_to_region(self, start, end): margin = self.RELATIVE_FOCUS_MARGIN start1 = (margin * start + end * margin - start) / (2 * margin - 1) end1 = (end - margin * start1) / (1 - margin) start1 = clamp(start1, 0, self._length) end1 = clamp(end1, 0, self._length) return (start1, end1)
def _focus_connection(self, connection, animate = False): """ Focuses the connection in the waveform and brings it into the visible range. The visible length is preserved. The position is aligned to the left or right of the visible range, with a certain margin defined by RELATIVE_FOCUS_MARGIN. If the connections boundary is already in the visible range, the visible position is not changing. :connection: the object connection to focus :align_right: focuses the position on the left or right side of the :animate: should be set to True if, if it should animate to the new position """ position = connection.getter() visible_length = self.visible_length visible_margin = visible_length * self.RELATIVE_FOCUS_MARGIN length = self._length if connection.align_right: start = min(connection.boundary_getter() - visible_margin, self.visible_start) if connection else 0 right = max(position + visible_margin, start + visible_length) self.set_visible_region(clamp(right - visible_length, 0, length - visible_length), clamp(right, visible_length, length), animate) else: end = max(connection.boundary_getter() + visible_margin, self.visible_end) if connection else length left = min(position - visible_margin, end - visible_length) self.set_visible_region(clamp(left, 0, length - visible_length), clamp(left + visible_length, visible_length, length), animate) self._focus_marker = FocusMarker(connection.focus_name, position) self.notify_focus_marker() self._request_select_region = True
def down_button(self, button): if self.shift_toggle.is_toggled: value = self._values[self._channel] self.index = clamp(value - self._bank_increment, 0, (self._range - 1)) else: value = self._values[self._channel] self.index = clamp(value - 1, 0, (self._range - 1))
def _insert_step(self, time_range, time_index, param_index, envelope, value): param = self._parameter_for_index(self.parameters, param_index) envelope_value = self._parameter_floats[time_index][param_index] sensitivity = self.parameter_infos[param_index].default_encoder_sensitivity * self.ENCODER_SENSITIVITY_FACTOR if param.is_quantized: value_to_insert = clamp(envelope_value + value / EnumerableSetting.STEP_SIZE, param.min, param.max) else: value_range = param.max - param.min value_to_insert = clamp(envelope_value + value * value_range * sensitivity, param.min, param.max) self._parameter_floats[time_index][param_index] = value_to_insert envelope.insert_step(time_range[0], time_range[1] - time_range[0], value_to_insert)
def _focus_object_by_identifier(self, identifier, animate=False): u""" Focuses the object in the timeline and brings it into the visible range. The visible length is preserved. The position is aligned to the left or right of the visible range, with a certain margin defined by RELATIVE_FOCUS_MARGIN. If the objects region boundary is already in the visible range, the visible position is not changing. :identifier: the object identifier to focus :animate: should be set to True if, if it should animate to the new position """ roi = self._get_roi_for_object_identifier(identifier) region = roi.region if self._locked_roi is not None and self._locked_roi.bound_by( identifier): if region.start < self.timeline_region.start: start = self.timeline_region.start new_visible_region = Region(start, start + self.visible_region.length) else: if region.end > self.timeline_region.end: end = self.timeline_region.end new_visible_region = Region( end - self.visible_region.length, end) else: new_visible_region = self._add_margin_to_region(region) self.set_visible_region(new_visible_region, force_animate=animate) else: visible_length = self.visible_region.length visible_margin = visible_length * self.RELATIVE_FOCUS_MARGIN timeline_start, timeline_end = self._timeline_region if roi.end_identifier == identifier: start = min(region.start - visible_margin, self.visible_region.start) right = max(region.end + visible_margin, start + visible_length) left = right - visible_length else: end = max(region.end + visible_margin, self.visible_region.end) left = min(region.start - visible_margin, end - visible_length) right = left + visible_length self.set_visible_region(Region( clamp(left, timeline_start, timeline_end - visible_length), clamp(right, timeline_start + visible_length, timeline_end)), force_animate=animate) self._request_select_region = True self.focus_marker = FocusMarker( self.focusable_object_descriptions[identifier].focus_name, region.end if roi.end_identifier == identifier else region.start) return
def zoom(self, value): animate = self._request_select_region if self._request_select_region or (self._process_unsnapping(value)): self._select_region(value > 0) source = self._source_roi.region_with_margin target = self._target_roi.region_with_margin easing_degree = calc_easing_degree_for_proportion( float(target.length) / float(source.length)) focused_region, focus_marker, margin_type = self._get_zoom_info_for_focused_object( ) t = inverse_interpolate_region( source, target, (self.visible_region), easing_degree, prefer_end=(margin_type == MarginType.START)) t = clamp(t + value * self.ZOOM_SENSITIVITY, 0.0, 1.0) region = interpolate_region(source, target, t, easing_degree) region = self._add_margin_to_zoomed_region(region, focused_region, margin_type) self.set_visible_region(region, force_animate=animate, source_action='zoom') self.focus_marker = focus_marker self.show_focus = True self.try_hide_focus_delayed() self._try_lock_region()
def select_item_index_with_offset(self, index, offset): if index != self.selected_item_index: if index >= 0: if index < len(self._items): self._offset = clamp(index - offset, 0, len(self._items)) self._normalize_offset(index) self._do_set_selected_item_index(index)
def convert_value_to_graphic(value, value_range): value_bar = GRAPH_VOL graph_range = float(len(value_bar)) value = clamp(int(value / value_range * graph_range), 0, len(value_bar) - 1) display_string = value_bar[value] return display_string
def insert_scene_button(self, _): try: song = self.song scenes = song.scenes song.create_scene(clamp(index_if(lambda s: s == song.view.selected_scene, scenes) + 1, 0, len(scenes))) except Live.Base.LimitationError: pass
def zoom(self, value): """ Zooms in or out of the waveform start value should be between -1.0 and 1.0, where 1.0 will zoom in as much as possible and -1.0 will zoom out completely. """ animate = self._request_select_region if self._request_select_region or self._process_unsnapping(value): self._select_region(value > 0) source = self._source_roi.region_with_margin target = self._target_roi.region_with_margin easing_degree = calc_easing_degree_for_proportion( float(target.length) / float(source.length)) focused_region, focus_marker, margin_type = self._get_zoom_info_for_focused_object( ) t = inverse_interpolate_region( source, target, self.visible_region, easing_degree, prefer_end=margin_type == MarginType.START) t = clamp(t + value * self.ZOOM_SENSITIVITY, 0.0, 1.0) region = interpolate_region(source, target, t, easing_degree) region = self._add_margin_to_zoomed_region(region, focused_region, margin_type) self.set_visible_region(region, force_animate=animate, source_action='zoom') self.focus_marker = focus_marker self.show_focus = True self.try_hide_focus_delayed() self._try_lock_region()
def _on_mode_changed(self, selected_mode): if selected_mode in SEND_MODE_NAMES: index = SEND_MODE_NAMES.index(selected_mode) self._selected_item = SEND_SECTIONS[clamp(index + self._send_offset, 0, self.number_sends - 1)] else: self._selected_item = MIXER_SECTIONS[1] if selected_mode == 'panning' else MIXER_SECTIONS[0] self.notify_selected_item()
def _normalize_offset(self, index): if index >= 0: if index >= self._offset + self._num_visible_items: self._offset = index - (self._num_visible_items - 1) elif index < self._offset: self._offset = index self._offset = clamp(self._offset, 0, len(self._items) - self._num_visible_items)
def _on_mode_changed(self, selected_mode): if selected_mode in SEND_MODE_NAMES: index = SEND_MODE_NAMES.index(selected_mode) self._selected_item = SEND_SECTIONS[clamp(index + self._send_offset, 0, self.number_sends - 1)] else: self._selected_item = MIXER_SECTIONS[1] if selected_mode == b'panning' else MIXER_SECTIONS[0] self.notify_selected_item()
def _modify_single_note(self, step_mute, time_step, length_offset, note): u""" Return a modified version of the passed in note taking into account current modifiers. If the note is not within the given step, returns the note as-is. If the time_step is inside a loop, the last part of the loop is considered as being the same as the part just before the loop, so the resulting note may, in this case, jump between the beginning and the end. """ pitch, time, length, velocity, mute = note if time_step.includes_time(time): time = time_step.clamp(time, self._nudge_offset) if length_offset <= -time_step.length and length + length_offset < time_step.length: if length > time_step.length: length = time_step.length else: length = max(0, length + length_offset) if self._provided_velocity: velocity = self._provided_velocity elif self.full_velocity: velocity = 127 else: velocity = clamp(velocity + self._velocity_offset, 1, 127) mute = not step_mute if self.mute_button.is_pressed else mute return ( pitch, time, length, velocity, mute)
def _navigate_mode(self, direction): new_index = 0 if self.selected_mode: old_index = self._mode_list.index(self.selected_mode) new_index = clamp(old_index + direction, 0, len(self._mode_list) - 1) self.selected_mode = self._mode_list[new_index] self._update_mode_nav_buttons()
def generate_velocity_curve(sensitivity, gain, dynamics): minw = 160 maxw = LookupTable.MAXW[sensitivity] gamma = LookupTable.GAMMA[gain] minv = LookupTable.MINV[gain] maxv = LookupTable.MAXV[gain] alpha = LookupTable.ALPHA[dynamics] p1x, p1y, p2x, p2y = calculate_points(alpha) curve = [] minw_index = int(minw) / 32 maxw_index = int(maxw) / 32 t = 0.0 for index in xrange(NUM_VELOCITY_CURVE_ENTRIES): w = index * 32.0 if w <= minw: velocity = 1.0 + (minv - 1.0) * float(index) / float(minw_index) elif w >= maxw: velocity = maxv + (127.0 - maxv) * float( index - maxw_index) / float(128 - maxw_index) else: wnorm = (w - minw) / (maxw - minw) b, t = bezier(wnorm, t, p1x, p1y, p2x, p2y) velonorm = gamma_func(b, gamma) velocity = minv + velonorm * (maxv - minv) curve.append(clamp(int(round(velocity)), 1, 127)) return curve
def _new_slice_time(self, old_slice_time, delta): previous_slice, next_slice = self._get_surrounding_slices(old_slice_time) change_in_samples = self._sample_change_from_delta(delta) min_second_slice_start = self._simpler.start_marker + self._get_min_first_slice_length() lower_bound = max(0, min_second_slice_start, previous_slice) upper_bound = min(next_slice, self._simpler.end_marker, self._simpler.sample_length) - MINIMUM_SLICE_DISTANCE return clamp(old_slice_time + change_in_samples, lower_bound, upper_bound)
def _set_warp_mode(self, value): if self.clip.warping: available_warp_modes = self.available_warp_modes warp_mode_index = available_warp_modes.index(self.clip.warp_mode) new_warp_mode_index = clamp(warp_mode_index + value, 0, len(available_warp_modes) - 1) self.clip.warp_mode = available_warp_modes[new_warp_mode_index]
def _scroll_bank(self, offset): if self._bank: new_index = clamp(self._bank.index + offset, 0, self._bank.bank_count() - 1) self._device_bank_registry.set_device_bank(self.device(), new_index) self._set_bank_index(new_index)
def handle_value(self, value, notify): range, position = self.handle.range, self.handle.position if self._grabbed or range[0] <= value - position < range[1]: self._offset = value - position self._grabbed = True else: notify(clamp(value - self._offset, 0, MAX_PITCHBEND))
def generate_velocity_curve(sensitivity, gain, dynamics): minw = 160 maxw = LookupTable.MAXW[sensitivity] gamma = LookupTable.GAMMA[gain] minv = LookupTable.MINV[gain] maxv = LookupTable.MAXV[gain] alpha = LookupTable.ALPHA[dynamics] p1x, p1y, p2x, p2y = calculate_points(alpha) curve = [] minw_index = int(minw) / 32 maxw_index = int(maxw) / 32 t = 0.0 for index in xrange(NUM_VELOCITY_CURVE_ENTRIES): w = index * 32.0 if w <= minw: velocity = 1.0 + (minv - 1.0) * float(index) / float(minw_index) elif w >= maxw: velocity = maxv + (127.0 - maxv) * float(index - maxw_index) / float(128 - maxw_index) else: wnorm = (w - minw) / (maxw - minw) b, t = bezier(wnorm, t, p1x, p1y, p2x, p2y) velonorm = gamma_func(b, gamma) velocity = minv + velonorm * (maxv - minv) curve.append(clamp(int(round(velocity)), 1, 127)) return curve
def handle_value(self, value, notify): range, position = self.handle.range, self.handle.position if not self._grabbed and range[0] <= value - position < range[1]: self._offset = value - position self._grabbed = True else: notify(clamp(value - self._offset, 0, MAX_PITCHBEND))
def zoom(self, value): """ Zooms in or out of the waveform start value should be between -1.0 and 1.0, where 1.0 will zoom in as much as possible and -1.0 will zoom out completely. """ animate = self._request_select_region if self._request_select_region: self._select_region(value > 0) source = self._source_region_getter() target = self._target_region_getter() source_length = float(source[1] - source[0]) target_length = float(target[1] - target[0]) easing_degree = calc_easing_degree_for_proportion(target_length / source_length) if source[0] != target[0]: t = interpolate_inverse(source[0], target[0], self.visible_start, easing_degree) else: t = interpolate_inverse(source[1], target[1], self.visible_end, easing_degree) t = clamp(t + value * self.ZOOM_SENSITIVITY, 0.0, 1.0) self.set_visible_region(interpolate(source[0], target[0], t, easing_degree), interpolate(source[1], target[1], t, easing_degree), animate=animate) self.show_focus = True self.try_hide_focus_delayed()
def _link_session_ring_by_paging(self): if not self._does_selection_change_cross_boundary(): return current_offset = self._session_ring.track_offset all_tracks = self._session_ring.tracks_to_use() new_offset = clamp(current_offset + self._selection_delta(), 0, len(self._session_ring.tracks_to_use())) self._session_ring.set_offsets(new_offset, self._session_ring.scene_offset)
def _modify_single_note(self, step_mute, time_step, length_offset, note): """ Return a modified version of the passed in note taking into account current modifiers. If the note is not within the given step, returns the note as-is. If the time_step is inside a loop, the last part of the loop is considered as being the same as the part just before the loop, so the resulting note may, in this case, jump between the beginning and the end. """ pitch, time, length, velocity, mute = note if time_step.includes_time(time): time = time_step.clamp(time, self._nudge_offset) if length_offset <= -time_step.length and length + length_offset < time_step.length: if length > time_step.length: length = time_step.length else: length = max(0, length + length_offset) if self._provided_velocity: velocity = self._provided_velocity elif self.full_velocity: velocity = 127 else: velocity = clamp(velocity + self._velocity_offset, 1, 127) mute = not step_mute if self.mute_button.is_pressed else mute return (pitch, time, length, velocity, mute)
def _jump_relative(self, relative_position): current_position = self.values.index(self.value) new_position = clamp(current_position + relative_position, 0, len(self.values) - 1) self.value = self.values[new_position] if current_position != new_position: return new_position
def _scroll_controls(self, delta): num_return_tracks = self._number_sends() self._scroll_offset = clamp( self._scroll_offset + delta, 0, num_return_tracks if num_return_tracks > self._max_return_tracks() else 0) self.notify_scroll_offset() self._update_controls() self._update_scroll_buttons()
def _on_fade_in_led_brightness_timer(self): if self._led_brightness < self._target_led_brightness: distance = float(self._target_led_brightness - MIN_BRIGHTNESS_FOR_FADE_IN) increment = distance / LED_FADE_IN_TIME * LED_FADE_IN_FREQUENCY self._led_brightness = clamp(self._led_brightness + increment, MIN_BRIGHTNESS_FOR_FADE_IN, self._target_led_brightness) self._led_brightness_element.send_value(int(round(self._led_brightness))) else: self._led_brightness_timer.stop()
def _scroll_controls(self, delta): num_return_tracks = self._number_sends() self._scroll_offset = clamp( self._scroll_offset + delta, 0, num_return_tracks if num_return_tracks > MAX_RETURN_TRACKS else 0 ) self.notify_scroll_offset() self._update_controls() self._update_scroll_buttons()
def clamp(self, time, extra_time=0.0): result = clamp( self._looped_time(time, extra_time), self.left_boundary(), self.start - self.offset + self.length - BEAT_TIME_EPSILON) if result < self.clip_start: return result - self.clip_start + self.clip_end else: return result
def _do_scroll(self, delta): selected_track = self._song.view.selected_track tracks = all_tracks(self._song) selected_track_index = index_if(lambda t: t == selected_track, tracks) len_tracks = len(tracks) new_index = selected_track_index + delta * self._track_provider.num_tracks self._song.view.selected_track = tracks[clamp(new_index, 0, len_tracks - 1)] self.notify_scrolled()
def _scroll_controls(self, delta): if self._troll_mode(): num_return_tracks = self._number_sends() self._scroll_offset = clamp(self._scroll_offset + delta, 0, 2) self.notify_scroll_offset() self._update_controls() self._update_scroll_buttons() else: return TrackMixerControlComponentBase._scroll_controls(self, delta)
def _insert_step(self, time_range, time_index, param_index, envelope, value): param = self._parameter_for_index(self.parameters, param_index) envelope_value = self._parameter_floats[time_index][param_index] sensitivity = self.parameter_infos[ param_index].default_encoder_sensitivity * self.ENCODER_SENSITIVITY_FACTOR if param.is_quantized: value_to_insert = clamp( envelope_value + value / EnumerableSetting.STEP_SIZE, param.min, param.max) else: value_range = param.max - param.min value_to_insert = clamp( envelope_value + value * value_range * sensitivity, param.min, param.max) self._parameter_floats[time_index][param_index] = value_to_insert envelope.insert_step(time_range[0], time_range[1] - time_range[0], value_to_insert)
def next_page(self): if self.can_scroll_down(): current_page = self.selected_item_index / self.num_visible_items last_page_index = len(self.items) - self.num_visible_items if self.selected_item_index < last_page_index: index = clamp((current_page + 1) * self.num_visible_items, 0, len(self.items) - self.num_visible_items) else: index = len(self.items) - 1 self.select_item_index_with_offset(index, 0)
def prev_page(self): if self.can_scroll_up(): current_page = self.selected_item_index / self.num_visible_items last_page_index = len(self.items) - self.num_visible_items if self.selected_item_index <= last_page_index: index = clamp((current_page - 1) * self.num_visible_items, 0, len(self.items) - self.num_visible_items) else: index = max(len(self.items) - self.num_visible_items, 0) self.select_item_index_with_offset(index, 0)
def _touch_strip_to_page_position(self, value): bank_size = self._slideable.page_length num_pad_rows = self._slideable.position_count max_pad_row = num_pad_rows - bank_size offset = bank_size - self._slideable.page_offset return clamp( int( int(value / MAX_PITCHBEND * num_pad_rows + offset) / float(bank_size)) * bank_size - offset, 0, max_pad_row)
def _set_option_names(self, value): self._option_names = value self.select_buttons.control_count = len(value) if self._selected_option: currently_selected_option = self.selected_option self.selected_option = clamp(self._selected_option, 0, len(self._option_names) - 1) if currently_selected_option != self.selected_option: self.notify_selected_option(self.selected_option) self._update_select_buttons() self._update_data_sources()
def _add_offset_to_selected_index(self, offset): if self.is_enabled() and self._scrollable_list: with self._delay_activation(): with self._in_encoder_selection(): self._selected_index_float = clamp( self._selected_index_float + offset * self.ENCODER_FACTOR, 0, len(self._scrollable_list.items)) self._scrollable_list.select_item_index_with_border( int(self._selected_index_float), 1)
def _touch_strip_to_page_position(self, value): bank_size = self._slideable.page_length num_pad_rows = self._slideable.position_count max_pad_row = num_pad_rows - bank_size offset = bank_size - self._slideable.page_offset return clamp( int(int(value / MAX_PITCHBEND * num_pad_rows + offset) / float(bank_size)) * bank_size - offset, 0, max_pad_row, )
def select_item_index_with_offset(self, index, offset): """ Selects an item index but moves the view such that there are, if possible, 'offset' number of elements visible before the selected one. Does nothing if the item was already selected. """ if not (index != self.selected_item_index and index >= 0 and index < len(self._items) and self.selected_item_index != -1): raise AssertionError self._offset = clamp(index - offset, 0, len(self._items)) self._normalize_offset(index) self._do_set_selected_item_index(index)
def select_item_index_with_offset(self, index, offset): u""" Selects an item index but moves the view such that there are, if possible, 'offset' number of elements visible before the selected one. Does nothing if the item was already selected. """ if index != self.selected_item_index and index >= 0 and index < len(self._items): assert self.selected_item_index != -1 self._offset = clamp(index - offset, 0, len(self._items)) self._normalize_offset(index) self._do_set_selected_item_index(index)
def select_item_index_with_border(self, index, border_size): """ Selects an item with an index. Moves the view if the selection would exceed the border of the current view. """ if self.fixed_offset is not None: self.select_item_index_with_offset(index, self.fixed_offset) elif index >= 0 and index < len(self._items): if not in_range(index, self._offset + border_size, self._offset + self._num_visible_items - border_size): offset = index - (self._num_visible_items - 2 * border_size) if self.selected_item_index < index else index - border_size self._offset = clamp(offset, 0, len(self._items)) self._normalize_offset(index) self._do_set_selected_item_index(index)
def _on_content_lists_changed(self): self._last_selected_item = None components = self._list_components contents = self._browser_model.content_lists[self._scroll_offset:] messages = self._browser_model.empty_list_messages scroll_depth = len(self._browser_model.content_lists) - len(self._list_components) self._max_scroll_offset = max(0, scroll_depth + 2) self._max_hierarchy = max(0, scroll_depth) for component, content, message in map(None, components, contents, messages): if component != None: component.scrollable_list = content component.empty_list_message = message active_lists = len(contents) num_head = clamp(active_lists - 1, 0, self.NUM_COLUMNS - 1) head = components[:num_head] last = components[num_head:] def set_data_sources_with_separator(component, sources, separator): for source in sources: source.separator = separator component.set_data_sources(sources) component.set_enabled(True) for idx, component in enumerate(head): offset = idx * self.COLUMN_SIZE sources = self._data_sources[offset:offset + self.COLUMN_SIZE] set_data_sources_with_separator(component, sources, '|') if last: offset = num_head * self.COLUMN_SIZE scrollable_list = last[0].scrollable_list if scrollable_list and find_if(lambda item: item.content.is_folder, scrollable_list.items): sources = self._data_sources[offset:offset + self.COLUMN_SIZE] map(DisplayDataSource.clear, self._data_sources[offset + self.COLUMN_SIZE:]) else: sources = self._data_sources[offset:] set_data_sources_with_separator(last[0], sources, '') for component in last[1:]: component.set_enabled(False) self.set_select_buttons(self._select_buttons) self.set_state_buttons(self._state_buttons) self.set_encoder_controls(self._encoder_controls) self._update_navigation_button_state()
def zoom(self, value): """ Zooms in or out of the waveform start value should be between -1.0 and 1.0, where 1.0 will zoom in as much as possible and -1.0 will zoom out completely. """ animate = self._request_select_region if self._request_select_region or self._process_unsnapping(value): self._select_region(value > 0) source = self._source_roi.region_with_margin target = self._target_roi.region_with_margin easing_degree = calc_easing_degree_for_proportion(float(target.length) / float(source.length)) focused_region, focus_marker, margin_type = self._get_zoom_info_for_focused_object() t = inverse_interpolate_region(source, target, self.visible_region, easing_degree, prefer_end=margin_type == MarginType.START) t = clamp(t + value * self.ZOOM_SENSITIVITY, 0.0, 1.0) region = interpolate_region(source, target, t, easing_degree) region = self._add_margin_to_zoomed_region(region, focused_region, margin_type) self.set_visible_region(region, force_animate=animate, source_action='zoom') self.focus_marker = focus_marker self.show_focus = True self.try_hide_focus_delayed() self._try_lock_region()
def _focus_object_by_identifier(self, identifier, animate = False): """ Focuses the object in the waveform and brings it into the visible range. The visible length is preserved. The position is aligned to the left or right of the visible range, with a certain margin defined by RELATIVE_FOCUS_MARGIN. If the objects region boundary is already in the visible range, the visible position is not changing. :identifier: the object identifier to focus :animate: should be set to True if, if it should animate to the new position """ roi = self._get_roi_for_object_identifier(identifier) region = roi.region if self._locked_roi is not None and self._locked_roi.bound_by(identifier): if region.start < self.waveform_region.start: start = self.waveform_region.start new_visible_region = Region(start, start + self.visible_region.length) elif region.end > self.waveform_region.end: end = self.waveform_region.end new_visible_region = Region(end - self.visible_region.length, end) else: new_visible_region = self._add_margin_to_region(region) self.set_visible_region(new_visible_region, force_animate=animate) else: visible_length = self.visible_region.length visible_margin = visible_length * self.RELATIVE_FOCUS_MARGIN waveform_start, waveform_end = self._waveform_region if roi.end_identifier == identifier: start = min(region.start - visible_margin, self.visible_region.start) right = max(region.end + visible_margin, start + visible_length) left = right - visible_length else: end = max(region.end + visible_margin, self.visible_region.end) left = min(region.start - visible_margin, end - visible_length) right = left + visible_length self.set_visible_region(Region(clamp(left, waveform_start, waveform_end - visible_length), clamp(right, waveform_start + visible_length, waveform_end)), force_animate=animate) self._request_select_region = True self.focus_marker = FocusMarker(self.focusable_object_descriptions[identifier].focus_name, region.end if roi.end_identifier == identifier else region.start)
def display_brightness_encoder(self, value, encoder): self._hardware_settings.display_brightness = clamp(self._hardware_settings.display_brightness + value, self._hardware_settings.min_display_brightness, self._hardware_settings.max_display_brightness)
def to_user_range(minv, maxv): return lambda v, s: clamp(v * (maxv - minv) + minv, minv, maxv)
def to_sample_count(value, simpler): return clamp(int(value * simpler.sample_length), 0, simpler.sample_length - 1)
def _clamp_value_to_parameter_range(self, value): return clamp(value, self.mapped_parameter.min, self.mapped_parameter.max)
def _set_selected_scale_index(self, index): index = clamp(index, 0, len(self._scale_list) - 1) self._note_layout.scale = self._scale_list[index]
def _zoom_to_internal(self, value, _parent): fudge = self._get_zoom_start_fudge() ** 10 ** (1.0 / self.ZOOM_EXP) linear_value = (value ** (1.0 / self.ZOOM_EXP) - fudge) / (1.0 - fudge) return clamp(linear_value, 0.0, 1.0)