def __init__(self, note_layout = None, *a, **k): assert note_layout is not None super(InstrumentComponent, self).__init__(*a, **k) self._note_layout = note_layout self._first_note = self.page_length * 3 + self.page_offset self._last_page_length = self.page_length self._last_page_offset = self.page_offset self._detail_clip = None self._has_notes = [False] * 128 self._has_notes_pattern = self._get_pattern(0) self._aftertouch_control = None self._aftertouch_mode = u'mono' self._show_notifications = True self.__on_detail_clip_changed.subject = self.song.view self.__on_detail_clip_changed() self._slider = SlideComponent(slideable=self, parent=self) self._touch_slider = SlideableTouchStripComponent(touch_slideable=self, parent=self) for event in (u'scale', u'root_note', u'is_in_key', u'is_fixed', u'is_horizontal', u'interval'): self.register_slot(self._note_layout, self._on_note_layout_changed, event) self._update_pattern()
def __init__(self, note_layout=None, *a, **k): raise note_layout is not None or AssertionError super(InstrumentComponent, self).__init__(*a, **k) self._note_layout = note_layout self._delete_button = None self._first_note = self.page_length * 3 + self.page_offset self._last_page_length = self.page_length self._delete_button = None self._last_page_offset = self.page_offset self._detail_clip = None self._has_notes = [False] * 128 self._has_notes_pattern = self._get_pattern(0) self._aftertouch_control = None self._slider = self.register_component(SlideComponent(self)) self._touch_slider = self.register_component( SlideableTouchStripComponent(self)) for event in ('scale', 'root_note', 'is_in_key', 'is_fixed', 'is_horizontal', 'interval'): self.register_slot(self._note_layout, self._on_note_layout_changed, event) self._update_pattern()
class InstrumentComponent(PlayableComponent, Slideable, Messenger): __events__ = ('pattern', ) matrix = control_matrix(PadControl) delete_button = ButtonControl() def __init__(self, note_layout=None, *a, **k): (super(InstrumentComponent, self).__init__)(*a, **k) self._note_layout = note_layout self._first_note = self.page_length * 3 + self.page_offset self._last_page_length = self.page_length self._last_page_offset = self.page_offset self._detail_clip = None self._has_notes = [False] * 128 self._has_notes_pattern = self._get_pattern(0) self._aftertouch_control = None self._aftertouch_mode = 'mono' self._show_notifications = True self._InstrumentComponent__on_detail_clip_changed.subject = self.song.view self._InstrumentComponent__on_detail_clip_changed() self._slider = SlideComponent(slideable=self, parent=self) self._touch_slider = SlideableTouchStripComponent(touch_slideable=self, parent=self) for event in ('scale', 'root_note', 'is_in_key', 'is_fixed', 'is_horizontal', 'interval'): self.register_slot(self._note_layout, self._on_note_layout_changed, event) self._update_pattern() @listens('detail_clip') def __on_detail_clip_changed(self): clip = self.song.view.detail_clip self.set_detail_clip(clip if (liveobj_valid(clip)) and ( clip.is_midi_clip) else None) def set_detail_clip(self, clip): if clip != self._detail_clip: self._detail_clip = clip self._on_clip_notes_changed.subject = clip self._on_loop_start_changed.subject = clip self._on_loop_end_changed.subject = clip self._on_clip_notes_changed() @listens('notes') def _on_clip_notes_changed(self): if self._detail_clip: self._has_notes = [False] * 128 loop_start = self._detail_clip.loop_start loop_length = self._detail_clip.loop_end - loop_start notes = self._detail_clip.get_notes_extended(from_time=loop_start, from_pitch=0, time_span=loop_length, pitch_span=128) for note in notes: self._has_notes[note.pitch] = True self.notify_contents() @listens('loop_start') def _on_loop_start_changed(self): self._on_loop_selection_changed() @listens('loop_end') def _on_loop_end_changed(self): self._on_loop_selection_changed() def _on_loop_selection_changed(self): self._on_clip_notes_changed() def contents(self, index): if self._detail_clip: note = self._has_notes_pattern[index].index if note is not None: return self._has_notes[note] return False return False @property def show_notifications(self): return self._show_notifications @show_notifications.setter def show_notifications(self, value): self._show_notifications = value @property def page_length(self): if self._note_layout.is_in_key: return len(self._note_layout.notes) return 12 @property def position_count(self): if not self._note_layout.is_in_key: return 139 offset = self.page_offset octaves = 11 if self._note_layout.notes[0] < 8 else 10 return offset + len(self._note_layout.notes) * octaves def _first_scale_note_offset(self): if not self._note_layout.is_in_key: return self._note_layout.notes[0] if self._note_layout.notes[0] == 0: return 0 return len(self._note_layout.notes) - index_if(lambda n: n >= 12, self._note_layout.notes) @property def page_offset(self): if self._note_layout.is_fixed: return 0 return self._first_scale_note_offset() def _get_position(self): return self._first_note def _set_position(self, note): self._first_note = note self._update_pattern() self._update_matrix() self.notify_position() position = property(_get_position, _set_position) @property def min_pitch(self): return self.pattern[0].index @property def max_pitch(self): identifiers = [control.identifier for control in self.matrix] if len(identifiers) > 0: return max(identifiers) return 127 @property def pattern(self): return self._pattern @matrix.pressed def matrix(self, button): self._on_matrix_pressed(button) def _on_matrix_pressed(self, button): if self.delete_button.is_pressed: pitch = self._get_note_info_for_coordinate(button.coordinate).index if pitch: if self._detail_clip: self._do_delete_pitch(pitch) @matrix.released def matrix(self, button): self._on_matrix_released(button) def _on_matrix_released(self, button): pass def _do_delete_pitch(self, pitch): clip = self._detail_clip if clip: note_name = pitch_index_to_string(pitch) loop_length = clip.loop_end - clip.loop_start clip.remove_notes_extended(from_time=(clip.loop_start), from_pitch=pitch, time_span=loop_length, pitch_span=1) self.show_notification(consts.MessageBoxText.DELETE_NOTES % note_name) @delete_button.pressed def delete_button(self, value): self._set_control_pads_from_script(True) @delete_button.released def delete_button(self, value): self._set_control_pads_from_script(False) def set_note_strip(self, strip): self._touch_slider.set_scroll_strip(strip) def set_octave_strip(self, strip): self._touch_slider.set_page_strip(strip) def set_octave_up_button(self, button): self._slider.set_scroll_page_up_button(button) def set_octave_down_button(self, button): self._slider.set_scroll_page_down_button(button) def set_scale_up_button(self, button): self._slider.set_scroll_up_button(button) def set_scale_down_button(self, button): self._slider.set_scroll_down_button(button) def set_aftertouch_control(self, control): self._aftertouch_control = control self._update_aftertouch() def set_aftertouch_mode(self, mode): if self._aftertouch_mode != mode: self._aftertouch_mode = mode self._update_aftertouch() def _align_first_note(self): self._first_note = self.page_offset + ( self._first_note - self._last_page_offset) * old_div( float(self.page_length), float(self._last_page_length)) if self._first_note >= self.position_count: self._first_note -= self.page_length self._last_page_length = self.page_length self._last_page_offset = self.page_offset def _on_note_layout_changed(self, _): self._update_scale() def show_pitch_range_notification(self): if self.is_enabled(): if self.show_notifications: self.show_notification( 'Play {start_note} to {end_note}'.format( start_note=(pitch_index_to_string( self.pattern.note(0, 0).index)), end_note=(pitch_index_to_string( self.pattern.note(self.width - 1, self.height - 1).index)))) def _update_scale(self): self._align_first_note() self._update_pattern() self._update_matrix() self.notify_position_count() self.notify_position() self.notify_contents() def update(self): super(InstrumentComponent, self).update() if self.is_enabled(): self._update_matrix() self._update_aftertouch() def _update_pattern(self): self._pattern = self._get_pattern() self._has_notes_pattern = self._get_pattern(0) self.notify_pattern() def _invert_and_swap_coordinates(self, coordinates): return (coordinates[1], self.height - 1 - coordinates[0]) def _get_note_info_for_coordinate(self, coordinate): x, y = self._invert_and_swap_coordinates(coordinate) return self.pattern.note(x, y) def _update_button_color(self, button): note_info = self._get_note_info_for_coordinate(button.coordinate) button.color = 'Instrument.' + note_info.color def _button_should_be_enabled(self, button): return self._get_note_info_for_coordinate( button.coordinate).index != None def _note_translation_for_button(self, button): note_info = self._get_note_info_for_coordinate(button.coordinate) return (note_info.index, note_info.channel) def _set_button_control_properties(self, button): super(InstrumentComponent, self)._set_button_control_properties(button) button.sensitivity_profile = 'default' if self._takeover_pads else 'instrument' def _update_matrix(self): self._update_control_from_script() self._update_note_translations() self._update_led_feedback() def _get_pattern(self, first_note=None): if first_note is None: first_note = int(round(self._first_note)) interval = self._note_layout.interval notes = self._note_layout.notes width = None height = None octave = old_div(first_note, self.page_length) offset = first_note % self.page_length - self._first_scale_note_offset( ) if interval == None: if self._note_layout.is_in_key: interval = len(self._note_layout.notes) if self._note_layout.is_horizontal: width = interval + 1 else: height = interval + 1 else: interval = 8 elif not self._note_layout.is_in_key: interval = [0, 2, 4, 5, 7, 9, 10, 11][interval] if self._note_layout.is_horizontal: steps = [1, interval] origin = [offset, 0] else: steps = [interval, 1] origin = [0, offset] return MelodicPattern(steps=steps, scale=notes, origin=origin, root_note=(octave * 12), chromatic_mode=(not self._note_layout.is_in_key), width=width, height=height) def _update_aftertouch(self): if self.is_enabled(): if self._aftertouch_control != None: self._aftertouch_control.send_value(self._aftertouch_mode)