def __contains__(self, argument: int) -> bool: r'''Is true when talea contains ``argument``. .. container:: example With preamble: >>> talea = abjad.rhythmmakertools.Talea( ... counts=[10], ... denominator=16, ... preamble=[1, -1, 1], ... ) >>> for i in range(1, 23 + 1): ... i, i in talea ... (1, True) (2, True) (3, True) (4, False) (5, False) (6, False) (7, False) (8, False) (9, False) (10, False) (11, False) (12, False) (13, True) (14, False) (15, False) (16, False) (17, False) (18, False) (19, False) (20, False) (21, False) (22, False) (23, True) ''' assert isinstance(argument, int), repr(argument) assert 0 < argument, repr(argument) if self.preamble: preamble = Sequence([abs(_) for _ in self.preamble]) cumulative = mathtools.cumulative_sums(preamble)[1:] if argument in cumulative: return True preamble_weight = preamble.weight() else: preamble_weight = 0 if self.counts is not None: counts = [abs(_) for _ in self.counts] else: counts = [] cumulative = mathtools.cumulative_sums(counts)[:-1] argument -= preamble_weight argument %= self.period return argument in cumulative
def test_mathtools_cumulative_sums_zero_01(): r'''Returns list of the cumulative sums of the integer elements in input. ''' assert mathtools.cumulative_sums([1, 2, 3]) == [0, 1, 3, 6] assert mathtools.cumulative_sums([10, -9, -8]) == [0, 10, 1, -7] assert mathtools.cumulative_sums([0, 0, 0, 5]) == [0, 0, 0, 0, 5] assert mathtools.cumulative_sums([-10, 10, -10, 10]) == \ [0, -10, 0, -10, 0]
def __init__( self, durations=None, include_long_duration_notes=False, include_long_duration_rests=False, isolated_nib_direction=None, use_stemlets=False, vertical_direction=None, ): Spanner.__init__( self, ) if durations: durations = tuple(durationtools.Duration(x) for x in durations) self._durations = durations self._include_long_duration_notes = bool(include_long_duration_notes) self._include_long_duration_rests = bool(include_long_duration_rests) assert isolated_nib_direction in (Left, Right, None) self._isolated_nib_direction = isolated_nib_direction if self._durations is not None: self._span_points = mathtools.cumulative_sums(self.durations)[1:] else: self._span_points = [self._get_duration()] self._use_stemlets = bool(use_stemlets) assert vertical_direction in (Up, Down, Center, None) self._vertical_direction = vertical_direction
def partition_by_ratio_of_durations(self, ratio): r'''Partition start-positioned payload expression by ratio of durations. Operates in place and returns newly constructed inventory. ''' from experimental.tools import musicexpressiontools element_durations = [ self._get_duration_of_expr(leaf) for leaf in self.elements ] integers = self._durations_to_integers(element_durations) parts = sequencetools.partition_sequence_by_ratio_of_weights( integers, ratio) part_lengths = [len(part) for part in parts] parts = sequencetools.partition_sequence_by_counts( self.elements, part_lengths) durations = [self._get_duration_of_list(part) for part in parts] payload_parts = self._split_payload_at_offsets(durations) start_offsets = mathtools.cumulative_sums(durations)[:-1] start_offsets = [ self.start_offset + start_offset for start_offset in start_offsets ] payload_expressions = \ musicexpressiontools.TimespanScopedSingleContextSetExpressionInventory() for payload_part, start_offset in zip(payload_parts, start_offsets): timespan = timespantools.Timespan(start_offset) payload_expression = type(self)( [], start_offset=timespan.start_offset, voice_name=self.voice_name, ) payload_expression._payload = payload_part payload_expressions.append(payload_expression) return payload_expressions
def from_tempo_scaled_durations(class_, durations, tempo=None): r'''Convert ``durations``, scaled by ``tempo`` into a ``QEventSequence``: >>> tempo = abjad.MetronomeMark((1, 4), 174) >>> durations = [(1, 4), (-3, 16), (1, 16), (-1, 2)] >>> sequence = \ ... abjad.quantizationtools.QEventSequence.from_tempo_scaled_durations( ... durations, tempo=tempo) >>> for q_event in sequence: ... print(format(q_event, 'storage')) ... abjad.quantizationtools.PitchedQEvent( offset=abjad.Offset(0, 1), pitches=( abjad.NamedPitch("c'"), ), ) abjad.quantizationtools.SilentQEvent( offset=abjad.Offset(10000, 29), ) abjad.quantizationtools.PitchedQEvent( offset=abjad.Offset(17500, 29), pitches=( abjad.NamedPitch("c'"), ), ) abjad.quantizationtools.SilentQEvent( offset=abjad.Offset(20000, 29), ) abjad.quantizationtools.TerminalQEvent( offset=abjad.Offset(40000, 29), ) Returns ``QEventSequence`` instance. ''' import abjad from abjad.tools import quantizationtools durations = [abjad.Duration(x) for x in durations] assert isinstance(tempo, indicatortools.MetronomeMark) durations = [ x for x in abjad.sequence(durations).sum_by_sign(sign=[-1]) if x ] durations = [tempo.duration_to_milliseconds(_) for _ in durations] offsets = mathtools.cumulative_sums([abs(_) for _ in durations]) q_events = [] for pair in zip(offsets, durations): offset = abjad.Offset(pair[0]) duration = pair[1] # negative duration indicates silence if duration < 0: q_event = quantizationtools.SilentQEvent(offset) # otherwise use middle C else: q_event = quantizationtools.PitchedQEvent(offset, [0]) q_events.append(q_event) # insert terminating silence QEvent q_events.append(quantizationtools.TerminalQEvent(offsets[-1])) return class_(q_events)
def __call__(self, position): position = durationtools.Offset(position) if position < 0: position = durationtools.Offset(0) if 1 < position: position = durationtools.Offset(1) if position == 0: return self.inflections[0] elif position == 1: return self.inflections[-1] ratio_sum = sum(self.ratio) positions = [durationtools.Offset(x) / ratio_sum for x in mathtools.cumulative_sums(self.ratio)] index = bisect.bisect(positions, position) position = float(position) x0 = float(positions[index - 1]) x1 = float(positions[index]) y0 = float(self.inflections[index - 1]) y1 = float(self.inflections[index]) dx = x1 - x0 dy = y1 - y0 m = float(dy) / float(dx) b = y0 - (m * x0) result = (position * m) + b result = pitchtools.NumberedInterval(int(result)) return result
def partition_by_ratio_of_durations(self, ratio): r'''Partition start-positioned payload expression by ratio of durations. Operates in place and returns newly constructed inventory. ''' from experimental.tools import musicexpressiontools element_durations = [ self._get_duration_of_expr(leaf) for leaf in self.elements] integers = self._durations_to_integers(element_durations) parts = sequencetools.partition_sequence_by_ratio_of_weights( integers, ratio) part_lengths = [len(part) for part in parts] parts = sequencetools.partition_sequence_by_counts( self.elements, part_lengths) durations = [self._get_duration_of_list(part) for part in parts] payload_parts = self._split_payload_at_offsets(durations) start_offsets = mathtools.cumulative_sums(durations)[:-1] start_offsets = [ self.start_offset + start_offset for start_offset in start_offsets] payload_expressions = \ musicexpressiontools.TimespanScopedSingleContextSetExpressionInventory() for payload_part, start_offset in zip(payload_parts, start_offsets): timespan = timespantools.Timespan(start_offset) payload_expression = type(self)( [], start_offset=timespan.start_offset, voice_name=self.voice_name, ) payload_expression._payload = payload_part payload_expressions.append(payload_expression) return payload_expressions
def join_subsequences(sequence): '''Join subsequences in `sequence`. .. container:: example **Example 1.** Joins tuples: :: >>> tuples = [(1, 2, 3), (), (4, 5), (), (6,)] >>> sequencetools.join_subsequences(tuples) (1, 2, 3, 4, 5, 6) .. container:: example **Example 2.** Joins lists: :: >>> lists = [[1, 2, 3], [], [4, 5], [], [6]] >>> sequencetools.join_subsequences(lists) [1, 2, 3, 4, 5, 6] Returns new object of `sequence` type. ''' if not isinstance(sequence, collections.Sequence): message = 'must be sequence: {!r}.' message = message.format(sequence) raise Exception(message) return mathtools.cumulative_sums(sequence, start=None)[-1]
def merge_duration_sequences(*sequences): r'''Merge duration `sequences`: :: >>> sequencetools.merge_duration_sequences([10, 10, 10], [7]) [7, 3, 10, 10] Merge more duration sequences: :: >>> sequencetools.merge_duration_sequences([10, 10, 10], [10, 10]) [10, 10, 10] The idea is that each sequence element represents a duration. Returns list. ''' from abjad.tools import sequencetools offset_lists = [] for sequence in sequences: offset_list = mathtools.cumulative_sums(sequence, start=None) offset_lists.append(offset_list) all_offsets = sequencetools.join_subsequences(offset_lists) all_offsets = list(sorted(set(all_offsets))) all_offsets.insert(0, 0) all_durations = mathtools.difference_series(all_offsets) return all_durations
def __init__( self, durations: typing.Iterable[Duration] = None, include_long_duration_notes: bool = False, include_long_duration_rests: bool = False, isolated_nib_direction: HorizontalAlignment = None, use_stemlets: bool = False, vertical_direction: VerticalAlignment = None, ) -> None: Spanner.__init__(self) durations_ = None if durations: durations_ = tuple(Duration(_) for _ in durations) self._durations = durations_ self._include_long_duration_notes = bool(include_long_duration_notes) self._include_long_duration_rests = bool(include_long_duration_rests) assert isolated_nib_direction in (Left, Right, None) self._isolated_nib_direction = isolated_nib_direction if self._durations is not None: self._span_points = mathtools.cumulative_sums(self.durations)[1:] else: self._span_points = [self._get_duration()] self._use_stemlets = bool(use_stemlets) assert vertical_direction in (Up, Down, Center, None) self._vertical_direction = vertical_direction
def join_subsequences(sequence): '''Join subsequences in `sequence`: :: >>> sequencetools.join_subsequences([(1, 2, 3), (), (4, 5), (), (6,)]) (1, 2, 3, 4, 5, 6) Returns newly constructed object of subsequence type. ''' return mathtools.cumulative_sums(sequence, start=None)[-1]
def join_subsequences(sequence): '''Join subsequences in `sequence`. :: >>> sequencetools.join_subsequences([(1, 2, 3), (), (4, 5), (), (6,)]) (1, 2, 3, 4, 5, 6) Returns newly constructed object of subsequence type. ''' return mathtools.cumulative_sums(sequence, start=None)[-1]
def cumulative_sums_pairwise(sequence): r'''Lists pairwise cumulative sums of `sequence` from ``0``. :: >>> mathtools.cumulative_sums_pairwise([1, 2, 3, 4, 5, 6]) [(0, 1), (1, 3), (3, 6), (6, 10), (10, 15), (15, 21)] Returns list of pairs. ''' from abjad.tools import mathtools from abjad.tools import sequencetools return list(sequencetools.iterate_sequence_pairwise_strict(mathtools.cumulative_sums(sequence)))
def cumulative_sums_pairwise(sequence): r'''Lists pairwise cumulative sums of `sequence` from ``0``. :: >>> mathtools.cumulative_sums_pairwise([1, 2, 3, 4, 5, 6]) [(0, 1), (1, 3), (3, 6), (6, 10), (10, 15), (15, 21)] Returns list of pairs. ''' from abjad.tools import mathtools from abjad.tools import sequencetools sums = mathtools.cumulative_sums(sequence) return list(sequencetools.iterate_sequence_nwise(sums))
def from_millisecond_durations(cls, milliseconds, fuse_silences=False): r'''Convert a sequence of millisecond durations ``durations`` into a ``QEventSequence``: :: >>> durations = [-250, 500, -1000, 1250, -1000] :: >>> sequence = \ ... quantizationtools.QEventSequence.from_millisecond_durations( ... durations) :: >>> for q_event in sequence: ... print(format(q_event, 'storage')) ... quantizationtools.SilentQEvent( offset=durationtools.Offset(0, 1), ) quantizationtools.PitchedQEvent( offset=durationtools.Offset(250, 1), pitches=( pitchtools.NamedPitch("c'"), ), ) quantizationtools.SilentQEvent( offset=durationtools.Offset(750, 1), ) quantizationtools.PitchedQEvent( offset=durationtools.Offset(1750, 1), pitches=( pitchtools.NamedPitch("c'"), ), ) quantizationtools.SilentQEvent( offset=durationtools.Offset(3000, 1), ) quantizationtools.TerminalQEvent( offset=durationtools.Offset(4000, 1), ) Returns ``QEventSequence`` instance. ''' from abjad.tools import quantizationtools if fuse_silences: durations = [x for x in \ sequencetools.sum_consecutive_elements_by_sign( milliseconds, sign=[-1]) if x] else: durations = milliseconds offsets = mathtools.cumulative_sums([abs(x) for x in durations]) q_events = [] for pair in zip(offsets, durations): offset = durationtools.Offset(pair[0]) duration = pair[1] if duration < 0: # negative duration indicates silence q_event = quantizationtools.SilentQEvent(offset) else: q_event = quantizationtools.PitchedQEvent(offset, [0]) q_events.append(q_event) q_events.append( quantizationtools.TerminalQEvent(durationtools.Offset( offsets[-1]))) return cls(q_events)
def partition_sequence_by_ratio_of_weights(sequence, weights): '''Partitions `sequence` by ratio of `weights`. :: >>> sequencetools.partition_sequence_by_ratio_of_weights( ... [1] * 10, [1, 1, 1]) [[1, 1, 1], [1, 1, 1, 1], [1, 1, 1]] :: >>> sequencetools.partition_sequence_by_ratio_of_weights( ... [1] * 10, [1, 1, 1, 1]) [[1, 1, 1], [1, 1], [1, 1, 1], [1, 1]] :: >>> sequencetools.partition_sequence_by_ratio_of_weights( ... [1] * 10, [2, 2, 3]) [[1, 1, 1], [1, 1, 1], [1, 1, 1, 1]] :: >>> sequencetools.partition_sequence_by_ratio_of_weights( ... [1] * 10, [3, 2, 2]) [[1, 1, 1, 1], [1, 1, 1], [1, 1, 1]] :: >>> sequencetools.partition_sequence_by_ratio_of_weights( ... [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2], [1, 1]) [[1, 1, 1, 1, 1, 1, 2, 2], [2, 2, 2, 2]] :: >>> sequencetools.partition_sequence_by_ratio_of_weights( ... [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2], [1, 1, 1]) [[1, 1, 1, 1, 1, 1], [2, 2, 2], [2, 2, 2]] Weights of parts of returned list equal `weights_ratio` proportions with some rounding magic. Returns list of lists. ''' from abjad.tools import sequencetools list_weight = mathtools.weight(sequence) weights_parts = mathtools.partition_integer_by_ratio(list_weight, weights) cumulative_weights = mathtools.cumulative_sums(weights_parts, start=None) result = [] sublist = [] result.append(sublist) current_cumulative_weight = cumulative_weights.pop(0) for n in sequence: if not isinstance(n, (int, long, float, fractions.Fraction)): message = 'must be number: {!r}.' message = message.format(n) raise TypeError(message) sublist.append(n) while current_cumulative_weight <= \ mathtools.weight(sequencetools.flatten_sequence(result)): try: current_cumulative_weight = cumulative_weights.pop(0) sublist = [] result.append(sublist) except IndexError: break return result
def partition_integer_by_ratio(n, ratio): r'''Partitions positive integer-equivalent `n` by `ratio`. .. container:: example >>> abjad.mathtools.partition_integer_by_ratio(10, [1, 2]) [3, 7] .. container:: example Partitions positive integer-equivalent `n` by `ratio` with negative parts: >>> abjad.mathtools.partition_integer_by_ratio(10, [1, -2]) [3, -7] .. container:: example Partitions negative integer-equivalent `n` by `ratio`: >>> abjad.mathtools.partition_integer_by_ratio(-10, [1, 2]) [-3, -7] .. container:: example Partitions negative integer-equivalent `n` by `ratio` with negative parts: >>> abjad.mathtools.partition_integer_by_ratio(-10, [1, -2]) [-3, 7] .. container:: example More examples: >>> abjad.mathtools.partition_integer_by_ratio(10, [1]) [10] >>> abjad.mathtools.partition_integer_by_ratio(10, [1, 1]) [5, 5] >>> abjad.mathtools.partition_integer_by_ratio(10, [1, -1, -1]) [3, -4, -3] >>> abjad.mathtools.partition_integer_by_ratio(-10, [1, 1, 1, 1]) [-3, -2, -3, -2] >>> abjad.mathtools.partition_integer_by_ratio(-10, [1, 1, 1, 1, 1]) [-2, -2, -2, -2, -2] Returns result with weight equal to absolute value of `n`. Returns list of integers. ''' from abjad.tools import mathtools if not mathtools.is_integer_equivalent_number(n): message = 'is not integer-equivalent number: {!r}.' message = message.format(n) raise TypeError(message) ratio = mathtools.Ratio(ratio).numbers if not all(mathtools.is_integer_equivalent_number(part) for part in ratio): message = 'some parts in {!r} not integer-equivalent numbers.' message = message.format(ratio) raise TypeError(message) result = [0] divisions = [ float(abs(n)) * abs(part) / mathtools.weight(ratio) for part in ratio ] cumulative_divisions = mathtools.cumulative_sums(divisions, start=None) for division in cumulative_divisions: rounded_division = int(round(division)) - sum(result) if division - round(division) == 0.5: rounded_division += 1 result.append(rounded_division) result = result[1:] if mathtools.sign(n) == -1: result = [-x for x in result] ratio_signs = [mathtools.sign(x) for x in ratio] result = [pair[0] * pair[1] for pair in zip(ratio_signs, result)] return result
def __call__( self, durations=None, layer=None, division_mask_seed=0, division_masks=None, padding=None, seed=None, start_offset=None, timespan_specifier=None, voice_name=None, ): import consort timespans = abjad.TimespanList() timespan_specifier = timespan_specifier or \ consort.TimespanSpecifier() seed = seed or 0 division_mask_seed = division_mask_seed or 0 durations = [_ for _ in durations if _] offsets = mathtools.cumulative_sums(durations, start_offset) if not offsets: return timespans offset_pair_count = len(offsets) - 1 if offset_pair_count == 1: offset_pair_count = 2 # make patterns happy iterator = consort.iterate_nwise(offsets) for i, offset_pair in enumerate(iterator): start_offset, stop_offset = offset_pair music_specifier = self[seed % len(self)] timespan = consort.PerformedTimespan( forbid_fusing=timespan_specifier.forbid_fusing, forbid_splitting=timespan_specifier.forbid_splitting, layer=layer, minimum_duration=timespan_specifier.minimum_duration, music_specifier=music_specifier, start_offset=start_offset, stop_offset=stop_offset, voice_name=voice_name, ) if not division_masks: timespans.append(timespan) else: output_mask = division_masks.get_matching_pattern( i, offset_pair_count + 1, rotation=division_mask_seed) if output_mask is None: timespans.append(timespan) elif isinstance(output_mask, rhythmmakertools.SustainMask): timespans.append(timespan) elif isinstance(output_mask, rhythmmakertools.SilenceMask): pass division_mask_seed += 1 if self.application_rate == 'division': seed += 1 if padding: silent_timespans = abjad.TimespanList() for shard in timespans.partition(True): silent_timespan_one = consort.SilentTimespan( layer=layer, start_offset=shard.start_offset - padding, stop_offset=shard.start_offset, voice_name=voice_name, ) silent_timespans.append(silent_timespan_one) silent_timespan_two = consort.SilentTimespan( layer=layer, start_offset=shard.stop_offset, stop_offset=shard.stop_offset + padding, voice_name=voice_name, ) silent_timespans.append(silent_timespan_two) silent_timespans.compute_logical_or() for timespan in timespans: silent_timespans - timespan timespans.extend(silent_timespans) timespans.sort() return timespans
def _span_points(self): if self.durations is not None: return mathtools.cumulative_sums(self.durations)[1:] return []
def from_tempo_scaled_durations(cls, durations, tempo=None): r'''Convert ``durations``, scaled by ``tempo`` into a ``QEventSequence``: :: >>> tempo = Tempo((1, 4), 174) >>> durations = [(1, 4), (-3, 16), (1, 16), (-1, 2)] :: >>> sequence = \ ... quantizationtools.QEventSequence.from_tempo_scaled_durations( ... durations, tempo=tempo) :: >>> for q_event in sequence: ... print format(q_event, 'storage') ... quantizationtools.PitchedQEvent( offset=durationtools.Offset(0, 1), pitches=( pitchtools.NamedPitch("c'"), ), ) quantizationtools.SilentQEvent( offset=durationtools.Offset(10000, 29), ) quantizationtools.PitchedQEvent( offset=durationtools.Offset(17500, 29), pitches=( pitchtools.NamedPitch("c'"), ), ) quantizationtools.SilentQEvent( offset=durationtools.Offset(20000, 29), ) quantizationtools.TerminalQEvent( offset=durationtools.Offset(40000, 29), ) Returns ``QEventSequence`` instance. ''' from abjad.tools import quantizationtools durations = [durationtools.Duration(x) for x in durations] assert isinstance(tempo, indicatortools.Tempo) durations = [x for x in sequencetools.sum_consecutive_sequence_elements_by_sign( durations, sign=[-1], ) if x] durations = [tempo.duration_to_milliseconds(x) for x in durations] offsets = mathtools.cumulative_sums(abs(x) for x in durations) q_events = [] for pair in zip(offsets, durations): offset = durationtools.Offset(pair[0]) duration = pair[1] if duration < 0: # negative duration indicates silence q_event = quantizationtools.SilentQEvent(offset) else: # otherwise, use middle-C q_event = quantizationtools.PitchedQEvent(offset, [0]) q_events.append(q_event) # insert terminating silence QEvent q_events.append(quantizationtools.TerminalQEvent(offsets[-1])) return cls(q_events)
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 from_millisecond_durations(cls, milliseconds, fuse_silences=False): r'''Convert a sequence of millisecond durations ``durations`` into a ``QEventSequence``: :: >>> durations = [-250, 500, -1000, 1250, -1000] :: >>> sequence = \ ... quantizationtools.QEventSequence.from_millisecond_durations( ... durations) :: >>> for q_event in sequence: ... print format(q_event, 'storage') ... quantizationtools.SilentQEvent( offset=durationtools.Offset(0, 1), ) quantizationtools.PitchedQEvent( offset=durationtools.Offset(250, 1), pitches=( pitchtools.NamedPitch("c'"), ), ) quantizationtools.SilentQEvent( offset=durationtools.Offset(750, 1), ) quantizationtools.PitchedQEvent( offset=durationtools.Offset(1750, 1), pitches=( pitchtools.NamedPitch("c'"), ), ) quantizationtools.SilentQEvent( offset=durationtools.Offset(3000, 1), ) quantizationtools.TerminalQEvent( offset=durationtools.Offset(4000, 1), ) Returns ``QEventSequence`` instance. ''' from abjad.tools import quantizationtools if fuse_silences: durations = [x for x in \ sequencetools.sum_consecutive_sequence_elements_by_sign( milliseconds, sign=[-1]) if x] else: durations = milliseconds offsets = mathtools.cumulative_sums([abs(x) for x in durations]) q_events = [] for pair in zip(offsets, durations): offset = durationtools.Offset(pair[0]) duration = pair[1] if duration < 0: # negative duration indicates silence q_event = quantizationtools.SilentQEvent(offset) else: q_event = quantizationtools.PitchedQEvent(offset, [0]) q_events.append(q_event) q_events.append(quantizationtools.TerminalQEvent( durationtools.Offset(offsets[-1]))) return cls(q_events)
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 = ##f } <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__()
# -*- coding: utf-8 -*- from abjad.tools import mathtools #meter_map = archipel.etc.implementation.data.archipel_meter_map_rev_2.copy() from archipel.etc.implementation.data.archipel_meter_map_rev_2 \ import archipel_meter_map_rev_2 as meter_map meter_map = meter_map.copy() from archipel.etc.implementation.utilities.keep_data import keep_data measures_per_section = [] for region in sorted(meter_map.keys()): for meter_list, tempo in meter_map[region]: measures_per_section.append(len(meter_list)) start_measure_indices = mathtools.cumulative_sums(measures_per_section) cur_section = 0 for region in sorted(meter_map.keys()): sections = meter_map[region] indices = start_measure_indices[cur_section:cur_section+len(sections)] new_sections = [] for (meters, tempo), index in zip(sections, indices): new_sections.append((meters, tempo, index)) meter_map[region] = new_sections cur_section += len(sections) #keep_data( # meter_map, # 'archipel_meter_map_rev_4', # header_line='from abjad.tools.mathtools import NonreducedFraction', # )
def partition_sequence_by_backgrounded_weights(sequence, weights): r'''Partition `sequence` by backgrounded `weights`: :: >>> sequencetools.partition_sequence_by_backgrounded_weights( ... [-5, -15, -10], [20, 10]) [[-5, -15], [-10]] Further examples: :: >>> sequencetools.partition_sequence_by_backgrounded_weights( ... [-5, -15, -10], [5, 5, 5, 5, 5, 5]) [[-5], [-15], [], [], [-10], []] :: >>> sequencetools.partition_sequence_by_backgrounded_weights( ... [-5, -15, -10], [1, 29]) [[-5], [-15, -10]] :: >>> sequencetools.partition_sequence_by_backgrounded_weights( ... [-5, -15, -10], [2, 28]) [[-5], [-15, -10]] :: >>> sequencetools.partition_sequence_by_backgrounded_weights( ... [-5, -15, -10], [1, 1, 1, 1, 1, 25]) [[-5], [], [], [], [], [-15, -10]] The term `backgrounded` is a short-hand concocted specifically for this function; rely on the formal definition to understand the function actually does. Input constraint: the weight of `sequence` must equal the weight of `weights` exactly. The signs of the elements in `sequence` are ignored. Formal definition: partition `sequence` into `parts` such that (1.) the length of `parts` equals the length of `weights`; (2.) the elements in `sequence` appear in order in `parts`; and (3.) some final condition that is difficult to formalize. Notionally what's going on here is that the elements of `weights` are acting as a list of successive time intervals into which the elements of `sequence` are being fit in accordance with the start offset of each `sequence` element. The function models the grouping together of successive timespans according to which of an underlying sequence of time intervals it is in which each time span begins. Note that, for any input to this function, the flattened output of this function always equals `sequence` exactly. Note too that while `partition` is being used here in the sense of the other partitioning functions in the API, the distinguishing feature is this funciton is its ability to produce empty lists as output. Returns list of `sequence` objects. ''' from abjad.tools import sequencetools assert all(0 < x for x in weights) assert mathtools.weight(sequence) == mathtools.weight(weights) start_offsets = \ mathtools.cumulative_sums([abs(x) for x in sequence])[:-1] indicator = zip(start_offsets, sequence) result = [] for interval_start, interval_stop in \ mathtools.cumulative_sums_pairwise(weights): part = [] for pair in indicator[:]: if interval_start <= pair[0] < interval_stop: part.append(pair[1]) indicator.remove(pair) result.append(part) return result
def partition_sequence_by_ratio_of_weights(sequence, weights): '''Partitions `sequence` by ratio of `weights`. :: >>> sequencetools.partition_sequence_by_ratio_of_weights( ... [1] * 10, [1, 1, 1]) [[1, 1, 1], [1, 1, 1, 1], [1, 1, 1]] :: >>> sequencetools.partition_sequence_by_ratio_of_weights( ... [1] * 10, [1, 1, 1, 1]) [[1, 1, 1], [1, 1], [1, 1, 1], [1, 1]] :: >>> sequencetools.partition_sequence_by_ratio_of_weights( ... [1] * 10, [2, 2, 3]) [[1, 1, 1], [1, 1, 1], [1, 1, 1, 1]] :: >>> sequencetools.partition_sequence_by_ratio_of_weights( ... [1] * 10, [3, 2, 2]) [[1, 1, 1, 1], [1, 1, 1], [1, 1, 1]] :: >>> sequencetools.partition_sequence_by_ratio_of_weights( ... [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2], [1, 1]) [[1, 1, 1, 1, 1, 1, 2, 2], [2, 2, 2, 2]] :: >>> sequencetools.partition_sequence_by_ratio_of_weights( ... [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2], [1, 1, 1]) [[1, 1, 1, 1, 1, 1], [2, 2, 2], [2, 2, 2]] Weights of parts of returned list equal `weights_ratio` proportions with some rounding magic. Returns list of lists. ''' from abjad.tools import sequencetools if not isinstance(sequence, collections.Sequence): message = 'must be sequence: {!r}.' message = message.format(sequence) raise Exception(message) list_weight = mathtools.weight(sequence) weights_parts = mathtools.partition_integer_by_ratio(list_weight, weights) cumulative_weights = mathtools.cumulative_sums(weights_parts, start=None) result = [] sublist = [] result.append(sublist) current_cumulative_weight = cumulative_weights.pop(0) for n in sequence: if not isinstance(n, (int, float, fractions.Fraction)): message = 'must be number: {!r}.' message = message.format(n) raise TypeError(message) sublist.append(n) while current_cumulative_weight <= \ mathtools.weight(sequencetools.flatten_sequence(result)): try: current_cumulative_weight = cumulative_weights.pop(0) sublist = [] result.append(sublist) except IndexError: break return result
def partition_integer_by_ratio(n, ratio): r'''Partitions positive integer-equivalent `n` by `ratio`. :: >>> mathtools.partition_integer_by_ratio(10, [1, 2]) [3, 7] Partitions positive integer-equivalent `n` by `ratio` with negative parts: :: >>> mathtools.partition_integer_by_ratio(10, [1, -2]) [3, -7] Partitions negative integer-equivalent `n` by `ratio`: :: >>> mathtools.partition_integer_by_ratio(-10, [1, 2]) [-3, -7] Partitions negative integer-equivalent `n` by `ratio` with negative parts: :: >>> mathtools.partition_integer_by_ratio(-10, [1, -2]) [-3, 7] Returns result with weight equal to absolute value of `n`. Raises type error on noninteger `n`. Returns list of integers. ''' from abjad.tools import mathtools if not mathtools.is_integer_equivalent_number(n): message = 'is not integer-equivalent number: {!r}.' message = message.format(n) raise TypeError(message) ratio = mathtools.Ratio(ratio).numbers if not all( mathtools.is_integer_equivalent_number(part) for part in ratio ): message = 'some parts in {!r} not integer-equivalent numbers.' message = message.format(ratio) raise TypeError(message) result = [0] divisions = [ float(abs(n)) * abs(part) / mathtools.weight(ratio) for part in ratio ] cumulative_divisions = mathtools.cumulative_sums(divisions, start=None) for division in cumulative_divisions: rounded_division = int(round(division)) - sum(result) #This makes rounding behave like python 2. Would be good to remove # in the long run if sys.version_info[0] == 3: if division - round(division) == 0.5: rounded_division += 1 result.append(rounded_division) result = result[1:] # adjust signs of output elements if mathtools.sign(n) == -1: result = [-x for x in result] ratio_signs = [mathtools.sign(x) for x in ratio] result = [pair[0] * pair[1] for pair in zip(ratio_signs, result)] # return result return result
def from_millisecond_pitch_pairs(cls, pairs): r'''Convert millisecond-duration:pitch pairs ``pairs`` into a ``QEventSequence``: :: >>> durations = [250, 500, 1000, 1250, 1000] >>> pitches = [(0,), None, (2, 3), None, (1,)] >>> pairs = tuple(zip(durations, pitches)) :: >>> sequence = \ ... quantizationtools.QEventSequence.from_millisecond_pitch_pairs( ... pairs) :: >>> for q_event in sequence: ... print(format(q_event, 'storage')) ... quantizationtools.PitchedQEvent( offset=durationtools.Offset(0, 1), pitches=( pitchtools.NamedPitch("c'"), ), ) quantizationtools.SilentQEvent( offset=durationtools.Offset(250, 1), ) quantizationtools.PitchedQEvent( offset=durationtools.Offset(750, 1), pitches=( pitchtools.NamedPitch("d'"), pitchtools.NamedPitch("ef'"), ), ) quantizationtools.SilentQEvent( offset=durationtools.Offset(1750, 1), ) quantizationtools.PitchedQEvent( offset=durationtools.Offset(3000, 1), pitches=( pitchtools.NamedPitch("cs'"), ), ) quantizationtools.TerminalQEvent( offset=durationtools.Offset(4000, 1), ) Returns ``QEventSequence`` instance. ''' from abjad.tools import quantizationtools assert isinstance(pairs, collections.Iterable) assert all(isinstance(x, collections.Iterable) for x in pairs) assert all(len(x) == 2 for x in pairs) assert all(0 < x[0] for x in pairs) for pair in pairs: assert isinstance( pair[1], (numbers.Number, type(None), collections.Iterable)) if isinstance(pair[1], collections.Iterable): assert 0 < len(pair[1]) assert all(isinstance(x, numbers.Number) for x in pair[1]) # fuse silences g = itertools.groupby(pairs, lambda x: x[1] is not None) groups = [] for value, group in g: if value: groups.extend(list(group)) else: duration = sum(x[0] for x in group) groups.append((duration, None)) # find offsets offsets = mathtools.cumulative_sums([abs(x[0]) for x in groups]) # build QEvents q_events = [] for pair in zip(offsets, groups): offset = durationtools.Offset(pair[0]) pitches = pair[1][1] if isinstance(pitches, collections.Iterable): assert all(isinstance(x, numbers.Number) for x in pitches) q_events.append( quantizationtools.PitchedQEvent(offset, pitches)) elif isinstance(pitches, type(None)): q_events.append(quantizationtools.SilentQEvent(offset)) elif isinstance(pitches, numbers.Number): q_events.append( quantizationtools.PitchedQEvent(offset, [pitches])) q_events.append( quantizationtools.TerminalQEvent(durationtools.Offset( offsets[-1]))) return cls(q_events)
def from_millisecond_pitch_pairs(cls, pairs): r'''Convert millisecond-duration:pitch pairs ``pairs`` into a ``QEventSequence``: :: >>> durations = [250, 500, 1000, 1250, 1000] >>> pitches = [(0,), None, (2, 3), None, (1,)] >>> pairs = zip(durations, pitches) :: >>> sequence = \ ... quantizationtools.QEventSequence.from_millisecond_pitch_pairs( ... pairs) :: >>> for q_event in sequence: ... print format(q_event, 'storage') ... quantizationtools.PitchedQEvent( offset=durationtools.Offset(0, 1), pitches=( pitchtools.NamedPitch("c'"), ), ) quantizationtools.SilentQEvent( offset=durationtools.Offset(250, 1), ) quantizationtools.PitchedQEvent( offset=durationtools.Offset(750, 1), pitches=( pitchtools.NamedPitch("d'"), pitchtools.NamedPitch("ef'"), ), ) quantizationtools.SilentQEvent( offset=durationtools.Offset(1750, 1), ) quantizationtools.PitchedQEvent( offset=durationtools.Offset(3000, 1), pitches=( pitchtools.NamedPitch("cs'"), ), ) quantizationtools.TerminalQEvent( offset=durationtools.Offset(4000, 1), ) Returns ``QEventSequence`` instance. ''' from abjad.tools import quantizationtools assert isinstance(pairs, collections.Iterable) assert all(isinstance(x, collections.Iterable) for x in pairs) assert all(len(x) == 2 for x in pairs) assert all(0 < x[0] for x in pairs) for pair in pairs: assert isinstance(pair[1], ( numbers.Number, type(None), collections.Iterable)) if isinstance(pair[1], collections.Iterable): assert 0 < len(pair[1]) assert all(isinstance(x, numbers.Number) for x in pair[1]) # fuse silences g = itertools.groupby(pairs, lambda x: x[1] is not None) groups = [] for value, group in g: if value: groups.extend(list(group)) else: duration = sum(x[0] for x in group) groups.append((duration, None)) # find offsets offsets = mathtools.cumulative_sums([abs(x[0]) for x in groups]) # build QEvents q_events = [] for pair in zip(offsets, groups): offset = durationtools.Offset(pair[0]) pitches = pair[1][1] if isinstance(pitches, collections.Iterable): assert all(isinstance(x, numbers.Number) for x in pitches) q_events.append(quantizationtools.PitchedQEvent(offset, pitches)) elif isinstance(pitches, type(None)): q_events.append(quantizationtools.SilentQEvent(offset)) elif isinstance(pitches, numbers.Number): q_events.append(quantizationtools.PitchedQEvent(offset, [pitches])) q_events.append(quantizationtools.TerminalQEvent( durationtools.Offset(offsets[-1]))) return cls(q_events)
def from_tempo_scaled_durations(cls, durations, tempo=None): r'''Convert ``durations``, scaled by ``tempo`` into a ``QEventSequence``: :: >>> tempo = Tempo((1, 4), 174) >>> durations = [(1, 4), (-3, 16), (1, 16), (-1, 2)] :: >>> sequence = \ ... quantizationtools.QEventSequence.from_tempo_scaled_durations( ... durations, tempo=tempo) :: >>> for q_event in sequence: ... print(format(q_event, 'storage')) ... quantizationtools.PitchedQEvent( offset=durationtools.Offset(0, 1), pitches=( pitchtools.NamedPitch("c'"), ), ) quantizationtools.SilentQEvent( offset=durationtools.Offset(10000, 29), ) quantizationtools.PitchedQEvent( offset=durationtools.Offset(17500, 29), pitches=( pitchtools.NamedPitch("c'"), ), ) quantizationtools.SilentQEvent( offset=durationtools.Offset(20000, 29), ) quantizationtools.TerminalQEvent( offset=durationtools.Offset(40000, 29), ) Returns ``QEventSequence`` instance. ''' from abjad.tools import quantizationtools durations = [durationtools.Duration(x) for x in durations] assert isinstance(tempo, indicatortools.Tempo) durations = [ x for x in sequencetools.sum_consecutive_elements_by_sign( durations, sign=[-1], ) if x ] durations = [tempo.duration_to_milliseconds(x) for x in durations] offsets = mathtools.cumulative_sums(abs(x) for x in durations) q_events = [] for pair in zip(offsets, durations): offset = durationtools.Offset(pair[0]) duration = pair[1] if duration < 0: # negative duration indicates silence q_event = quantizationtools.SilentQEvent(offset) else: # otherwise, use middle-C q_event = quantizationtools.PitchedQEvent(offset, [0]) q_events.append(q_event) # insert terminating silence QEvent q_events.append(quantizationtools.TerminalQEvent(offsets[-1])) return cls(q_events)
def partition_integer_by_ratio(n, ratio): r'''Partitions positive integer-equivalent `n` by `ratio`. :: >>> mathtools.partition_integer_by_ratio(10, [1, 2]) [3, 7] Partitions positive integer-equivalent `n` by `ratio` with negative parts: :: >>> mathtools.partition_integer_by_ratio(10, [1, -2]) [3, -7] Partitions negative integer-equivalent `n` by `ratio`: :: >>> mathtools.partition_integer_by_ratio(-10, [1, 2]) [-3, -7] Partitions negative integer-equivalent `n` by `ratio` with negative parts: :: >>> mathtools.partition_integer_by_ratio(-10, [1, -2]) [-3, 7] Returns result with weight equal to absolute value of `n`. Raises type error on noninteger `n`. Returns list of integers. ''' from abjad.tools import mathtools if not mathtools.is_integer_equivalent_number(n): message = 'is not integer-equivalent number: {!r}.' message = message.format(n) raise TypeError(message) ratio = mathtools.Ratio(ratio).numbers if not all(mathtools.is_integer_equivalent_number(part) for part in ratio): message = 'some parts in {!r} not integer-equivalent numbers.' message = message.format(ratio) raise TypeError(message) result = [0] divisions = [ float(abs(n)) * abs(part) / mathtools.weight(ratio) for part in ratio ] cumulative_divisions = mathtools.cumulative_sums(divisions, start=None) for division in cumulative_divisions: rounded_division = int(round(division)) - sum(result) #This makes rounding behave like python 2. Would be good to remove # in the long run if sys.version_info[0] == 3: if division - round(division) == 0.5: rounded_division += 1 result.append(rounded_division) result = result[1:] # adjust signs of output elements if mathtools.sign(n) == -1: result = [-x for x in result] ratio_signs = [mathtools.sign(x) for x in ratio] result = [pair[0] * pair[1] for pair in zip(ratio_signs, result)] # return result return result