def split_sequence_extended_to_weights(sequence, weights, overhang=True): '''Split sequence extended to weights. .. container:: example **Example 1.** Split sequence extended to weights with overhang: :: >>> sequencetools.split_sequence_extended_to_weights( ... [1, 2, 3, 4, 5], [7, 7, 7], overhang=True) [[1, 2, 3, 1], [3, 4], [1, 1, 2, 3], [4, 5]] .. container:: example **Example 2.** Split sequence extended to weights without overhang: :: >>> sequencetools.split_sequence_extended_to_weights( ... [1, 2, 3, 4, 5], [7, 7, 7], overhang=False) [[1, 2, 3, 1], [3, 4], [1, 1, 2, 3]] Returns sequence of sequence objects. ''' from abjad.tools import sequencetools n = int(math.ceil(float(mathtools.weight(weights)) / mathtools.weight(sequence))) sequence = sequencetools.repeat_sequence_n_times(sequence, n) return sequencetools.split_sequence_by_weights(sequence, weights, cyclic=False, overhang=overhang)
def _fracture_right(self, i): self, left, right = ComplexBeamSpanner._fracture_right(self, i) weights = [left.get_duration(), right.get_duration()] assert sum(self.durations) == sum(weights) split_durations = sequencetools.split_sequence_by_weights( self.durations, weights, cyclic=False, overhang=False) left_durations, right_durations = split_durations left._durations = left_durations right._durations = right_durations return self, left, right
def _make_secondary_duration_pairs( self, duration_pairs, secondary_divisions): if not secondary_divisions: return duration_pairs[:] numerators = [duration_pair.numerator for duration_pair in duration_pairs] secondary_numerators = sequencetools.split_sequence_by_weights( numerators, secondary_divisions, cyclic=True, overhang=True) secondary_numerators = \ sequencetools.flatten_sequence(secondary_numerators) denominator = duration_pairs[0].denominator secondary_duration_pairs = \ [(n, denominator) for n in secondary_numerators] return secondary_duration_pairs
def _split_payload_at_offsets(self, offsets): from experimental.tools import musicexpressiontools divisions = self.payload.divisions self._payload = musicexpressiontools.DivisionList( [], voice_name=self.voice_name, start_offset=self.start_offset) shards = sequencetools.split_sequence_by_weights( divisions, offsets, cyclic=False, overhang=True) result, total_duration = [], durationtools.Duration(0) for shard in shards: shard = musicexpressiontools.DivisionList( shard, voice_name=self.voice_name, start_offset=total_duration) result.append(shard) total_duration += shard.duration return result
def _make_numeric_map_part( self, numerator, prefix, suffix, is_note_filled=True, ): prefix_weight = mathtools.weight(prefix) suffix_weight = mathtools.weight(suffix) middle = numerator - prefix_weight - suffix_weight if numerator < prefix_weight: weights = [numerator] prefix = sequencetools.split_sequence_by_weights( prefix, weights, cyclic=False, overhang=False)[0] middle = self._make_middle_of_numeric_map_part(middle) suffix_space = numerator - prefix_weight if suffix_space <= 0: suffix = () elif suffix_space < suffix_weight: weights = [suffix_space] suffix = sequencetools.split_sequence_by_weights( suffix, weights, cyclic=False, overhang=False)[0] numeric_map_part = prefix + middle + suffix return numeric_map_part
def partition_sequence_by_weights_exactly( sequence, weights, cyclic=False, overhang=False, ): r'''Partition `sequence` by `weights` exactly. :: >>> sequence = [3, 3, 3, 3, 4, 4, 4, 4, 5] .. container:: example **Example 1.** Partition sequence once by weights exactly without overhang: :: >>> sequencetools.partition_sequence_by_weights_exactly( ... sequence, ... [3, 9], ... cyclic=False, ... overhang=False, ... ) [[3], [3, 3, 3]] .. container:: example **Example 2.** Partition sequence once by weights exactly with overhang: :: >>> sequencetools.partition_sequence_by_weights_exactly( ... sequence, ... [3, 9], ... cyclic=False, ... overhang=True, ... ) [[3], [3, 3, 3], [4, 4, 4, 4, 5]] .. container:: example **Example 3.** Partition sequence cyclically by weights exactly without overhang: :: >>> sequencetools.partition_sequence_by_weights_exactly( ... sequence, ... [12], ... cyclic=True, ... overhang=False, ... ) [[3, 3, 3, 3], [4, 4, 4]] .. container:: example **Example 4.** Partition sequence cyclically by weights exactly with overhang: :: >>> sequencetools.partition_sequence_by_weights_exactly( ... sequence, ... [12], ... cyclic=True, ... overhang=True, ... ) [[3, 3, 3, 3], [4, 4, 4], [4, 5]] Returns list sequence objects. ''' from abjad.tools import sequencetools candidate = sequencetools.split_sequence_by_weights( sequence, weights, cyclic=cyclic, overhang=overhang, ) flattened_candidate = sequencetools.flatten_sequence(candidate) if flattened_candidate == sequence[:len(flattened_candidate)]: return candidate else: raise PartitionError('can not partition exactly.')
def split( self, durations, fracture_spanners=False, cyclic=False, tie_split_notes=True, ): r'''Splits component or selection by `durations`. .. container:: example **Example 1.** Split leaves: :: >>> staff = Staff("c'8 e' d' f' c' e' d' f'") >>> leaves = staff.select_leaves() >>> hairpin = spannertools.HairpinSpanner(descriptor='p < f') >>> attach(hairpin, leaves) >>> staff.override.dynamic_line_spanner.staff_padding = 3 >>> show(staff) # doctest: +SKIP .. doctest:: >>> f(staff) \new Staff \with { \override DynamicLineSpanner #'staff-padding = #3 } { c'8 \< \p e'8 d'8 f'8 c'8 e'8 d'8 f'8 \f } :: >>> durations = [Duration(3, 16), Duration(7, 32)] >>> result = mutate(leaves).split( ... durations, ... tie_split_notes=False, ... ) >>> show(staff) # doctest: +SKIP .. doctest:: >>> f(staff) \new Staff \with { \override DynamicLineSpanner #'staff-padding = #3 } { c'8 \< \p e'16 e'16 d'8 f'32 f'16. c'8 e'8 d'8 f'8 \f } .. container:: example **Example 2.** Split leaves and fracture crossing spanners: :: >>> staff = Staff("c'8 e' d' f' c' e' d' f'") >>> leaves = staff.select_leaves() >>> hairpin = spannertools.HairpinSpanner(descriptor='p < f') >>> attach(hairpin, leaves) >>> staff.override.dynamic_line_spanner.staff_padding = 3 >>> show(staff) # doctest: +SKIP .. doctest:: >>> f(staff) \new Staff \with { \override DynamicLineSpanner #'staff-padding = #3 } { c'8 \< \p e'8 d'8 f'8 c'8 e'8 d'8 f'8 \f } :: >>> durations = [Duration(3, 16), Duration(7, 32)] >>> result = mutate(leaves).split( ... durations, ... fracture_spanners=True, ... tie_split_notes=False, ... ) >>> show(staff) # doctest: +SKIP .. doctest:: >>> f(staff) \new Staff \with { \override DynamicLineSpanner #'staff-padding = #3 } { c'8 \< \p e'16 \f e'16 \< \p d'8 f'32 \f f'16. \< \p c'8 e'8 d'8 f'8 \f } .. container:: example **Example 3.** Split leaves cyclically: :: >>> staff = Staff("c'8 e' d' f' c' e' d' f'") >>> leaves = staff.select_leaves() >>> hairpin = spannertools.HairpinSpanner(descriptor='p < f') >>> attach(hairpin, leaves) >>> staff.override.dynamic_line_spanner.staff_padding = 3 >>> show(staff) # doctest: +SKIP .. doctest:: >>> f(staff) \new Staff \with { \override DynamicLineSpanner #'staff-padding = #3 } { c'8 \< \p e'8 d'8 f'8 c'8 e'8 d'8 f'8 \f } :: >>> durations = [Duration(3, 16), Duration(7, 32)] >>> result = mutate(leaves).split( ... durations, ... cyclic=True, ... tie_split_notes=False, ... ) >>> show(staff) # doctest: +SKIP .. doctest:: >>> f(staff) \new Staff \with { \override DynamicLineSpanner #'staff-padding = #3 } { c'8 \< \p e'16 e'16 d'8 f'32 f'16. c'16. c'32 e'8 d'16 d'16 f'8 \f } .. container:: example **Example 4.** Split leaves cyclically and fracture spanners: :: >>> staff = Staff("c'8 e' d' f' c' e' d' f'") >>> leaves = staff.select_leaves() >>> hairpin = spannertools.HairpinSpanner(descriptor='p < f') >>> attach(hairpin, leaves) >>> staff.override.dynamic_line_spanner.staff_padding = 3 >>> show(staff) # doctest: +SKIP .. doctest:: >>> f(staff) \new Staff \with { \override DynamicLineSpanner #'staff-padding = #3 } { c'8 \< \p e'8 d'8 f'8 c'8 e'8 d'8 f'8 \f } :: >>> durations = [Duration(3, 16), Duration(7, 32)] >>> result = mutate(leaves).split( ... durations, ... cyclic=True, ... fracture_spanners=True, ... tie_split_notes=False, ... ) >>> show(staff) # doctest: +SKIP .. doctest:: >>> f(staff) \new Staff \with { \override DynamicLineSpanner #'staff-padding = #3 } { c'8 \< \p e'16 \f e'16 \< \p d'8 f'32 \f f'16. \< \p c'16. \f c'32 \< \p e'8 d'16 \f d'16 \< \p f'8 \f } .. container:: example **Example 5.** Split tupletted leaves and fracture crossing spanners: :: >>> staff = Staff() >>> staff.append(Tuplet((2, 3), "c'4 d' e'")) >>> staff.append(Tuplet((2, 3), "c'4 d' e'")) >>> leaves = staff.select_leaves() >>> slur = spannertools.SlurSpanner() >>> attach(slur, leaves) >>> show(staff) # doctest: +SKIP .. doctest:: >>> f(staff) \new Staff { \times 2/3 { c'4 ( d'4 e'4 } \times 2/3 { c'4 d'4 e'4 ) } } :: >>> durations = [Duration(1, 4)] >>> result = mutate(leaves).split( ... durations, ... fracture_spanners=True, ... tie_split_notes=False, ... ) >>> show(staff) # doctest: +SKIP .. doctest:: >>> f(staff) \new Staff { \times 2/3 { c'4 ( d'8 ) d'8 ( e'4 } \times 2/3 { c'4 d'4 e'4 ) } } Returns list of selections. ''' from abjad.tools import scoretools from abjad.tools import leaftools from abjad.tools import selectiontools # check input components = self._client single_component_input = False if isinstance(components, scoretools.Component): single_component_input = True components = selectiontools.Selection(components) assert all( isinstance(x, scoretools.Component) for x in components) if not isinstance(components, selectiontools.Selection): components = selectiontools.Selection(components) durations = [durationtools.Duration(x) for x in durations] # return if no split to be done if not durations: if single_component_input: return components else: return [], components # calculate total component duration total_component_duration = components.get_duration() total_split_duration = sum(durations) # calculate durations if cyclic: durations = sequencetools.repeat_sequence_to_weight_exactly( durations, total_component_duration) elif total_split_duration < total_component_duration: final_offset = total_component_duration - sum(durations) durations.append(final_offset) elif total_component_duration < total_split_duration: durations = sequencetools.truncate_sequence_to_weight( durations, total_component_duration) # keep copy of durations to partition result components durations_copy = durations[:] # calculate total split duration total_split_duration = sum(durations) assert total_split_duration == total_component_duration # initialize loop variables result, shard = [], [] offset_index, offset_count = 0, len(durations) current_shard_duration = durationtools.Duration(0) remaining_components = list(components[:]) advance_to_next_offset = True # loop and build shards by grabbing next component # and next duration each time through loop while True: # grab next split point if advance_to_next_offset: if durations: next_split_point = durations.pop(0) else: break advance_to_next_offset = True # grab next component from input stack of components if remaining_components: current_component = remaining_components.pop(0) else: break # find where current component endpoint will position us candidate_shard_duration = current_shard_duration + \ current_component._get_duration() # if current component would fill current shard exactly if candidate_shard_duration == next_split_point: shard.append(current_component) result.append(shard) shard = [] current_shard_duration = durationtools.Duration(0) offset_index += 1 # if current component would exceed current shard elif next_split_point < candidate_shard_duration: local_split_duration = \ next_split_point - current_shard_duration if isinstance(current_component, leaftools.Leaf): leaf_split_durations = [local_split_duration] current_duration = current_component._get_duration() additional_required_duration = \ current_duration - local_split_duration split_durations = sequencetools.split_sequence_by_weights( durations, [additional_required_duration], cyclic=False, overhang=True, ) additional_durations = split_durations[0] leaf_split_durations.extend(additional_durations) durations = split_durations[-1] leaf_shards = current_component._split( leaf_split_durations, cyclic=False, fracture_spanners=fracture_spanners, tie_split_notes=tie_split_notes, ) shard.extend(leaf_shards) result.append(shard) offset_index += len(additional_durations) else: left_list, right_list = \ current_component._split_by_duration( local_split_duration, fracture_spanners=fracture_spanners, tie_split_notes=tie_split_notes, ) shard.extend(left_list) result.append(shard) remaining_components.__setitem__(slice(0, 0), right_list) shard = [] offset_index += 1 current_shard_duration = durationtools.Duration(0) # if current component would not fill current shard elif candidate_shard_duration < next_split_point: shard.append(current_component) current_shard_duration += current_component._get_duration() advance_to_next_offset = False else: raise ValueError # append any stub shard if len(shard): result.append(shard) # append any unexamined components if len(remaining_components): result.append(remaining_components) # partition split components according to input durations result = sequencetools.flatten_sequence(result) result = selectiontools.ContiguousSelection(result) result = result.partition_by_durations_exactly(durations_copy) # return list of shards result = [selectiontools.Selection(x) for x in result] return result
def rotate(self, n, fracture_spanners=True): r'''Rotate start-positioned rhythm payload expression. Example 1. Rotate by count: :: >>> payload = [Container("c'8 d'8 e'8 f'8")] >>> expression = \ ... musicexpressiontools.StartPositionedRhythmPayloadExpression( ... payload, Offset(0)) :: >>> result = expression.rotate(-1) :: >>> print expression.storage_format musicexpressiontools.StartPositionedRhythmPayloadExpression( payload=containertools.Container( music=[{d'8, e'8, f'8}, {c'8}] ), start_offset=durationtools.Offset(0, 1) ) Example 2. Rotate by duration: :: >>> payload = [Container("c'8 d'8 e'8 f'8")] >>> expression = \ ... musicexpressiontools.StartPositionedRhythmPayloadExpression( ... payload, Offset(0)) :: >>> result = expression.rotate(-Duration(3, 16)) :: >>> print expression.storage_format musicexpressiontools.StartPositionedRhythmPayloadExpression( payload=containertools.Container( music=[{d'16, e'8, f'8}, {c'8, d'16}] ), start_offset=durationtools.Offset(0, 1) ) Operates in place and returns start-positioned rhythm payload expression. ''' from experimental.tools import musicexpressiontools if isinstance(n, int): leaves = datastructuretools.CyclicTuple(self.payload.select_leaves()) if 0 < n: split_offset = leaves[-n]._get_timespan().start_offset elif n == 0: return self else: split_offset = leaves[-(n+1)]._get_timespan().stop_offset elif isinstance(n, musicexpressiontools.RotationIndicator): rotation_indicator = n if rotation_indicator.level is None: components_at_level = self.payload.select_leaves() else: components_at_level = [] for component in \ iterationtools.iterate_components_in_expr(self.payload): score_index = component._get_parentage().score_index if len(score_index) == rotation_indicator.level: components_at_level.append(component) components_at_level = datastructuretools.CyclicTuple(components_at_level) if isinstance(rotation_indicator.index, int): if 0 < rotation_indicator.index: split_offset = components_at_level[ -rotation_indicator.index]._get_timespan().start_offset elif n == 0: return self else: split_offset = components_at_level[ -(rotation_indicator.index+1)]._get_timespan().stop_offset else: index = durationtools.Duration(rotation_indicator.index) if 0 <= index: split_offset = self.payload._get_duration() - index else: split_offset = abs(index) if rotation_indicator.fracture_spanners is not None: fracture_spanners = rotation_indicator.fracture_spanners else: n = durationtools.Duration(n) if 0 <= n: split_offset = self.payload._get_duration() - n else: split_offset = abs(n) #self._debug(split_offset, 'split offset') try: payload_duration = getattr(self, 'payload') except AttributeError: payload_duration = self.payload._get_duration() if split_offset == payload_duration: return self if fracture_spanners: result = mutationtools.mutate([self.payload]).split( [split_offset], cyclic=False, fracture_spanners=True, tie_split_notes=False, ) left_half, right_half = result[0][0], result[-1][0] payload = containertools.Container() payload.extend(right_half) payload.extend(left_half) assert inspect(payload).is_well_formed() self._payload = payload else: result = mutationtools.mutate(self.payload[:]).split( [split_offset], cyclic=False, fracture_spanners=False, tie_split_notes=False, ) left_half, right_half = result[0], result[-1] spanner_classes = (spannertools.DuratedComplexBeamSpanner, ) descendants = self.payload._get_descendants() for spanner in descendants.get_spanners(spanner_classes): if left_half[-1] in spanner and right_half[0] in spanner: leaf_right_of_split = right_half[0] split_offset_in_beam = spanner._duration_offset_in_me( leaf_right_of_split) left_durations, right_durations = \ sequencetools.split_sequence_by_weights( spanner.durations, [split_offset_in_beam], cyclic=False, overhang=True, ) new_durations = right_durations + left_durations spanner._durations = new_durations new_payload = right_half + left_half self.payload._music = new_payload for component in new_payload: component._update_later(offsets=True) for spanner in self.payload._get_descendants().get_spanners(): spanner._components.sort( lambda x, y: cmp(x._get_parentage().score_index, y._get_parentage().score_index)) assert inspect(self.payload).is_well_formed() return self