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, scoretools.Container): selection = select(self.payload[0], contiguous=True) left = mutate(selection).copy()[0] selection = select(expr.payload[0], contiguous=True) right = mutate(selection).copy()[0] payload = scoretools.Container([left, right]) for component in payload[:]: component._extract() payload = scoretools.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 _construct_simultaneous_music(self, music): def is_separator(x): if isinstance(x, lilypondparsertools.LilyPondEvent): if x.name == 'VoiceSeparator': return True return False from abjad.tools import lilypondparsertools container = scoretools.Container() container.is_simultaneous = True # check for voice separators groups = [] for value, group in itertools.groupby(music, is_separator): if not value: groups.append(list(group)) # without voice separators if 1 == len(groups): #assert all(isinstance(x, scoretools.Context) for x in groups[0]) container.extend(groups[0]) # with voice separators else: for group in groups: container.append( scoretools.Voice( self._construct_sequential_music(group)[:])) return container
def _make_container(self, division): from abjad.tools import rhythmmakertools duration_spelling_specifier = self.duration_spelling_specifier if duration_spelling_specifier is None: duration_spelling_specifier = \ rhythmmakertools.DurationSpellingSpecifier() forbidden_written_duration = \ duration_spelling_specifier.forbidden_written_duration time_signature = indicatortools.TimeSignature(division) implied_prolation = time_signature.implied_prolation numerator, denominator = division.pair denominator = mathtools.greatest_power_of_two_less_equal(denominator) assert mathtools.is_positive_integer_power_of_two(denominator) exponent = self.exponent or 0 denominator_multiplier = 2**exponent denominator *= denominator_multiplier unit_duration = durationtools.Duration(1, denominator) if forbidden_written_duration is not None: multiplier = 1 while forbidden_written_duration <= unit_duration: unit_duration /= 2 multiplier *= 2 numerator *= multiplier numerator *= denominator_multiplier notes = scoretools.make_notes(numerator * [0], [unit_duration]) if implied_prolation == 1: result = scoretools.Container(notes) else: multiplier = implied_prolation result = scoretools.Tuplet(multiplier, notes) return result
def _fuse_tuplets(self): from abjad.tools import scoretools assert self._all_are_contiguous_components_in_same_parent( self, prototype=(scoretools.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: message = 'tuplets must carry same multiplier.' raise ValueError(message) if type(tuplet) != first_type: message = 'tuplets must be same type.' raise TypeError(message) if isinstance(first, scoretools.FixedDurationTuplet): total_contents_duration = sum([x._contents_duration for x in self]) new_target_duration = first_multiplier * total_contents_duration new_tuplet = scoretools.FixedDurationTuplet( new_target_duration, []) elif isinstance(first, scoretools.Tuplet): new_tuplet = scoretools.Tuplet(first_multiplier, []) else: message = 'unknown tuplet type.' raise TypeError(message) wrapped = False if self[0]._get_parentage().root is not \ self[-1]._get_parentage().root: dummy_container = scoretools.Container(self) wrapped = True mutate(self).swap(new_tuplet) if wrapped: del (dummy_container[:]) return new_tuplet
def __init__(self, payload=None, start_offset=None, voice_name=None): from abjad.tools import lilypondfiletools if isinstance(payload, lilypondfiletools.LilyPondFile): payload = payload.items[:] payload = scoretools.Container(music=payload) StartPositionedPayloadExpression.__init__( self, payload=payload, start_offset=start_offset, voice_name=voice_name, )
def parse_rtm_syntax(rtm): r'''Parses RTM syntax. :: >>> rtm = '(1 (1 (1 (1 1)) 1))' >>> rhythmtreetools.parse_rtm_syntax(rtm) FixedDurationTuplet(Duration(1, 4), "c'8 c'16 c'16 c'8") Also supports fractional durations: :: >>> rtm = '(3/4 (1 1/2 (4/3 (1 -1/2 1))))' >>> rhythmtreetools.parse_rtm_syntax(rtm) FixedDurationTuplet(Duration(3, 16), 'c\'8 c\'16 FixedDurationTuplet(Duration(1, 6), "c\'8 r16 c\'8")') :: >>> print(format(_)) \tweak #'text #tuplet-number::calc-fraction-text \times 9/17 { c'8 c'16 \tweak #'edge-height #'(0.7 . 0) \times 8/15 { c'8 r16 c'8 } } Returns fixed-duration tuplet or container. ''' from abjad.tools import rhythmtreetools result = rhythmtreetools.RhythmTreeParser()(rtm) con = scoretools.Container() for node in result: tuplet = node((1, 4)) # following line added 2012-08-01. tb. tuplet = tuplet[0] if tuplet.is_trivial: con.extend(tuplet[:]) else: con.append(tuplet) if len(con) == 1: return con[0] return con
def _cleanup(self, parsed): container = scoretools.Container() for x in parsed: container.append(x) parsed = container leaves = parsed.select_leaves(allow_discontiguous_leaves=True) if leaves: self._apply_spanners(leaves) for leaf in leaves: detach(indicatortools.Annotation, leaf) if 1 < self._toplevel_component_count: return parsed return parsed[0]
def construct(self): r'''Constructs sequential music. Returns Abjad container. ''' from abjad.tools import lilypondparsertools container = scoretools.Container([]) for x in self.music: if isinstance(x, scoretools.Component): container.append(x) elif isinstance(x, type(self)): container.extend(x.construct()) return container
def _cleanup(self, parsed): import abjad container = scoretools.Container() for x in parsed: container.append(x) parsed = container leaves = abjad.select(parsed).leaves() if leaves: self._apply_spanners(leaves) for leaf in leaves: detach(dict, leaf) if 1 < self._toplevel_component_count: return parsed return parsed[0]
def _construct_sequential_music(self, music): # indicator sorting could be rewritten into a single list using tuplets # with t[0] being 'forward' or 'backward' and t[1] being the indicator # as this better preserves attachment order. Not clear if we need it. container = scoretools.Container() previous_leaf = None apply_forward = [] apply_backward = [] # sort events into forward or backwards attaching # and attach them to the proper leaf for x in music: if isinstance(x, scoretools.Component) \ and not isinstance(x, scoretools.GraceContainer): for indicator in apply_forward: attach(indicator, x) if previous_leaf: for indicator in apply_backward: attach(indicator, previous_leaf) else: for indicator in apply_backward: attach(indicator, x) apply_forward = [] apply_backward = [] previous_leaf = x container.append(x) else: if isinstance(x, ( indicatortools.BarLine, indicatortools.PageBreak, indicatortools.SystemBreak, )): apply_backward.append(x) elif isinstance(x, indicatortools.LilyPondCommand): if x.name in ('breathe', ): apply_backward.append(x) else: apply_forward.append(x) # attach remaining events to last leaf # or to the container itself if there were no leaves if previous_leaf: for indicator in apply_forward: attach(indicator, previous_leaf) for indicator in apply_backward: attach(indicator, previous_leaf) else: for indicator in apply_forward: attach(indicator, container) for indicator in apply_backward: attach(indicator, container) return container
def _split_payload_at_offsets(self, offsets): assert isinstance(self.payload, scoretools.Container) music = self.payload self._payload = scoretools.Container() shards = 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(): inspect_(shard).tabulate_well_formedness_violations_in_expr() return shards
def make_desordre_cell(pitches): '''The function constructs and returns a *Désordre cell*. `pitches` is a list of numbers or, more generally, pitch tokens. ''' notes = [scoretools.Note(pitch, (1, 8)) for pitch in pitches] beam = spannertools.Beam() attach(beam, notes) slur = spannertools.Slur() attach(slur, notes) clef = indicatortools.Dynamic('f') attach(clef, notes[0]) dynamic = indicatortools.Dynamic('p') attach(dynamic, notes[1]) # make the lower voice lower_voice = scoretools.Voice(notes) lower_voice.name = 'RH Lower Voice' command = indicatortools.LilyPondCommand('voiceTwo') attach(command, lower_voice) n = int(math.ceil(len(pitches) / 2.)) chord = scoretools.Chord([pitches[0], pitches[0] + 12], (n, 8)) articulation = indicatortools.Articulation('>') attach(articulation, chord) # make the upper voice upper_voice = scoretools.Voice([chord]) upper_voice.name = 'RH Upper Voice' command = indicatortools.LilyPondCommand('voiceOne') attach(command, upper_voice) # combine them together container = scoretools.Container([lower_voice, upper_voice]) container.is_simultaneous = True # make all 1/8 beats breakable leaves = select(lower_voice).by_leaf() for leaf in leaves[:-1]: bar_line = indicatortools.BarLine('') attach(bar_line, leaf) return container
def _apply_logical_tie_masks(self, selections): from abjad.tools import rhythmmakertools if self.logical_tie_masks is None: return selections # wrap every selection in a temporary container; # this allows the call to mutate().replace() to work containers = [] for selection in selections: container = scoretools.Container(selection) attach('temporary container', container) containers.append(container) logical_ties = iterate(selections).by_logical_tie() logical_ties = list(logical_ties) total_logical_ties = len(logical_ties) for index, logical_tie in enumerate(logical_ties[:]): matching_mask = self.logical_tie_masks.get_matching_pattern( index, total_logical_ties, ) if not isinstance(matching_mask, rhythmmakertools.SilenceMask): continue if isinstance(logical_tie.head, scoretools.Rest): continue for leaf in logical_tie: rest = scoretools.Rest(leaf.written_duration) inspector = inspect_(leaf) if inspector.has_indicator(durationtools.Multiplier): multiplier = inspector.get_indicator( durationtools.Multiplier, ) multiplier = durationtools.Multiplier(multiplier) attach(multiplier, rest) mutate(leaf).replace([rest]) detach(spannertools.Tie, rest) # remove every temporary container and recreate selections new_selections = [] for container in containers: inspector = inspect_(container) assert inspector.get_indicator(str) == 'temporary container' new_selection = mutate(container).eject_contents() new_selections.append(new_selection) return new_selections
def evaluate(self): r'''Evaluate rhythm-maker rhythm region expression. Returns none when nonevaluable. Returns start-positioned rhythm payload expression when evaluable. ''' from experimental.tools import musicexpressiontools if not self.division_list: return leaf_lists = self.source_expression(self.division_list.pairs) rhythm_containers = [] for x in leaf_lists: if isinstance(x, selectiontools.Selection): x = scoretools.Container(x) rhythm_containers.append(x) expression = \ musicexpressiontools.StartPositionedRhythmPayloadExpression( payload=rhythm_containers, start_offset=self.start_offset) self._beam_rhythm_containers(rhythm_containers) expression._voice_name = self.division_list.voice_name return expression
def parse_rtm_syntax(rtm): r'''Parses RTM syntax. .. container:: example Parses tuplet: >>> rtm = '(1 (1 (1 (1 1)) 1))' >>> tuplet = abjad.rhythmtreetools.parse_rtm_syntax(rtm) >>> abjad.show(tuplet) # doctest: +SKIP .. docs:: >>> abjad.f(tuplet) \times 2/3 { c'8 c'16 c'16 c'8 } .. container:: example Also supports fractional durations: >>> rtm = '(3/4 (1 1/2 (4/3 (1 -1/2 1))))' >>> tuplet = abjad.rhythmtreetools.parse_rtm_syntax(rtm) >>> abjad.show(tuplet) # doctest: +SKIP .. docs:: >>> abjad.f(tuplet) \tweak text #tuplet-number::calc-fraction-text \times 9/17 { c'8 c'16 \tweak edge-height #'(0.7 . 0) \times 8/15 { c'8 r16 c'8 } } Returns tuplet or container. ''' from abjad.tools import rhythmtreetools result = rhythmtreetools.RhythmTreeParser()(rtm) con = scoretools.Container() for node in result: tuplet = node((1, 4)) # following line added 2012-08-01. tb. tuplet = tuplet[0] if tuplet.trivial(): con.extend(tuplet[:]) else: con.append(tuplet) if len(con) == 1: return con[0] return con
def p_container__BRACE_L__component_list__BRACE_R(self, p): r'''container : BRACE_L component_list BRACE_R ''' p[0] = scoretools.Container() for component in p[2]: p[0].append(component)
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(format(expression)) musicexpressiontools.StartPositionedRhythmPayloadExpression( payload=scoretools.Container( "{ 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(format(expression)) musicexpressiontools.StartPositionedRhythmPayloadExpression( payload=scoretools.Container( "{ 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.RotationExpression): rotation_expression = n if rotation_expression.level is None: components_at_level = self.payload.select_leaves() else: components_at_level = [] for component in \ iterate(self.payload).by_class(): score_index = component._get_parentage().score_index if len(score_index) == rotation_expression.level: components_at_level.append(component) components_at_level = datastructuretools.CyclicTuple( components_at_level) if isinstance(rotation_expression.index, int): if 0 < rotation_expression.index: split_offset = components_at_level[-rotation_expression. index]._get_timespan( ).start_offset elif n == 0: return self else: split_offset = components_at_level[-( rotation_expression.index + 1)]._get_timespan().stop_offset else: index = durationtools.Duration(rotation_expression.index) if 0 <= index: split_offset = self.payload._get_duration() - index else: split_offset = abs(index) if rotation_expression.fracture_spanners is not None: fracture_spanners = rotation_expression.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 = 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 = scoretools.Container() payload.extend(right_half) payload.extend(left_half) assert inspect_(payload).is_well_formed() self._payload = payload else: result = mutate(self.payload[:]).split( [split_offset], cyclic=False, fracture_spanners=False, tie_split_notes=False, ) left_half, right_half = result[0], result[-1] prototype = (spannertools.DuratedComplexBeam, ) descendants = self.payload._get_descendants() for spanner in descendants.get_spanners(prototype): if left_half[-1] in spanner and right_half[0] in spanner: leaf_right_of_split = right_half[0] split_offset_in_beam = spanner._start_offset_in_me( leaf_right_of_split) left_durations, right_durations = \ sequencetools.split_sequence( 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( key=lambda x: x._get_parentage().score_index) assert inspect_(self.payload).is_well_formed() return self
def make_mozart_score(): r'''Makes Mozart score. ''' score_template = templatetools.TwoStaffPianoScoreTemplate() score = score_template() # select the measures to use choices = abjad.demos.mozart.choose_mozart_measures() # create and populate the volta containers treble_volta = scoretools.Container() bass_volta = scoretools.Container() for choice in choices[:7]: treble, bass = abjad.demos.mozart.make_mozart_measure(choice) treble_volta.append(treble) bass_volta.append(bass) # attach indicators to the volta containers command = indicatortools.LilyPondCommand('repeat volta 2', 'before') attach(command, treble_volta) command = indicatortools.LilyPondCommand('repeat volta 2', 'before') attach(command, bass_volta) # append the volta containers to our staves score['RH Voice'].append(treble_volta) score['LH Voice'].append(bass_volta) # create and populate the alternative ending containers treble_alternative = scoretools.Container() bass_alternative = scoretools.Container() for choice in choices[7:9]: treble, bass = abjad.demos.mozart.make_mozart_measure(choice) treble_alternative.append(treble) bass_alternative.append(bass) # attach indicators to the alternative containers command = indicatortools.LilyPondCommand('alternative', 'before') attach(command, treble_alternative) command = indicatortools.LilyPondCommand('alternative', 'before') attach(command, bass_alternative) # append the alternative containers to our staves score['RH Voice'].append(treble_alternative) score['LH Voice'].append(bass_alternative) # create the remaining measures for choice in choices[9:]: treble, bass = abjad.demos.mozart.make_mozart_measure(choice) score['RH Voice'].append(treble) score['LH Voice'].append(bass) # attach indicators time_signature = indicatortools.TimeSignature((3, 8)) attach(time_signature, score['RH Staff']) bar_line = indicatortools.BarLine('|.') attach(bar_line, score['RH Voice'][-1]) bar_line = indicatortools.BarLine('|.') attach(bar_line, score['LH Voice'][-1]) # remove the old, default piano instrument attached to the piano staff # and attach a custom instrument mark detach(instrumenttools.Instrument, score['Piano Staff']) klavier = instrumenttools.Piano( instrument_name='Katzenklavier', short_instrument_name='kk.', ) attach(klavier, score['Piano Staff']) return score