Beispiel #1
0
def select(expr=None, contiguous=False):
    r'''Selects `expr`.

    Returns selection.
    '''
    from abjad.tools import scoretools
    from abjad.tools import selectiontools
    from abjad.tools import spannertools
    Selection = selectiontools.Selection
    if contiguous:
        if isinstance(expr, (list, tuple)):
            assert Selection._all_are_contiguous_components_in_same_logical_voice(
                expr)
        return selectiontools.ContiguousSelection(expr)
    elif isinstance(expr, scoretools.Component):
        return selectiontools.ContiguousSelection(expr)
    elif hasattr(expr, '_music'):
        music = expr._music
        return selectiontools.Selection(music)
    elif isinstance(expr, spannertools.Spanner):
        music = expr._components
        return selectiontools.Selection(music)
    elif expr is None:
        return selectiontools.Selection()
    else:
        return selectiontools.Selection(expr)
Beispiel #2
0
    def leaves_grouped_by_immediate_parents(self):
        r'''Leaves in logical tie grouped by immediate parents of leaves.

        Returns list of lists.
        '''
        from abjad.tools import selectiontools
        result = []
        pairs_generator = itertools.groupby(self, lambda x: id(x._parent))
        for key, values_generator in pairs_generator:
            group = selectiontools.ContiguousSelection(list(values_generator))
            result.append(group)
        return result
Beispiel #3
0
 def _split_by_duration(
     self,
     duration,
     fracture_spanners=False,
     tie_split_notes=True,
     use_messiaen_style_ties=False,
     ):
     from abjad.tools import indicatortools
     from abjad.tools import pitchtools
     from abjad.tools import selectiontools
     # check input
     duration = durationtools.Duration(duration)
     # calculate durations
     leaf_multiplied_duration = self._multiplied_duration
     prolation = self._get_parentage(include_self=False).prolation
     preprolated_duration = duration / prolation
     # handle boundary cases
     if preprolated_duration <= 0:
         return ([], [self])
     if leaf_multiplied_duration <= preprolated_duration:
         return ([self], [])
     # create new leaf
     new_leaf = copy.copy(self)
     self._splice([new_leaf], grow_spanners=True)
     # adjust leaf
     self._detach_grace_containers(kind='after')
     # adjust new leaf
     new_leaf._detach_grace_containers(kind='grace')
     left_leaf_list = self._set_duration(
         preprolated_duration,
         use_messiaen_style_ties=use_messiaen_style_ties,
         )
     right_preprolated_duration = \
         leaf_multiplied_duration - preprolated_duration
     right_leaf_list = new_leaf._set_duration(
         right_preprolated_duration,
         use_messiaen_style_ties=use_messiaen_style_ties,
         )
     leaf_left_of_split = left_leaf_list[-1]
     leaf_right_of_split = right_leaf_list[0]
     leaves_around_split = (leaf_left_of_split, leaf_right_of_split)
     if fracture_spanners:
         for spanner in leaf_left_of_split._get_spanners():
             index = spanner._index(leaf_left_of_split)
             spanner._fracture(index, direction=Right)
     # tie split notes, rests and chords as specified
     if pitchtools.Pitch.is_pitch_carrier(self) and tie_split_notes:
         selection = selectiontools.ContiguousSelection(leaves_around_split)
         selection._attach_tie_spanner_to_leaf_pair(
             use_messiaen_style_ties=use_messiaen_style_ties,
             )
     return left_leaf_list, right_leaf_list
