def to_fixed_multiplier(self): r'''Change fixed-duration tuplet to (unqualified) tuplet. .. container:: example **Example:** :: >>> tuplet = tuplettools.FixedDurationTuplet((2, 8), []) >>> tuplet.extend("c'8 d'8 e'8") >>> show(tuplet) # doctest: +SKIP :: >>> tuplet FixedDurationTuplet(1/4, [c'8, d'8, e'8]) :: >>> new_tuplet = tuplet.to_fixed_multiplier() >>> show(new_tuplet) # doctest: +SKIP :: >>> new_tuplet Tuplet(2/3, [c'8, d'8, e'8]) Returns new tuplet. ''' from abjad.tools import tuplettools new_tuplet = tuplettools.Tuplet(self.multiplier, []) mutationtools.mutate(self).swap(new_tuplet) return new_tuplet
def _fuse_tuplets(self): from abjad.tools import containertools from abjad.tools import tuplettools assert self._all_are_contiguous_components_in_same_parent( self, component_classes=(tuplettools.Tuplet,)) if len(self) == 0: return None first = self[0] first_multiplier = first.multiplier first_type = type(first) for tuplet in self[1:]: if tuplet.multiplier != first_multiplier: raise TupletFuseError('tuplets must carry same multiplier.') if type(tuplet) != first_type: raise TupletFuseError('tuplets must be same type.') if isinstance(first, tuplettools.FixedDurationTuplet): total_contents_duration = sum( [x._contents_duration for x in self]) new_target_duration = first_multiplier * total_contents_duration new_tuplet = tuplettools.FixedDurationTuplet( new_target_duration, []) elif isinstance(first, tuplettools.Tuplet): new_tuplet = tuplettools.Tuplet(first_multiplier, []) else: raise TypeError('unknown tuplet type.') wrapped = False if self[0]._get_parentage().root is not \ self[-1]._get_parentage().root: dummy_container = containertools.Container(self) wrapped = True mutationtools.mutate(self).swap(new_tuplet) if wrapped: del(dummy_container[:]) return new_tuplet
def __or__(self, expr): r'''Logical OR of two payload expressions. Payload expression must be able to fuse. Returns timespan inventory. ''' assert self._can_fuse(expr) if isinstance(self.payload, containertools.Container): selection = select(self.payload[0], contiguous=True) left = mutationtools.mutate(selection).copy()[0] selection = select(expr.payload[0], contiguous=True) right = mutationtools.mutate(selection).copy()[0] payload = containertools.Container([left, right]) for component in payload[:]: component._extract() payload = containertools.Container([payload]) else: payload = self.payload + expr.payload result = type(self)( [], start_offset=self.timespan.start_offset, voice_name=self.voice_name, ) result._payload = payload return timespantools.TimespanInventory([result])
def __call__(self, expr): for i, note in enumerate(iterationtools.iterate_notes_in_expr(expr)): cluster_width = self.cluster_widths[i] start = note.written_pitch.diatonic_pitch_number diatonic_numbers = range(start, start + cluster_width) chromatic_numbers = [ (12 * (x // 7)) + pitchtools.PitchClass._diatonic_pitch_class_number_to_pitch_class_number[ x % 7] for x in diatonic_numbers ] chord_pitches = [pitchtools.NamedPitch(x) for x in chromatic_numbers] chord = scoretools.Chord(note) chord[:] = [] chord.extend(chord_pitches) mutationtools.mutate(note).replace(chord)
def _split_payload_at_offsets(self, offsets): assert isinstance(self.payload, containertools.Container) music = self.payload self._payload = containertools.Container() shards = mutationtools.mutate([music]).split( offsets, cyclic=False, fracture_spanners=True, ) shards = [shard[0] for shard in shards] for shard in shards: if not inspect(shard).is_well_formed(): wellformednesstools.tabulate_well_formedness_violations_in_expr(shard) return shards
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 to_tuplet(self, proportions, dotted=False, is_diminution=True): r"""Change tie chain to tuplet. .. container:: example **Example 1.** Change tie chain to diminished tuplet: :: >>> staff = Staff(r"c'8 ~ c'16 cqs''4") >>> crescendo = spannertools.HairpinSpanner(descriptor='p < f') >>> attach(crescendo, staff[:]) >>> staff.override.dynamic_line_spanner.staff_padding = 3 >>> time_signature = contexttools.TimeSignatureMark((7, 16)) >>> attach(time_signature, staff) TimeSignatureMark((7, 16))(Staff{3}) .. doctest:: >>> f(staff) \new Staff \with { \override DynamicLineSpanner #'staff-padding = #3 } { \time 7/16 c'8 \< \p ~ c'16 cqs''4 \f } :: >>> show(staff) # doctest: +SKIP :: >>> tie_chain = inspect(staff[0]).get_tie_chain() >>> tie_chain.to_tuplet([2, 1, 1, 1], is_diminution=True) FixedDurationTuplet(3/16, [c'8, c'16, c'16, c'16]) .. doctest:: >>> f(staff) \new Staff \with { \override DynamicLineSpanner #'staff-padding = #3 } { \time 7/16 \tweak #'text #tuplet-number::calc-fraction-text \times 3/5 { c'8 \< \p c'16 c'16 c'16 } cqs''4 \f } :: >>> show(staff) # doctest: +SKIP .. container:: example **Example 2.** Change tie chain to augmented tuplet: :: >>> staff = Staff(r"c'8 ~ c'16 cqs''4") >>> crescendo = spannertools.HairpinSpanner(descriptor='p < f') >>> attach(crescendo, staff[:]) >>> staff.override.dynamic_line_spanner.staff_padding = 3 >>> time_signature = contexttools.TimeSignatureMark((7, 16)) >>> attach(time_signature, staff) TimeSignatureMark((7, 16))(Staff{3}) .. doctest:: >>> f(staff) \new Staff \with { \override DynamicLineSpanner #'staff-padding = #3 } { \time 7/16 c'8 \< \p ~ c'16 cqs''4 \f } :: >>> show(staff) # doctest: +SKIP :: >>> tie_chain = inspect(staff[0]).get_tie_chain() >>> tie_chain.to_tuplet([2, 1, 1, 1], is_diminution=False) FixedDurationTuplet(3/16, [c'16, c'32, c'32, c'32]) .. doctest:: >>> f(staff) \new Staff \with { \override DynamicLineSpanner #'staff-padding = #3 } { \time 7/16 \tweak #'text #tuplet-number::calc-fraction-text \times 6/5 { c'16 \< \p c'32 c'32 c'32 } cqs''4 \f } :: >>> show(staff) # doctest: +SKIP Returns tuplet. """ from abjad.tools import scoretools from abjad.tools import mathtools from abjad.tools import mutationtools from abjad.tools import notetools from abjad.tools import spannertools from abjad.tools import tuplettools # coerce input proportions = mathtools.Ratio(proportions) # find target duration of fixed-duration tuplet target_duration = self._preprolated_duration # find prolated duration of each note in tuplet prolated_duration = target_duration / sum(proportions) # find written duration of each notes in tuplet if is_diminution: if dotted: basic_written_duration = prolated_duration.equal_or_greater_assignable else: basic_written_duration = prolated_duration.equal_or_greater_power_of_two else: if dotted: basic_written_duration = prolated_duration.equal_or_lesser_assignable else: basic_written_duration = prolated_duration.equal_or_lesser_power_of_two # find written duration of each note in tuplet written_durations = [x * basic_written_duration for x in proportions] # make tuplet notes try: notes = [notetools.Note(0, x) for x in written_durations] except AssignabilityError: denominator = target_duration._denominator note_durations = [durationtools.Duration(x, denominator) for x in proportions] notes = notetools.make_notes(0, note_durations) # make tuplet tuplet = tuplettools.FixedDurationTuplet(target_duration, notes) # replace tie chain with tuplet mutationtools.mutate(self).replace(tuplet) # untie tuplet for spanner in tuplet._get_spanners(spannertools.TieSpanner): spanner.detach() # return tuplet return tuplet
def recurse(tie_chain, depth=0): offsets = get_offsets_at_depth(depth) #print 'DEPTH:', depth tie_chain_duration = tie_chain._preprolated_duration tie_chain_start_offset = tie_chain.get_timespan().start_offset tie_chain_stop_offset = tie_chain.get_timespan().stop_offset tie_chain_starts_in_offsets = tie_chain_start_offset in offsets tie_chain_stops_in_offsets = tie_chain_stop_offset in offsets if not is_acceptable_tie_chain( tie_chain_duration, tie_chain_starts_in_offsets, tie_chain_stops_in_offsets): #print 'UNACCEPTABLE:', tie_chain, tie_chain_start_offset, tie_chain_stop_offset #print '\t', ' '.join([str(x) for x in offsets]) split_offset = None offsets = get_offsets_at_depth(depth) # If the tie chain's start aligns, take the latest possible offset. if tie_chain_starts_in_offsets: offsets = reversed(offsets) for offset in offsets: if tie_chain_start_offset < offset < tie_chain_stop_offset: split_offset = offset break #print '\tABS:', split_offset if split_offset is not None: split_offset -= tie_chain_start_offset #print '\tREL:', split_offset #print '' shards = \ mutationtools.mutate(tie_chain[:]).split([split_offset]) tie_chains = \ [selectiontools.TieChain(shard) for shard in shards] for tie_chain in tie_chains: recurse(tie_chain, depth=depth) else: #print '' recurse(tie_chain, depth=depth+1) elif is_boundary_crossing_tie_chain( tie_chain_start_offset, tie_chain_stop_offset): #print 'BOUNDARY CROSSING', tie_chain, tie_chain_start_offset, tie_chain_stop_offset offsets = boundary_offsets if tie_chain_start_offset in boundary_offsets: offsets = reversed(boundary_offsets) split_offset = None for offset in offsets: if tie_chain_start_offset < offset < tie_chain_stop_offset: split_offset = offset break assert split_offset is not None #print '\tABS:', split_offset split_offset -= tie_chain_start_offset #print '\tREL:', split_offset #print '' shards = \ mutationtools.mutate(tie_chain[:]).split([split_offset]) tie_chains = \ [selectiontools.TieChain(shard) for shard in shards] for tie_chain in tie_chains: recurse(tie_chain, depth=depth) else: #print 'ACCEPTABLE:', tie_chain, tie_chain_start_offset, tie_chain_stop_offset #print '\t', ' '.join([str(x) for x in offsets]) #print '' tie_chain[:]._fuse()
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
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