def on_used_pad_value(self, value, button): """ Handles deleting or quantizing note lanes if certain modifiers are pressed. This is a standard implementation that can be overridden. """ if is_button_pressed(self._delete_button): self.handle_note_delete(value != 0, button.message_identifier()) elif is_button_pressed(self._quantize_button) and value: self.handle_note_quantize()
def _launch_button_value(self, value): """ Overrides standard to deal with new modifiers and handle new functionality. """ if self.is_enabled(): if is_button_pressed(self._select_button) and value: self._do_select_clip(self._clip_slot) elif self._clip_slot is not None: if is_button_pressed(self._delete_button): if value: self._do_delete_clip() elif is_button_pressed(self._duplicate_button): if value: self._do_duplicate_clip() elif is_button_pressed(self._double_button): if value: self._do_double_clip() elif is_button_pressed(self._quantize_button): if value: self._do_quantize_clip() else: if self._should_arm: if value: self._do_track_arm() if self._can_do_fixed_length_recording(): self._do_fixed_length_recording() return elif value and self._can_do_fixed_length_recording(): self._do_fixed_length_recording() return self._do_launch_clip(value) return
def on_used_pad_value(self, value, button): if self._is_slicing(): if is_button_pressed(self._delete_button): self.handle_note_delete(value != 0, button.message_identifier()) elif value: if self.select_pressed(): pad_idx = self._used_pads.index(button) + self._octave_offset if pad_idx < self._num_slices: self._simpler.view.selected_slice = self._simpler.sample.slices[pad_idx] elif is_button_pressed(self._quantize_button): self.handle_note_quantize()
def handle_unall_functions(self): """ Handles deleting/quantizing all notes if certain modifiers are pressed. This is a standard implementation that can be overridden. """ if self._clip and self.select_pressed(): if is_button_pressed(self._delete_button): delete_all_notes(self._clip) return True if is_button_pressed( self._quantize_button) and self._quantize_component: self._quantize_component.quantize_clip(self._clip) return True return False
def _launch_value(self, value): """ Overrides standard to deal with new modifier. """ if self.is_enabled(): if is_button_pressed(self._select_button) and value: self._do_select_scene(self._scene) elif self._scene is not None: if is_button_pressed(self._delete_button): if value: self._do_delete_scene(self._scene) elif is_button_pressed(self._duplicate_button): if value: self._do_duplicate_scene() else: self._do_launch_scene(value) return
def _on_launch_button_value(self, value, button): if self.is_enabled() and value: btn_index = self._launch_buttons.index(button) if is_button_pressed(self._store_button): self._snaps[btn_index] = SessionSnap(self.song()) self._snaps[btn_index].store() self._update_launch_buttons() self._notify_snap_data() elif is_button_pressed(self._delete_button): self._snaps[btn_index] = None button.set_light('DefaultButton.Off') self._notify_snap_data() elif self._snaps[btn_index] is not None: quantized = not is_button_pressed(self._shift_button) self._snaps[btn_index].recall(quantized) return
def _on_cue_button_value(self, value, button): if self.is_enabled() and value: btn_index = self._cue_buttons.index(button) if btn_index < len(self._cues): cues = list(self.song().cue_points) cue_time = self._cue_times[btn_index] cue = None for c in cues: if c.time == cue_time: cue = c break if cue: if self._handle_extra_cue_button_function( button, cue_time): return self.component_message('Triggered Cue', cue.name, header_2=format_absolute_time( self.song(), cue.time)) if is_button_pressed(self._shift_button): self.song().current_song_time = cue.time else: if self.song( ).is_playing and btn_index != self._current_cue_index: self._update_cue_buttons() button.set_light('CuePoint.Triggered') else: self._current_cue_index = -1 cue.jump() return
def increment_scroll_position(self, factor): if not is_button_pressed(self._shift_button): factor *= 12 if self._can_scroll_octave(factor < 0): self._octave_offset += factor self.update() self._display_note_range()
def _on_play_toggle_button(self, value): """ If Clip is playing and not triggered to stop, this will stop it with or without quantization depending on whether shift is pressed. Otherwise, this will launch the clip with or without quantization/legato depending on whether shift is pressed. """ if self.is_enabled() and self.is_session_clip and value: track = self._clip.canonical_parent.canonical_parent if track.fired_slot_index != -2 and (self._clip.is_playing or self._clip.is_triggered or self._clip.is_recording): track.stop_all_clips(not is_button_pressed(self._shift_button)) elif is_button_pressed(self._shift_button): self._clip.canonical_parent.fire(force_legato=True, launch_quantization=LSQ) else: self._clip.fire()
def _on_button_value(self, value, button): if value and self._snap_component: btn_id = self._snap_buttons.index(button) snap = self._snap_data[btn_id] if is_button_pressed(self._delete_button): self.delete_snap(snap, btn_id) return self.store_or_recall_snap(snap, btn_id)
def _handle_extra_cue_button_function(self, button, cue_time): """ Handles storing or deleting snaps if possible. """ cue = self._find_cue_by_time(cue_time) if cue: if is_button_pressed(self._store_button): if cue['snap'] is None: cue['snap'] = SessionSnap(self.song()) cue['snap'].store() self._update_cue_button(button, cue_time) self._notify_snap_data() return True if is_button_pressed(self._delete_button): cue['snap'] = None self._update_cue_button(button, cue_time) self._notify_snap_data() return True return False
def _is_assignment_toggle_gesture(self, ctrl_index, value): def_criteria = ctrl_index == 0 and is_button_pressed( self._shift_button) if def_criteria: if self._controls_are_absolute: return value == 127 return value == 1 return False
def _update_shift_button(self): if self.is_enabled() and self._shift_button and self._handle_shift_led: value = 'HazMap.Modifier' if is_button_pressed(self._shift_button): value = 'HazMap.ModifierPressed' elif self._is_mapping: value = 'HazMap.ModifierMapping' self._shift_button.set_light(value)
def _can_scroll_octave(self, is_decrease): if not self.is_enabled() or not self._captured_notes: return False factor = 1 if is_button_pressed(self._shift_button) else 12 if is_decrease: return self._captured_notes[ 0] - factor + self._octave_offset in MIDI_RANGE return self._captured_notes[ (-1)] + factor + self._octave_offset in MIDI_RANGE
def on_used_pad_value(self, value, button): if self._drum_rack: if is_button_pressed(self._delete_button): self.handle_note_delete(value != 0, button.message_identifier()) elif value: pad_id = button.message_identifier() dr_pad = self._drum_rack.drum_pads[pad_id] if self.select_pressed(): self._drum_rack.view.selected_drum_pad = dr_pad self.component_message('Pad Selection', dr_pad.name) elif is_button_pressed(self._mute_button): dr_pad.mute = not dr_pad.mute elif is_button_pressed(self._solo_button): dr_pad.solo = not dr_pad.solo elif is_button_pressed(self._quantize_button): self.handle_note_quantize() elif is_button_pressed(self._duplicate_button): self._handle_pad_copy(button, pad_id, dr_pad)
def _on_loop_button_value(self, value): """ Toggles/resets the clip's loop. """ if self.is_enabled() and self._clip and value: if is_button_pressed(self._shift_button) and self._clip.looping: self._clip.loop_start = 0.0 self._clip.loop_end = self._clip.end_marker else: self._clip.looping = not self._clip.looping if self._zoom_loop_on_edit: self._clip.view.show_loop() self._clip.view.show_loop()
def alt_select_button(self, _): """ Handles delete, duplicating or plain selecting with optional playing clip selection. """ if self.is_enabled() and live_object_is_valid(self._track): t = self._track if is_button_pressed(self._delete_button): delete_track(self.song(), t, self.component_message) elif is_button_pressed(self._duplicate_button): duplicate_track(self.song(), t, self.component_message) else: reg_track = t in self.song().tracks select_track = self.song().view.selected_track != t select_clip = reg_track and is_button_pressed( self._shift_button) self._track_was_selected = not (select_track or select_clip) if not self._track_was_selected: self.song().view.selected_track = t if select_clip and t.is_visible and t.playing_slot_index >= 0: self._song.view.highlighted_clip_slot = list( t.clip_slots)[t.playing_slot_index]
def _update_add_cue_button(self): if self.is_enabled() and self._add_cue_button: has_cue = self.song().current_song_time in self._cue_times if is_button_pressed(self._shift_button): turn_on = not self.song().is_playing and has_cue self._add_cue_button.set_light( 'Global.CanDelete' if turn_on else 'Global.CannotDelete') else: turn_on = self.song().is_playing or not has_cue self._add_cue_button.set_light( 'Global.CanAdd' if turn_on else 'Global.CannotAdd')
def _update_cue_button(self, button, cue_time): """ Overrides standard to indicate if button has an associated snap or if can delete snap. """ if self.is_enabled(): cue = self._find_cue_by_time(cue_time) if cue: if cue['snap'] is None: button.set_light('CuePoint.Present') else: button.set_light('Global.CanDelete' if is_button_pressed( self._delete_button) else 'Global.HasSnap') return
def _on_add_cue_button_value(self, value): if value: has_cue = self.song().current_song_time in self._cue_times if is_button_pressed(self._shift_button): if not self.song().is_playing and has_cue: for k, v in self._cues.iteritems(): if v['time'] == self.song().current_song_time: self.component_message('Deleted Cue', k.name) break self.song().set_or_delete_cue() elif not has_cue: self.song().set_or_delete_cue()
def handle_unall_functions(self): if self._drum_rack: if self.select_pressed(): if is_button_pressed(self._mute_button): for pad in self._drum_rack.drum_pads: pad.mute = False return True if is_button_pressed(self._solo_button): for pad in self._drum_rack.drum_pads: pad.solo = False return True if is_button_pressed(self._delete_button) and self._clip: delete_all_notes(self._clip) return True if is_button_pressed( self._quantize_button ) and self._clip and self._quantize_component: self._quantize_component.quantize_clip(self._clip) return True return False
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_page_button_value(self, value, _): if self.is_enabled(): if not self._clip: if value and self._track: create_sequence_clip(self.application(), self._track) return if value: pressed = get_group_buttons_pressed(self._page_buttons) start = pressed[0] * self._page_length if is_button_pressed(self._delete_button): self._clip.remove_notes(start, 0, self._page_length, 128) self._show_info('Deleted', start, start + self._page_length) elif is_button_pressed(self._duplicate_button): if pressed[0] < self._num_page_buttons - 1: self._clip.remove_notes(start + self._page_length, 0, self._page_length, 128) n_to_dupe = self._clip.get_notes( start, 0, self._page_length, 128) target_notes = [] for n in n_to_dupe: target_notes.append( (n[0], n[1] + self._page_length, n[2], n[3], n[4])) self._clip.set_notes(tuple(target_notes)) self._show_info('Duplicated', start, start + self._page_length) elif len(pressed) == 2: self._set_page_range(pressed[0], pressed[1]) self._last_page_button_index = -1 else: should_adjust = self._last_page_button_index == pressed[0] self._set_page_range(pressed[0], pressed[0], adjust_clip=should_adjust) self._last_page_button_index = pressed[0]
def increment_scroll_position(self, factor): """ This needs the quantized handling because full drum rack pages don't actually start until the 1st (instead of 0th) row. """ current_pos = self._drum_rack.view.drum_pads_scroll_position should_quantize = self._scroll_by_4_by_default != is_button_pressed( self._shift_button) quantized_factor = PAGE_SIZE if should_quantize: distance = (current_pos - FULL_PAGE_OFFSET) % PAGE_SIZE if distance: if factor > 0: quantized_factor = PAGE_SIZE - distance else: quantized_factor = distance actual_factor = (quantized_factor if should_quantize else 1) * factor self._drum_rack.view.drum_pads_scroll_position = max( 0, min(MAX_DR_SCROLL_POS, current_pos + actual_factor))
def _handle_launch(self, value): """ Handles launching the clip (or not if select is pressed) with legato or with quantization override. """ if is_button_pressed(self._select_button): return if self._legato_active: if value: self._clip.canonical_parent.fire( force_legato=True, launch_quantization=self._quantize_component.quantization) elif value: last_qntz = int(self.song().clip_trigger_quantization) self.song( ).clip_trigger_quantization = self._quantize_component.quantization self._clip.set_fire_button_state(True) self.song().clip_trigger_quantization = last_qntz else: self._clip.set_fire_button_state(False)
def _update_button_sliders(self): if self.is_enabled() and self._controls and self._is_button_slider: height = self._controls[0].height() - 1 delete_btn = self._controls[0].get_button(0) assign_btn = self._controls[0].get_button(height) shift_pressed = is_button_pressed(self._shift_button) if shift_pressed: delete_btn.set_light('DefaultButton.Off' if self. _is_deleting else 'HazMap.DeleteButton') assign_value = 'HazMap.IsMapping' if self._is_mapping else 'HazMap.MapButton' assign_btn.set_light( 'HazMap.IsDeleting' if self._is_deleting else assign_value) elif self._is_mapping: delete_btn.set_light('DefaultButton.Off') for i, c in enumerate(self._controls): btn = c.get_button(height) if btn: a = self._assignments[(i + self._page_index)] btn.set_light( 'HazMap.HasAssign' if a else 'HazMap.NoAssign')
def _on_position_buttons_value(self, value, button): """ Calculates the position within the clip that is associated with the given button and calls overridable methods to handle performing the position action. If the realign button is pressed, this will realign the clip's playing position with that of the song. """ if self.is_enabled() and self._clip: if value: if is_button_pressed(self._realign_button): self.realign_playing_position() else: start_offset = 0.0 + int( self._clip.looping) * self._clip.loop_start btn_pos = (self._clip.loop_end - start_offset) / len( self._position_buttons) * self._position_buttons.index( button) + start_offset end = self._clip.loop_end if self._clip.looping and end > self._clip.end_marker: end = self._clip.end_marker if 0.0 <= btn_pos <= end - MIN_CLIP_LOOP_LENGTH: self.perform_position_action(btn_pos) else: self._off_method()
def _navigate_devices(self, direction): view = self.application().view if not view.is_view_visible('Detail') or not view.is_view_visible( 'Detail/DeviceChain'): view.show_view('Detail') view.show_view('Detail/DeviceChain') elif is_button_pressed(self._shift_button): rack = get_enclosing_rack(self._device) if rack: if direction == NavDirection.right: if rack.view.is_showing_chain_devices: increment_selected_chain( rack, 1, wrap=True, show_msg=self.component_message) else: rack.view.is_showing_chain_devices = True else: rack.view.is_showing_chain_devices = False else: view.scroll_view(direction, 'Detail/DeviceChain', False)
def _on_chains_changed(self): if not is_button_pressed(self._duplicate_button): self._update_all_pad_settings() self._update_all_pad_leds()
def select_pressed(self): """ Returns whether the select button (if present) is pressed. If it's not present, returns the pressed state of the shift button. """ if self._select_button: return is_button_pressed(self._select_button) return is_button_pressed(self._shift_button)