Beispiel #4
0
    def select_leaves(
        self,
        start=0,
        stop=None,
        leaf_classes=None,
        recurse=True,
        allow_discontiguous_leaves=False,
    ):
        r'''Selects leaves in container.

        ..  container:: example

            **Example 1.** Selects leaves from container:

            ::

                >>> 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 selectiontools
        Selection = selectiontools.Selection
        leaf_classes = leaf_classes or (scoretools.Leaf, )
        expr = self
        if recurse:
            expr = iterate(expr).by_class(scoretools.Leaf)
        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
Beispiel #5
0
 def _split(
     self,
     durations,
     cyclic=False,
     fracture_spanners=False,
     tie_split_notes=True,
     use_messiaen_style_ties=False,
     ):
     from abjad.tools import pitchtools
     from abjad.tools import selectiontools
     from abjad.tools import scoretools
     from abjad.tools import spannertools
     durations = [durationtools.Duration(x) for x in durations]
     if cyclic:
         durations = sequencetools.repeat_sequence_to_weight(
             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(
         durations,
         weight=self._get_duration(),
         )
     result = []
     leaf_prolation = self._get_parentage(include_self=False).prolation
     timespan = self._get_timespan()
     start_offset = timespan.start_offset
     for duration in durations:
         new_leaf = copy.copy(self)
         preprolated_duration = duration / leaf_prolation
         shard = new_leaf._set_duration(
             preprolated_duration,
             use_messiaen_style_ties=use_messiaen_style_ties,
             )
         for x in shard:
             if isinstance(x, scoretools.Leaf):
                 x_duration = x.written_duration * leaf_prolation
             else:
                 x_duration = x.multiplied_duration * leaf_prolation
             stop_offset = x_duration + start_offset
             x._start_offset = start_offset
             x._stop_offset = stop_offset
             x._timespan = timespantools.Timespan(
                 start_offset=start_offset,
                 stop_offset=stop_offset,
                 )
             start_offset = stop_offset
         shard = [x._get_parentage().root for x in shard]
         result.append(shard)
     flattened_result = sequencetools.flatten_sequence(result)
     flattened_result = selectiontools.SliceSelection(flattened_result)
     prototype = (spannertools.Tie,)
     parentage = self._get_parentage()
     if parentage._get_spanners(prototype=prototype):
         selection = select(flattened_result)
         for component in selection:
             # TODO: make top-level detach() work here
             for spanner in component._get_spanners(prototype):
                 spanner._sever_all_components()
             #detach(prototype, component)
     # 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')
         detach(object, middle_leaf)
     # adjust last leaf
     last_leaf = flattened_result[-1]
     last_leaf._detach_grace_containers(kind='grace')
     detach(object, last_leaf)
     # tie split notes, rests and chords as specified
     if pitchtools.Pitch.is_pitch_carrier(self) and tie_split_notes:
         flattened_result_leaves = iterate(flattened_result).by_class(
             scoretools.Leaf)
         # TODO: implement SliceSelection._attach_tie_spanner_to_leaves()
         for leaf_pair in sequencetools.iterate_sequence_nwise(
             flattened_result_leaves):
             selection = selectiontools.ContiguousSelection(leaf_pair)
             selection._attach_tie_spanner_to_leaf_pair(
                 use_messiaen_style_ties=use_messiaen_style_ties,
                 )
     # return result
     return result
Beispiel #6
0
 def _split_by_duration(
     self,
     duration,
     fracture_spanners=False,
     tie_split_notes=True,
     use_messiaen_style_ties=False,
 ):
     from abjad.tools import scoretools
     from abjad.tools import selectiontools
     # 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, scoretools.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
             scoretools.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):
         message = 'measures can not nest.'
         raise Exception(message)
     # 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, scoretools.Leaf):
         assert isinstance(bottom, scoretools.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,
             use_messiaen_style_ties=use_messiaen_style_ties,
         )
         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 iterate(bottom).by_class(scoretools.Leaf):
             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,
                           scoretools.Container)
         i = duration_crossing_container.index(previous)
         left, right = duration_crossing_container._split_at_index(
             i,
             fracture_spanners=fracture_spanners,
         )
         previous = right
     # NOTE: If logical tie here is convenience, then fusing is good.
     #       If logical tie here is user-given, then fusing is less good.
     #       Maybe later model difference between user logical ties and not.
     left_logical_tie = leaf_left_of_split._get_logical_tie()
     right_logical_tie = leaf_right_of_split._get_logical_tie()
     left_logical_tie._fuse_leaves_by_immediate_parent()
     right_logical_tie._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, scoretools.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(
                     use_messiaen_style_ties=use_messiaen_style_ties, )
     # return pair of left and right list-wrapped halves of container
     return ([left], [right])
Beispiel #7
0
def apply_full_measure_tuplets_to_contents_of_measures_in_expr(
        expr, supplement=None):
    r'''Applies full-measure tuplets to contents of measures in `expr`:

    ::

        >>> staff = Staff([
        ...     Measure((2, 8), "c'8 d'8"),
        ...     Measure((3, 8), "e'8 f'8 g'8")])
        >>> show(staff) # doctest: +SKIP

    ..  doctest::

        >>> print(format(staff))
        \new Staff {
            {
                \time 2/8
                c'8
                d'8
            }
            {
                \time 3/8
                e'8
                f'8
                g'8
            }
        }

    ::

        >>> scoretools.apply_full_measure_tuplets_to_contents_of_measures_in_expr(staff)
        >>> show(staff) # doctest: +SKIP

    ..  doctest::

        >>> print(format(staff))
        \new Staff {
            {
                \time 2/8
                {
                    c'8
                    d'8
                }
            }
            {
                \time 3/8
                {
                    e'8
                    f'8
                    g'8
                }
            }
        }

    Returns none.
    '''
    from abjad.tools import selectiontools
    from abjad.tools import scoretools

    supplement = selectiontools.ContiguousSelection(supplement)
    assert isinstance(supplement, selectiontools.ContiguousSelection)

    for measure in iterate(expr).by_class(scoretools.Measure):
        target_duration = measure._preprolated_duration
        tuplet = scoretools.FixedDurationTuplet(target_duration, measure[:])
        if supplement:
            new_supplement = mutate(supplement).copy()
            tuplet.extend(new_supplement)
Beispiel #8
0
 def _set_item(
     self,
     i,
     expr,
     withdraw_components_in_expr_from_crossing_spanners=True,
     ):
     r'''This method exists beacuse __setitem__ can not accept keywords.
     Note that setting
     withdraw_components_in_expr_from_crossing_spanners=False
     constitutes a composer-unsafe use of this method.
     Only private methods should set this keyword.
     '''
     from abjad.tools import indicatortools
     from abjad.tools import scoretools
     from abjad.tools import selectiontools
     from abjad.tools import spannertools
     # cache indicators attached to components in expr
     expr_indicators = []
     for component in iterate(expr).by_class():
         indicators = component._get_indicators(unwrap=False)
         expr_indicators.extend(indicators)
     # item assignment
     if isinstance(i, int):
         if isinstance(expr, str):
             expr = self._parse_string(expr)[:]
             assert len(expr) == 1, repr(expr)
             expr = expr[0]
         assert all(isinstance(x, scoretools.Component) for x in [expr])
         if any(isinstance(x, scoretools.GraceContainer) for x in [expr]):
             message = 'must attach grace container to note or chord.'
             raise Exception(message)
         old = self[i]
         selection = selectiontools.ContiguousSelection(old)
         spanners_receipt = selection._get_dominant_spanners()
         for child in iterate([old]).by_class():
             for spanner in child._get_spanners():
                 spanner._remove(child)
         if i < 0:
             i = len(self) + i
         del(self[i])
         # must withdraw from spanners before withdrawing from parentage!
         # otherwise begin / end assessments don't work!
         if withdraw_components_in_expr_from_crossing_spanners:
             selection = selectiontools.SliceSelection([expr])
             selection._withdraw_from_crossing_spanners()
         expr._set_parent(self)
         self._music.insert(i, expr)
         for spanner, index in spanners_receipt:
             spanner._insert(index, expr)
             expr._spanners.add(spanner)
     # slice assignment
     else:
         if isinstance(expr, str):
             expr = self._parse_string(expr)[:]
         elif isinstance(expr, list) and \
             len(expr) == 1 and \
             isinstance(expr[0], str):
             expr = self._parse_string(expr[0])[:]
         prototype = (scoretools.Component, selectiontools.Selection)
         assert all(isinstance(x, prototype) for x in expr)
         new_expr = []
         for item in expr:
             if isinstance(item, selectiontools.Selection):
                 new_expr.extend(item)
             else:
                 new_expr.append(item)
         expr = new_expr
         assert all(isinstance(x, scoretools.Component) for x in expr)
         if any(isinstance(x, scoretools.GraceContainer) for x in expr):
             message = 'must attach grace container to note or chord.'
             raise Exception(message)
         if i.start == i.stop and i.start is not None \
             and i.stop is not None and i.start <= -len(self):
             start, stop = 0, 0
         else:
             start, stop, stride = i.indices(len(self))
         old = self[start:stop]
         spanners_receipt = self._get_spanners_that_dominate_slice(
             start, stop)
         for component in old:
             for child in iterate([component]).by_class():
                 for spanner in child._get_spanners():
                     spanner._remove(child)
         del(self[start:stop])
         # must withdraw before setting in self!
         # otherwise circular withdraw ensues!
         if withdraw_components_in_expr_from_crossing_spanners:
             selection = selectiontools.SliceSelection(expr)
             if selection._all_are_contiguous_components_in_same_logical_voice(
                 selection):
                 selection._withdraw_from_crossing_spanners()
         self._music.__setitem__(slice(start, start), expr)
         for component in expr:
             component._set_parent(self)
         for spanner, index in spanners_receipt:
             for component in reversed(expr):
                 spanner._insert(index, component)
                 component._spanners.add(spanner)
     for indicator in expr_indicators:
         if hasattr(indicator, '_update_effective_context'):
             indicator._update_effective_context()
Beispiel #9
0
 def _splice(
     self,
     components,
     direction=Right,
     grow_spanners=True,
     ):
     from abjad.tools import scoretools
     from abjad.tools import selectiontools
     assert all(isinstance(x, scoretools.Component) for x in components)
     selection = selectiontools.ContiguousSelection(self)
     if direction == Right:
         if grow_spanners:
             insert_offset = self._get_timespan().stop_offset
             receipt = selection._get_dominant_spanners()
             for spanner, index in receipt:
                 insert_component = None
                 for component in spanner:
                     start_offset = component._get_timespan().start_offset
                     if start_offset == insert_offset:
                         insert_component = component
                         break
                 if insert_component is not None:
                     insert_index = spanner._index(insert_component)
                 else:
                     insert_index = len(spanner)
                 for component in reversed(components):
                     spanner._insert(insert_index, component)
                     component._spanners.add(spanner)
         selection = selectiontools.SliceSelection(self)
         parent, start, stop = \
             selection._get_parent_and_start_stop_indices()
         if parent is not None:
             if grow_spanners:
                 for component in reversed(components):
                     component._set_parent(parent)
                     parent._music.insert(start + 1, component)
             else:
                 after = stop + 1
                 parent.__setitem__(slice(after, after), components)
         return [self] + components
     else:
         if grow_spanners:
             offset = self._get_timespan().start_offset
             receipt = selection._get_dominant_spanners()
             for spanner, x in receipt:
                 for component in spanner:
                     if component._get_timespan().start_offset == offset:
                         index = spanner._index(component)
                         break
                 else:
                     message = 'no component in spanner at offset.'
                     raise ValueError(message)
                 for component in reversed(components):
                     spanner._insert(index, component)
                     component._spanners.add(spanner)
         selection = selectiontools.SliceSelection(self)
         parent, start, stop = \
             selection._get_parent_and_start_stop_indices()
         if parent is not None:
             if grow_spanners:
                 for component in reversed(components):
                     component._set_parent(parent)
                     parent._music.insert(start, component)
             else:
                 parent.__setitem__(slice(start, start), components)
         return components + [self]