def _update_all_leaf_indices_and_measure_numbers(component): r'''Call only when updating offsets. No separate state flags exist for leaf indices or measure numbers. ''' from abjad.tools import contexttools from abjad.tools import iterationtools parentage = component._get_parentage() score_root = parentage.root if isinstance(score_root, contexttools.Context): contexts = iterationtools.iterate_contexts_in_expr(score_root) for context in contexts: for leaf_index, leaf in enumerate( iterationtools.iterate_leaves_in_expr(context)): leaf._leaf_index = leaf_index for measure_index, measure in enumerate( iterationtools.iterate_measures_in_expr(context)): measure_number = measure_index + 1 measure._measure_number = measure_number else: for leaf_index, leaf in enumerate( iterationtools.iterate_leaves_in_expr(score_root)): leaf._leaf_index = leaf_index for measure_index, measure in enumerate( iterationtools.iterate_measures_in_expr(score_root)): measure_number = measure_index + 1 measure._measure_number = measure_number
def label_leaves_in_expr_with_tuplet_depth(expr, markup_direction=Down): r'''Label leaves in `expr` with tuplet depth: :: >>> staff = Staff("c'8 d'8 e'8 f'8 g'8") >>> tuplettools.FixedDurationTuplet(Duration(2, 8), staff[-3:]) FixedDurationTuplet(1/4, [e'8, f'8, g'8]) >>> labeltools.label_leaves_in_expr_with_tuplet_depth(staff) >>> f(staff) \new Staff { c'8 _ \markup { \small 0 } d'8 _ \markup { \small 0 } \times 2/3 { e'8 _ \markup { \small 1 } f'8 _ \markup { \small 1 } g'8 _ \markup { \small 1 } } } :: >>> show(staff) # doctest: +SKIP Returns none. ''' for leaf in iterationtools.iterate_leaves_in_expr(expr): label = markuptools.MarkupCommand( 'small', str(leaf._get_parentage().tuplet_depth)) markup = markuptools.Markup(label, markup_direction) attach(markup, leaf)
def label_leaves_in_expr_with_leaf_indices(expr, markup_direction=Down): r'''Label leaves in `expr` with leaf indices: :: >>> staff = Staff("c'8 d'8 e'8 f'8") >>> labeltools.label_leaves_in_expr_with_leaf_indices(staff) >>> f(staff) \new Staff { c'8 _ \markup { \small 0 } d'8 _ \markup { \small 1 } e'8 _ \markup { \small 2 } f'8 _ \markup { \small 3 } } :: >>> show(staff) # doctest: +SKIP Returns none. ''' for i, leaf in enumerate(iterationtools.iterate_leaves_in_expr(expr)): label = markuptools.MarkupCommand('small', str(i)) markup = markuptools.Markup(label, markup_direction) attach(markup, leaf)
def label_leaves_in_expr_with_leaf_numbers(expr, markup_direction=Down): r'''Label leaves in `expr` with leaf numbers: :: >>> staff = Staff("c'8 d'8 e'8 f'8") >>> labeltools.label_leaves_in_expr_with_leaf_numbers(staff) >>> f(staff) \new Staff { c'8 _ \markup { \small 1 } d'8 _ \markup { \small 2 } e'8 _ \markup { \small 3 } f'8 _ \markup { \small 4 } } :: >>> show(staff) # doctest: +SKIP Number leaves starting from ``1``. Returns none. ''' for i, leaf in enumerate(iterationtools.iterate_leaves_in_expr(expr)): leaf_number = i + 1 label = markuptools.MarkupCommand('small', str(leaf_number)) markup = markuptools.Markup(label, markup_direction) attach(markup, leaf)
def __call__(self, expr, offset=0): leaves = list(iterationtools.iterate_leaves_in_expr(expr)) groups = list(iterationtools.iterate_runs_in_expr( leaves, (notetools.Note, scoretools.Chord))) hairpin_tokens = datastructuretools.CyclicList(self.hairpin_tokens) for i, group in enumerate(groups): if not isinstance(group, selectiontools.SliceSelection): group = selectiontools.SliceSelection(group) is_short_group = False hairpin_token = hairpin_tokens[offset+i] if len(group) == 1: is_short_group = True elif self.minimum_duration is not None: if group.get_duration() < self.minimum_duration: is_short_group = True if is_short_group: start_dynamic = hairpin_token[0] #contexttools.DynamicMark(start_dynamic)(group[0]) command = marktools.LilyPondCommandMark(start_dynamic, 'right') attach(command, group[0]) else: descriptor = ' '.join([x for x in hairpin_token if x]) hairpin = spannertools.HairpinSpanner( descriptor=descriptor, include_rests=False, ) attach(hairpin, group) return expr
def label_leaves_in_expr_with_pitch_numbers(expr, markup_direction=Down): r'''Label leaves in `expr` with pitch numbers: :: >>> staff = Staff(leaftools.make_leaves([None, 12, [13, 14, 15], None], [(1, 4)])) >>> labeltools.label_leaves_in_expr_with_pitch_numbers(staff) >>> f(staff) \new Staff { r4 c''4 _ \markup { \small 12 } <cs'' d'' ef''>4 _ \markup { \column { \small 15 \small 14 \small 13 } } r4 } :: >>> show(staff) # doctest: +SKIP Returns none. ''' for leaf in iterationtools.iterate_leaves_in_expr(expr): for pitch in reversed(pitchtools.PitchSegment.from_selection(leaf)): if pitch is not None: label = markuptools.MarkupCommand('small', str(pitch.pitch_number)) markup = markuptools.Markup(label, markup_direction) attach(markup, leaf)
def color_leaves_in_expr(expr, color): r"""Color leaves in `expr`: :: >>> staff = Staff("cs'8. [ r8. s8. <c' cs' a'>8. ]") .. doctest:: >>> f(staff) \new Staff { cs'8. [ r8. s8. <c' cs' a'>8. ] } :: >>> show(staff) # doctest: +SKIP :: >>> labeltools.color_leaves_in_expr(staff, 'red') .. doctest:: >>> f(staff) \new Staff { \once \override Accidental #'color = #red \once \override Beam #'color = #red \once \override Dots #'color = #red \once \override NoteHead #'color = #red \once \override Stem #'color = #red cs'8. [ \once \override Dots #'color = #red \once \override Rest #'color = #red r8. s8. \once \override Accidental #'color = #red \once \override Beam #'color = #red \once \override Dots #'color = #red \once \override NoteHead #'color = #red \once \override Stem #'color = #red <c' cs' a'>8. ] } :: >>> show(staff) # doctest: +SKIP Returns none. """ from abjad.tools import labeltools for leaf in iterationtools.iterate_leaves_in_expr(expr): labeltools.color_leaf(leaf, color)
def _duration_in_seconds(self): from abjad.tools import iterationtools if self.is_simultaneous: return max([durationtools.Duration(0)] + [x._get_duration(in_seconds=True) for x in self]) else: duration = durationtools.Duration(0) for leaf in iterationtools.iterate_leaves_in_expr(self): duration += leaf._get_duration(in_seconds=True) return duration
def _copy_and_include_enclosing_containers(self): from abjad.tools import scoretools from abjad.tools import iterationtools from abjad.tools import leaftools from abjad.tools.mutationtools import mutate # get governor parentage = self[0]._get_parentage(include_self=True) governor = parentage._get_governor() # find start and stop indices in governor governor_leaves = list(governor.select_leaves()) for i, x in enumerate(governor_leaves): if x is self[0]: start_index_in_governor = i for i, x in enumerate(governor_leaves): if x is self[-1]: stop_index_in_governor = i # copy governor governor_copy = mutate(governor).copy() copied_leaves = governor_copy.select_leaves() # find start and stop leaves in copy of governor start_leaf = copied_leaves[start_index_in_governor] stop_leaf = copied_leaves[stop_index_in_governor] # trim governor copy forwards from first leaf found_start_leaf = False while not found_start_leaf: leaf = iterationtools.iterate_leaves_in_expr(governor_copy).next() if leaf is start_leaf: found_start_leaf = True else: leaf._remove_and_shrink_durated_parent_containers() # trim governor copy backwards from last leaf found_stop_leaf = False while not found_stop_leaf: reverse_iterator = iterationtools.iterate_leaves_in_expr( governor_copy, reverse=True) leaf = reverse_iterator.next() if leaf is stop_leaf: found_stop_leaf = True else: leaf._remove_and_shrink_durated_parent_containers() # return trimmed governor copy return governor_copy
def _run(self, expr): violators = [] spanner_classes = (spannertools.OctavationSpanner, ) for leaf in iterationtools.iterate_leaves_in_expr(expr): spanners = leaf._get_descendants()._get_spanners(spanner_classes) if 1 < len(spanners): for spanner in spanners: if spanner not in violators: violators.append(spanner) total = expr._get_descendants()._get_spanners(spanner_classes) return violators, len(total)
def _run(self, expr): violators = [] total = 0 for leaf in iterationtools.iterate_leaves_in_expr(expr): total += 1 if leaf._has_spanner(spannertools.BeamSpanner): beam = leaf._get_spanner(spannertools.BeamSpanner) if not isinstance(beam, spannertools.DuratedComplexBeamSpanner): flag_count = leaf.written_duration.flag_count if flag_count < 1: violators.append(leaf) return violators, total
def _get_composite_offset_difference_series_from_leaves_in_expr(expr): from abjad.tools import iterationtools offsets = [] for leaf in iterationtools.iterate_leaves_in_expr(expr): start_offset = leaf._get_timespan().start_offset if start_offset not in offsets: offsets.append(start_offset) stop_offset = leaf._get_timespan().stop_offset if stop_offset not in offsets: offsets.append(stop_offset) offsets.sort() return list(mathtools.difference_series(offsets))
def _run(self, expr): violators = [] spanner_classes = (spannertools.BeamSpanner,) all_beams = set() for leaf in iterationtools.iterate_leaves_in_expr(expr): beams = leaf._get_spanners(spanner_classes) all_beams.update(beams) if 1 < len(beams): for beam in beams: if beam not in violators: violators.append(beam) total = len(all_beams) return violators, total
def respell_with_sharps(self): r'''Respell named pitches in mutation client with sharps: :: >>> staff = Staff("c'8 cs'8 d'8 ef'8 e'8 f'8") >>> show(staff) # doctest: +SKIP .. doctest:: >>> f(staff) \new Staff { c'8 cs'8 d'8 ef'8 e'8 f'8 } :: >>> mutate(staff).respell_with_sharps() >>> show(staff) # doctest: +SKIP .. doctest:: >>> f(staff) \new Staff { c'8 cs'8 d'8 ds'8 e'8 f'8 } Returns none. ''' from abjad.tools import scoretools from abjad.tools import iterationtools for leaf in iterationtools.iterate_leaves_in_expr(self._client): if isinstance(leaf, scoretools.Chord): for note_head in leaf.note_heads: note_head.written_pitch = \ note_head.written_pitch.respell_with_sharps() elif hasattr(leaf, 'written_pitch'): leaf.written_pitch = leaf.written_pitch.respell_with_sharps()
def _initialize_components(self, components): if components: raise Exception('deprecated') from abjad.tools import contexttools from abjad.tools import iterationtools if isinstance(components, scoretools.Component): components = [components] elif not components: components = [] assert not any( isinstance(x, contexttools.Context) for x in components), repr(components) if self._contiguity_constraint == 'logical voice': leaves = list(iterationtools.iterate_leaves_in_expr(components)) assert Selection._all_are_contiguous_components_in_same_logical_voice(leaves) self.extend(components)
def select_leaves( self, start=0, stop=None, leaf_classes=None, recurse=True, allow_discontiguous_leaves=False, ): r'''Selects leaves in container. .. container:: example :: >>> container = Container("c'8 d'8 r8 e'8") :: >>> container.select_leaves() ContiguousSelection(Note("c'8"), Note("d'8"), Rest('r8'), Note("e'8")) Returns contiguous leaf selection or free leaf selection. ''' from abjad.tools import scoretools from abjad.tools import iterationtools from abjad.tools import leaftools from abjad.tools import selectiontools Selection = selectiontools.Selection leaf_classes = leaf_classes or (leaftools.Leaf,) expr = self if recurse: expr = iterationtools.iterate_leaves_in_expr(expr) music = [ component for component in expr if isinstance(component, leaf_classes) ] music = music[start:stop] if allow_discontiguous_leaves: selection = selectiontools.Selection(music=music) else: assert Selection._all_are_contiguous_components_in_same_logical_voice( music) selection = selectiontools.ContiguousSelection(music=music) return selection
def _run(self, expr): violators = [] total = 0 for leaf in iterationtools.iterate_leaves_in_expr(expr): total += 1 flags = leaf.written_duration.flag_count left = getattr(leaf.set, 'stem_left_beam_count', None) right = getattr(leaf.set, 'stem_right_beam_count', None) if left is not None: if flags < left or \ (left < flags and right not in (flags, None)): if leaf not in violators: violators.append(leaf) if right is not None: if flags < right or \ (right < flags and left not in (flags, None)): if leaf not in violators: violators.append(leaf) return violators, total
def _add_ties(self, result): from abjad.tools import selectiontools leaves = list(iterationtools.iterate_leaves_in_expr(result)) written_durations = [leaf.written_duration for leaf in leaves] weights = [durationtools.Duration(numerator, self.talea_denominator) for numerator in self.talea] parts = sequencetools.partition_sequence_by_weights_exactly( written_durations, weights=weights, cyclic=True, overhang=True) counts = [len(part) for part in parts] parts = sequencetools.partition_sequence_by_counts(leaves, counts) spanner_classes = (spannertools.TieSpanner,) for part in parts: part = selectiontools.SliceSelection(part) tie_spanner = spannertools.TieSpanner() # this is voodoo to temporarily neuter the contiguity constraint tie_spanner._contiguity_constraint = None for component in part: for spanner in component._get_spanners( spanner_classes=spanner_classes): spanner.detach() tie_spanner.extend(part)
def remove_markup_from_leaves_in_expr(expr): r'''Remove markup from leaves in `expr`: :: >>> staff = Staff("c'8 d'8 e'8 f'8") >>> labeltools.label_leaves_in_expr_with_pitch_class_numbers(staff) >>> f(staff) \new Staff { c'8 _ \markup { \small 0 } d'8 _ \markup { \small 2 } e'8 _ \markup { \small 4 } f'8 _ \markup { \small 5 } } :: >>> show(staff) # doctest: +SKIP :: >>> labeltools.remove_markup_from_leaves_in_expr(staff) >>> f(staff) \new Staff { c'8 d'8 e'8 f'8 } :: >>> show(staff) # doctest: +SKIP Returns none. ''' for leaf in iterationtools.iterate_leaves_in_expr(expr): for markup in leaf._get_markup(): markup.detach()
def _run(self, expr): violators = [] spanner_classes = (spannertools.GlissandoSpanner,) for leaf in iterationtools.iterate_leaves_in_expr(expr): glissandi = leaf._get_spanners(spanner_classes) if 1 < len(glissandi): if len(glissandi) == 2: common_leaves = set(glissandi[0].leaves) & \ set(glissandi[1].leaves) if len(common_leaves) == 1: x = list(common_leaves)[0] if (glissandi[0]._is_my_first_leaf(x) and glissandi[1]._is_my_last_leaf(x)) or \ (glissandi[1]._is_my_first_leaf(x) and glissandi[0]._is_my_last_leaf(x)): break for glissando in glissandi: if glissando not in violators: violators.append(glissando) total = expr._get_descendants()._get_spanners(spanner_classes) return violators, len(total)
def __call__(self, expr, offset=0): leaves = list(iterationtools.iterate_leaves_in_expr(expr)) leaves = self._remove_outer_rests_from_sequence(leaves) #group = leaves group = selectiontools.SliceSelection(leaves) is_short_group = False if len(group) == 1: is_short_group = True elif self.minimum_duration is not None: if group.duration < self.minimum_duration: is_short_group = True if is_short_group: start_dynamic = self.hairpin_token[0] #contexttools.DynamicMark(start_dynamic)(group[0]) command = marktools.LilyPondCommandMark(start_dynamic, 'right') attach(command, group[0]) else: descriptor = ' '.join([x for x in self.hairpin_token if x]) hairpin = spannertools.HairpinSpanner( descriptor=descriptor, include_rests=False, ) attach(hairpin, group) return expr
def list_named_pitches_in_expr(expr): '''List named pitches in `expr`: :: >>> staff = Staff("c'4 d'4 e'4 f'4") >>> beam = spannertools.BeamSpanner() >>> attach(beam, staff[:]) :: >>> for x in pitchtools.list_named_pitches_in_expr(beam): ... x ... NamedPitch("c'") NamedPitch("d'") NamedPitch("e'") NamedPitch("f'") Returns tuple. ''' from abjad.tools import spannertools from abjad.tools import iterationtools from abjad.tools import leaftools from abjad.tools import pitchtools from abjad.tools import resttools # TODO: remove try-except try: result = pitchtools.get_named_pitch_from_pitch_carrier(expr) return pitchtools.PitchSegment( tokens=(result,), item_class=pitchtools.NamedPitch, ) except (TypeError, MissingPitchError, ExtraPitchError): result = [] if hasattr(expr, 'written_pitches'): result.extend(expr.written_pitches) # for pitch arrays elif hasattr(expr, 'pitches'): result.extend(expr.pitches) elif isinstance(expr, spannertools.Spanner): for leaf in expr.leaves: if hasattr(leaf, 'written_pitch') and not isinstance(leaf, resttools.Rest): result.append(leaf.written_pitch) elif hasattr(leaf, 'written_pitches'): result.extend(leaf.written_pitches) elif isinstance(expr, pitchtools.PitchSet): result.extend(sorted(list(expr))) elif isinstance(expr, (list, tuple, set)): for x in expr: result.extend(list_named_pitches_in_expr(x)) else: for leaf in iterationtools.iterate_leaves_in_expr(expr): if hasattr(leaf, 'written_pitch') and not isinstance(leaf, resttools.Rest): result.append(leaf.written_pitch) elif hasattr(leaf, 'written_pitches'): result.extend(leaf.written_pitches) return pitchtools.PitchSegment( tokens=result, item_class=pitchtools.NamedPitch, )
def iterate_nontrivial_tie_chains_in_expr(expr, reverse=False): r'''Iterate nontrivial tie chains forward in `expr`: :: >>> staff = Staff(r"c'4 ~ \times 2/3 { c'16 d'8 } e'8 f'4 ~ f'16") .. doctest:: >>> f(staff) \new Staff { c'4 ~ \times 2/3 { c'16 d'8 } e'8 f'4 ~ f'16 } :: >>> for x in \ ... iterationtools.iterate_nontrivial_tie_chains_in_expr(staff): ... x ... TieChain(Note("c'4"), Note("c'16")) TieChain(Note("f'4"), Note("f'16")) Iterate nontrivial tie chains backward in `expr`: :: >>> for x in \ ... iterationtools.iterate_nontrivial_tie_chains_in_expr( ... staff, reverse=True): ... x ... TieChain(Note("f'4"), Note("f'16")) TieChain(Note("c'4"), Note("c'16")) Returns generator. ''' from abjad.tools import iterationtools from abjad.tools import spannertools spanner_classes = (spannertools.TieSpanner, ) if not reverse: for leaf in iterationtools.iterate_leaves_in_expr(expr): tie_spanners = leaf._get_spanners(spanner_classes) if not tie_spanners or \ tuple(tie_spanners)[0]._is_my_last_leaf(leaf): tie_chain = leaf._get_tie_chain() if not tie_chain.is_trivial: yield tie_chain else: for leaf in iterationtools.iterate_leaves_in_expr(expr, reverse=True): tie_spanners = leaf._get_spanners(spanner_classes) if not(tie_spanners) or \ tuple(tie_spanners)[0]._is_my_first_leaf(leaf): tie_chain = leaf._get_tie_chain() if not tie_chain.is_trivial: yield tie_chain
def _split_by_duration( self, duration, fracture_spanners=False, tie_split_notes=True, ): from abjad.tools import scoretools from abjad.tools import containertools from abjad.tools import iterationtools from abjad.tools import leaftools from abjad.tools import measuretools from abjad.tools import notetools from abjad.tools import resttools from abjad.tools import selectiontools from abjad.tools import spannertools # check input duration = durationtools.Duration(duration) assert 0 <= duration, repr(duration) # if zero duration then return empty list and self if duration == 0: return [], self # get split point score offset global_split_point = self._get_timespan().start_offset + duration # get any duration-crossing descendents cross_offset = self._get_timespan().start_offset + duration duration_crossing_descendants = [] for descendant in self._get_descendants(): start_offset = descendant._get_timespan().start_offset stop_offset = descendant._get_timespan().stop_offset if start_offset < cross_offset < stop_offset: duration_crossing_descendants.append(descendant) # get any duration-crossing measure descendents measures = [ x for x in duration_crossing_descendants if isinstance(x, measuretools.Measure) ] # if we must split a power-of-two measure at non-power-of-two # split point then go ahead and transform the power-of-two measure # to non-power-of-two equivalent now; # code that crawls and splits later on will be happier if len(measures) == 1: measure = measures[0] split_point_in_measure = \ global_split_point - measure._get_timespan().start_offset if measure.has_non_power_of_two_denominator: if not measure.implied_prolation ==\ split_point_in_measure.implied_prolation: raise NotImplementedError elif not mathtools.is_nonnegative_integer_power_of_two( split_point_in_measure.denominator): non_power_of_two_factors = mathtools.remove_powers_of_two( split_point_in_measure.denominator) non_power_of_two_factors = mathtools.factors( non_power_of_two_factors) non_power_of_two_product = 1 for non_power_of_two_factor in non_power_of_two_factors: non_power_of_two_product *= non_power_of_two_factor measuretools.scale_measure_denominator_and_adjust_measure_contents( measure, non_power_of_two_product) # rederive duration crosses with possibly new measure contents cross_offset = self._get_timespan().start_offset + duration duration_crossing_descendants = [] for descendant in self._get_descendants(): start_offset = descendant._get_timespan().start_offset stop_offset = descendant._get_timespan().stop_offset if start_offset < cross_offset < stop_offset: duration_crossing_descendants.append(descendant) elif 1 < len(measures): raise Exception('measures can not nest.') # 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, leaftools.Leaf): assert isinstance(bottom, leaftools.Leaf) did_split_leaf = True split_point_in_bottom = \ global_split_point - bottom._get_timespan().start_offset left_list, right_list = bottom._split_by_duration( split_point_in_bottom, fracture_spanners=fracture_spanners, tie_split_notes=tie_split_notes, ) right = right_list[0] leaf_right_of_split = right leaf_left_of_split = left_list[-1] 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 iterationtools.iterate_leaves_in_expr(bottom): if leaf._get_timespan().start_offset == global_split_point: leaf_right_of_split = leaf leaf_left_of_split = leaf_right_of_split._get_leaf(-1) break else: message = 'can not split empty container {!r}.' message = message.format(bottom) raise Exception(message) # find component to right of split that is also immediate child of # last duration-crossing container for component in \ leaf_right_of_split._get_parentage(include_self=True): if component._parent is duration_crossing_containers[-1]: highest_level_component_right_of_split = component break else: message = 'should we be able to get here?' raise ValueError(message) # crawl back up through duration-crossing containers and # fracture spanners if requested if fracture_spanners: start_offset = leaf_right_of_split._get_timespan().start_offset for parent in leaf_right_of_split._get_parentage(): if parent._get_timespan().start_offset == start_offset: for spanner in parent._get_spanners(): index = spanner.index(parent) spanner.fracture(index, direction=Left) if parent is component: break # crawl back up through duration-crossing containers and split each previous = highest_level_component_right_of_split for duration_crossing_container in \ reversed(duration_crossing_containers): assert isinstance( duration_crossing_container, containertools.Container) i = duration_crossing_container.index(previous) left, right = duration_crossing_container._split_at_index( i, fracture_spanners=fracture_spanners, ) previous = right # NOTE: If tie chain here is convenience, then fusing is good. # If tie chain here is user-given, then fusing is less good. # Maybe later model difference between user tie chains and not. left_tie_chain = leaf_left_of_split._get_tie_chain() right_tie_chain = leaf_right_of_split._get_tie_chain() left_tie_chain._fuse_leaves_by_immediate_parent() right_tie_chain._fuse_leaves_by_immediate_parent() # 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, notetools.Note): if leaf_left_of_split._get_parentage().root is \ leaf_right_of_split._get_parentage().root: leaves_around_split = \ (leaf_left_of_split, leaf_right_of_split) selection = selectiontools.ContiguousSelection( leaves_around_split) selection._attach_tie_spanner_to_leaf_pair() # return pair of left and right list-wrapped halves of container return ([left], [right])
def from_score(score, populate=True): r'''Make pitch array from `score`. .. container:: example **Example 1.** Make empty pitch array from score: :: >>> score = Score([]) >>> score.append(Staff("c'8 d'8 e'8 f'8")) >>> score.append(Staff("c'4 d'4")) >>> score.append( ... Staff( ... tuplettools.FixedDurationTuplet( ... Duration(2, 8), "c'8 d'8 e'8") * 2)) .. doctest:: >>> f(score) \new Score << \new Staff { c'8 d'8 e'8 f'8 } \new Staff { c'4 d'4 } \new Staff { \times 2/3 { c'8 d'8 e'8 } \times 2/3 { c'8 d'8 e'8 } } >> :: >>> show(score) # doctest: +SKIP :: >>> array = pitcharraytools.PitchArray.from_score( ... score, populate=False) :: >>> print array [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] .. container:: example **Example 2.** Make populated pitch array from `score`: :: >>> score = Score([]) >>> score.append(Staff("c'8 d'8 e'8 f'8")) >>> score.append(Staff("c'4 d'4")) >>> score.append( ... Staff( ... tuplettools.FixedDurationTuplet( ... Duration(2, 8), "c'8 d'8 e'8") * 2)) .. doctest:: >>> f(score) \new Score << \new Staff { c'8 d'8 e'8 f'8 } \new Staff { c'4 d'4 } \new Staff { \times 2/3 { c'8 d'8 e'8 } \times 2/3 { c'8 d'8 e'8 } } >> :: >>> show(score) # doctest: +SKIP :: >>> array = pitcharraytools.PitchArray.from_score( ... score, populate=True) :: >>> print array [c' ] [d' ] [e' ] [f' ] [c' ] [d' ] [c'] [d' ] [e'] [c'] [d' ] [e'] Returns pitch array. ''' time_intervals = \ PitchArray._get_composite_offset_difference_series_from_leaves_in_expr( score) array_width = len(time_intervals) array_depth = len(score) pitch_array = PitchArray(array_depth, array_width) tokens = notetools.make_quarter_notes_with_lilypond_duration_multiplier( [0], time_intervals) for leaf_iterable, pitch_array_row in \ zip(score, pitch_array.rows): durations = [] for leaf in iterationtools.iterate_leaves_in_expr(leaf_iterable): durations.append(leaf._get_duration()) parts = mutationtools.mutate(tokens).split( durations, cyclic=False, fracture_spanners=False, ) part_lengths = [len(part) for part in parts] cells = pitch_array_row.cells grouped_cells = sequencetools.partition_sequence_by_counts( cells, part_lengths, cyclic=False, overhang=False, ) for group in grouped_cells: pitch_array_row.merge(group) leaves = iterationtools.iterate_leaves_in_expr(leaf_iterable) if populate: for cell, leaf in zip(pitch_array_row.cells, leaves): cell.pitches.extend( pitchtools.list_named_pitches_in_expr(leaf)) return pitch_array
def _split( self, durations, cyclic=False, fracture_spanners=False, tie_split_notes=True, ): from abjad.tools import iterationtools from abjad.tools import pitchtools from abjad.tools import selectiontools from abjad.tools import spannertools durations = [durationtools.Duration(x) for x in durations] if cyclic: durations = sequencetools.repeat_sequence_to_weight_exactly( durations, self._get_duration()) durations = [durationtools.Duration(x) for x in durations] if sum(durations) < self._get_duration(): last_duration = self._get_duration() - sum(durations) durations.append(last_duration) sequencetools.truncate_sequence_to_weight( durations, self._get_duration()) result = [] leaf_prolation = self._get_parentage(include_self=False).prolation leaf_copy = copy.copy(self) for duration in durations: new_leaf = copy.copy(self) preprolated_duration = duration / leaf_prolation shard = new_leaf._set_duration(preprolated_duration) shard = [x._get_parentage().root for x in shard] result.append(shard) flattened_result = sequencetools.flatten_sequence(result) flattened_result = selectiontools.SliceSelection(flattened_result) spanner_classes = (spannertools.TieSpanner,) parentage = self._get_parentage() if parentage._get_spanners(spanner_classes=spanner_classes): selection = selectiontools.select(flattened_result) for component in selection: for mark in component._get_spanners( spanner_classes=spanner_classes): mark.detach() # replace leaf with flattened result selection = selectiontools.SliceSelection(self) parent, start, stop = selection._get_parent_and_start_stop_indices() if parent: parent.__setitem__(slice(start, stop + 1), flattened_result) else: selection._give_dominant_spanners(flattened_result) selection._withdraw_from_crossing_spanners() # fracture spanners if fracture_spanners: first_shard = result[0] for spanner in first_shard[-1]._get_spanners(): index = spanner.index(first_shard[-1]) spanner.fracture(index, direction=Right) last_shard = result[-1] for spanner in last_shard[0]._get_spanners(): index = spanner.index(last_shard[0]) spanner.fracture(index, direction=Left) for middle_shard in result[1:-1]: for spanner in middle_shard[0]._get_spanners(): index = spanner.index(middle_shard[0]) spanner.fracture(index, direction=Left) for spanner in middle_shard[-1]._get_spanners(): index = spanner.index(middle_shard[-1]) spanner.fracture(index, direction=Right) # adjust first leaf first_leaf = flattened_result[0] self._detach_grace_containers(kind='after') # adjust any middle leaves for middle_leaf in flattened_result[1:-1]: middle_leaf._detach_grace_containers(kind='grace') self._detach_grace_containers(kind='after') for mark in middle_leaf._get_marks(): mark.detach() # adjust last leaf last_leaf = flattened_result[-1] last_leaf._detach_grace_containers(kind='grace') for mark in last_leaf._get_marks(): mark.detach() # tie split notes, rests and chords as specified if pitchtools.Pitch.is_pitch_carrier(self) and tie_split_notes: flattened_result_leaves = iterationtools.iterate_leaves_in_expr( flattened_result) # TODO: implement SliceSelection._attach_tie_spanner_to_leaves() for leaf_pair in sequencetools.iterate_sequence_pairwise_strict( flattened_result_leaves): selection = selectiontools.ContiguousSelection(leaf_pair) selection._attach_tie_spanner_to_leaf_pair() # return result return result
def label_leaves_in_expr_with_leaf_durations( expr, label_durations=True, label_written_durations=True, markup_direction=Down, ): r'''Label leaves in expression with leaf durations. .. container:: example **Example 1.** Label leaves with written durations: :: >>> tuplet = Tuplet((2, 3), "c'8 d'8 e'8") >>> staff = stafftools.RhythmicStaff([tuplet]) >>> staff.override.text_script.staff_padding = 2.5 >>> staff.override.time_signature.stencil = False >>> labeltools.label_leaves_in_expr_with_leaf_durations( ... tuplet, ... label_durations=False, ... label_written_durations=True) :: >>> show(staff) # doctest: +SKIP .. doctest:: >>> f(staff) \new RhythmicStaff \with { \override TextScript #'staff-padding = #2.5 \override TimeSignature #'stencil = ##f } { \times 2/3 { c'8 _ \markup { \small 1/8 } d'8 _ \markup { \small 1/8 } e'8 _ \markup { \small 1/8 } } } .. container:: example **Example 2.** Label leaves with actual durations: :: >>> tuplet = Tuplet((2, 3), "c'8 d'8 e'8") >>> staff = stafftools.RhythmicStaff([tuplet]) >>> staff.override.text_script.staff_padding = 2.5 >>> staff.override.time_signature.stencil = False >>> labeltools.label_leaves_in_expr_with_leaf_durations( ... tuplet, ... label_durations=True, ... label_written_durations=False) :: >>> show(staff) # doctest: +SKIP .. doctest:: >>> f(staff) \new RhythmicStaff \with { \override TextScript #'staff-padding = #2.5 \override TimeSignature #'stencil = ##f } { \times 2/3 { c'8 _ \markup { \small 1/12 } d'8 _ \markup { \small 1/12 } e'8 _ \markup { \small 1/12 } } } .. container:: example **Example 3.** Label leaves in tuplet with both written and actual durations: :: >>> tuplet = Tuplet((2, 3), "c'8 d'8 e'8") >>> staff = stafftools.RhythmicStaff([tuplet]) >>> staff.override.text_script.staff_padding = 2.5 >>> staff.override.time_signature.stencil = False >>> labeltools.label_leaves_in_expr_with_leaf_durations( ... tuplet, ... label_durations=True, ... label_written_durations=True) :: >>> show(staff) # doctest: +SKIP .. doctest:: >>> f(staff) \new RhythmicStaff \with { \override TextScript #'staff-padding = #2.5 \override TimeSignature #'stencil = ##f } { \times 2/3 { c'8 _ \markup { \column { \small 1/8 \small 1/12 } } d'8 _ \markup { \column { \small 1/8 \small 1/12 } } e'8 _ \markup { \column { \small 1/8 \small 1/12 } } } } Returns none. ''' spanner_classes = (spannertools.TieSpanner,) for leaf in iterationtools.iterate_leaves_in_expr(expr): tie_spanners = leaf._get_spanners(spanner_classes) if not tie_spanners: if leaf.lilypond_duration_multiplier is not None: multiplier = '* %s' % str(leaf.lilypond_duration_multiplier) else: multiplier = '' if label_written_durations: label = markuptools.MarkupCommand( 'small', '{}{}'.format( str(leaf.written_duration), multiplier)) markup = markuptools.Markup(label, markup_direction) attach(markup, leaf) if label_durations: label = markuptools.MarkupCommand( 'small', str(leaf._get_duration())) markup = markuptools.Markup(label, markup_direction) attach(markup, leaf) elif tuple(tie_spanners)[0]._is_my_first_leaf(leaf): tie = tie_spanners.pop() if label_written_durations: written = sum([x.written_duration for x in tie]) label = markuptools.MarkupCommand('small', str(written)) markup = markuptools.Markup(label, markup_direction) attach(markup, leaf) if label_durations: prolated = sum([x._get_duration() for x in tie]) label = markuptools.MarkupCommand('small', str(prolated)) markup = markuptools.Markup(label, markup_direction) attach(markup, leaf)