def _insert_step(self, time_range, time_index, param_index, envelope, value):
     param = self.parameters[param_index]
     envelope_value = self._parameter_floats[time_index][param_index]
     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, 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)
예제 #2
0
 def _insert_step(self, time_range, time_index, param_index, envelope, value):
     param = self.parameters[param_index]
     envelope_value = self._parameter_floats[time_index][param_index]
     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, 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)
예제 #3
0
 def _touch_strip_to_scroll_position(self, value, offset):
     detailed = self._shift_button and self._shift_button.is_pressed()
     max_pitchbend = 16384.0
     num_pad_rows = 32
     max_pad_row = 28
     bank_size = 4
     offsetted_value = clamp(value - offset, 0, max_pitchbend)
     return min(int(offsetted_value / max_pitchbend *
                    num_pad_rows), max_pad_row) if detailed else clamp(
                        int(
                            int(value / max_pitchbend * num_pad_rows + 3) /
                            float(bank_size)) * bank_size -
                        3, 0, max_pad_row)
예제 #4
0
 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 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 _on_content_lists_changed(self):
        components = self._list_components
        contents = self._browser_model.content_lists
        messages = self._browser_model.empty_list_messages
        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:
            sources = self._data_sources[num_head * self.COLUMN_SIZE:]
            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)
 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 _on_record_quantization_value(self, value):
     self._record_quantization_float = clamp(
         self._record_quantization_float + value, 0.0, 1.0)
     self._record_quantization = float_to_record_quantization(
         self._record_quantization_float)
     self._update_record_quantization()
     self._update_record_quantization_display()
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
예제 #10
0
 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_clip_warp_mode_value(self, value):
     if self._clip != None:
         self._warp_mode_encoder_value = clamp(self._warp_mode_encoder_value + value, 0.0, 1.0)
         if self._clip.warping:
             warp_mode_index = int(self._warp_mode_encoder_value * (len(self._available_warp_modes) - 1))
             self._clip.warp_mode = self._available_warp_modes[warp_mode_index]
     return
 def _touch_strip_to_scroll_position(self, value, offset):
     detailed = self._shift_button and self._shift_button.is_pressed()
     max_pitchbend = 16384.0
     num_pad_rows = 32
     max_pad_row = 28
     bank_size = 4
     offsetted_value = clamp(value - offset, 0, max_pitchbend)
     return min(int(offsetted_value / max_pitchbend * num_pad_rows), max_pad_row) if detailed else clamp(int(int(value / max_pitchbend * num_pad_rows + 3) / float(bank_size)) * bank_size - 3, 0, max_pad_row)
 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 _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)
예제 #15
0
 def _set_option_names(self, value):
     self._option_names = 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_data_sources()
예제 #16
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)
예제 #17
0
 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)
예제 #18
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)
예제 #19
0
 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)
예제 #20
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 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
예제 #22
0
 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 _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 _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 visible_drum_pads(self):
     if self._visible_drum_pads and self._all_drum_pads:
         first_pad = first(self._visible_drum_pads)
         if first_pad:
             size = self.width * self.height
             first_note = first_pad.note
             if first_note > 128 - size:
                 size = 128 - first_note
             offset = clamp(first_note, 0, 128 - len(self._visible_drum_pads))
             return self._all_drum_pads[offset : offset + size]
     return []
 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 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)
예제 #27
0
 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)
예제 #28
0
	def visible_drum_pads(self):
		if self._visible_drum_pads and self._all_drum_pads:
			first_pad = first(self._visible_drum_pads)
			if first_pad:
				size = self.width * self.height
				first_note = first_pad.note
				if first_note > 128 - size:
					size = 128 - first_note
				offset = clamp(first_note, 0, 128 - len(self._visible_drum_pads))
				return self._all_drum_pads[offset:offset + size]
		return []
예제 #29
0
 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)
예제 #30
0
 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):
        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()
        return
    def _on_content_lists_changed(self):
        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()
        return
예제 #33
0
    def set(self, base_name=None, playing_slot_index=None, preset_index=None):
        # type: (Optional[str], Optional[int], Optional[int]) -> None
        playing_slot_index = playing_slot_index if playing_slot_index is not None else self.playing_slot_index
        playing_slot_index = clamp(playing_slot_index, -1,
                                   len(self.track.song.scenes) - 1)

        if base_name and base_name != self.base_name:
            # noinspection PyUnresolvedReferences
            self.notify_base_name()

        name = "%s - %s" % (base_name if base_name else self.base_name,
                            playing_slot_index)

        if self.track.instrument:
            preset_index = preset_index if preset_index is not None else self.preset_index
            preset_index = max(0, preset_index)
            name += " - %s" % preset_index

        self.track.name = name
    def _on_content_lists_changed(self):
        components = self._list_components
        contents = self._browser_model.content_lists
        messages = self._browser_model.empty_list_messages
        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:
            sources = self._data_sources[num_head * self.COLUMN_SIZE:]
            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)
 def _tempo_encoder_value(self, value):
     if self.is_enabled():
         step = 0.1 if self.shift_button.is_pressed else 1.0
         amount = value - 128 if value >= 64 else value
         self.song().tempo = clamp(self.song().tempo + amount * step, 20, 999)
 def _scroll_position(self, delta):
     if self.is_enabled():
         model = self._slideable
         model.position = clamp(model.position + delta, 0, model.position_count - model.page_length)
 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 on_num_sends_changed(self):
     self.send_select_buttons.control_count = clamp(self.num_sends, 0, 8)
 def _clamp_send_index(self):
     self._selected_send_index = clamp(self._selected_send_index, 0, self.num_sends - 1)
     if self._selected_send_index % 2 > 0:
         self._selected_send_index -= 1
