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, repeat_ties=False): import abjad new_duration = Duration(new_duration) # change LilyPond multiplier if leaf already has LilyPond multiplier if self._get_indicators(Multiplier): detach(Multiplier, self) multiplier = new_duration.__div__(self.written_duration) attach(multiplier, self) return select(self) # change written duration if new duration is assignable try: self.written_duration = new_duration return select(self) except exceptions.AssignabilityError: pass # make new notes or tuplets if new duration is nonassignable maker = abjad.NoteMaker(repeat_ties=repeat_ties, ) components = maker(0, new_duration) if isinstance(components[0], Leaf): tied_leaf_count = len(components) - 1 tied_leaves = tied_leaf_count * self all_leaves = [self] + tied_leaves for leaf, component in zip(all_leaves, components): leaf.written_duration = component.written_duration self._splice(tied_leaves, grow_spanners=True) if not inspect(self).has_spanner(abjad.Tie): tie = abjad.Tie() if tie._attachment_test(self): tie = abjad.Tie(repeat=repeat_ties) attach(tie, all_leaves) return select(all_leaves) else: assert isinstance(components[0], abjad.Tuplet) tuplet = components[0] components = tuplet[:] tied_leaf_count = len(components) - 1 tied_leaves = tied_leaf_count * self all_leaves = [self] + tied_leaves for leaf, component in zip(all_leaves, components): leaf.written_duration = component.written_duration self._splice(tied_leaves, grow_spanners=True) if not inspect(self).has_spanner(abjad.Tie): tie = abjad.Tie() if tie._attachment_test(self): tie = abjad.Tie(repeat=repeat_ties) attach(tie, all_leaves) multiplier = tuplet.multiplier tuplet = abjad.Tuplet(multiplier, []) abjad.mutate(all_leaves).wrap(tuplet) return select(tuplet)
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 _initialize_components(self, components): if (isinstance(components, collections.Iterable) and not isinstance(components, str)): components_ = [] for item in components: if isinstance(item, Selection): components_.extend(item) elif isinstance(item, str): parsed = self._parse_string(item) components_.append(parsed) else: components_.append(item) components = components_ for component in components: if not isinstance(component, Component): message = f'must be component: {component!r}.' raise Exception(component) if self._all_are_orphan_components(components): self._components = list(components) self[:]._set_parents(self) elif isinstance(components, str): parsed = self._parse_string(components) self._components = [] self.is_simultaneous = parsed.is_simultaneous if ( parsed.is_simultaneous or not select(parsed[:]).are_contiguous_logical_voice() ): while len(parsed): self.append(parsed.pop(0)) else: self[:] = parsed[:] else: raise TypeError(f"can't initialize container from {components!r}.")
def _leaf(self, n): from .Container import Container from .OnBeatGraceContainer import OnBeatGraceContainer assert n in (-1, 0, 1), repr(n) if n == 0: return self sibling = self._sibling(n) if sibling is None: return None if n == 1: components = sibling._get_descendants_starting_with() else: assert n == -1 if (isinstance(sibling, Container) and len(sibling) == 2 and any( isinstance(_, OnBeatGraceContainer) for _ in sibling)): if isinstance(sibling[0], OnBeatGraceContainer): main_voice = sibling[1] else: main_voice = sibling[0] return main_voice[-1] components = sibling._get_descendants_stopping_with() for component in components: if not isinstance(component, Leaf): continue if select([self, component]).are_logical_voice(): return component
def _get_leaves_grouped_by_immediate_parents(self): result = [] pairs_generator = itertools.groupby(self, lambda x: id(x._parent)) for key, values_generator in pairs_generator: group = select(list(values_generator)) result.append(group) return result
def _initialize_components(self, components): if isinstance(components, collections.abc.Iterable) and not isinstance( components, str ): components_ = [] for item in components: if isinstance(item, Selection): components_.extend(item) elif isinstance(item, str): parsed = self._parse_string(item) components_.append(parsed) else: components_.append(item) components = components_ for component in components: if not isinstance(component, Component): message = f"must be component: {component!r}." raise Exception(component) if self._all_are_orphan_components(components): self._components = list(components) self[:]._set_parents(self) elif isinstance(components, str): parsed = self._parse_string(components) self._components = [] self.is_simultaneous = parsed.is_simultaneous if ( parsed.is_simultaneous or not select(parsed[:]).are_contiguous_logical_voice() ): while len(parsed): self.append(parsed.pop(0)) else: self[:] = parsed[:] else: raise TypeError(f"can't initialize container from {components!r}.")
def _attachment_test_all(self, argument): if self._skip_attachment_test_all: return True result = self._at_least_two_leaves(argument) if result is not True: return result leaves = select(argument).leaves() return True
def _at_least_two_leaves(self, argument): leaves = select(argument).leaves() if 1 < len(leaves): return True return [ 'Requires at least two leaves.', f'Not just {leaves[0]!r}.', ]
def _extract(self, scale_contents=False): if scale_contents: self._scale_contents(self.multiplier) selection = select([self]) parent, start, stop = selection._get_parent_and_start_stop_indices() components = list(getattr(self, "components", ())) parent.__setitem__(slice(start, stop + 1), components) return self
def _extract(self, scale_contents=False): if scale_contents: self._scale_contents(self.multiplier) selection = select([self]) parent, start, stop = selection._get_parent_and_start_stop_indices() components = list(getattr(self, 'components', ())) parent.__setitem__(slice(start, stop + 1), components) return self
def __getitem__(self, argument) -> typing.Union[Leaf, Selection]: """ Gets leaf or selection identified by ``argument``. """ if isinstance(argument, slice): leaves = self.leaves.__getitem__(argument) return select(leaves) return self.leaves.__getitem__(argument)
def _set_leaf_durations(self): if self.leaf_duration is None: return for leaf in select(self).leaves(): duration = abjad_inspect(leaf).duration() if duration != self.leaf_duration: multiplier = self.leaf_duration / duration leaf.multiplier = multiplier
def leaves(self) -> Selection: """ Gets leaves in spanner. """ for leaf in self._leaves: if not isinstance(leaf, Leaf): message = f'spanners attach only to leaves (not {leaf!s}).' raise Exception(message) return select(self._leaves)
def previous(component): new_component = component._get_nth_component_in_time_order_from(-1) if new_component is None: return candidates = new_component._get_descendants_stopping_with() candidates = [x for x in candidates if isinstance(x, Leaf)] for candidate in candidates: selection = select([component, candidate]) if selection.are_logical_voice(): return candidate
def __getitem__(self, argument) -> typing.Union[Component, Selection]: """ Gets item or slice identified by ``argument``. Traverses top-level items only. """ if isinstance(argument, int): return self.components.__getitem__(argument) elif isinstance(argument, slice) and not self.is_simultaneous: return select(self.components.__getitem__(argument)) elif isinstance(argument, slice) and self.is_simultaneous: return select(self.components.__getitem__(argument)) elif isinstance(argument, str): if argument not in self._named_children: raise ValueError(f"can not find component named {argument!r}.") elif 1 < len(self._named_children.__getitem__(argument)): raise ValueError(f"multiple components named {argument!r}.") return self._named_children.__getitem__(argument)[0] raise ValueError(f"can not get container at {argument!r}.")
def __getitem__(self, argument) -> typing.Union[Component, Selection]: """ Gets item or slice identified by ``argument``. Traverses top-level items only. """ if isinstance(argument, int): return self.components.__getitem__(argument) elif isinstance(argument, slice) and not self.is_simultaneous: return select(self.components.__getitem__(argument)) elif isinstance(argument, slice) and self.is_simultaneous: return select(self.components.__getitem__(argument)) elif isinstance(argument, str): if argument not in self._named_children: raise ValueError(f'can not find component named {argument!r}.') elif 1 < len(self._named_children.__getitem__(argument)): raise ValueError(f'multiple components named {argument!r}.') return self._named_children.__getitem__(argument)[0] raise ValueError(f'can not get container at {argument!r}.')
def _extend(self, leaves): leaf_input = list(self[-1:]) leaf_input.extend(leaves) leaf_input = select(leaf_input) if self._contiguity_constraint == 'logical voice': if not leaf_input.are_contiguous_logical_voice(): message = f'{self!r} leaves must be contiguous:\n' message += f' {leaf_input}' raise Exception(message) for leaf in leaves: self._append(leaf)
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 _initialize_rhythm(self, rhythm): import abjad if isinstance(rhythm, abjad.Component): selection = select([rhythm]) elif isinstance(rhythm, abjad.Selection): selection = rhythm else: message = 'rhythm must be duration, component or selection: {!r}.' message = message.format(rhythm) raise TypeError(message) assert isinstance(selection, abjad.Selection) return selection
def _append(self, leaf): if self._ignore_attachment_test: pass elif not self._attachment_test(leaf): raise Exception(f'can not attach {self!r} to {leaf!r}.') if self._contiguity_constraint == 'logical voice': leaves = self[-1:] + [leaf] leaves = select(leaves) if not leaves.are_contiguous_logical_voice(): raise Exception(type(self), leaves) leaf._append_spanner(self) self._leaves.append(leaf)
def _initialize_rhythm(self, rhythm): import abjad if isinstance(rhythm, abjad.Component): selection = select([rhythm]) elif isinstance(rhythm, abjad.Selection): selection = rhythm else: message = "rhythm must be duration, component or selection: {!r}." message = message.format(rhythm) raise TypeError(message) assert isinstance(selection, abjad.Selection) return selection
def _get_on_beat_anchor_leaf(self): container = self._parent if container is None: return None if len(container) != 2: message = "Combine on-beat grace container with one other voice." raise Exception(message) if container.index(self) == 0: anchor_voice = container[-1] else: assert container.index(self) == 1 anchor_voice = container[0] anchor_leaf = select(anchor_voice).leaf(0, grace=False) return anchor_leaf
def _leaf(self, n): assert n in (-1, 0, 1), repr(n) if n == 0: return self sibling = self._sibling(n) if sibling is None: return None if n == 1: components = sibling._get_descendants_starting_with() else: components = sibling._get_descendants_stopping_with() for component in components: if not isinstance(component, Leaf): continue if select([self, component]).are_logical_voice(): return component
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 _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 __init__(self, component=None, cross_offset=None): assert isinstance(component, (Component, type(None))) self._component = component if component is None: components = () else: components = list(select(component).components()) result = [] if cross_offset is None: result = components else: for component in components: append_x = True if not (inspect(component).timespan().start_offset < cross_offset and cross_offset < inspect(component).timespan().stop_offset): append_x = False if append_x: result.append(component) self._components = tuple(result)
def _split_by_duration( self, duration, tie_split_notes=True, repeat_ties=False, ): if self.is_simultaneous: return self._split_simultaneous_by_duration( duration=duration, tie_split_notes=tie_split_notes, repeat_ties=repeat_ties, ) duration = Duration(duration) assert 0 <= duration, repr(duration) if duration == 0: return [], self # get split point score offset timespan = inspect(self).timespan() global_split_point = timespan.start_offset + duration # get any duration-crossing descendents cross_offset = timespan.start_offset + duration duration_crossing_descendants = [] for descendant in inspect(self).descendants(): timespan = inspect(descendant).timespan() start_offset = timespan.start_offset stop_offset = timespan.stop_offset if start_offset < cross_offset < stop_offset: duration_crossing_descendants.append(descendant) # any duration-crossing leaf will be at end of list bottom = duration_crossing_descendants[-1] did_split_leaf = False # if split point necessitates leaf split if isinstance(bottom, Leaf): assert isinstance(bottom, Leaf) did_split_leaf = True timespan = inspect(bottom).timespan() start_offset = timespan.start_offset split_point_in_bottom = global_split_point - start_offset new_leaves = bottom._split_by_durations( [split_point_in_bottom], tie_split_notes=tie_split_notes, repeat_ties=repeat_ties, ) for leaf in new_leaves: timespan = inspect(leaf).timespan() if timespan.stop_offset == global_split_point: leaf_left_of_split = leaf if timespan.start_offset == global_split_point: leaf_right_of_split = leaf duration_crossing_containers = duration_crossing_descendants[:-1] if not len(duration_crossing_containers): return left_list, right_list # if split point falls between leaves # then find leaf to immediate right of split point # in order to start upward crawl through duration-crossing containers else: duration_crossing_containers = duration_crossing_descendants[:] for leaf in iterate(bottom).leaves(): timespan = inspect(leaf).timespan() if timespan.start_offset == global_split_point: leaf_right_of_split = leaf leaf_left_of_split = inspect(leaf).leaf(-1) break else: raise Exception('can not split empty container {bottom!r}.') assert leaf_left_of_split is not None assert leaf_right_of_split is not None # find component to right of split # that is also immediate child of last duration-crossing container for component in inspect(leaf_right_of_split).parentage(): parent = inspect(component).parentage().parent if parent is duration_crossing_containers[-1]: highest_level_component_right_of_split = component break else: raise ValueError('should not be able to get here.') # crawl back up through duration-crossing containers and split each previous = highest_level_component_right_of_split for container in reversed(duration_crossing_containers): assert isinstance(container, Container) index = container.index(previous) left, right = container._split_at_index(index) previous = right # reapply tie here if crawl above killed tie applied to leaves if did_split_leaf: if ( tie_split_notes and isinstance(leaf_left_of_split, Note) ): if ( inspect(leaf_left_of_split).parentage().root is inspect(leaf_right_of_split).parentage().root ): leaves_around_split = ( leaf_left_of_split, leaf_right_of_split, ) selection = select(leaves_around_split) selection._attach_tie_to_leaves(repeat_ties=repeat_ties) # return list-wrapped halves of container return [left], [right]
def _get_contents(self): result = [] result.append(self) result.extend(getattr(self, "components", [])) result = select(result) return result
def __delitem__(self, i): r""" Deletes components(s) at index ``i`` in container. .. container:: example Deletes first tuplet in voice: >>> voice = abjad.Voice() >>> voice.append(abjad.Tuplet((2, 3), "c'4 d'4 e'4")) >>> voice.append(abjad.Tuplet((2, 3), "e'4 d'4 c'4")) >>> leaves = abjad.select(voice).leaves() >>> abjad.slur(leaves) >>> abjad.show(voice) # doctest: +SKIP .. docs:: >>> abjad.f(voice) \new Voice { \times 2/3 { c'4 ( d'4 e'4 } \times 2/3 { e'4 d'4 c'4 ) } } >>> tuplet_1 = voice[0] >>> del(voice[0]) >>> start_slur = abjad.StartSlur() >>> leaf = abjad.select(voice).leaf(0) >>> abjad.attach(start_slur, leaf) First tuplet no longer appears in voice: >>> abjad.show(voice) # doctest: +SKIP .. docs:: >>> abjad.f(voice) \new Voice { \times 2/3 { e'4 ( d'4 c'4 ) } } >>> abjad.inspect(voice).wellformed() True First tuplet must have start slur removed: >>> abjad.detach(abjad.StartSlur, tuplet_1[0]) (StartSlur(),) >>> abjad.show(tuplet_1) # doctest: +SKIP .. docs:: >>> abjad.f(tuplet_1) \times 2/3 { c'4 d'4 e'4 } >>> abjad.inspect(tuplet_1).wellformed() True Returns none. """ components = self[i] if not isinstance(components, Selection): components = select([components]) components._set_parents(None)
def hairpin( descriptor: str, argument: typing.Union[Component, Selection], *, selector: typings.Selector = 'abjad.select().leaves()', ) -> None: r""" Attaches hairpin indicators. .. container:: example With three-part string descriptor: >>> staff = abjad.Staff("c'4 d' e' f'") >>> abjad.hairpin('p < f', staff[:]) >>> abjad.override(staff[0]).dynamic_line_spanner.staff_padding = 4 >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff { \once \override DynamicLineSpanner.staff-padding = #4 c'4 \p \< d'4 e'4 f'4 \f } .. container:: example With dynamic objects: >>> staff = abjad.Staff("c'4 d' e' f'") >>> start = abjad.Dynamic('niente', command=r'\!') >>> trend = abjad.DynamicTrend('o<|') >>> abjad.tweak(trend).color = 'blue' >>> stop = abjad.Dynamic('"f"') >>> abjad.hairpin([start, trend, stop], staff[:]) >>> abjad.override(staff[0]).dynamic_line_spanner.staff_padding = 4 >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff { \once \override DynamicLineSpanner.staff-padding = #4 c'4 \! - \tweak color #blue - \tweak circled-tip ##t - \tweak stencil #abjad-flared-hairpin \< d'4 e'4 f'4 _ #(make-dynamic-script (markup #:whiteout #:line ( #:general-align Y -2 #:normal-text #:larger "“" #:hspace -0.4 #:dynamic "f" #:hspace -0.2 #:general-align Y -2 #:normal-text #:larger "”" ) ) ) } """ import abjad indicators: typing.List = [] start_dynamic: typing.Optional[Dynamic] dynamic_trend: typing.Optional[DynamicTrend] stop_dynamic: typing.Optional[Dynamic] known_shapes = DynamicTrend('<').known_shapes if isinstance(descriptor, str): for string in descriptor.split(): if string in known_shapes: dynamic_trend = DynamicTrend(string) indicators.append(dynamic_trend) else: dynamic = Dynamic(string) indicators.append(dynamic) else: assert isinstance(descriptor, list), repr(descriptor) indicators = descriptor start_dynamic, dynamic_trend, stop_dynamic = None, None, None if len(indicators) == 1: if isinstance(indicators[0], Dynamic): start_dynamic = indicators[0] else: dynamic_trend = indicators[0] elif len(indicators) == 2: if isinstance(indicators[0], Dynamic): start_dynamic = indicators[0] dynamic_trend = indicators[1] else: dynamic_trend = indicators[0] stop_dynamic = indicators[1] elif len(indicators) == 3: start_dynamic, dynamic_trend, stop_dynamic = indicators else: raise Exception(indicators) assert isinstance(start_dynamic, Dynamic), repr(start_dynamic) if isinstance(selector, str): selector = eval(selector) assert isinstance(selector, Expression) argument = selector(argument) leaves = select(argument).leaves() start_leaf = leaves[0] stop_leaf = leaves[-1] if start_dynamic is not None: attach(start_dynamic, start_leaf) if dynamic_trend is not None: attach(dynamic_trend, start_leaf) if stop_dynamic is not None: attach(stop_dynamic, stop_leaf)
def attach_defaults(self, argument) -> typing.List: """ Attaches defaults to all staff and staff group contexts in ``argument`` when ``argument`` is a score. Attaches defaults to ``argument`` (without iterating ``argument``) when ``argument`` is a staff or staff group. Returns list of one wrapper for every indicator attached. """ assert isinstance(argument, (Score, Staff, StaffGroup)), repr(argument) wrappers: typing.List[Wrapper] = [] tag = const.REMOVE_ALL_EMPTY_STAVES empty_prototype = (MultimeasureRest, Skip) prototype = (Staff, StaffGroup) if isinstance(argument, Score): staff__groups = select(argument).components(prototype) staves = select(argument).components(Staff) elif isinstance(argument, Staff): staff__groups = [argument] staves = [argument] else: assert isinstance(argument, StaffGroup), repr(argument) staff__groups = [argument] staves = [] for staff__group in staff__groups: leaf = None voices = select(staff__group).components(Voice) # find leaf 0 in first nonempty voice for voice in voices: leaves = [] for leaf_ in select(voice).leaves(): if inspect(leaf_).annotation(const.HIDDEN) is not True: leaves.append(leaf_) if not all(isinstance(_, empty_prototype) for _ in leaves): leaf = inspect(voice).leaf(0) break # otherwise, find first leaf in voice in non-removable staff if leaf is None: for voice in voices: voice_might_vanish = False for component in inspect(voice).parentage(): if inspect(component).annotation(tag) is True: voice_might_vanish = True if not voice_might_vanish: leaf = inspect(voice).leaf(0) if leaf is not None: break # otherwise, as last resort find first leaf in first voice if leaf is None: leaf = inspect(voices[0]).leaf(0) if leaf is None: continue instrument = inspect(leaf).indicator(instruments.Instrument) if instrument is None: string = "default_instrument" instrument = inspect(staff__group).annotation(string) if instrument is not None: wrapper = attach( instrument, leaf, context=staff__group.lilypond_type, tag="abjad.ScoreTemplate.attach_defaults", wrapper=True, ) wrappers.append(wrapper) margin_markup = inspect(leaf).indicator(MarginMarkup) if margin_markup is None: string = "default_margin_markup" margin_markup = inspect(staff__group).annotation(string) if margin_markup is not None: wrapper = attach( margin_markup, leaf, tag=Tag("-PARTS").prepend( "abjad.ScoreTemplate.attach_defaults" ), wrapper=True, ) wrappers.append(wrapper) for staff in staves: leaf = inspect(staff).leaf(0) clef = inspect(leaf).indicator(Clef) if clef is not None: continue clef = inspect(staff).annotation("default_clef") if clef is not None: wrapper = attach( clef, leaf, tag="abjad.ScoreTemplate.attach_defaults", wrapper=True, ) wrappers.append(wrapper) return wrappers
def _split_by_duration( self, duration, tie_split_notes=True, repeat_ties=False ): if self.is_simultaneous: return self._split_simultaneous_by_duration( duration=duration, tie_split_notes=tie_split_notes, repeat_ties=repeat_ties, ) duration = Duration(duration) assert 0 <= duration, repr(duration) if duration == 0: return [], self # get split point score offset timespan = inspect(self).timespan() global_split_point = timespan.start_offset + duration # get any duration-crossing descendents cross_offset = timespan.start_offset + duration duration_crossing_descendants = [] for descendant in inspect(self).descendants(): timespan = inspect(descendant).timespan() start_offset = timespan.start_offset stop_offset = timespan.stop_offset if start_offset < cross_offset < stop_offset: duration_crossing_descendants.append(descendant) # any duration-crossing leaf will be at end of list bottom = duration_crossing_descendants[-1] did_split_leaf = False # if split point necessitates leaf split if isinstance(bottom, Leaf): assert isinstance(bottom, Leaf) did_split_leaf = True timespan = inspect(bottom).timespan() start_offset = timespan.start_offset split_point_in_bottom = global_split_point - start_offset new_leaves = bottom._split_by_durations( [split_point_in_bottom], tie_split_notes=tie_split_notes, repeat_ties=repeat_ties, ) for leaf in new_leaves: timespan = inspect(leaf).timespan() if timespan.stop_offset == global_split_point: leaf_left_of_split = leaf if timespan.start_offset == global_split_point: leaf_right_of_split = leaf duration_crossing_containers = duration_crossing_descendants[:-1] if not len(duration_crossing_containers): return left_list, right_list # if split point falls between leaves # then find leaf to immediate right of split point # in order to start upward crawl through duration-crossing containers else: duration_crossing_containers = duration_crossing_descendants[:] for leaf in iterate(bottom).leaves(): timespan = inspect(leaf).timespan() if timespan.start_offset == global_split_point: leaf_right_of_split = leaf leaf_left_of_split = inspect(leaf).leaf(-1) break else: raise Exception("can not split empty container {bottom!r}.") assert leaf_left_of_split is not None assert leaf_right_of_split is not None # find component to right of split # that is also immediate child of last duration-crossing container for component in inspect(leaf_right_of_split).parentage(): parent = inspect(component).parentage().parent if parent is duration_crossing_containers[-1]: highest_level_component_right_of_split = component break else: raise ValueError("should not be able to get here.") # crawl back up through duration-crossing containers and split each previous = highest_level_component_right_of_split for container in reversed(duration_crossing_containers): assert isinstance(container, Container) index = container.index(previous) left, right = container._split_at_index(index) previous = right # reapply tie here if crawl above killed tie applied to leaves if did_split_leaf: if tie_split_notes and isinstance(leaf_left_of_split, Note): if ( inspect(leaf_left_of_split).parentage().root is inspect(leaf_right_of_split).parentage().root ): leaves_around_split = ( leaf_left_of_split, leaf_right_of_split, ) selection = select(leaves_around_split) selection._attach_tie_to_leaves(repeat_ties=repeat_ties) # return list-wrapped halves of container return [left], [right]
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 _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 attach_defaults(self, argument) -> typing.List: """ Attaches defaults to all staff and staff group contexts in ``argument`` when ``argument`` is a score. Attaches defaults to ``argument`` (without iterating ``argument``) when ``argument`` is a staff or staff group. Returns list of one wrapper for every indicator attached. """ assert isinstance(argument, (Score, Staff, StaffGroup)), repr(argument) wrappers: typing.List[Wrapper] = [] tag = const.REMOVE_ALL_EMPTY_STAVES empty_prototype = (MultimeasureRest, Skip) prototype = (Staff, StaffGroup) if isinstance(argument, Score): staff__groups = select(argument).components(prototype) staves = select(argument).components(Staff) elif isinstance(argument, Staff): staff__groups = [argument] staves = [argument] else: assert isinstance(argument, StaffGroup), repr(argument) staff__groups = [argument] staves = [] for staff__group in staff__groups: leaf = None voices = select(staff__group).components(Voice) # find leaf 0 in first nonempty voice for voice in voices: leaves = [] for leaf_ in select(voice).leaves(): if inspect(leaf_).has_indicator(const.HIDDEN): leaves.append(leaf_) if not all(isinstance(_, empty_prototype) for _ in leaves): leaf = inspect(voice).leaf(0) break # otherwise, find first leaf in voice in non-removable staff if leaf is None: for voice in voices: voice_might_vanish = False for component in inspect(voice).parentage(): if inspect(component).annotation(tag) is True: voice_might_vanish = True if not voice_might_vanish: leaf = inspect(voice).leaf(0) if leaf is not None: break # otherwise, as last resort find first leaf in first voice if leaf is None: leaf = inspect(voices[0]).leaf(0) if leaf is None: continue instrument = inspect(leaf).indicator(instruments.Instrument) if instrument is None: string = "default_instrument" instrument = inspect(staff__group).annotation(string) if instrument is not None: wrapper = attach( instrument, leaf, context=staff__group.lilypond_type, tag=Tag("abjad.ScoreTemplate.attach_defaults(1)"), wrapper=True, ) wrappers.append(wrapper) margin_markup = inspect(leaf).indicator(MarginMarkup) if margin_markup is None: string = "default_margin_markup" margin_markup = inspect(staff__group).annotation(string) if margin_markup is not None: wrapper = attach( margin_markup, leaf, tag=abjad_tags.NOT_PARTS.append( Tag("abjad.ScoreTemplate.attach_defaults(2)")), wrapper=True, ) wrappers.append(wrapper) for staff in staves: leaf = inspect(staff).leaf(0) clef = inspect(leaf).indicator(Clef) if clef is not None: continue clef = inspect(staff).annotation("default_clef") if clef is not None: wrapper = attach( clef, leaf, tag=Tag("abjad.ScoreTemplate.attach_defaults(3)"), wrapper=True, ) wrappers.append(wrapper) return wrappers
def _split_by_durations( self, durations, cyclic=False, fracture_spanners=False, tie_split_notes=True, repeat_ties=False, ): import abjad 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) result_selections = [] # detach grace containers 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() assert all(isinstance(_, abjad.Selection) for _ in result_selections) assert all(isinstance(_, Component) for _ in result_components) assert result_leaves.are_leaves() if inspect(self).has_spanner(abjad.Tie): for leaf in result_leaves: detach(abjad.Tie, leaf) # strip result leaves of indicators (other than multipliers) for leaf in result_leaves: multiplier = inspect(leaf).indicator(Multiplier) detach(object, leaf) if multiplier is not None: attach(multiplier, leaf) # replace leaf with flattened result selection = select(self) parent, start, stop = selection._get_parent_and_start_stop_indices() if parent: parent.__setitem__(slice(start, stop + 1), result_components) else: selection._give_dominant_spanners(result_components) selection._withdraw_from_crossing_spanners() # fracture spanners if fracture_spanners: first_selection = result_selections[0] for spanner in inspect(first_selection[-1]).spanners(): index = spanner._index(first_selection[-1]) spanner._fracture(index, direction=enums.Right) last_selection = result_selections[-1] for spanner in inspect(last_selection[0]).spanners(): index = spanner._index(last_selection[0]) spanner._fracture(index, direction=enums.Left) for middle_selection in result_selections[1:-1]: spanners = inspect(middle_selection[0]).spanners() for spanner in spanners: index = spanner._index(middle_selection[0]) spanner._fracture(index, direction=enums.Left) spanners = inspect(middle_selection[-1]).spanners() for spanner in spanners: index = spanner._index(middle_selection[-1]) spanner._fracture(index, direction=enums.Right) # move indicators first_result_leaf = result_leaves[0] last_result_leaf = result_leaves[-1] for indicator in inspect(self).indicators(): if isinstance(indicator, Multiplier): continue 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, abjad.GraceContainer), repr(container) attach(container, first_result_leaf) if after_grace_container is not None: container = after_grace_container[0] prototype = abjad.AfterGraceContainer assert isinstance(container, prototype), repr(container) attach(container, last_result_leaf) if isinstance(result_components[0], abjad.Tuplet): abjad.mutate(result_components).fuse() # tie split notes if isinstance(self, (abjad.Note, abjad.Chord)) and tie_split_notes: result_leaves._attach_tie_to_leaves(repeat_ties=repeat_ties, ) assert isinstance(result_selections, list), repr(result_selections) assert all(isinstance(_, abjad.Selection) for _ in result_selections) return result_selections
def _attachment_test_all(self, argument): if isinstance(argument, (Chord, Note)): return True assert all(isinstance(_, Leaf) for _ in argument) leaves = select(argument).leaves() return 1 <= len(leaves)