def _split_simultaneous_by_duration( self, duration, tie_split_notes=True, repeat_ties=False, ): assert self.is_simultaneous left_components, right_components = [], [] for component in self[:]: halves = component._split_by_duration( duration=duration, tie_split_notes=tie_split_notes, repeat_ties=repeat_ties, ) left_components_, right_components_ = halves left_components.extend(left_components_) right_components.extend(right_components_) left_components = select(left_components) right_components = select(right_components) left_container = self.__copy__() right_container = self.__copy__() left_container.extend(left_components) right_container.extend(right_components) if inspect(self).parentage().parent is not None: containers = select([left_container, right_container]) mutate(self).replace(containers) # return list-wrapped halves of container return [left_container], [right_container]
def _split_simultaneous_by_duration( self, duration, tie_split_notes=True, repeat_ties=False ): assert self.is_simultaneous left_components, right_components = [], [] for component in self[:]: halves = component._split_by_duration( duration=duration, tie_split_notes=tie_split_notes, repeat_ties=repeat_ties, ) left_components_, right_components_ = halves left_components.extend(left_components_) right_components.extend(right_components_) left_components = select(left_components) right_components = select(right_components) left_container = self.__copy__() right_container = self.__copy__() left_container.extend(left_components) right_container.extend(right_components) if inspect(self).parentage().parent is not None: containers = select([left_container, right_container]) mutate(self).replace(containers) # return list-wrapped halves of container return [left_container], [right_container]
def _set_duration(self, new_duration): from .Chord import Chord from .Note import Note from .NoteMaker import NoteMaker from .Tuplet import Tuplet from abjad.spanners import tie as abjad_tie new_duration = Duration(new_duration) if self.multiplier is not None: multiplier = new_duration.__div__(self.written_duration) self.multiplier = multiplier return select(self) try: self.written_duration = new_duration return select(self) except exceptions.AssignabilityError: pass maker = NoteMaker() components = maker(0, new_duration) new_leaves = select(components).leaves() following_leaf_count = len(new_leaves) - 1 following_leaves = following_leaf_count * self all_leaves = [self] + following_leaves for leaf, new_leaf in zip(all_leaves, new_leaves): leaf.written_duration = new_leaf.written_duration logical_tie = self._get_logical_tie() logical_tie_leaves = list(logical_tie.leaves) for leaf in logical_tie: detach(Tie, leaf) detach(RepeatTie, leaf) if self._parent is not None: index = self._parent.index(self) next_ = index + 1 self._parent[next_:next_] = following_leaves index = logical_tie_leaves.index(self) next_ = index + 1 logical_tie_leaves[next_:next_] = following_leaves if 1 < len(logical_tie_leaves) and isinstance(self, (Note, Chord)): abjad_tie(logical_tie_leaves) if isinstance(components[0], Leaf): return select(all_leaves) else: assert isinstance(components[0], Tuplet) assert len(components) == 1 tuplet = components[0] multiplier = tuplet.multiplier tuplet = Tuplet(multiplier, []) mutate(all_leaves).wrap(tuplet) return select(tuplet)
def _set_duration(self, new_duration, repeat_ties=False): from .Chord import Chord from .Note import Note from .NoteMaker import NoteMaker from .Tuplet import Tuplet from abjad.spanners import tie as abjad_tie new_duration = Duration(new_duration) if self.multiplier is not None: multiplier = new_duration.__div__(self.written_duration) self.multiplier = multiplier return select(self) try: self.written_duration = new_duration return select(self) except exceptions.AssignabilityError: pass maker = NoteMaker(repeat_ties=repeat_ties) components = maker(0, new_duration) new_leaves = select(components).leaves() following_leaf_count = len(new_leaves) - 1 following_leaves = following_leaf_count * self all_leaves = [self] + following_leaves for leaf, new_leaf in zip(all_leaves, new_leaves): leaf.written_duration = new_leaf.written_duration logical_tie = self._get_logical_tie() logical_tie_leaves = list(logical_tie.leaves) for leaf in logical_tie: detach(TieIndicator, leaf) detach(RepeatTie, leaf) if self._parent is not None: index = self._parent.index(self) next_ = index + 1 self._parent[next_:next_] = following_leaves index = logical_tie_leaves.index(self) next_ = index + 1 logical_tie_leaves[next_:next_] = following_leaves if 1 < len(logical_tie_leaves) and isinstance(self, (Note, Chord)): abjad_tie(logical_tie_leaves) if isinstance(components[0], Leaf): return select(all_leaves) else: assert isinstance(components[0], Tuplet) assert len(components) == 1 tuplet = components[0] multiplier = tuplet.multiplier tuplet = Tuplet(multiplier, []) mutate(all_leaves).wrap(tuplet) return select(tuplet)
def __mul__(self, n): """ Copies component `n` times and detaches spanners. Returns list of new components. """ components = [] for i in range(n): component = mutate(self).copy() components.append(component) result = select(components) return result
def __mul__(self, n): """ Copies component `n` times and detaches spanners. Returns list of new components. """ components = [] for i in range(n): component = mutate(self).copy() components.append(component) result = select(components) return result
def _add_or_remove_notes_to_achieve_written_duration( self, new_written_duration): from abjad.spanners import tie as abjad_tie from .NoteMaker import NoteMaker from .Tuplet import Tuplet new_written_duration = Duration(new_written_duration) maker = NoteMaker() if new_written_duration.is_assignable: self[0].written_duration = new_written_duration for leaf in self[1:]: mutate(leaf).extract() detach(Tie, self[0]) detach(RepeatTie, self[0]) elif new_written_duration.has_power_of_two_denominator: durations = maker(0, [new_written_duration]) for leaf, token in zip(self, durations): leaf.written_duration = token.written_duration if len(self) == len(durations): pass elif len(durations) < len(self): for leaf in self[len(durations):]: mutate(leaf).extract() elif len(self) < len(durations): # detach(Tie, self[0]) detach(Tie, self[0]) detach(RepeatTie, self[0]) difference = len(durations) - len(self) extra_leaves = self[0] * difference for extra_leaf in extra_leaves: # detach(Tie, extra_leaf) detach(Tie, extra_leaf) detach(RepeatTie, extra_leaf) extra_tokens = durations[len(self):] for leaf, token in zip(extra_leaves, extra_tokens): leaf.written_duration = token.written_duration parent = inspect(self[-1]).parentage().parent index = parent.index(self[-1]) next_ = index + 1 parent[next_:next_] = extra_leaves leaves = self.leaves + extra_leaves # attach(Tie(), leaves) abjad_tie(leaves) else: components = maker(0, new_written_duration) assert isinstance(components[0], Tuplet) tuplet = components[0] logical_tie = tuplet[0]._get_logical_tie() duration = logical_tie._get_preprolated_duration() leaves_ = self._add_or_remove_notes_to_achieve_written_duration( duration) multiplier = tuplet.multiplier tuplet = Tuplet(multiplier, []) # mutate(self.leaves).wrap(tuplet) mutate(leaves_).wrap(tuplet) return self[0]._get_logical_tie()
def _split_at_index(self, i): """ Splits container to the left of index ``i``. Preserves tuplet multiplier when container is a tuplet. Preserves time signature denominator when container is a measure. Resizes resizable containers. Returns split parts. """ from .Tuplet import Tuplet # partition my components left_components = self[:i] right_components = self[i:] # instantiate new left and right containers if isinstance(self, Tuplet): multiplier = self.multiplier left = type(self)(multiplier, []) mutate(left_components).wrap(left) right = type(self)(multiplier, []) mutate(right_components).wrap(right) else: left = self.__copy__() mutate(left_components).wrap(left) right = self.__copy__() mutate(right_components).wrap(right) # save left and right containers together for iteration halves = (left, right) nonempty_halves = [half for half in halves if len(half)] # incorporate left and right parents in score if possible selection = select(self) parent, start, stop = selection._get_parent_and_start_stop_indices() if parent is not None: parent._components.__setitem__( slice(start, stop + 1), nonempty_halves ) for part in nonempty_halves: part._set_parent(parent) else: left._set_parent(None) right._set_parent(None) # return new left and right containers return halves
def _match_anchor_leaf(self): from .Chord import Chord from .Note import Note first_grace = abjad_inspect(self).leaf(0) if not isinstance(first_grace, (Note, Chord)): message = f"must start with note or chord:\n" message += f" {repr(self)}" raise Exception(message) anchor_leaf = self._get_on_beat_anchor_leaf() if isinstance(anchor_leaf, (Note, Chord)) and isinstance(first_grace, (Note, Chord)): if isinstance(first_grace, Note): chord = Chord(first_grace) mutate(first_grace).replace(chord) first_grace = chord anchor_pitches = abjad_inspect(anchor_leaf).pitches() highest_pitch = list(sorted(anchor_pitches))[-1] if highest_pitch not in first_grace.note_heads: first_grace.note_heads.append(highest_pitch) grace_mate_head = first_grace.note_heads.get(highest_pitch) tweak(grace_mate_head).font_size = 0 tweak(grace_mate_head).transparent = True
def _split_at_index(self, i): """ Splits container to the left of index ``i``. Preserves tuplet multiplier when container is a tuplet. Preserves time signature denominator when container is a measure. Resizes resizable containers. Returns split parts. """ from .Tuplet import Tuplet # partition my components left_components = self[:i] right_components = self[i:] # instantiate new left and right containers if isinstance(self, Tuplet): multiplier = self.multiplier left = type(self)(multiplier, []) mutate(left_components).wrap(left) right = type(self)(multiplier, []) mutate(right_components).wrap(right) else: left = self.__copy__() mutate(left_components).wrap(left) right = self.__copy__() mutate(right_components).wrap(right) # save left and right containers together for iteration halves = (left, right) nonempty_halves = [half for half in halves if len(half)] # incorporate left and right parents in score if possible selection = select(self) parent, start, stop = selection._get_parent_and_start_stop_indices() if parent is not None: parent._components.__setitem__(slice(start, stop + 1), nonempty_halves) for part in nonempty_halves: part._set_parent(parent) else: left._set_parent(None) right._set_parent(None) # return new left and right containers return halves
def to_tuplet(self, proportions): r""" Changes logical tie to tuplet. .. container:: example >>> staff = abjad.Staff(r"df'8 c'8 ~ c'16 cqs''4") >>> abjad.attach(abjad.Dynamic('p'), staff[0]) >>> abjad.attach(abjad.HairpinIndicator('<'), staff[0]) >>> abjad.attach(abjad.Dynamic('f'), staff[-1]) >>> abjad.override(staff).dynamic_line_spanner.staff_padding = 3 >>> time_signature = abjad.TimeSignature((9, 16)) >>> abjad.attach(time_signature, staff[0]) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff \with { \override DynamicLineSpanner.staff-padding = #3 } { \time 9/16 df'8 \p \< c'8 ~ c'16 cqs''4 \f } >>> logical_tie = abjad.inspect(staff[1]).logical_tie() >>> logical_tie.to_tuplet([2, 1, 1, 1]) Tuplet(Multiplier(3, 5), "c'8 c'16 c'16 c'16") .. docs:: >>> abjad.f(staff) \new Staff \with { \override DynamicLineSpanner.staff-padding = #3 } { \time 9/16 df'8 \p \< \tweak text #tuplet-number::calc-fraction-text \times 3/5 { c'8 c'16 c'16 c'16 } cqs''4 \f } >>> abjad.show(staff) # doctest: +SKIP .. container:: example >>> staff = abjad.Staff(r"c'8 ~ c'16 cqs''4") >>> abjad.hairpin('p < f', staff[:]) >>> abjad.override(staff).dynamic_line_spanner.staff_padding = 3 >>> time_signature = abjad.TimeSignature((7, 16)) >>> abjad.attach(time_signature, staff[0]) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff \with { \override DynamicLineSpanner.staff-padding = #3 } { \time 7/16 c'8 \p \< ~ c'16 cqs''4 \f } Returns tuplet. """ from .Note import Note from .Note import Note from .NoteMaker import NoteMaker from .Tuplet import Tuplet proportions = Ratio(proportions) target_duration = self._get_preprolated_duration() prolated_duration = target_duration / sum(proportions.numbers) basic_written_duration = \ prolated_duration.equal_or_greater_power_of_two written_durations = [ _ * basic_written_duration for _ in proportions.numbers ] maker = NoteMaker() try: notes = [Note(0, _) for _ in written_durations] except exceptions.AssignabilityError: denominator = target_duration._denominator note_durations = [ Duration(_, denominator) for _ in proportions.numbers ] notes = maker(0, note_durations) tuplet = Tuplet.from_duration(target_duration, notes) for leaf in self: detach(TieIndicator, leaf) detach(RepeatTie, leaf) mutate(self).replace(tuplet) return tuplet
def rhythm( class_, selections, divisions=None, attach_lilypond_voice_commands=None, implicit_scaling=None, pitched_staff=None, simultaneous_selections=None, time_signatures=None, ): r""" Makes rhythm-styled LilyPond file. .. container:: example Makes rhythmic staff: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... divisions, ... ) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file[abjad.Score] >>> abjad.f(score) \new Score << \new GlobalContext { { % measure \time 3/4 s1 * 3/4 } % measure { % measure \time 4/8 s1 * 1/2 } % measure { % measure \time 1/4 s1 * 1/4 } % measure } \new RhythmicStaff { { % measure \time 3/4 c'8 [ c'8 c'8 c'8 c'8 c'8 ] } % measure { % measure \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } % measure { % measure \time 1/4 c'8 [ c'8 ] } % measure } >> .. container:: example Set time signatures explicitly: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... [(6, 8), (4, 8), (2, 8)], ... ) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file[abjad.Score] >>> abjad.f(score) \new Score << \new GlobalContext { { % measure \time 6/8 s1 * 3/4 } % measure { % measure \time 4/8 s1 * 1/2 } % measure { % measure \time 2/8 s1 * 1/4 } % measure } \new RhythmicStaff { { % measure \time 6/8 c'8 [ c'8 c'8 c'8 c'8 c'8 ] } % measure { % measure \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } % measure { % measure \time 2/8 c'8 [ c'8 ] } % measure } >> .. container:: example Makes pitched staff: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... divisions, ... pitched_staff=True, ... ) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> abjad.f(lilypond_file[abjad.Score]) \new Score << \new GlobalContext { { % measure \time 3/4 s1 * 3/4 } % measure { % measure \time 4/8 s1 * 1/2 } % measure { % measure \time 1/4 s1 * 1/4 } % measure } \new Staff { { % measure \time 3/4 c'8 [ c'8 c'8 c'8 c'8 c'8 ] } % measure { % measure \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } % measure { % measure \time 1/4 c'8 [ c'8 ] } % measure } >> .. container:: example Makes simultaneous voices: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> for note in abjad.iterate(selections).components(abjad.Note): ... note.written_pitch = abjad.NamedPitch("e'") ... >>> selection_1 = selections[0] + selections[1] + selections[2] >>> selections = [ ... maker(12 * [0], [(1, 16)]), ... maker(16 * [0], [(1, 32)]), ... maker(4 * [0], [(1, 16)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> selection_2 = selections[0] + selections[1] + selections[2] >>> selections = { ... 'Voice 1': selection_1, ... 'Voice 2': selection_2, ... } >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... divisions, ... ) >>> voice_1 = lilypond_file['Voice 1'] >>> abjad.attach(abjad.LilyPondLiteral(r'\voiceOne'), voice_1) >>> voice_2 = lilypond_file['Voice 2'] >>> abjad.attach(abjad.LilyPondLiteral(r'\voiceTwo'), voice_2) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> abjad.f(lilypond_file[abjad.Score]) \new Score << \new GlobalContext { { % measure \time 3/4 s1 * 3/4 } % measure { % measure \time 4/8 s1 * 1/2 } % measure { % measure \time 1/4 s1 * 1/4 } % measure } \new Staff << \context Voice = "Voice 1" { \voiceOne e'8 [ e'8 e'8 e'8 e'8 e'8 ] e'16 [ e'16 e'16 e'16 e'16 e'16 e'16 e'16 ] e'8 [ e'8 ] } \context Voice = "Voice 2" { \voiceTwo c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] c'32 [ c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 ] c'16 [ c'16 c'16 c'16 ] } >> >> Returns LilyPond file. """ if isinstance(selections, list): for selection in selections: if not isinstance(selection, Selection): message = f'must be selection: {selection!r}.' raise TypeError(message) elif isinstance(selections, dict): for selection in selections.values(): if not isinstance(selection, Selection): message = f'must be selection: {selection!r}.' raise TypeError(message) else: message = f'must be list or dictionary: {selections!r}.' raise TypeError(message) score = Score() lilypond_file = LilyPondFile.new( score, includes=['default.ily', 'rhythm-maker-docs.ily'], ) if pitched_staff is None: if isinstance(selections, list): selections_ = selections elif isinstance(selections, dict): selections_ = selections.values() else: raise TypeError(selections) for note in iterate(selections_).leaves(Note): if note.written_pitch != NamedPitch("c'"): pitched_staff = True break if isinstance(selections, list): if divisions is None: duration = abjad_inspect(selections).duration() divisions = [duration] time_signatures = time_signatures or divisions maker = MeasureMaker(implicit_scaling=implicit_scaling) measures = maker(time_signatures) if pitched_staff: staff = Staff(measures) else: staff = Staff(measures, lilypond_type='RhythmicStaff') selections = sequence(selections).flatten(depth=-1) selections_ = copy.deepcopy(selections) try: agent = mutate(staff) measures = agent.replace_measure_contents(selections) except StopIteration: if pitched_staff: staff = Staff(selections_) else: staff = Staff( selections_, lilypond_type='RhythmicStaff', ) elif isinstance(selections, dict): voices = [] for voice_name in sorted(selections): selections_ = selections[voice_name] selections_ = sequence(selections_).flatten(depth=-1) selections_ = copy.deepcopy(selections_) voice = Voice(selections_, name=voice_name) if attach_lilypond_voice_commands: voice_name_to_command_string = { 'Voice 1': 'voiceOne', 'Voice 2': 'voiceTwo', 'Voice 3': 'voiceThree', 'Voice 4': 'voiceFour', } command_string = voice_name_to_command_string.get( voice_name, ) if command_string: command = LilyPondLiteral('\\' + command_string) attach(command, voice) voices.append(voice) staff = Staff(voices, is_simultaneous=True) if divisions is None: duration = abjad_inspect(staff).duration() divisions = [duration] else: message = 'must be list or dictionary of selections:' message += f' {selections!r}.' raise TypeError(message) score.append(staff) assert isinstance(divisions, collections.Sequence), repr(divisions) time_signatures = time_signatures or divisions context = Context(lilypond_type='GlobalContext') maker = MeasureMaker(implicit_scaling=implicit_scaling) measures = maker(time_signatures) context.extend(measures) score.insert(0, context) return lilypond_file
def _split_by_durations( self, durations, cyclic=False, tie_split_notes=True, repeat_ties=False, ): from .AfterGraceContainer import AfterGraceContainer from .Chord import Chord from .GraceContainer import GraceContainer from .Note import Note from .Selection import Selection from .Tuplet import Tuplet durations = [Duration(_) for _ in durations] durations = Sequence(durations) leaf_duration = inspect(self).duration() if cyclic: durations = durations.repeat_to_weight(leaf_duration) if sum(durations) < leaf_duration: last_duration = leaf_duration - sum(durations) durations = list(durations) durations.append(last_duration) durations = Sequence(durations) durations = durations.truncate(weight=leaf_duration) originally_tied = inspect(self).has_indicator(TieIndicator) originally_repeat_tied = inspect(self).has_indicator(RepeatTie) result_selections = [] grace_container = self._detach_grace_container() after_grace_container = self._detach_after_grace_container() leaf_prolation = inspect(self).parentage().prolation for duration in durations: new_leaf = copy.copy(self) preprolated_duration = duration / leaf_prolation selection = new_leaf._set_duration( preprolated_duration, repeat_ties=repeat_ties, ) result_selections.append(selection) result_components = Sequence(result_selections).flatten(depth=-1) result_components = select(result_components) result_leaves = select(result_components).leaves(grace_notes=False) assert all(isinstance(_, Selection) for _ in result_selections) assert all(isinstance(_, Component) for _ in result_components) assert result_leaves.are_leaves() # for leaf in result_leaves: # detach(Tie, leaf) # strip result leaves of all indicators for leaf in result_leaves: detach(object, leaf) # replace leaf with flattened result if self._parent is not None: mutate(self).replace(result_components) # move indicators first_result_leaf = result_leaves[0] last_result_leaf = result_leaves[-1] for indicator in inspect(self).indicators(): detach(indicator, self) direction = getattr(indicator, '_time_orientation', enums.Left) if direction is enums.Left: attach(indicator, first_result_leaf) elif direction == enums.Right: attach(indicator, last_result_leaf) else: raise ValueError(direction) # move grace containers if grace_container is not None: container = grace_container[0] assert isinstance(container, GraceContainer), repr(container) attach(container, first_result_leaf) if after_grace_container is not None: container = after_grace_container[0] prototype = AfterGraceContainer assert isinstance(container, prototype), repr(container) attach(container, last_result_leaf) if isinstance(result_components[0], Tuplet): mutate(result_components).fuse() # tie split notes if (tie_split_notes and isinstance(self, (Note, Chord)) and 1 < len(result_leaves)): result_leaves._attach_tie_to_leaves(repeat_ties=repeat_ties) #assert not inspect(result_leaves[0]).has_indicator(RepeatTie) detach(RepeatTie, result_leaves[0]) #assert not inspect(result_leaves[-1]).has_indicator(TieIndicator) detach(TieIndicator, result_leaves[-1]) if originally_repeat_tied: tie = RepeatTie() attach(tie, result_leaves[0]) if originally_tied: tie = TieIndicator() attach(tie, result_leaves[-1]) assert isinstance(result_leaves, Selection) assert all(isinstance(_, Leaf) for _ in result_leaves) return result_leaves
def on_beat_grace_container( contents, anchor_voice_selection, *, anchor_voice_number=2, do_not_beam=None, do_not_slash=None, do_not_slur=None, do_not_stop_polyphony=None, font_size=-3, grace_voice_number=1, leaf_duration=None, ): r""" Makes on-beat grace container and wraps around ``selection``. .. container:: example GRACE NOTES ABOVE. Note-to-note anchor: >>> music_voice = abjad.Voice("c'4 d' e' f'", name="Music_Voice") >>> string = "g'8 a' b' c'' d'' c'' b' a' b' c'' d''" >>> result = abjad.on_beat_grace_container( ... string, music_voice[1:3], leaf_duration=(1, 30) ... ) >>> staff = abjad.Staff([music_voice]) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff { \context Voice = "Music_Voice" { c'4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 %! abjad.on_beat_grace_container(1) \slash %! abjad.on_beat_grace_container(2) \voiceOne %! abjad.on_beat_grace_container(3) < \tweak font-size #0 \tweak transparent ##t d' g' >8 * 4/15 [ ( a'8 * 4/15 b'8 * 4/15 c''8 * 4/15 d''8 * 4/15 c''8 * 4/15 b'8 * 4/15 a'8 * 4/15 b'8 * 4/15 c''8 * 4/15 d''8 * 4/15 ) ] } \context Voice = "Music_Voice" { \voiceTwo %! abjad.on_beat_grace_container(4) d'4 e'4 } >> \oneVoice %! abjad.on_beat_grace_container(5) f'4 } } Note-to-chord anchor: >>> music_voice = abjad.Voice( ... "<a c'>4 <b d'> <c' e'> <d' f'>", name="Music_Voice" ... ) >>> string = "g'8 a' b' c'' d'' c'' b' a' b' c'' d''" >>> result = abjad.on_beat_grace_container( ... string, music_voice[1:3], leaf_duration=(1, 30) ... ) >>> staff = abjad.Staff([music_voice]) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff { \context Voice = "Music_Voice" { <a c'>4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 %! abjad.on_beat_grace_container(1) \slash %! abjad.on_beat_grace_container(2) \voiceOne %! abjad.on_beat_grace_container(3) < \tweak font-size #0 \tweak transparent ##t d' g' >8 * 4/15 [ ( a'8 * 4/15 b'8 * 4/15 c''8 * 4/15 d''8 * 4/15 c''8 * 4/15 b'8 * 4/15 a'8 * 4/15 b'8 * 4/15 c''8 * 4/15 d''8 * 4/15 ) ] } \context Voice = "Music_Voice" { \voiceTwo %! abjad.on_beat_grace_container(4) <b d'>4 <c' e'>4 } >> \oneVoice %! abjad.on_beat_grace_container(5) <d' f'>4 } } Chord-to-note anchor: >>> music_voice = abjad.Voice("c'4 d' e' f'", name="Music_Voice") >>> string = "<g' b'>8 a' b' c'' d'' c'' b' a' b' c'' d''" >>> result = abjad.on_beat_grace_container( ... string, music_voice[1:3], leaf_duration=(1, 30) ... ) >>> staff = abjad.Staff([music_voice]) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff { \context Voice = "Music_Voice" { c'4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 %! abjad.on_beat_grace_container(1) \slash %! abjad.on_beat_grace_container(2) \voiceOne %! abjad.on_beat_grace_container(3) < \tweak font-size #0 \tweak transparent ##t d' g' b' >8 * 4/15 [ ( a'8 * 4/15 b'8 * 4/15 c''8 * 4/15 d''8 * 4/15 c''8 * 4/15 b'8 * 4/15 a'8 * 4/15 b'8 * 4/15 c''8 * 4/15 d''8 * 4/15 ) ] } \context Voice = "Music_Voice" { \voiceTwo %! abjad.on_beat_grace_container(4) d'4 e'4 } >> \oneVoice %! abjad.on_beat_grace_container(5) f'4 } } Chord-to-chord anchor: >>> music_voice = abjad.Voice( ... "<a c'>4 <b d'> <c' e'> <d' f'>", name="Music_Voice" ... ) >>> string = "<g' b'>8 a' b' c'' d'' c'' b' a' b' c'' d''" >>> result = abjad.on_beat_grace_container( ... string, music_voice[1:3], leaf_duration=(1, 30) ... ) >>> staff = abjad.Staff([music_voice]) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff { \context Voice = "Music_Voice" { <a c'>4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 %! abjad.on_beat_grace_container(1) \slash %! abjad.on_beat_grace_container(2) \voiceOne %! abjad.on_beat_grace_container(3) < \tweak font-size #0 \tweak transparent ##t d' g' b' >8 * 4/15 [ ( a'8 * 4/15 b'8 * 4/15 c''8 * 4/15 d''8 * 4/15 c''8 * 4/15 b'8 * 4/15 a'8 * 4/15 b'8 * 4/15 c''8 * 4/15 d''8 * 4/15 ) ] } \context Voice = "Music_Voice" { \voiceTwo %! abjad.on_beat_grace_container(4) <b d'>4 <c' e'>4 } >> \oneVoice %! abjad.on_beat_grace_container(5) <d' f'>4 } } .. container:: example GRACE NOTES BELOW. Note-to-note anchor: >>> music_voice = abjad.Voice("c'4 d' e' f'", name="Music_Voice") >>> string = "g8 a b c' d' c' b a b c' d'" >>> result = abjad.on_beat_grace_container( ... string, ... music_voice[1:3], ... anchor_voice_number=1, ... grace_voice_number=2, ... leaf_duration=(1, 30), ... ) >>> staff = abjad.Staff([music_voice]) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff { \context Voice = "Music_Voice" { c'4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 %! abjad.on_beat_grace_container(1) \slash %! abjad.on_beat_grace_container(2) \voiceTwo %! abjad.on_beat_grace_container(3) < g \tweak font-size #0 \tweak transparent ##t d' >8 * 4/15 [ ( a8 * 4/15 b8 * 4/15 c'8 * 4/15 d'8 * 4/15 c'8 * 4/15 b8 * 4/15 a8 * 4/15 b8 * 4/15 c'8 * 4/15 d'8 * 4/15 ) ] } \context Voice = "Music_Voice" { \voiceOne %! abjad.on_beat_grace_container(4) d'4 e'4 } >> \oneVoice %! abjad.on_beat_grace_container(5) f'4 } } Note-to-chord anchor: >>> music_voice = abjad.Voice( ... "<c' e'>4 <d' f'> <e' g'> <f' a'>", name="Music_Voice" ... ) >>> string = "g8 a b c' d' c' b a b c' d'" >>> result = abjad.on_beat_grace_container( ... string, ... music_voice[1:3], ... anchor_voice_number=1, ... grace_voice_number=2, ... leaf_duration=(1, 30), ... ) >>> staff = abjad.Staff([music_voice]) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff { \context Voice = "Music_Voice" { <c' e'>4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 %! abjad.on_beat_grace_container(1) \slash %! abjad.on_beat_grace_container(2) \voiceTwo %! abjad.on_beat_grace_container(3) < g \tweak font-size #0 \tweak transparent ##t f' >8 * 4/15 [ ( a8 * 4/15 b8 * 4/15 c'8 * 4/15 d'8 * 4/15 c'8 * 4/15 b8 * 4/15 a8 * 4/15 b8 * 4/15 c'8 * 4/15 d'8 * 4/15 ) ] } \context Voice = "Music_Voice" { \voiceOne %! abjad.on_beat_grace_container(4) <d' f'>4 <e' g'>4 } >> \oneVoice %! abjad.on_beat_grace_container(5) <f' a'>4 } } Chord-to-note anchor: >>> music_voice = abjad.Voice("c'4 d' e' f'", name="Music_Voice") >>> string = "<e g>8 a b c' d' c' b a b c' d'" >>> result = abjad.on_beat_grace_container( ... string, ... music_voice[1:3], ... anchor_voice_number=1, ... grace_voice_number=2, ... leaf_duration=(1, 30), ... ) >>> staff = abjad.Staff([music_voice]) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff { \context Voice = "Music_Voice" { c'4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 %! abjad.on_beat_grace_container(1) \slash %! abjad.on_beat_grace_container(2) \voiceTwo %! abjad.on_beat_grace_container(3) < e g \tweak font-size #0 \tweak transparent ##t d' >8 * 4/15 [ ( a8 * 4/15 b8 * 4/15 c'8 * 4/15 d'8 * 4/15 c'8 * 4/15 b8 * 4/15 a8 * 4/15 b8 * 4/15 c'8 * 4/15 d'8 * 4/15 ) ] } \context Voice = "Music_Voice" { \voiceOne %! abjad.on_beat_grace_container(4) d'4 e'4 } >> \oneVoice %! abjad.on_beat_grace_container(5) f'4 } } Chord-to-chord anchor: >>> music_voice = abjad.Voice( ... "<c' e'>4 <d' f'> <e' g'> <f' a'>", name="Music_Voice" ... ) >>> string = "<e g>8 a b c' d' c' b a b c' d'" >>> result = abjad.on_beat_grace_container( ... string, ... music_voice[1:3], ... anchor_voice_number=1, ... grace_voice_number=2, ... leaf_duration=(1, 30), ... ) >>> staff = abjad.Staff([music_voice]) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff { \context Voice = "Music_Voice" { <c' e'>4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 %! abjad.on_beat_grace_container(1) \slash %! abjad.on_beat_grace_container(2) \voiceTwo %! abjad.on_beat_grace_container(3) < e g \tweak font-size #0 \tweak transparent ##t f' >8 * 4/15 [ ( a8 * 4/15 b8 * 4/15 c'8 * 4/15 d'8 * 4/15 c'8 * 4/15 b8 * 4/15 a8 * 4/15 b8 * 4/15 c'8 * 4/15 d'8 * 4/15 ) ] } \context Voice = "Music_Voice" { \voiceOne %! abjad.on_beat_grace_container(4) <d' f'>4 <e' g'>4 } >> \oneVoice %! abjad.on_beat_grace_container(5) <f' a'>4 } } .. container:: example Raises exception when duration of on-beat grace container exceeds duration of anchor container: >>> music_voice = abjad.Voice("c'4 d' e' f'", name="Music_Voice") >>> string = "g'8 a' b' c'' d'' c'' b' a' b' c'' d''" >>> result = abjad.on_beat_grace_container( ... string, music_voice[1:2], leaf_duration=(1, 8) ... ) Traceback (most recent call last): ... Exception: grace Duration(11, 8) exceeds anchor Duration(1, 4). """ from .Container import Container from .Selection import Selection from .Voice import Voice from abjad.spanners import beam from abjad.spanners import slur def _site(n): return Tag(f"abjad.on_beat_grace_container({n})") assert isinstance(anchor_voice_selection, Selection) if not anchor_voice_selection.are_contiguous_same_parent( ignore_before_after_grace=True): message = "selection must be contiguous in same parent:\n" message += f" {repr(anchor_voice_selection)}" raise Exception(message) on_beat_grace_container = OnBeatGraceContainer(contents, leaf_duration=leaf_duration) if not isinstance(anchor_voice_selection, Selection): raise Exception(f"must be selection:\n {repr(anchor_voice_selection)}") anchor_leaf = abjad_inspect(anchor_voice_selection).leaf(0) anchor_voice = abjad_inspect(anchor_leaf).parentage().get(Voice) if anchor_voice.name is None: raise Exception( f"anchor voice must be named:\n {repr(anchor_voice)}") anchor_voice_insert = Voice(name=anchor_voice.name) mutate(anchor_voice_selection).wrap(anchor_voice_insert) container = Container(simultaneous=True) mutate(anchor_voice_insert).wrap(container) container.insert(0, on_beat_grace_container) on_beat_grace_container._match_anchor_leaf() on_beat_grace_container._set_leaf_durations() insert_duration = abjad_inspect(anchor_voice_insert).duration() grace_container_duration = abjad_inspect( on_beat_grace_container).duration() if insert_duration < grace_container_duration: message = f"grace {repr(grace_container_duration)}" message += f" exceeds anchor {repr(insert_duration)}." raise Exception(message) if font_size is not None: string = rf"\set fontSize = #{font_size}" literal = LilyPondLiteral(string) attach(literal, on_beat_grace_container, tag=_site(1)) if not do_not_beam: beam(on_beat_grace_container[:]) if not do_not_slash: literal = LilyPondLiteral(r"\slash") attach(literal, on_beat_grace_container[0], tag=_site(2)) if not do_not_slur: slur(on_beat_grace_container[:]) voice_number_to_string = { 1: r"\voiceOne", 2: r"\voiceTwo", 3: r"\voiceThree", 4: r"\voiceFour", } first_grace = abjad_inspect(on_beat_grace_container).leaf(0) one_voice_literal = LilyPondLiteral(r"\oneVoice", format_slot="absolute_before") string = voice_number_to_string.get(grace_voice_number, None) if string is not None: literal detach(one_voice_literal, anchor_leaf) attach(LilyPondLiteral(string), first_grace, tag=_site(3)) string = voice_number_to_string.get(anchor_voice_number, None) if string is not None: detach(one_voice_literal, anchor_leaf) attach(LilyPondLiteral(string), anchor_leaf, tag=_site(4)) if not do_not_stop_polyphony: last_anchor_leaf = abjad_inspect(anchor_voice_selection).leaf(-1) next_leaf = abjad_inspect(last_anchor_leaf).leaf(1) if next_leaf is not None: literal = LilyPondLiteral(r"\oneVoice", format_slot="absolute_before") attach(literal, next_leaf, tag=_site(5)) return on_beat_grace_container
def _split_by_durations(self, durations, cyclic=False): from .Chord import Chord from .Note import Note from .Selection import Selection from .Tuplet import Tuplet durations = [Duration(_) for _ in durations] durations = Sequence(durations) leaf_duration = inspect(self).duration() if cyclic: durations = durations.repeat_to_weight(leaf_duration) if sum(durations) < leaf_duration: last_duration = leaf_duration - sum(durations) durations = list(durations) durations.append(last_duration) durations = Sequence(durations) durations = durations.truncate(weight=leaf_duration) originally_tied = inspect(self).has_indicator(Tie) originally_repeat_tied = inspect(self).has_indicator(RepeatTie) result_selections = [] # detach grace containers before_grace_container = self._before_grace_container if before_grace_container is not None: detach(before_grace_container, self) after_grace_container = self._after_grace_container if after_grace_container is not None: detach(after_grace_container, self) # do other things leaf_prolation = inspect(self).parentage().prolation for duration in durations: new_leaf = copy.copy(self) preprolated_duration = duration / leaf_prolation selection = new_leaf._set_duration(preprolated_duration) result_selections.append(selection) result_components = Sequence(result_selections).flatten(depth=-1) result_components = select(result_components) result_leaves = select(result_components).leaves(grace=False) assert all(isinstance(_, Selection) for _ in result_selections) assert all(isinstance(_, Component) for _ in result_components) assert result_leaves.are_leaves() # strip result leaves of all indicators for leaf in result_leaves: detach(object, leaf) # replace leaf with flattened result if inspect(self).parentage().parent is not None: mutate(self).replace(result_components) # move indicators first_result_leaf = result_leaves[0] last_result_leaf = result_leaves[-1] for indicator in inspect(self).indicators(): detach(indicator, self) direction = getattr(indicator, "_time_orientation", enums.Left) if direction is enums.Left: attach(indicator, first_result_leaf) elif direction == enums.Right: attach(indicator, last_result_leaf) else: raise ValueError(direction) # reattach grace containers if before_grace_container is not None: attach(before_grace_container, first_result_leaf) if after_grace_container is not None: attach(after_grace_container, last_result_leaf) # fuse tuplets if isinstance(result_components[0], Tuplet): mutate(result_components).fuse() # tie split notes if isinstance(self, (Note, Chord)) and 1 < len(result_leaves): result_leaves._attach_tie_to_leaves() if originally_repeat_tied and not inspect( result_leaves[0]).has_indicator(RepeatTie): attach(RepeatTie(), result_leaves[0]) if originally_tied and not inspect( result_leaves[-1]).has_indicator(Tie): attach(Tie(), result_leaves[-1]) assert isinstance(result_leaves, Selection) assert all(isinstance(_, Leaf) for _ in result_leaves) return result_leaves
def _split_by_durations( self, durations, cyclic=False, tie_split_notes=True, repeat_ties=False ): from .AfterGraceContainer import AfterGraceContainer from .Chord import Chord from .GraceContainer import GraceContainer from .Note import Note from .Selection import Selection from .Tuplet import Tuplet durations = [Duration(_) for _ in durations] durations = Sequence(durations) leaf_duration = inspect(self).duration() if cyclic: durations = durations.repeat_to_weight(leaf_duration) if sum(durations) < leaf_duration: last_duration = leaf_duration - sum(durations) durations = list(durations) durations.append(last_duration) durations = Sequence(durations) durations = durations.truncate(weight=leaf_duration) originally_tied = inspect(self).has_indicator(TieIndicator) originally_repeat_tied = inspect(self).has_indicator(RepeatTie) result_selections = [] grace_container = self._detach_grace_container() after_grace_container = self._detach_after_grace_container() leaf_prolation = inspect(self).parentage().prolation for duration in durations: new_leaf = copy.copy(self) preprolated_duration = duration / leaf_prolation selection = new_leaf._set_duration( preprolated_duration, repeat_ties=repeat_ties ) result_selections.append(selection) result_components = Sequence(result_selections).flatten(depth=-1) result_components = select(result_components) result_leaves = select(result_components).leaves(grace_notes=False) assert all(isinstance(_, Selection) for _ in result_selections) assert all(isinstance(_, Component) for _ in result_components) assert result_leaves.are_leaves() # for leaf in result_leaves: # detach(Tie, leaf) # strip result leaves of all indicators for leaf in result_leaves: detach(object, leaf) # replace leaf with flattened result if self._parent is not None: mutate(self).replace(result_components) # move indicators first_result_leaf = result_leaves[0] last_result_leaf = result_leaves[-1] for indicator in inspect(self).indicators(): detach(indicator, self) direction = getattr(indicator, "_time_orientation", enums.Left) if direction is enums.Left: attach(indicator, first_result_leaf) elif direction == enums.Right: attach(indicator, last_result_leaf) else: raise ValueError(direction) # move grace containers if grace_container is not None: container = grace_container[0] assert isinstance(container, GraceContainer), repr(container) attach(container, first_result_leaf) if after_grace_container is not None: container = after_grace_container[0] prototype = AfterGraceContainer assert isinstance(container, prototype), repr(container) attach(container, last_result_leaf) if isinstance(result_components[0], Tuplet): mutate(result_components).fuse() # tie split notes if ( tie_split_notes and isinstance(self, (Note, Chord)) and 1 < len(result_leaves) ): result_leaves._attach_tie_to_leaves(repeat_ties=repeat_ties) # assert not inspect(result_leaves[0]).has_indicator(RepeatTie) detach(RepeatTie, result_leaves[0]) # assert not inspect(result_leaves[-1]).has_indicator(TieIndicator) detach(TieIndicator, result_leaves[-1]) if originally_repeat_tied: tie = RepeatTie() attach(tie, result_leaves[0]) if originally_tied: tie = TieIndicator() attach(tie, result_leaves[-1]) assert isinstance(result_leaves, Selection) assert all(isinstance(_, Leaf) for _ in result_leaves) return result_leaves