예제 #40
0
 def _scroll_position(self, delta):
     if self.is_enabled():
         model = self._slideable
         model.position = clamp(model.position + delta, 0, model.position_count - model.page_length)
예제 #41
0
 def _on_clip_transpose_value(self, value):
     if self._clip != None:
         self._pitch_coarse = clamp(
             self._pitch_coarse + value * 96 * self._encoder_factor, -48.0,
             48.0)
         self._clip.pitch_coarse = int(self._pitch_coarse)
 def clamp(self, time, extra_time = 0.0):
     return clamp(time + extra_time, self.left_boundary(), self.right_boundary())
예제 #43
0
 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]
     return new_position if current_position != new_position else None
 def _on_clip_gain_value(self, value):
     if self._clip != None:
         delta = value * self._encoder_factor
         new_gain = self._clip.gain + delta
         self._clip.gain = clamp(new_gain, 0.0, 1.0)
 def _on_quantize_amount_value(self, value):
     self._quantize_amount = clamp(self._quantize_amount + value, 0.0, 1.0)
     self._update_quantize_amount_display()
 def _on_swing_amount_value(self, value):
     self.song().swing_amount = clamp(self.song().swing_amount + value * 0.5, 0.0, 0.5)
        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.
        """
        if time_step.includes_time(time):
            time = time_step.clamp(time, self._nudge_offset)
            if self._length_offset <= -time_step.length and length + self._length_offset < time_step.length:
                if length > time_step.length:
                    length = time_step.length
            else:
                length = max(0, length + self._length_offset)
            velocity = 127 if self.full_velocity else clamp(velocity + self._velocity_offset, 1, 127)
            mute = not step_mute if self._mute_button and self._mute_button.is_pressed() else mute
        return (pitch,
         time,
         length,
         velocity,
         mute)

    def _min_max_for_notes(self, notes, start_time, min_max_values = None):
        for note in notes:
            note_values = list(note[:4])
            note_values[1] -= start_time
            for index, value in enumerate(note_values):
                if not min_max_values:
                    min_max_values = [(99999, -99999)] * 4
                min_value, max_value = min_max_values[index]
 def _change_swing_amount_value(self, value):
     self._set_swing_amount_value(
         clamp(self.song().swing_amount + value * 0.025, 0.0, 0.99))
예제 #49
0
 def _on_tracks_changed(self):
     tracks = tracks_to_use_from_song(self.song())
     self._track_offset = clamp(self._track_offset, 0, len(tracks) - 1)
     self._on_fired_slot_index_changed.replace_subjects(tracks, count())
     self._on_playing_slot_index_changed.replace_subjects(tracks, count())
     self._update_all_stop_buttons()
 def _on_record_quantization_value(self, value):
     self._record_quantization_float = clamp(self._record_quantization_float + value, 0.0, 1.0)
     self._record_quantization = float_to_record_quantization(self._record_quantization_float)
     self._update_record_quantization()
     self._update_record_quantization_display()
 def on_num_sends_changed(self):
     self.send_select_buttons.control_count = clamp(self.num_sends, 0, 8)
 def _tempo_encoder_value(self, value):
     if self.is_enabled():
         step = 0.1 if self.shift_button.is_pressed else 1.0
         amount = value - 128 if value >= 64 else value
         self.song().tempo = clamp(self.song().tempo + amount * step, 20,
                                   999)
        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.
        """
        if time_step.includes_time(time):
            time = time_step.clamp(time, self._nudge_offset)
            if self._length_offset <= -time_step.length and length + self._length_offset < time_step.length:
                if length > time_step.length:
                    length = time_step.length
            else:
                length = max(0, length + self._length_offset)
            velocity = 127 if self.full_velocity else clamp(
                velocity + self._velocity_offset, 1, 127)
            mute = not step_mute if self._mute_button and self._mute_button.is_pressed(
            ) else mute
        return (pitch, time, length, velocity, mute)

    def _min_max_for_notes(self, notes, start_time, min_max_values=None):
        for note in notes:
            note_values = list(note[:4])
            note_values[1] -= start_time
            for index, value in enumerate(note_values):
                if not min_max_values:
                    min_max_values = [(99999, -99999)] * 4
                min_value, max_value = min_max_values[index]
                min_max_values[index] = (min(value,
                                             min_value), max(value, max_value))
예제 #54
0
 def _on_clip_gain_value(self, value):
     if self._clip != None:
         delta = value * self._encoder_factor
         new_gain = self._clip.gain + delta
         self._clip.gain = clamp(new_gain, 0.0, 1.0)
 def clamp(self, time, extra_time=0.0):
     return clamp(time + extra_time, self.left_boundary(),
                  self.right_boundary())
 def _page_length_in_beats(self):
     return clamp(self._paginator.page_length, 0.5, self._one_measure_in_beats)
 def _on_clip_transpose_value(self, value):
     if self._clip != None:
         self._pitch_coarse = clamp(self._pitch_coarse + value * 96 * self._encoder_factor, -48.0, 48.0)
         self._clip.pitch_coarse = int(self._pitch_coarse)