def get_offset_indices( self, timespan_1, timespan_2_start_offsets, timespan_2_stop_offsets, ): r'''Gets offset indices of compound inequality. ''' from abjad.tools import timespantools from abjad.tools import timespantools timespans = timespantools.TimespanInventory() for element in self: # TODO: compress the following two branches if isinstance(element, type(self)): result = element.get_offset_indices(timespan_1, timespan_2_start_offsets, timespan_2_stop_offsets) timespans.extend(result) elif isinstance(element, timespantools.Inequality): offset_indices = element.get_offset_indices( timespan_1, timespan_2_start_offsets, timespan_2_stop_offsets) timespan = timespantools.Timespan(*offset_indices) timespans.append(timespan) else: message = 'unknown inequality: {!r}.' message = message(element) raise TypeError(message) if self.logical_operator == 'and': result = timespans.compute_logical_and() elif self.logical_operator == 'or': timespans.sort() result = timespans.compute_logical_or() elif self.logical_operator == 'xor': result = timespans.compute_logical_xor() else: message = 'unknown logical operator: {!r}.' message = mesage.format(self.logical_operator) raise ValueError(message) return result
def __init__(self, name=None): self._after_grace = None self._dependent_expressions = [] self._grace = None self._indicator_expressions = [] self._indicators_are_current = False self._is_forbidden_to_update = False self._logical_measure_number = None self._offsets_are_current = False self._offsets_in_seconds_are_current = False self._lilypond_grob_name_manager = None self._parent = None self._lilypond_setting_name_manager = None self._spanners = set() self._start_offset = None self._start_offset_in_seconds = None self._stop_offset = None self._stop_offset_in_seconds = None self._timespan = timespantools.Timespan() self._name = None if name is not None: self.name = name # name must be setup *after* parent
def __call__(self, timespan=None, offset=None): r'''Evaluates time relation: >>> time_relation() True Raises value error is either `offset` or `timespan` is none. Otherwise returns boolean. ''' from abjad.tools import timespantools timespan = timespan or self.timespan offset = offset or self.offset if timespan is None or offset is None: message = 'time relation is not fully loaded.' raise ValueError(message) if not isinstance(timespan, timespantools.Timespan): timespan = timespantools.Timespan()._get_timespan(timespan) offset = durationtools.Offset(offset) truth_value = self.inequality.evaluate_offset_inequality( timespan.start_offset, timespan.stop_offset, offset) return truth_value
def evaluate(self): from experimental.tools import musicexpressiontools expression = musicexpressiontools.StartPositionedRhythmPayloadExpression( [], start_offset=self.start_offset, voice_name=self.voice_name, ) wrapped_component = copy.deepcopy(self.source_expression) expression._payload = wrapped_component start_offset, stop_offset = \ self.start_offset, self.start_offset + self.total_duration keep_timespan = timespantools.Timespan(start_offset, stop_offset) timespan = expression.timespan assert not keep_timespan.starts_before_timespan_starts(timespan) assert timespan.start_offset == keep_timespan.start_offset expression = expression & keep_timespan assert isinstance(expression, timespantools.TimespanInventory) assert len(expression) == 1 expression = expression[0] assert isinstance( expression, musicexpressiontools.StartPositionedRhythmPayloadExpression) expression.repeat_to_stop_offset(stop_offset) return expression
# -*- encoding: utf-8 -*- import pytest import random from abjad.tools import sequencetools from abjad.tools import timespantools from supriya import timetools pairs = [] for _ in range(3): timespan_collection = timetools.TimespanCollection() start_offset = 0 for _ in range(5): duration = random.randint(1, 5) stop_offset = start_offset + duration timespan = timespantools.Timespan( start_offset=start_offset, stop_offset=stop_offset, ) timespan_collection.insert(timespan) start_offset += stop_offset start_offset = int(timespan_collection.start_offset - 1) stop_offset = int(timespan_collection.stop_offset + 1) indices = tuple(range(start_offset, stop_offset + 1)) for pair in \ sequencetools.yield_all_unordered_pairs_of_sequence(indices): start_offset, stop_offset = sorted(pair) target_timespan = timespantools.Timespan( start_offset=start_offset, stop_offset=stop_offset, ) pairs.append((timespan_collection, target_timespan)) random.shuffle(pairs)
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
def timespan(self): return timespantools.Timespan( start_offset=self.start_offset, stop_offset=self.stop_offset_high, )
def __illustrate__(self, denominator=16, range_=None, scale=None): r'''Illustrates meter inventory. .. container:: example :: >>> meter_inventory = metertools.MeterInventory([ ... (3, 4), (5, 16), (7, 8), ... ]) >>> show(meter_inventory, scale=0.5) # doctest: +SKIP .. doctest >>> illustration = meter_inventory.__illustrate__() >>> print(format(illustration)) % ... <BLANKLINE> \version "..." \language "english" <BLANKLINE> \header { tagline = \markup {} } <BLANKLINE> \layout {} <BLANKLINE> \paper {} <BLANKLINE> \markup { \column { \combine \combine \translate #'(1.0 . 1) \sans \fontsize #-3 \center-align \fraction 3 4 \translate #'(49.387... . 1) \sans \fontsize #-3 \center-align \fraction 5 16 \translate #'(69.548... . 1) \sans \fontsize #-3 \center-align \fraction 7 8 \combine \postscript #" 0.2 setlinewidth 1 0.5 moveto 49.387... 0.5 lineto stroke 1 1.25 moveto 1 -0.25 lineto stroke 49.387... 1.25 moveto 49.387... -0.25 lineto stroke 49.387... 0.5 moveto 69.548... 0.5 lineto stroke 49.387... 1.25 moveto 49.387... -0.25 lineto stroke 69.548... 1.25 moveto 69.548... -0.25 lineto stroke 69.548... 0.5 moveto 126 0.5 lineto stroke 69.548... 1.25 moveto 69.548... -0.25 lineto stroke 126 1.25 moveto 126 -0.25 lineto stroke " \postscript #" 1 -2 moveto 0 -6.153... rlineto stroke 5.032... -2 moveto 0 -1.538... rlineto stroke 9.064... -2 moveto 0 -3.076... rlineto stroke 13.096... -2 moveto 0 -1.538... rlineto stroke 17.129... -2 moveto 0 -4.615... rlineto stroke 21.161... -2 moveto 0 -1.538... rlineto stroke 25.193... -2 moveto 0 -3.076... rlineto stroke 29.225... -2 moveto 0 -1.538... rlineto stroke 33.258... -2 moveto 0 -4.615... rlineto stroke 37.290... -2 moveto 0 -1.538... rlineto stroke 41.322... -2 moveto 0 -3.076... rlineto stroke 45.354... -2 moveto 0 -1.538... rlineto stroke 49.387... -2 moveto 0 -6.153... rlineto stroke 49.387... -2 moveto 0 -10.909... rlineto stroke 53.419... -2 moveto 0 -3.636... rlineto stroke 57.451... -2 moveto 0 -3.636... rlineto stroke 61.483... -2 moveto 0 -7.272... rlineto stroke 65.516... -2 moveto 0 -3.636... rlineto stroke 69.548... -2 moveto 0 -10.909... rlineto stroke 69.548... -2 moveto 0 -5.517... rlineto stroke 73.580... -2 moveto 0 -1.379... rlineto stroke 77.612... -2 moveto 0 -2.758... rlineto stroke 81.645... -2 moveto 0 -1.379... rlineto stroke 85.677... -2 moveto 0 -2.758... rlineto stroke 89.709... -2 moveto 0 -1.379... rlineto stroke 93.741... -2 moveto 0 -4.137... rlineto stroke 97.774... -2 moveto 0 -1.379... rlineto stroke 101.806... -2 moveto 0 -2.758... rlineto stroke 105.838... -2 moveto 0 -1.379... rlineto stroke 109.870... -2 moveto 0 -4.137... rlineto stroke 113.903... -2 moveto 0 -1.379... rlineto stroke 117.935... -2 moveto 0 -2.758... rlineto stroke 121.967... -2 moveto 0 -1.379... rlineto stroke 126 -2 moveto 0 -5.517... rlineto stroke " } } Returns LilyPond file. ''' from abjad.tools import metertools durations = [_.duration for _ in self] total_duration = sum(durations) offsets = mathtools.cumulative_sums(durations, start=0) timespan_inventory = timespantools.TimespanInventory() for one, two in sequencetools.iterate_sequence_nwise(offsets): timespan = timespantools.Timespan( start_offset=one, stop_offset=two, ) timespan_inventory.append(timespan) if range_ is not None: minimum, maximum = range_ else: minimum, maximum = 0, total_duration minimum = float(durationtools.Offset(minimum)) maximum = float(durationtools.Offset(maximum)) if scale is None: scale = 1. assert 0 < scale postscript_scale = 125. / (maximum - minimum) postscript_scale *= float(scale) postscript_x_offset = (minimum * postscript_scale) - 1 timespan_markup = timespan_inventory._make_timespan_inventory_markup( timespan_inventory, postscript_x_offset, postscript_scale, draw_offsets=False, ) ps = markuptools.Postscript() rational_x_offset = durationtools.Offset(0) for meter in self: kernel_denominator = denominator or meter.denominator kernel = metertools.MetricAccentKernel.from_meter( meter, kernel_denominator) for offset, weight in sorted(kernel.kernel.items()): weight = float(weight) * -40 ps_x_offset = float(rational_x_offset + offset) ps_x_offset *= postscript_scale ps_x_offset += 1 ps = ps.moveto(ps_x_offset, -2) ps = ps.rlineto(0, weight) ps = ps.stroke() rational_x_offset += meter.duration ps = markuptools.Markup.postscript(ps) lines_markup = markuptools.Markup.combine(timespan_markup, ps) fraction_markups = [] for meter, offset in zip(self, offsets): numerator, denominator = meter.numerator, meter.denominator fraction = markuptools.Markup.fraction(numerator, denominator) fraction = fraction.center_align().fontsize(-3).sans() x_translation = (float(offset) * postscript_scale) x_translation -= postscript_x_offset fraction = fraction.translate((x_translation, 1)) fraction_markups.append(fraction) fraction_markup = fraction_markups[0] for markup in fraction_markups[1:]: fraction_markup = markuptools.Markup.combine( fraction_markup, markup) markup = markuptools.Markup.column([fraction_markup, lines_markup]) return markup.__illustrate__()
def __call__(self, timespan_1=None, timespan_2=None): r'''Evaluate time relation. .. container:: example **Example 1.** Evaluate time relation without substitution: :: >>> timespan_1 = timespantools.Timespan(5, 15) >>> timespan_2 = timespantools.Timespan(10, 20) :: >>> time_relation = timespantools.timespan_2_starts_during_timespan_1( ... timespan_1=timespan_1, ... timespan_2=timespan_2, ... hold=True, ... ) :: >>> print(format(time_relation)) timespantools.TimespanTimespanTimeRelation( inequality=timespantools.CompoundInequality( [ timespantools.SimpleInequality('timespan_1.start_offset <= timespan_2.start_offset'), timespantools.SimpleInequality('timespan_2.start_offset < timespan_1.stop_offset'), ], logical_operator='and', ), timespan_1=timespantools.Timespan( start_offset=durationtools.Offset(5, 1), stop_offset=durationtools.Offset(15, 1), ), timespan_2=timespantools.Timespan( start_offset=durationtools.Offset(10, 1), stop_offset=durationtools.Offset(20, 1), ), ) :: >>> time_relation() True .. container:: example **Example 2.** Substitute `timespan_1` during evaluation: :: >>> new_timespan_1 = timespantools.Timespan(0, 10) :: >>> new_timespan_1 Timespan(start_offset=Offset(0, 1), stop_offset=Offset(10, 1)) :: >>> time_relation(timespan_1=new_timespan_1) False .. container:: example **Example 3.** Substitute `timespan_2` during evaluation: :: >>> new_timespan_2 = timespantools.Timespan(2, 12) :: >>> new_timespan_2 Timespan(start_offset=Offset(2, 1), stop_offset=Offset(12, 1)) :: >>> time_relation(timespan_2=new_timespan_2) False .. container:: example **Example 4.** Substitute both `timespan_1` and `timespan_2` during evaluation: :: >>> time_relation( ... timespan_1=new_timespan_1, ... timespan_2=new_timespan_2, ... ) True Raise value error if either `timespan_1` or `timespan_2` is none. Otherwise return boolean. ''' from abjad.tools import timespantools timespan_1 = timespan_1 or self.timespan_1 timespan_2 = timespan_2 or self.timespan_2 if timespan_1 is None or timespan_2 is None: message = 'time relation is not fully loaded: {!r}.' raise ValueError(message.format(self)) if not isinstance(timespan_1, timespantools.Timespan): timespan_1 = timespantools.Timespan()._get_timespan(timespan_1) if not isinstance(timespan_2, timespantools.Timespan): timespan_2 = timespantools.Timespan()._get_timespan(timespan_2) truth_value = self.inequality.evaluate( timespan_1.start_offset, timespan_1.stop_offset, timespan_2.start_offset, timespan_2.stop_offset) return truth_value
def repeat_to_duration(self, duration): r'''Repeat start-positioned rhythm payload expression to `duration`. Example 1. Repeat to duration less than start-positioned rhythm payload expression: :: >>> payload = [Container("c'8 d'8 e'8 f'8")] >>> expression = \ ... musicexpressiontools.StartPositionedRhythmPayloadExpression( ... payload, Offset(0)) :: >>> result = expression.repeat_to_duration(Duration(5, 16)) :: >>> print(format(expression)) musicexpressiontools.StartPositionedRhythmPayloadExpression( payload=scoretools.Container( "{ c'8 d'8 e'16 }" ), start_offset=durationtools.Offset(0, 1), ) Example 2. Repeat to duration greater than start-positioned rhythm payload expression: :: >>> payload = [Container("c'8 d'8 e'8 f'8")] >>> expression = \ ... musicexpressiontools.StartPositionedRhythmPayloadExpression( ... payload, Offset(0)) :: >>> result = expression.repeat_to_duration(Duration(13, 16)) :: >>> print(format(expression)) musicexpressiontools.StartPositionedRhythmPayloadExpression( payload=scoretools.Container( "{ c'8 d'8 e'8 f'8 } { c'8 d'8 e'16 }" ), start_offset=durationtools.Offset(0, 1), ) Operates in place and returns start-positioned rhythm payload expression. ''' if self.timespan.duration < duration: stop_offset = self.start_offset + duration return self.repeat_to_stop_offset(stop_offset) elif duration < self.timespan.duration: stop_offset = self.start_offset + duration timespan = timespantools.Timespan(self.start_offset, stop_offset) result = self & timespan assert len(result) == 1, repr(result) result = result[0] return result elif self.timespan.duration == duration: return self
def sort_and_split_set_expressions(self): r'''Operates in place and returns inventory. ''' cooked_set_expressions = [] for raw_set_expression in self[:]: set_expression_was_delayed, set_expression_was_split = False, False set_expressions_to_remove, set_expressions_to_curtail = [], [] set_expressions_to_delay, set_expressions_to_split = [], [] for cooked_set_expression in cooked_set_expressions: if raw_set_expression.target_timespan.contains_timespan_improperly( cooked_set_expression): set_expressions_to_remove.append(cooked_set_expression) elif raw_set_expression.target_timespan.delays_timespan( cooked_set_expression): set_expressions_to_delay.append(cooked_set_expression) elif raw_set_expression.target_timespan.curtails_timespan( cooked_set_expression): set_expressions_to_curtail.append(cooked_set_expression) elif raw_set_expression.target_timespan.trisects_timespan( cooked_set_expression): set_expressions_to_split.append(cooked_set_expression) for set_expression_to_remove in set_expressions_to_remove: cooked_set_expressions.remove(set_expression_to_remove) for set_expression_to_curtail in set_expressions_to_curtail: timespan = timespantools.Timespan( set_expression_to_curtail.target_timespan.start_offset, raw_set_expression.target_timespan.start_offset) set_expression_to_curtail._target_timespan = timespan for set_expression_to_delay in set_expressions_to_delay: timespan = timespantools.Timespan( raw_set_expression.target_timespan.stop_offset, set_expression_to_delay.target_timespan.stop_offset) set_expression_to_delay._target_timespan = timespan set_expression_was_delayed = True # TODO: branch inside and implement a method to split # while treating cyclic payload smartly. # or, alternatively, special-case for set_expressions # that cover the entire duration of score. for set_expression_to_split in set_expressions_to_split: left_set_expression = set_expression_to_split middle_set_expression = raw_set_expression right_set_expression = copy.deepcopy(left_set_expression) timespan = timespantools.Timespan( left_set_expression.target_timespan.start_offset, middle_set_expression.target_timespan.start_offset) left_set_expression._target_timespan = timespan timespan = timespantools.Timespan( middle_set_expression.target_timespan.stop_offset, right_set_expression.target_timespan.stop_offset) right_set_expression._target_timespan = timespan set_expression_was_split = True if set_expression_was_delayed: index = cooked_set_expressions.index(cooked_set_expression) cooked_set_expressions.insert(index, raw_set_expression) elif set_expression_was_split: cooked_set_expressions.append(middle_set_expression) cooked_set_expressions.append(right_set_expression) else: cooked_set_expressions.append(raw_set_expression) cooked_set_expressions.sort() #self._debug_values(cooked_set_expressions, 'cooked') #self._debug_values(cooked_set_expressions, 'cooked') self[:] = cooked_set_expressions return self
music_specifier = new( ersilia.pitch_pipe_music_specifier, rhythm_maker__division_masks=[ rhythmmakertools.SustainMask( pattern=patterntools.Pattern( indices=[0, -1], ), ), ], attachment_handler__dynamic_expressions=consort.DynamicExpression( start_dynamic_tokens='fp', stop_dynamic_tokens='niente', ), ) segment_maker.add_setting( timespan_identifier=timespantools.Timespan(0, (3, 2)), timespan_maker=new( ersilia.tutti_timespan_maker, fuse_groups=True, timespan_specifier=consort.TimespanSpecifier( minimum_duration=0, ), ), guitar_pp=music_specifier, piano_pp=music_specifier, percussion_pp=music_specifier, bass_pp=music_specifier, ) segment_maker.add_setting( timespan_identifier=[
from abjad.tools import timespantools from ersilia.materials import abbreviations ### SEGMENT ### segment_maker = ersilia.ErsiliaSegmentMaker( desired_duration_in_seconds=90, name='Chemish', permitted_time_signatures=ersilia.permitted_time_signatures, tempo=abjad.Tempo((1, 4), 80), ) ### PEDAL ### segment_maker.add_setting( timespan_identifier=timespantools.Timespan(start_offset=1), timespan_maker=new( ersilia.sustained_timespan_maker, fuse_groups=True, ), percussion=ersilia.percussion_low_pedal_music_specifier, ) segment_maker.add_setting( timespan_identifier=[-1, 1], timespan_maker=new( ersilia.sustained_timespan_maker, fuse_groups=True, ), bass=new( ersilia.string_low_pedal_music_specifier,
def _get_node_ctimespan(self, node): return timespantools.Timespan( start_offset=node.start_offset, stop_offset=node.stop_offset_high, )
def timespan(self): r'''Start-positioned payload expression timespan. Returns timespan. ''' return timespantools.Timespan(self.start_offset, self._stop_offset)