def test_mathtools_remove_powers_of_two_01(): r'''Remove powers of two from integer n. ''' assert mathtools.remove_powers_of_two(10) == 5 assert mathtools.remove_powers_of_two(20) == 5 assert mathtools.remove_powers_of_two(30) == 15 assert mathtools.remove_powers_of_two(40) == 5 assert mathtools.remove_powers_of_two(50) == 25 assert mathtools.remove_powers_of_two(60) == 15 assert mathtools.remove_powers_of_two(70) == 35 assert mathtools.remove_powers_of_two(80) == 5 assert mathtools.remove_powers_of_two(90) == 45
def move_full_measure_tuplet_prolation_to_measure_time_signature(expr): r'''Moves prolation of full-measure tuplet to time signature of measure. Measures usually become non-power-of-two as as result. .. container:: example :: >>> tuplet = scoretools.FixedDurationTuplet(Duration(2, 8), "c'8 d'8 e'8") >>> measure = Measure((2, 8), [tuplet]) >>> measure.implicit_scaling = True >>> scoretools.move_full_measure_tuplet_prolation_to_measure_time_signature(measure) .. doctest:: >>> print(format(measure)) { \time 3/12 \scaleDurations #'(2 . 3) { c'8 d'8 e'8 } } Returns none. ''' from abjad.tools import indicatortools from abjad.tools import scoretools for measure in iterate(expr).by_class(scoretools.Measure): if len(measure) == 1: if isinstance(measure[0], scoretools.Tuplet): tuplet = measure[0] tuplet_multiplier = tuplet.multiplier tuplet_denominator = tuplet_multiplier.denominator reduced_denominator = mathtools.remove_powers_of_two( tuplet_denominator) time_signature = measure.time_signature time_signature_rational = durationtools.Duration( time_signature.numerator, time_signature.denominator) numerator = time_signature_rational.numerator * reduced_denominator denominator = time_signature_rational.denominator * reduced_denominator time_signature = indicatortools.TimeSignature( (numerator, denominator)) detach(indicatortools.TimeSignature, measure) attach(time_signature, measure) if time_signature.has_non_power_of_two_denominator: measure.implicit_scaling = True time_signature_multiplier = \ measure.time_signature.implied_prolation written_adjustment = tuplet_multiplier.__div__( time_signature_multiplier) tuplet._extract() measure._scale_contents(written_adjustment)
def move_full_measure_tuplet_prolation_to_measure_time_signature(expr): r'''Moves prolation of full-measure tuplet to time signature of measure. Measures usually become non-power-of-two as as result. .. container:: example :: >>> tuplet = scoretools.FixedDurationTuplet(Duration(2, 8), "c'8 d'8 e'8") >>> measure = Measure((2, 8), [tuplet]) >>> measure.implicit_scaling = True >>> scoretools.move_full_measure_tuplet_prolation_to_measure_time_signature(measure) .. doctest:: >>> print format(measure) { \time 3/12 \scaleDurations #'(2 . 3) { c'8 d'8 e'8 } } Returns none. ''' from abjad.tools import indicatortools from abjad.tools import scoretools for measure in iterate(expr).by_class(scoretools.Measure): if len(measure) == 1: if isinstance(measure[0], scoretools.Tuplet): tuplet = measure[0] tuplet_multiplier = tuplet.multiplier tuplet_denominator = tuplet_multiplier.denominator reduced_denominator = mathtools.remove_powers_of_two(tuplet_denominator) time_signature = measure.time_signature time_signature_rational = durationtools.Duration( time_signature.numerator, time_signature.denominator) numerator = time_signature_rational.numerator * reduced_denominator denominator = time_signature_rational.denominator * reduced_denominator time_signature = indicatortools.TimeSignature((numerator, denominator)) detach(indicatortools.TimeSignature, measure) attach(time_signature, measure) if time_signature.has_non_power_of_two_denominator: measure.implicit_scaling = True time_signature_multiplier = \ measure.time_signature.implied_prolation written_adjustment = tuplet_multiplier / time_signature_multiplier tuplet._extract() measure._scale_contents(written_adjustment)
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])
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])