Source code for abjadext.rmakers.makers

"""
Makers.
"""
import inspect
import math
import types
import typing

import abjad

from . import classes as _classes


def _apply_ties_to_split_notes(
    tuplets,
    unscaled_end_counts,
    unscaled_preamble,
    unscaled_talea,
    talea,
):
    leaves = abjad.select.leaves(tuplets)
    written_durations = [leaf.written_duration for leaf in leaves]
    written_durations = list(written_durations)
    total_duration = abjad.sequence.weight(written_durations)
    preamble_weights = []
    if unscaled_preamble:
        preamble_weights = []
        for numerator in unscaled_preamble:
            pair = (numerator, talea.denominator)
            duration = abjad.Duration(*pair)
            weight = abs(duration)
            preamble_weights.append(weight)
    preamble_duration = sum(preamble_weights)
    if total_duration <= preamble_duration:
        preamble_parts = abjad.sequence.partition_by_weights(
            written_durations,
            weights=preamble_weights,
            allow_part_weights=abjad.MORE,
            cyclic=True,
            overhang=True,
        )
        talea_parts = []
    else:
        assert preamble_duration < total_duration
        preamble_parts = abjad.sequence.partition_by_weights(
            written_durations,
            weights=preamble_weights,
            allow_part_weights=abjad.EXACT,
            cyclic=False,
            overhang=False,
        )
        talea_weights = []
        for numerator in unscaled_talea:
            pair = (numerator, talea.denominator)
            weight = abs(abjad.Duration(*pair))
            talea_weights.append(weight)
        preamble_length = len(abjad.sequence.flatten(preamble_parts))
        talea_written_durations = written_durations[preamble_length:]
        talea_parts = abjad.sequence.partition_by_weights(
            talea_written_durations,
            weights=talea_weights,
            allow_part_weights=abjad.MORE,
            cyclic=True,
            overhang=True,
        )
    parts = preamble_parts + talea_parts
    part_durations = abjad.sequence.flatten(parts)
    assert part_durations == list(written_durations)
    counts = [len(part) for part in parts]
    parts = abjad.sequence.partition_by_counts(leaves, counts)
    for i, part in enumerate(parts):
        if any(isinstance(_, abjad.Rest) for _ in part):
            continue
        if len(part) == 1:
            continue
        abjad.tie(part)
    # TODO: this will need to be generalized and better tested:
    if unscaled_end_counts:
        total = len(unscaled_end_counts)
        end_leaves = leaves[-total:]
        for leaf in reversed(end_leaves):
            previous_leaf = abjad.get.leaf(leaf, -1)
            if previous_leaf is not None:
                abjad.detach(abjad.Tie, previous_leaf)


def _assert_are_pairs_durations_or_time_signatures(argument):
    for item in abjad.sequence.flatten(argument, classes=(list,)):
        if not isinstance(item, tuple | abjad.Duration | abjad.TimeSignature):
            raise Exception(argument)


def _fix_rounding_error(leaves, total_duration, interpolation):
    duration = abjad.get.duration(leaves)
    if not duration == total_duration:
        needed_duration = total_duration - abjad.get.duration(leaves[:-1])
        multiplier = needed_duration / interpolation.written_duration
        pair = abjad.duration.pair(multiplier)
        leaves[-1].multiplier = pair


def _function_name(frame):
    function_name = frame.f_code.co_name
    string = f"rmakers.{function_name}()"
    return abjad.Tag(string)


def _get_interpolations(interpolations, previous_state):
    specifiers_ = interpolations
    if specifiers_ is None:
        specifiers_ = abjad.CyclicTuple([_classes.Interpolation()])
    elif isinstance(specifiers_, _classes.Interpolation):
        specifiers_ = abjad.CyclicTuple([specifiers_])
    else:
        specifiers_ = abjad.CyclicTuple(specifiers_)
    string = "durations_consumed"
    durations_consumed = previous_state.get(string, 0)
    specifiers_ = abjad.sequence.rotate(specifiers_, n=-durations_consumed)
    specifiers_ = abjad.CyclicTuple(specifiers_)
    return specifiers_


def _interpolate_cosine(y1, y2, mu) -> float:
    mu2 = (1 - math.cos(mu * math.pi)) / 2
    return y1 * (1 - mu2) + y2 * mu2


def _interpolate_divide(
    total_duration, start_duration, stop_duration, exponent="cosine"
) -> str | list[float]:
    """
    Divides ``total_duration`` into durations computed from interpolating between
    ``start_duration`` and ``stop_duration``.

    ..  container:: example

        >>> rmakers.functions._interpolate_divide(
        ...     total_duration=10,
        ...     start_duration=1,
        ...     stop_duration=1,
        ...     exponent=1,
        ... )
        [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
        >>> sum(_)
        10.0

        >>> rmakers.functions._interpolate_divide(
        ...     total_duration=10,
        ...     start_duration=5,
        ...     stop_duration=1,
        ... )
        [4.798..., 2.879..., 1.326..., 0.995...]
        >>> sum(_)
        10.0

    Set ``exponent`` to ``'cosine'`` for cosine interpolation.

    Set ``exponent`` to a numeric value for exponential interpolation with
    ``exponent`` as the exponent.

    Scales resulting durations so that their sum equals ``total_duration`` exactly.
    """
    if total_duration <= 0:
        message = "Total duration must be positive."
        raise ValueError(message)
    if start_duration <= 0 or stop_duration <= 0:
        message = "Both 'start_duration' and 'stop_duration'"
        message += " must be positive."
        raise ValueError(message)
    if total_duration < (stop_duration + start_duration):
        return "too small"
    durations = []
    total_duration = float(total_duration)
    partial_sum = 0.0
    while partial_sum < total_duration:
        if exponent == "cosine":
            duration = _interpolate_cosine(
                start_duration, stop_duration, partial_sum / total_duration
            )
        else:
            duration = _interpolate_exponential(
                start_duration,
                stop_duration,
                partial_sum / total_duration,
                exponent,
            )
        durations.append(duration)
        partial_sum += duration
    durations = [_ * total_duration / sum(durations) for _ in durations]
    return durations


def _interpolate_exponential(y1, y2, mu, exponent=1) -> float:
    """
    Interpolates between ``y1`` and ``y2`` at position ``mu``.

    ..  container:: example

        Exponents equal to 1 leave durations unscaled:

        >>> for mu in (0, 0.25, 0.5, 0.75, 1):
        ...     rmakers.functions._interpolate_exponential(100, 200, mu, exponent=1)
        ...
        100
        125.0
        150.0
        175.0
        200

        Exponents greater than 1 generate ritardandi:

        >>> for mu in (0, 0.25, 0.5, 0.75, 1):
        ...     rmakers.functions._interpolate_exponential(100, 200, mu, exponent=2)
        ...
        100
        106.25
        125.0
        156.25
        200

        Exponents less than 1 generate accelerandi:

        >>> for mu in (0, 0.25, 0.5, 0.75, 1):
        ...     rmakers.functions._interpolate_exponential(100, 200, mu, exponent=0.5)
        ...
        100.0
        150.0
        170.71067811865476
        186.60254037844388
        200.0

    """
    result = y1 * (1 - mu**exponent) + y2 * mu**exponent
    return result


def _make_accelerando(
    duration, interpolations, index, *, tag: abjad.Tag = abjad.Tag()
) -> abjad.Tuplet:
    """
    Makes notes with LilyPond multipliers equal to ``duration``.

    Total number of notes not specified: total duration is specified instead.

    Selects interpolation specifier at ``index`` in ``interpolations``.

    Computes duration multipliers interpolated from interpolation specifier start to
    stop.

    Sets note written durations according to interpolation specifier.
    """
    assert isinstance(duration, abjad.Duration)
    assert all(isinstance(_, _classes.Interpolation) for _ in interpolations)
    assert isinstance(index, int)
    interpolation = interpolations[index]
    durations = _interpolate_divide(
        total_duration=duration,
        start_duration=interpolation.start_duration,
        stop_duration=interpolation.stop_duration,
    )
    if durations == "too small":
        notes = abjad.makers.make_notes([0], [duration], tag=tag)
        tuplet = abjad.Tuplet((1, 1), notes, tag=tag)
        return tuplet
    durations = _round_durations(durations, 2**10)
    notes = []
    for i, duration_ in enumerate(durations):
        written_duration = interpolation.written_duration
        multiplier = duration_ / written_duration
        pair = abjad.duration.pair(multiplier)
        note = abjad.Note(0, written_duration, multiplier=pair, tag=tag)
        notes.append(note)
    _fix_rounding_error(notes, duration, interpolation)
    tuplet = abjad.Tuplet((1, 1), notes, tag=tag)
    return tuplet


def _make_incised_duration_lists(
    pairs,
    prefix_talea,
    prefix_counts,
    suffix_talea,
    suffix_counts,
    extra_counts,
    incise,
):
    assert all(isinstance(_, tuple) for _ in pairs), repr(pairs)
    duration_lists, prefix_talea_index, suffix_talea_index = [], 0, 0
    for pair_index, pair in enumerate(pairs):
        prefix_length = prefix_counts[pair_index]
        suffix_length = suffix_counts[pair_index]
        start = prefix_talea_index
        stop = prefix_talea_index + prefix_length
        prefix = prefix_talea[start:stop]
        start = suffix_talea_index
        stop = suffix_talea_index + suffix_length
        suffix = suffix_talea[start:stop]
        prefix_talea_index += prefix_length
        suffix_talea_index += suffix_length
        prolation_addendum = extra_counts[pair_index]
        numerator = pair[0] + (prolation_addendum % pair[0])
        duration_list = _make_duration_list(numerator, prefix, suffix, incise)
        duration_lists.append(duration_list)
    for duration_list in duration_lists:
        assert all(isinstance(_, abjad.Duration) for _ in duration_list)
    return duration_lists


def _make_leaf_and_tuplet_list(
    durations,
    increase_monotonic=None,
    forbidden_note_duration=None,
    forbidden_rest_duration=None,
    tag=None,
) -> list[abjad.Leaf | abjad.Tuplet]:
    assert all(isinstance(_, abjad.Duration) for _ in durations), repr(durations)
    assert all(_ != 0 for _ in durations), repr(durations)
    leaves_and_tuplets: list[abjad.Leaf | abjad.Tuplet] = []
    pitches: list[int | None]
    for duration in durations:
        if 0 < duration:
            pitches = [0]
        else:
            pitches = [None]
        duration = abs(duration)
        leaves_and_tuplets_ = abjad.makers.make_leaves(
            pitches,
            [duration],
            increase_monotonic=increase_monotonic,
            forbidden_note_duration=forbidden_note_duration,
            forbidden_rest_duration=forbidden_rest_duration,
            tag=tag,
        )
        # TODO: is this needed?
        if (
            1 < len(leaves_and_tuplets_)
            and abjad.get.logical_tie(leaves_and_tuplets_[0]).is_trivial
            and not isinstance(leaves_and_tuplets_[0], abjad.Rest)
        ):
            abjad.tie(leaves_and_tuplets_)
        leaves_and_tuplets.extend(leaves_and_tuplets_)
    return leaves_and_tuplets


def _make_middle_durations(middle_duration, incise):
    assert isinstance(middle_duration, abjad.Duration), repr(middle_duration)
    assert middle_duration.denominator == 1, repr(middle_duration)
    assert isinstance(incise, _classes.Incise), repr(incise)
    durations = []
    if not (incise.fill_with_rests):
        if not incise.outer_tuplets_only:
            if 0 < middle_duration:
                if incise.body_ratio is not None:
                    shards = abjad.math.divide_integer_by_ratio(
                        middle_duration.numerator, incise.body_ratio
                    )
                    durations_ = [abjad.Duration(_) for _ in shards]
                    durations.extend(durations_)
                else:
                    durations.append(middle_duration)
        else:
            if 0 < middle_duration:
                durations.append(middle_duration)
    else:
        if not incise.outer_tuplets_only:
            if 0 < middle_duration:
                durations.append(-abs(middle_duration))
        else:
            if 0 < middle_duration:
                durations.append(-abs(middle_duration))
    assert isinstance(durations, list)
    assert all(isinstance(_, abjad.Duration) for _ in durations), repr(durations)
    return durations


def _make_numerator_lists(
    pairs, preamble, talea, extra_counts, end_counts, read_talea_once_only
):
    assert all(isinstance(_, tuple) for _ in pairs), repr(pairs)
    assert all(isinstance(_, int) for _ in end_counts), repr(end_counts)
    assert all(isinstance(_, int) for _ in preamble), repr(preamble)
    for count in talea:
        assert isinstance(count, int) or count in "+-", repr(talea)
    if "+" in talea or "-" in talea:
        assert not preamble, repr(preamble)
    prolated_pairs = _make_prolated_pairs(pairs, extra_counts)
    pairs = []
    for item in prolated_pairs:
        if isinstance(item, tuple):
            pairs.append(item)
        else:
            pairs.append(item.pair)
    if not preamble and not talea:
        return pairs, None
    prolated_numerators = [_[0] for _ in pairs]
    expanded_talea = None
    if "-" in talea or "+" in talea:
        total_weight = sum(prolated_numerators)
        talea_ = list(talea)
        if "-" in talea:
            index = talea_.index("-")
        else:
            index = talea_.index("+")
        talea_[index] = 0
        explicit_weight = sum([abs(_) for _ in talea_])
        implicit_weight = total_weight - explicit_weight
        if "-" in talea:
            implicit_weight *= -1
        talea_[index] = implicit_weight
        expanded_talea = tuple(talea_)
        talea = abjad.CyclicTuple(expanded_talea)
    numerator_lists = _split_talea_extended_to_weights(
        preamble, read_talea_once_only, talea, prolated_numerators
    )
    if end_counts:
        end_counts = list(end_counts)
        end_weight = abjad.sequence.weight(end_counts)
        numerator_list_weights = [abjad.sequence.weight(_) for _ in numerator_lists]
        counts = abjad.sequence.flatten(numerator_lists)
        counts_weight = abjad.sequence.weight(counts)
        assert end_weight <= counts_weight, repr(end_counts)
        left = counts_weight - end_weight
        right = end_weight
        counts = abjad.sequence.split(counts, [left, right])
        counts = counts[0] + end_counts
        assert abjad.sequence.weight(counts) == counts_weight
        numerator_lists = abjad.sequence.partition_by_weights(
            counts, numerator_list_weights
        )
    for numerator_list in numerator_lists:
        assert all(isinstance(_, int) for _ in numerator_list), repr(numerator_list)
    return numerator_lists, expanded_talea


def _make_duration_list(numerator, prefix, suffix, incise, *, is_note_filled=True):
    numerator = abjad.Duration(numerator)
    prefix = [abjad.Duration(_) for _ in prefix]
    suffix = [abjad.Duration(_) for _ in suffix]
    prefix_weight = abjad.math.weight(prefix)
    suffix_weight = abjad.math.weight(suffix)
    middle_duration = numerator - prefix_weight - suffix_weight
    assert isinstance(middle_duration, abjad.Duration), repr(middle_duration)
    if numerator < prefix_weight:
        weights = [numerator]
        prefix = abjad.sequence.split(prefix, weights, cyclic=False, overhang=False)[0]
    middle_durations = _make_middle_durations(middle_duration, incise)
    suffix_space = numerator - prefix_weight
    if suffix_space <= 0:
        suffix = []
    elif suffix_space < suffix_weight:
        weights = [suffix_space]
        suffix = abjad.sequence.split(suffix, weights, cyclic=False, overhang=False)[0]
    assert all(isinstance(_, abjad.Duration) for _ in prefix), repr(prefix)
    assert all(isinstance(_, abjad.Duration) for _ in suffix), repr(suffix)
    duration_list = prefix + middle_durations + suffix
    assert all(isinstance(_, abjad.Duration) for _ in duration_list), repr(
        duration_list
    )
    return duration_list


def _make_outer_tuplets_only_incised_duration_lists(
    pairs,
    prefix_talea,
    prefix_counts,
    suffix_talea,
    suffix_counts,
    extra_counts,
    incise,
):
    assert all(isinstance(_, tuple) for _ in pairs), repr(pairs)
    numeric_map, prefix_talea_index, suffix_talea_index = [], 0, 0
    prefix_length, suffix_length = prefix_counts[0], suffix_counts[0]
    start = prefix_talea_index
    stop = prefix_talea_index + prefix_length
    prefix = prefix_talea[start:stop]
    start = suffix_talea_index
    stop = suffix_talea_index + suffix_length
    suffix = suffix_talea[start:stop]
    if len(pairs) == 1:
        prolation_addendum = extra_counts[0]
        numerator = getattr(pairs[0], "numerator", pairs[0][0])
        numerator += prolation_addendum % numerator
        numeric_map_part = _make_duration_list(numerator, prefix, suffix, incise)
        numeric_map.append(numeric_map_part)
    else:
        prolation_addendum = extra_counts[0]
        if isinstance(pairs[0], tuple):
            numerator = pairs[0][0]
        else:
            numerator = pairs[0].numerator
        numerator += prolation_addendum % numerator
        numeric_map_part = _make_duration_list(numerator, prefix, (), incise)
        numeric_map.append(numeric_map_part)
        for i, pair in enumerate(pairs[1:-1]):
            index = i + 1
            prolation_addendum = extra_counts[index]
            numerator = pair[0]
            numerator += prolation_addendum % numerator
            numeric_map_part = _make_duration_list(numerator, (), (), incise)
            numeric_map.append(numeric_map_part)
        try:
            index = i + 2
            prolation_addendum = extra_counts[index]
        except UnboundLocalError:
            index = 1 + 2
            prolation_addendum = extra_counts[index]
        if isinstance(pairs[-1], tuple):
            numerator = pairs[-1][0]
        else:
            numerator = pairs[-1].numerator
        numerator += prolation_addendum % numerator
        numeric_map_part = _make_duration_list(numerator, (), suffix, incise)
        numeric_map.append(numeric_map_part)
    return numeric_map


def _make_prolated_pairs(pairs, extra_counts):
    prolated_pairs = []
    for i, pair in enumerate(pairs):
        if not extra_counts:
            prolated_pairs.append(pair)
            continue
        prolation_addendum = extra_counts[i]
        numerator = pair[0]
        if 0 <= prolation_addendum:
            prolation_addendum %= numerator
        else:
            # NOTE: do not remove the following (nonfunctional) if-else;
            #       preserved for backwards compatability.
            use_old_extra_counts_logic = False
            if use_old_extra_counts_logic:
                prolation_addendum %= numerator
            else:
                prolation_addendum %= -numerator
        numerator, denominator = pair
        prolated_pair = (numerator + prolation_addendum, denominator)
        prolated_pairs.append(prolated_pair)
    assert all(isinstance(_, tuple) for _ in prolated_pairs)
    return prolated_pairs


def _make_state_dictionary(
    *,
    durations_consumed,
    logical_ties_produced,
    previous_durations_consumed,
    previous_incomplete_last_note,
    previous_logical_ties_produced,
    state,
):
    durations_consumed_ = previous_durations_consumed + durations_consumed
    state["durations_consumed"] = durations_consumed_
    logical_ties_produced_ = previous_logical_ties_produced + logical_ties_produced
    if previous_incomplete_last_note:
        logical_ties_produced_ -= 1
    state["logical_ties_produced"] = logical_ties_produced_
    state = dict(sorted(state.items()))
    return state


def _make_talea_tuplets(
    durations,
    self_extra_counts,
    previous_state,
    self_read_talea_once_only,
    spelling,
    self_state,
    talea,
    tag,
):
    assert all(isinstance(_, abjad.Duration) for _ in durations), repr(durations)
    prepared = _prepare_talea_rhythm_maker_input(
        self_extra_counts, previous_state, talea
    )
    scaled = _scale_rhythm_maker_input(durations, talea.denominator, prepared)
    assert scaled.counts.talea
    numerator_lists, expanded_talea = _make_numerator_lists(
        scaled.pairs,
        scaled.counts.preamble,
        scaled.counts.talea,
        scaled.counts.extra_counts,
        scaled.counts.end_counts,
        self_read_talea_once_only,
    )
    if expanded_talea is not None:
        unscaled_talea = expanded_talea
    else:
        unscaled_talea = prepared.talea
    talea_weight_consumed = sum(abjad.sequence.weight(_) for _ in numerator_lists)
    duration_lists = [
        [abjad.Duration(_, scaled.lcd) for _ in n] for n in numerator_lists
    ]
    leaf_lists = []
    for duration_list in duration_lists:
        leaf_list = _make_leaf_and_tuplet_list(
            duration_list,
            increase_monotonic=spelling.increase_monotonic,
            forbidden_note_duration=spelling.forbidden_note_duration,
            forbidden_rest_duration=spelling.forbidden_rest_duration,
            tag=tag,
        )
        leaf_lists.append(leaf_list)
    if not scaled.counts.extra_counts:
        tuplets = [abjad.Tuplet((1, 1), _) for _ in leaf_lists]
    else:
        durations_ = [abjad.Duration(_) for _ in scaled.pairs]
        tuplets = _make_talea_rhythm_maker_tuplets(durations_, leaf_lists, tag=tag)
    _apply_ties_to_split_notes(
        tuplets,
        prepared.end_counts,
        prepared.preamble,
        unscaled_talea,
        talea,
    )
    for tuplet in abjad.iterate.components(tuplets, abjad.Tuplet):
        tuplet.normalize_multiplier()
    assert isinstance(self_state, dict)
    advanced_talea = _classes.Talea(
        counts=prepared.talea,
        denominator=talea.denominator,
        end_counts=prepared.end_counts,
        preamble=prepared.preamble,
    )
    if "+" in prepared.talea or "-" in prepared.talea:
        pass
    elif talea_weight_consumed not in advanced_talea:
        last_leaf = abjad.get.leaf(tuplets, -1)
        if isinstance(last_leaf, abjad.Note):
            self_state["incomplete_last_note"] = True
    string = "talea_weight_consumed"
    assert isinstance(previous_state, dict)
    self_state[string] = previous_state.get(string, 0)
    self_state[string] += talea_weight_consumed
    return tuplets


def _make_talea_rhythm_maker_tuplets(durations, leaf_lists, *, tag):
    assert all(isinstance(_, abjad.Duration) for _ in durations), repr(durations)
    assert len(durations) == len(leaf_lists)
    tuplets = []
    for duration, leaf_list in zip(durations, leaf_lists):
        tuplet = abjad.Tuplet.from_duration(duration, leaf_list, tag=tag)
        tuplets.append(tuplet)
    return tuplets


def _make_tuplet_rhythm_maker_music(
    durations,
    self_tuplet_ratios,
    *,
    tag=None,
):
    tuplets = []
    tuplet_ratios = abjad.CyclicTuple(self_tuplet_ratios)
    for i, duration in enumerate(durations):
        ratio = tuplet_ratios[i]
        tuplet = abjad.makers.tuplet_from_duration_and_ratio(duration, ratio, tag=tag)
        tuplets.append(tuplet)
    return tuplets


def _prepare_incised_input(incise, extra_counts):
    cyclic_prefix_talea = abjad.CyclicTuple(incise.prefix_talea)
    cyclic_prefix_counts = abjad.CyclicTuple(incise.prefix_counts or (0,))
    cyclic_suffix_talea = abjad.CyclicTuple(incise.suffix_talea)
    cyclic_suffix_counts = abjad.CyclicTuple(incise.suffix_counts or (0,))
    cyclic_extra_counts = abjad.CyclicTuple(extra_counts or (0,))
    return types.SimpleNamespace(
        prefix_talea=cyclic_prefix_talea,
        prefix_counts=cyclic_prefix_counts,
        suffix_talea=cyclic_suffix_talea,
        suffix_counts=cyclic_suffix_counts,
        extra_counts=cyclic_extra_counts,
    )


def _prepare_talea_rhythm_maker_input(self_extra_counts, previous_state, talea):
    talea_weight_consumed = previous_state.get("talea_weight_consumed", 0)
    talea = talea.advance(talea_weight_consumed)
    end_counts = talea.end_counts or ()
    preamble = talea.preamble or ()
    talea = talea.counts or ()
    talea = abjad.CyclicTuple(talea)
    extra_counts = list(self_extra_counts or [])
    durations_consumed = previous_state.get("durations_consumed", 0)
    extra_counts = abjad.sequence.rotate(extra_counts, -durations_consumed)
    extra_counts = abjad.CyclicTuple(extra_counts)
    return types.SimpleNamespace(
        end_counts=end_counts,
        extra_counts=extra_counts,
        preamble=preamble,
        talea=talea,
    )


def _round_durations(durations, denominator):
    durations_ = []
    for duration in durations:
        numerator = int(round(duration * denominator))
        duration_ = abjad.Duration(numerator, denominator)
        durations_.append(duration_)
    return durations_


def _scale_rhythm_maker_input(durations, talea_denominator, counts):
    assert all(isinstance(_, abjad.Duration) for _ in durations), repr(durations)
    talea_denominator = talea_denominator or 1
    scaled_pairs = durations[:]
    dummy_pair = (1, talea_denominator)
    scaled_pairs.append(dummy_pair)
    scaled_pairs = abjad.Duration.durations_to_nonreduced_fractions(scaled_pairs)
    dummy_pair = scaled_pairs.pop()
    lcd = dummy_pair[1]
    multiplier = lcd / talea_denominator
    assert abjad.math.is_integer_equivalent(multiplier)
    multiplier = int(multiplier)
    scaled_counts = types.SimpleNamespace()
    for name, vector in counts.__dict__.items():
        vector = [multiplier * _ for _ in vector]
        cyclic_vector = abjad.CyclicTuple(vector)
        setattr(scaled_counts, name, cyclic_vector)
    assert len(scaled_pairs) == len(durations)
    assert len(scaled_counts.__dict__) == len(counts.__dict__)
    assert all(isinstance(_, tuple) for _ in scaled_pairs), repr(scaled_pairs)
    return types.SimpleNamespace(pairs=scaled_pairs, lcd=lcd, counts=scaled_counts)


def _split_talea_extended_to_weights(preamble, read_talea_once_only, talea, weights):
    assert abjad.math.all_are_positive_integers(weights)
    preamble_weight = abjad.math.weight(preamble)
    talea_weight = abjad.math.weight(talea)
    weight = abjad.math.weight(weights)
    if read_talea_once_only and preamble_weight + talea_weight < weight:
        message = f"{preamble!s} + {talea!s} is too short"
        message += f" to read {weights} once."
        raise Exception(message)
    if weight <= preamble_weight:
        talea = list(preamble)
        talea = abjad.sequence.truncate(talea, weight=weight)
    else:
        weight -= preamble_weight
        talea = abjad.sequence.repeat_to_weight(talea, weight)
        talea = list(preamble) + list(talea)
    talea = abjad.sequence.split(talea, weights, cyclic=True)
    return talea


[docs]def accelerando( durations, *interpolations: typing.Sequence[abjad.typings.Duration], previous_state: dict | None = None, spelling: _classes.Spelling = _classes.Spelling(), state: dict | None = None, tag: abjad.Tag | None = None, ) -> list[abjad.Tuplet]: r""" Makes one accelerando (or ritardando) for each duration in ``durations``. .. container:: example >>> def make_lilypond_file(pairs, interpolations): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.accelerando(durations, *interpolations) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.feather_beam(voice) ... rmakers.duration_bracket(voice) ... rmakers.swap_length_1(voice) ... score = lilypond_file["Score"] ... abjad.override(score).TupletBracket.padding = 2 ... abjad.override(score).TupletBracket.bracket_visibility = True ... return lilypond_file .. container:: example Makes accelerandi: >>> pairs = [(4, 8), (3, 8), (4, 8), (3, 8)] >>> interpolations = [[(1, 8), (1, 20), (1, 16)]] >>> lilypond_file = make_lilypond_file(pairs, interpolations) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" \with { \override TupletBracket.bracket-visibility = ##t \override TupletBracket.padding = 2 } { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \override TupletNumber.text = \markup \scale #'(0.75 . 0.75) \rhythm { 2 } \times 1/1 { \once \override Beam.grow-direction = #right \time 4/8 c'16 * 63/32 [ c'16 * 115/64 c'16 * 91/64 c'16 * 35/32 c'16 * 29/32 c'16 * 13/16 ] } \revert TupletNumber.text \override TupletNumber.text = \markup \scale #'(0.75 . 0.75) \rhythm { 4. } \times 1/1 { \once \override Beam.grow-direction = #right \time 3/8 c'16 * 117/64 [ c'16 * 99/64 c'16 * 69/64 c'16 * 13/16 c'16 * 47/64 ] } \revert TupletNumber.text \override TupletNumber.text = \markup \scale #'(0.75 . 0.75) \rhythm { 2 } \times 1/1 { \once \override Beam.grow-direction = #right \time 4/8 c'16 * 63/32 [ c'16 * 115/64 c'16 * 91/64 c'16 * 35/32 c'16 * 29/32 c'16 * 13/16 ] } \revert TupletNumber.text \override TupletNumber.text = \markup \scale #'(0.75 . 0.75) \rhythm { 4. } \times 1/1 { \once \override Beam.grow-direction = #right \time 3/8 c'16 * 117/64 [ c'16 * 99/64 c'16 * 69/64 c'16 * 13/16 c'16 * 47/64 ] } \revert TupletNumber.text } } } .. container:: example Makes ritardandi: >>> pairs = [(4, 8), (3, 8), (4, 8), (3, 8)] >>> interpolations = [[(1, 20), (1, 8), (1, 16)]] >>> lilypond_file = make_lilypond_file(pairs, interpolations) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" \with { \override TupletBracket.bracket-visibility = ##t \override TupletBracket.padding = 2 } { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \override TupletNumber.text = \markup \scale #'(0.75 . 0.75) \rhythm { 2 } \times 1/1 { \once \override Beam.grow-direction = #left \time 4/8 c'16 * 3/4 [ c'16 * 25/32 c'16 * 7/8 c'16 * 65/64 c'16 * 79/64 c'16 * 49/32 c'16 * 29/16 ] } \revert TupletNumber.text \override TupletNumber.text = \markup \scale #'(0.75 . 0.75) \rhythm { 4. } \times 1/1 { \once \override Beam.grow-direction = #left \time 3/8 c'16 * 5/8 [ c'16 * 43/64 c'16 * 51/64 c'16 * 65/64 c'16 * 85/64 c'16 * 25/16 ] } \revert TupletNumber.text \override TupletNumber.text = \markup \scale #'(0.75 . 0.75) \rhythm { 2 } \times 1/1 { \once \override Beam.grow-direction = #left \time 4/8 c'16 * 3/4 [ c'16 * 25/32 c'16 * 7/8 c'16 * 65/64 c'16 * 79/64 c'16 * 49/32 c'16 * 29/16 ] } \revert TupletNumber.text \override TupletNumber.text = \markup \scale #'(0.75 . 0.75) \rhythm { 4. } \times 1/1 { \once \override Beam.grow-direction = #left \time 3/8 c'16 * 5/8 [ c'16 * 43/64 c'16 * 51/64 c'16 * 65/64 c'16 * 85/64 c'16 * 25/16 ] } \revert TupletNumber.text } } } .. container:: example Makes accelerandi and ritardandi, alternatingly: >>> pairs = [(4, 8), (3, 8), (4, 8), (3, 8)] >>> interpolations = [[(1, 8), (1, 20), (1, 16)], [(1, 20), (1, 8), (1, 16)]] >>> lilypond_file = make_lilypond_file(pairs, interpolations) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" \with { \override TupletBracket.bracket-visibility = ##t \override TupletBracket.padding = 2 } { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \override TupletNumber.text = \markup \scale #'(0.75 . 0.75) \rhythm { 2 } \times 1/1 { \once \override Beam.grow-direction = #right \time 4/8 c'16 * 63/32 [ c'16 * 115/64 c'16 * 91/64 c'16 * 35/32 c'16 * 29/32 c'16 * 13/16 ] } \revert TupletNumber.text \override TupletNumber.text = \markup \scale #'(0.75 . 0.75) \rhythm { 4. } \times 1/1 { \once \override Beam.grow-direction = #left \time 3/8 c'16 * 5/8 [ c'16 * 43/64 c'16 * 51/64 c'16 * 65/64 c'16 * 85/64 c'16 * 25/16 ] } \revert TupletNumber.text \override TupletNumber.text = \markup \scale #'(0.75 . 0.75) \rhythm { 2 } \times 1/1 { \once \override Beam.grow-direction = #right \time 4/8 c'16 * 63/32 [ c'16 * 115/64 c'16 * 91/64 c'16 * 35/32 c'16 * 29/32 c'16 * 13/16 ] } \revert TupletNumber.text \override TupletNumber.text = \markup \scale #'(0.75 . 0.75) \rhythm { 4. } \times 1/1 { \once \override Beam.grow-direction = #left \time 3/8 c'16 * 5/8 [ c'16 * 43/64 c'16 * 51/64 c'16 * 65/64 c'16 * 85/64 c'16 * 25/16 ] } \revert TupletNumber.text } } } .. container:: example Populates short duration with single note: >>> pairs = [(5, 8), (3, 8), (1, 8)] >>> interpolations = [[(1, 8), (1, 20), (1, 16)]] >>> lilypond_file = make_lilypond_file(pairs, interpolations) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" \with { \override TupletBracket.bracket-visibility = ##t \override TupletBracket.padding = 2 } { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \override TupletNumber.text = \markup \scale #'(0.75 . 0.75) \rhythm { 2 ~ 8 } \times 1/1 { \once \override Beam.grow-direction = #right \time 5/8 c'16 * 61/32 [ c'16 * 115/64 c'16 * 49/32 c'16 * 5/4 c'16 * 33/32 c'16 * 57/64 c'16 * 13/16 c'16 * 25/32 ] } \revert TupletNumber.text \override TupletNumber.text = \markup \scale #'(0.75 . 0.75) \rhythm { 4. } \times 1/1 { \once \override Beam.grow-direction = #right \time 3/8 c'16 * 117/64 [ c'16 * 99/64 c'16 * 69/64 c'16 * 13/16 c'16 * 47/64 ] } \revert TupletNumber.text { \time 1/8 c'8 } } } } """ _assert_are_pairs_durations_or_time_signatures(durations) durations = [abjad.Duration(_) for _ in durations] tag = tag or abjad.Tag() tag = tag.append(_function_name(inspect.currentframe())) interpolations_ = [] for interpolation in interpolations: interpolation_durations = [abjad.Duration(_) for _ in interpolation] interpolation_ = _classes.Interpolation(*interpolation_durations) interpolations_.append(interpolation_) previous_state = previous_state or {} if state is None: state = {} interpolations_ = _get_interpolations(interpolations_, previous_state) tuplets = [] for i, duration in enumerate(durations): tuplet = _make_accelerando(duration, interpolations_, i, tag=tag) tuplets.append(tuplet) voice = abjad.Voice(tuplets) logical_ties_produced = len(abjad.select.logical_ties(voice)) new_state = _make_state_dictionary( durations_consumed=len(durations), logical_ties_produced=logical_ties_produced, previous_durations_consumed=previous_state.get("durations_consumed", 0), previous_incomplete_last_note=previous_state.get("incomplete_last_note", False), previous_logical_ties_produced=previous_state.get("logical_ties_produced", 0), state=state, ) components, tuplets = abjad.mutate.eject_contents(voice), [] for component in components: assert isinstance(component, abjad.Tuplet) tuplets.append(component) state.clear() state.update(new_state) return tuplets
[docs]def even_division( durations, denominators: typing.Sequence[int], *, denominator: str | int = "from_counts", extra_counts: typing.Sequence[int] = (0,), previous_state: dict | None = None, spelling: _classes.Spelling = _classes.Spelling(), state: dict | None = None, tag: abjad.Tag | None = None, ) -> list[abjad.Tuplet]: r""" Makes one even-division tuplet for each duration in ``durations``. Basic example: .. container:: example >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.even_division(durations, [8], extra_counts=[0, 0, 1]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.force_diminution(voice) ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = [(5, 16), (6, 16), (6, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \times 5/8 { \time 5/16 c'4 c'4 } \time 6/16 c'8 [ c'8 c'8 ] \tweak text #tuplet-number::calc-fraction-text \times 3/4 { c'8 [ c'8 c'8 c'8 ] } } } } .. container:: example Understanding the ``denominators`` argument to ``rmakers.even_division()``. .. container:: example Fills tuplets with 16th notes and 8th notes, alternately: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.even_division(durations, [16, 8]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = [(3, 16), (3, 8), (3, 4)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 3/16 c'16 [ c'16 c'16 ] \time 3/8 c'8 [ c'8 c'8 ] \time 3/4 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } } } .. container:: example Fills tuplets with 8th notes: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.even_division(durations, [8]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = [(3, 16), (3, 8), (3, 4)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 3/16 c'8. \time 3/8 c'8 [ c'8 c'8 ] \time 3/4 c'8 [ c'8 c'8 c'8 c'8 c'8 ] } } } (Fills tuplets less than twice the duration of an eighth note with a single attack.) .. container:: example Fills tuplets with quarter notes: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.even_division(durations, [4]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = [(3, 16), (3, 8), (3, 4)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 3/16 c'8. \time 3/8 c'4. \time 3/4 c'4 c'4 c'4 } } } (Fills tuplets less than twice the duration of a quarter note with a single attack.) .. container:: example Fills tuplets with half notes: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.even_division(durations, [2]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = [(3, 16), (3, 8), (3, 4)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 3/16 c'8. \time 3/8 c'4. \time 3/4 c'2. } } } (Fills tuplets less than twice the duration of a half note with a single attack.) .. container:: example Using ``rmakers.even_division()`` with the ``denominator`` keyword. .. container:: example With ``denominator=None``. Expresses tuplet ratios in the usual way with numerator and denominator relatively prime: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.even_division( ... durations, [16], extra_counts=[4], denominator=None ... ) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... return lilypond_file >>> pairs = [(4, 8), (3, 8), (4, 8), (3, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 2/3 { \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \times 2/3 { \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } } } } .. container:: example With ``denominator=4``: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.even_division( ... durations, [16], extra_counts=[4], denominator=4 ... ) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... return lilypond_file >>> pairs = [(4, 8), (3, 8), (4, 8), (3, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 4/6 { \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \times 4/6 { \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } } } } .. container:: example With ``denominator=8``: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.even_division( ... durations, [16], extra_counts=[4], denominator=8 ... ) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... return lilypond_file >>> pairs = [(4, 8), (3, 8), (4, 8), (3, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 8/12 { \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \times 8/12 { \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } } } } .. container:: example With ``denominator=16``: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.even_division( ... durations, [16], extra_counts=[4], denominator=16 ... ) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... return lilypond_file >>> pairs = [(4, 8), (3, 8), (4, 8), (3, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 16/24 { \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \times 16/24 { \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } } } } .. container:: example With ``denominator="from_counts"``: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.even_division( ... durations, [16], extra_counts=[4], denominator="from_counts" ... ) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... return lilypond_file >>> pairs = [(4, 8), (3, 8), (4, 8), (3, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 8/12 { \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 6/10 { \time 3/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \times 8/12 { \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 6/10 { \time 3/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } } } } .. container:: example Using ``rmakers.even_division()`` with the ``extra_counts`` keyword. .. container:: example Adds extra counts to tuplets according to a pattern of three elements: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.even_division( ... durations, [16], extra_counts=[0, 1, 2] ... ) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = [(3, 8), (3, 8), (3, 8), (3, 8), (3, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 3/8 c'16 [ c'16 c'16 c'16 c'16 c'16 ] \tweak text #tuplet-number::calc-fraction-text \times 6/7 { c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 6/8 { c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } c'16 [ c'16 c'16 c'16 c'16 c'16 ] \tweak text #tuplet-number::calc-fraction-text \times 6/7 { c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 ] } } } } .. container:: example **Modular handling of positive values.** Denote by ``unprolated_note_count`` the number counts included in a tuplet when ``extra_counts`` is set to zero. Then extra counts equals ``extra_counts % unprolated_note_count`` when ``extra_counts`` is positive. This is likely to be intuitive; compare with the handling of negative values, below. For positive extra counts, the modulus of transformation of a tuplet with six notes is six: >>> import math >>> unprolated_note_count = 6 >>> modulus = unprolated_note_count >>> extra_counts = list(range(12)) >>> labels = [] >>> for count in extra_counts: ... modular_count = count % modulus ... label = rf"\markup {{ {count:3} becomes {modular_count:2} }}" ... labels.append(label) Which produces the following pattern of changes: >>> def make_lilypond_file(pairs, extra_counts): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.even_division( ... durations, [16], extra_counts=extra_counts ... ) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = 12 * [(6, 16)] >>> lilypond_file = make_lilypond_file(pairs, extra_counts) >>> staff = lilypond_file["Staff"] >>> abjad.override(staff).TextScript.staff_padding = 7 >>> leaves = abjad.select.leaves(staff) >>> groups = abjad.select.group_by_measure(leaves) >>> for group, label in zip(groups, labels): ... markup = abjad.Markup(label) ... abjad.attach(markup, group[0], direction=abjad.UP) ... >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f \override TextScript.staff-padding = 7 } { \context Voice = "Voice" { \time 6/16 c'16 ^ \markup { 0 becomes 0 } [ c'16 c'16 c'16 c'16 c'16 ] \tweak text #tuplet-number::calc-fraction-text \times 6/7 { c'16 ^ \markup { 1 becomes 1 } [ c'16 c'16 c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 6/8 { c'16 ^ \markup { 2 becomes 2 } [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \times 6/9 { c'16 ^ \markup { 3 becomes 3 } [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 6/10 { c'16 ^ \markup { 4 becomes 4 } [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 6/11 { c'16 ^ \markup { 5 becomes 5 } [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } c'16 ^ \markup { 6 becomes 0 } [ c'16 c'16 c'16 c'16 c'16 ] \tweak text #tuplet-number::calc-fraction-text \times 6/7 { c'16 ^ \markup { 7 becomes 1 } [ c'16 c'16 c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 6/8 { c'16 ^ \markup { 8 becomes 2 } [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \times 6/9 { c'16 ^ \markup { 9 becomes 3 } [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 6/10 { c'16 ^ \markup { 10 becomes 4 } [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 6/11 { c'16 ^ \markup { 11 becomes 5 } [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } } } } This modular formula ensures that rhythm-maker ``denominators`` are always respected: a very large number of extra counts never causes a ``16``-denominated tuplet to result in 32nd- or 64th-note rhythms. .. container:: example **Modular handling of negative values.** Denote by ``unprolated_note_count`` the number of counts included in a tuplet when ``extra_counts`` is set to zero. Further, let ``modulus = ceiling(unprolated_note_count / 2)``. Then extra counts equals ``-(abs(extra_counts) % modulus)`` when ``extra_counts`` is negative. For negative extra counts, the modulus of transformation of a tuplet with six notes is three: >>> import math >>> unprolated_note_count = 6 >>> modulus = math.ceil(unprolated_note_count / 2) >>> extra_counts = [0, -1, -2, -3, -4, -5, -6, -7, -8] >>> labels = [] >>> for count in extra_counts: ... modular_count = -(abs(count) % modulus) ... label = rf"\markup {{ {count:3} becomes {modular_count:2} }}" ... labels.append(label) Which produces the following pattern of changes: >>> def make_lilypond_file(pairs, extra_counts): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.even_division( ... durations, [16], extra_counts=extra_counts ... ) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = 9 * [(6, 16)] >>> lilypond_file = make_lilypond_file(pairs, extra_counts) >>> staff = lilypond_file["Staff"] >>> abjad.override(staff).TextScript.staff_padding = 8 >>> leaves = abjad.select.leaves(staff) >>> groups = abjad.select.group_by_measure(leaves) >>> for group, label in zip(groups, labels): ... markup = abjad.Markup(label) ... abjad.attach(markup, group[0], direction=abjad.UP) ... >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f \override TextScript.staff-padding = 8 } { \context Voice = "Voice" { \time 6/16 c'16 ^ \markup { 0 becomes 0 } [ c'16 c'16 c'16 c'16 c'16 ] \tweak text #tuplet-number::calc-fraction-text \times 6/5 { c'16 ^ \markup { -1 becomes -1 } [ c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 6/4 { c'16 ^ \markup { -2 becomes -2 } [ c'16 c'16 c'16 ] } c'16 ^ \markup { -3 becomes 0 } [ c'16 c'16 c'16 c'16 c'16 ] \tweak text #tuplet-number::calc-fraction-text \times 6/5 { c'16 ^ \markup { -4 becomes -1 } [ c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 6/4 { c'16 ^ \markup { -5 becomes -2 } [ c'16 c'16 c'16 ] } c'16 ^ \markup { -6 becomes 0 } [ c'16 c'16 c'16 c'16 c'16 ] \tweak text #tuplet-number::calc-fraction-text \times 6/5 { c'16 ^ \markup { -7 becomes -1 } [ c'16 c'16 c'16 c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 6/4 { c'16 ^ \markup { -8 becomes -2 } [ c'16 c'16 c'16 ] } } } } This modular formula ensures that rhythm-maker ``denominators`` are always respected: a very small number of extra counts never causes a ``16``-denominated tuplet to result in 8th- or quarter-note rhythms. """ _assert_are_pairs_durations_or_time_signatures(durations) tag = tag or abjad.Tag() tag = tag.append(_function_name(inspect.currentframe())) durations = [abjad.Duration(_) for _ in durations] assert all(isinstance(_, int) for _ in denominators), repr(denominators) if denominator is not None and not isinstance(denominator, int): assert denominator in ("from_counts",), repr(denominator) assert all(isinstance(_, int) for _ in extra_counts), repr(extra_counts) previous_state = previous_state or {} if state is None: state = {} tuplets = [] assert isinstance(previous_state, dict) durations_consumed = previous_state.get("durations_consumed", 0) denominators_ = list(denominators) denominators_ = abjad.sequence.rotate(denominators_, -durations_consumed) cyclic_denominators = abjad.CyclicTuple(denominators_) extra_counts_ = extra_counts or [0] extra_counts__ = list(extra_counts_) extra_counts__ = abjad.sequence.rotate(extra_counts__, -durations_consumed) cyclic_extra_counts = abjad.CyclicTuple(extra_counts__) for i, duration in enumerate(durations): if not abjad.math.is_positive_integer_power_of_two(duration.denominator): raise Exception(f"non-power-of-two durations not implemented: {duration}") denominator_ = cyclic_denominators[i] extra_count = cyclic_extra_counts[i] basic_duration = abjad.Duration(1, denominator_) unprolated_note_count = None if duration < 2 * basic_duration: notes = abjad.makers.make_notes([0], [duration], tag=tag) else: unprolated_note_count = duration / basic_duration unprolated_note_count = int(unprolated_note_count) unprolated_note_count = unprolated_note_count or 1 if 0 < extra_count: modulus = unprolated_note_count extra_count = extra_count % modulus elif extra_count < 0: modulus = int(math.ceil(unprolated_note_count / 2.0)) extra_count = abs(extra_count) % modulus extra_count *= -1 note_count = unprolated_note_count + extra_count durations_ = note_count * [basic_duration] notes = abjad.makers.make_notes([0], durations_, tag=tag) assert all(_.written_duration.denominator == denominator_ for _ in notes) tuplet_duration = duration tuplet = abjad.Tuplet.from_duration(tuplet_duration, notes, tag=tag) if denominator == "from_counts" and unprolated_note_count is not None: tuplet.denominator = unprolated_note_count elif isinstance(denominator, int): tuplet.denominator = denominator tuplets.append(tuplet) assert all(isinstance(_, abjad.Tuplet) for _ in tuplets), repr(tuplets) voice = abjad.Voice(tuplets) logical_ties_produced = len(abjad.select.logical_ties(voice)) new_state = _make_state_dictionary( durations_consumed=len(durations), logical_ties_produced=logical_ties_produced, previous_durations_consumed=previous_state.get("durations_consumed", 0), previous_incomplete_last_note=previous_state.get("incomplete_last_note", False), previous_logical_ties_produced=previous_state.get("logical_ties_produced", 0), state=state, ) components, tuplets = abjad.mutate.eject_contents(voice), [] for component in components: assert isinstance(component, abjad.Tuplet) tuplets.append(component) state.clear() state.update(new_state) return tuplets
[docs]def incised( durations, *, body_ratio: tuple[int, ...] = (1,), extra_counts: typing.Sequence[int] = (), fill_with_rests: bool = False, outer_tuplets_only: bool = False, prefix_counts: typing.Sequence[int] = (), prefix_talea: typing.Sequence[int] = (), spelling: _classes.Spelling = _classes.Spelling(), suffix_counts: typing.Sequence[int] = (), suffix_talea: typing.Sequence[int] = (), tag: abjad.Tag | None = None, talea_denominator: int | None = None, ) -> list[abjad.Tuplet]: r""" Makes one incised tuplet for each duration in ``durations``. Set ``prefix_talea=[-1]`` with ``prefix_counts=[1]`` to incise a rest at the start of each tuplet: .. container:: example >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.incised( ... durations, ... prefix_talea=[-1], ... prefix_counts=[1], ... talea_denominator=16, ... ) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = 4 * [(5, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 5/16 r16 c'4 r16 c'4 r16 c'4 r16 c'4 } } } Set ``prefix_talea=[-1]`` with ``prefix_counts=[2]`` to incise 2 rests at the start of each tuplet: .. container:: example >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.incised( ... durations, ... prefix_talea=[-1], ... prefix_counts=[2], ... talea_denominator=16, ... ) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = 4 * [(5, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 5/16 r16 r16 c'8. r16 r16 c'8. r16 r16 c'8. r16 r16 c'8. } } } Set ``prefix_talea=[1]`` with ``prefix_counts=[1]`` to incise 1 note at the start of each tuplet: .. container:: example >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.incised( ... durations, ... prefix_talea=[1], ... prefix_counts=[1], ... talea_denominator=16, ... ) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = 4 * [(5, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 5/16 c'16 c'4 c'16 c'4 c'16 c'4 c'16 c'4 } } } Set ``prefix_talea=[1]`` with ``prefix_counts=[2]`` to incise 2 notes at the start of each tuplet: .. container:: example >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.incised( ... durations, ... prefix_talea=[1], ... prefix_counts=[2], ... talea_denominator=16, ... ) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = 4 * [(5, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 5/16 c'16 [ c'16 c'8. ] c'16 [ c'16 c'8. ] c'16 [ c'16 c'8. ] c'16 [ c'16 c'8. ] } } } Incise rests at the beginning and end of each tuplet like this: .. container:: example >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.incised( ... durations, ... extra_counts=[1], ... prefix_talea=[-1], ... prefix_counts=[1], ... suffix_talea=[-1], ... suffix_counts=[1], ... talea_denominator=16, ... ) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = 4 * [(5, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \times 5/6 { \time 5/16 r16 c'4 r16 } \tweak text #tuplet-number::calc-fraction-text \times 5/6 { r16 c'4 r16 } \tweak text #tuplet-number::calc-fraction-text \times 5/6 { r16 c'4 r16 } \tweak text #tuplet-number::calc-fraction-text \times 5/6 { r16 c'4 r16 } } } } Set ``body_ratio=(1, 1)`` to divide the middle part of each tuplet ``1:1``: .. container:: example >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.incised( ... durations, ... body_ratio=(1, 1), ... talea_denominator=16, ... ) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = 4 * [(5, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 5/16 c'8 [ ~ c'32 c'8 ~ c'32 ] c'8 [ ~ c'32 c'8 ~ c'32 ] c'8 [ ~ c'32 c'8 ~ c'32 ] c'8 [ ~ c'32 c'8 ~ c'32 ] } } } Set ``body_ratio=(1, 1, 1)`` to divide the middle part of each tuplet ``1:1:1``: .. container:: example TODO. Allow nested tuplets to clean up notation: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.incised( ... durations, ... body_ratio=(1, 1, 1), ... talea_denominator=16, ... ) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = 4 * [(5, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak edge-height #'(0.7 . 0) \times 32/48 { \time 5/16 c'8 [ ~ c'32 } \tweak edge-height #'(0.7 . 0) \times 32/48 { c'8 ~ c'32 } \tweak edge-height #'(0.7 . 0) \times 32/48 { c'8 ~ c'32 ] } \tweak edge-height #'(0.7 . 0) \times 32/48 { c'8 [ ~ c'32 } \tweak edge-height #'(0.7 . 0) \times 32/48 { c'8 ~ c'32 } \tweak edge-height #'(0.7 . 0) \times 32/48 { c'8 ~ c'32 ] } \tweak edge-height #'(0.7 . 0) \times 32/48 { c'8 [ ~ c'32 } \tweak edge-height #'(0.7 . 0) \times 32/48 { c'8 ~ c'32 } \tweak edge-height #'(0.7 . 0) \times 32/48 { c'8 ~ c'32 ] } \tweak edge-height #'(0.7 . 0) \times 32/48 { c'8 [ ~ c'32 } \tweak edge-height #'(0.7 . 0) \times 32/48 { c'8 ~ c'32 } \tweak edge-height #'(0.7 . 0) \times 32/48 { c'8 ~ c'32 ] } } } } """ tag = tag or abjad.Tag() tag = tag.append(_function_name(inspect.currentframe())) _assert_are_pairs_durations_or_time_signatures(durations) durations = [abjad.Duration(_) for _ in durations] incise = _classes.Incise( body_ratio=body_ratio, fill_with_rests=fill_with_rests, outer_tuplets_only=outer_tuplets_only, prefix_talea=prefix_talea, prefix_counts=prefix_counts, suffix_talea=suffix_talea, suffix_counts=suffix_counts, talea_denominator=talea_denominator, ) prepared = _prepare_incised_input(incise, extra_counts) counts = types.SimpleNamespace( prefix_talea=prepared.prefix_talea, suffix_talea=prepared.suffix_talea, extra_counts=prepared.extra_counts, ) talea_denominator = incise.talea_denominator scaled = _scale_rhythm_maker_input(durations, talea_denominator, counts) if incise.outer_tuplets_only: duration_lists = _make_outer_tuplets_only_incised_duration_lists( scaled.pairs, scaled.counts.prefix_talea, prepared.prefix_counts, scaled.counts.suffix_talea, prepared.suffix_counts, scaled.counts.extra_counts, incise, ) else: duration_lists = _make_incised_duration_lists( scaled.pairs, scaled.counts.prefix_talea, prepared.prefix_counts, scaled.counts.suffix_talea, prepared.suffix_counts, scaled.counts.extra_counts, incise, ) leaf_and_tuplet_lists = [] for duration_list in duration_lists: duration_list = [_ for _ in duration_list if _ != abjad.Duration(0)] duration_list = [abjad.Duration(_, scaled.lcd) for _ in duration_list] leaf_and_tuplet_list_ = _make_leaf_and_tuplet_list( duration_list, forbidden_note_duration=spelling.forbidden_note_duration, forbidden_rest_duration=spelling.forbidden_rest_duration, increase_monotonic=spelling.increase_monotonic, tag=tag, ) leaf_and_tuplet_lists.append(leaf_and_tuplet_list_) durations = [abjad.Duration(_) for _ in scaled.pairs] tuplets = _make_talea_rhythm_maker_tuplets( durations, leaf_and_tuplet_lists, tag=tag ) assert all(isinstance(_, abjad.Tuplet) for _ in tuplets) return tuplets
[docs]def multiplied_duration( durations, prototype: type = abjad.Note, *, duration: abjad.typings.Duration = (1, 1), spelling: _classes.Spelling = _classes.Spelling(), tag: abjad.Tag | None = None, ) -> list[abjad.Leaf]: r""" Makes one leaf with multiplier for each duration in ``durations``. .. container:: example >>> time_signatures = rmakers.time_signatures([(1, 4), (3, 16), (5, 8), (1, 3)]) >>> durations = [abjad.Duration(_) for _ in time_signatures] >>> components = rmakers.multiplied_duration(durations) >>> lilypond_file = rmakers.example(components, time_signatures) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 1/4 c'1 * 1/4 \time 3/16 c'1 * 3/16 \time 5/8 c'1 * 5/8 #(ly:expect-warning "strange time signature found") \time 1/3 c'1 * 1/3 } } } .. container:: example Makes multiplied-duration whole notes when ``duration`` is unset: >>> time_signatures = rmakers.time_signatures([(1, 4), (3, 16), (5, 8), (1, 3)]) >>> durations = [abjad.Duration(_) for _ in time_signatures] >>> components = rmakers.multiplied_duration(durations) >>> lilypond_file = rmakers.example(components, time_signatures) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 1/4 c'1 * 1/4 \time 3/16 c'1 * 3/16 \time 5/8 c'1 * 5/8 #(ly:expect-warning "strange time signature found") \time 1/3 c'1 * 1/3 } } } Makes multiplied-duration half notes when ``duration=(1, 2)``: >>> time_signatures = rmakers.time_signatures([(1, 4), (3, 16), (5, 8), (1, 3)]) >>> durations = [abjad.Duration(_) for _ in time_signatures] >>> components = rmakers.multiplied_duration(durations, duration=(1, 2)) >>> lilypond_file = rmakers.example(components, time_signatures) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 1/4 c'2 * 2/4 \time 3/16 c'2 * 6/16 \time 5/8 c'2 * 10/8 #(ly:expect-warning "strange time signature found") \time 1/3 c'2 * 2/3 } } } Makes multiplied-duration quarter notes when ``duration=(1, 4)``: >>> time_signatures = rmakers.time_signatures([(1, 4), (3, 16), (5, 8), (1, 3)]) >>> durations = [abjad.Duration(_) for _ in time_signatures] >>> components = rmakers.multiplied_duration(durations, duration=(1, 4)) >>> lilypond_file = rmakers.example(components, time_signatures) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 1/4 c'4 * 4/4 \time 3/16 c'4 * 12/16 \time 5/8 c'4 * 20/8 #(ly:expect-warning "strange time signature found") \time 1/3 c'4 * 4/3 } } } .. container:: example Makes multiplied-duration notes when ``prototype`` is unset: >>> time_signatures = rmakers.time_signatures([(1, 4), (3, 16), (5, 8), (1, 3)]) >>> durations = [abjad.Duration(_) for _ in time_signatures] >>> components = rmakers.multiplied_duration(durations) >>> lilypond_file = rmakers.example(components, time_signatures) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 1/4 c'1 * 1/4 \time 3/16 c'1 * 3/16 \time 5/8 c'1 * 5/8 #(ly:expect-warning "strange time signature found") \time 1/3 c'1 * 1/3 } } } .. container:: example Makes multiplied-duration rests when ``prototype=abjad.Rest``: >>> time_signatures = rmakers.time_signatures([(1, 4), (3, 16), (5, 8), (1, 3)]) >>> durations = [abjad.Duration(_) for _ in time_signatures] >>> components = rmakers.multiplied_duration(durations, abjad.Rest) >>> lilypond_file = rmakers.example(components, time_signatures) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 1/4 r1 * 1/4 \time 3/16 r1 * 3/16 \time 5/8 r1 * 5/8 #(ly:expect-warning "strange time signature found") \time 1/3 r1 * 1/3 } } } .. container:: example Makes multiplied-duration multimeasures rests when ``prototype=abjad.MultimeasureRest``: >>> time_signatures = rmakers.time_signatures([(1, 4), (3, 16), (5, 8), (1, 3)]) >>> durations = [abjad.Duration(_) for _ in time_signatures] >>> components = rmakers.multiplied_duration(durations, abjad.MultimeasureRest) >>> lilypond_file = rmakers.example(components, time_signatures) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 1/4 R1 * 1/4 \time 3/16 R1 * 3/16 \time 5/8 R1 * 5/8 #(ly:expect-warning "strange time signature found") \time 1/3 R1 * 1/3 } } } .. container:: example Makes multiplied-duration skips when ``prototype=abjad.Skip``: >>> time_signatures = rmakers.time_signatures([(1, 4), (3, 16), (5, 8), (1, 3)]) >>> durations = [abjad.Duration(_) for _ in time_signatures] >>> components = rmakers.multiplied_duration(durations, abjad.Skip) >>> lilypond_file = rmakers.example(components, time_signatures) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 1/4 s1 * 1/4 \time 3/16 s1 * 3/16 \time 5/8 s1 * 5/8 #(ly:expect-warning "strange time signature found") \time 1/3 s1 * 1/3 } } } """ tag = tag or abjad.Tag() tag = tag.append(_function_name(inspect.currentframe())) _assert_are_pairs_durations_or_time_signatures(durations) durations = [abjad.Duration(_) for _ in durations] duration = abjad.Duration(duration) leaf: abjad.Leaf leaves = [] for duration_ in durations: pair = duration_.numerator, duration_.denominator pair = abjad.duration.divide_pair(pair, duration) if prototype is abjad.Note: leaf = prototype("c'", duration, multiplier=pair, tag=tag) else: leaf = prototype(duration, multiplier=pair, tag=tag) leaves.append(leaf) assert all(isinstance(_, abjad.Leaf) for _ in leaves), repr(leaves) return leaves
[docs]def note( durations, *, spelling: _classes.Spelling = _classes.Spelling(), tag: abjad.Tag | None = None, ) -> list[abjad.Leaf | abjad.Tuplet]: r""" Makes one note for every duration in ``durations``. Silences every other logical tie: .. container:: example >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... nested_music = rmakers.note(durations) ... components = abjad.sequence.flatten(nested_music) ... container = abjad.Container(components) ... logical_ties = abjad.select.logical_ties(container) ... logical_ties = abjad.select.get(logical_ties, [0], 2) ... rmakers.force_rest(logical_ties) ... components = abjad.mutate.eject_contents(container) ... lilypond_file = rmakers.example(components, time_signatures) ... return lilypond_file >>> pairs = [(4, 8), (3, 8), (4, 8), (3, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 4/8 r2 \time 3/8 c'4. \time 4/8 r2 \time 3/8 c'4. } } } .. container:: example Forces rest at every logical tie: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... nested_music = rmakers.note(durations) ... components = abjad.sequence.flatten(nested_music) ... container = abjad.Container(components) ... logical_ties = abjad.select.logical_ties(container) ... rmakers.force_rest(logical_ties) ... components = abjad.mutate.eject_contents(container) ... lilypond_file = rmakers.example(components, time_signatures) ... return lilypond_file >>> pairs = [(4, 8), (3, 8), (4, 8), (5, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 4/8 r2 \time 3/8 r4. \time 4/8 r2 \time 5/8 r2 r8 } } } .. container:: example Force-rests every other note, except for the first and last: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... nested_music = rmakers.note(durations) ... components = abjad.sequence.flatten(nested_music) ... container = abjad.Container(components) ... logical_ties = abjad.select.logical_ties(container) ... logical_ties = abjad.select.get(logical_ties, [0], 2)[1:-1] ... rmakers.force_rest(logical_ties) ... components = abjad.mutate.eject_contents(container) ... lilypond_file = rmakers.example(components, time_signatures) ... return lilypond_file >>> pairs = [(4, 8), (3, 8), (4, 8), (3, 8), (2, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 4/8 c'2 \time 3/8 c'4. \time 4/8 r2 \time 3/8 c'4. \time 2/8 c'4 } } } .. container:: example Beams the notes in each duration: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... nested_music = rmakers.note(durations) ... components = abjad.sequence.flatten(nested_music) ... lilypond_file = rmakers.example(components, time_signatures) ... voice = lilypond_file["Voice"] ... logical_ties = abjad.select.logical_ties(voice, pitched=True) ... rmakers.beam(logical_ties) ... return lilypond_file >>> pairs = [(5, 32), (5, 32)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 5/32 c'8 [ ~ c'32 ] c'8 [ ~ c'32 ] } } } .. container:: example Beams notes grouped by ``durations``: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... nested_music = rmakers.note(durations) ... components = abjad.sequence.flatten(nested_music) ... lilypond_file = rmakers.example(components, time_signatures) ... voice = lilypond_file["Voice"] ... logical_ties = abjad.select.logical_ties(voice) ... rmakers.beam_groups(logical_ties) ... return lilypond_file >>> pairs = [(5, 32), (5, 32)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \set stemLeftBeamCount = 0 \set stemRightBeamCount = 1 \time 5/32 c'8 [ ~ \set stemLeftBeamCount = 3 \set stemRightBeamCount = 1 c'32 \set stemLeftBeamCount = 1 \set stemRightBeamCount = 1 c'8 ~ \set stemLeftBeamCount = 3 \set stemRightBeamCount = 0 c'32 ] } } } .. container:: example Makes no beams: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... nested_music = rmakers.note(durations) ... components = abjad.sequence.flatten(nested_music) ... container = abjad.Container(components) ... components = abjad.mutate.eject_contents(container) ... lilypond_file = rmakers.example(components, time_signatures) ... return lilypond_file >>> pairs = [(5, 32), (5, 32)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 5/32 c'8 ~ c'32 c'8 ~ c'32 } } } .. container:: example Does not tie across ``durations``: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... nested_music = rmakers.note(durations) ... components = abjad.sequence.flatten(nested_music) ... container = abjad.Container(components) ... components = abjad.mutate.eject_contents(container) ... lilypond_file = rmakers.example(components, time_signatures) ... return lilypond_file >>> pairs = [(4, 8), (3, 8), (4, 8), (3, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 4/8 c'2 \time 3/8 c'4. \time 4/8 c'2 \time 3/8 c'4. } } } .. container:: example Ties across ``durations``: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... nested_music = rmakers.note(durations) ... components = abjad.sequence.flatten(nested_music) ... container = abjad.Container(components) ... logical_ties = abjad.select.logical_ties(container)[:-1] ... leaves = [abjad.select.leaf(_, -1) for _ in logical_ties] ... rmakers.tie(leaves) ... components = abjad.mutate.eject_contents(container) ... lilypond_file = rmakers.example(components, time_signatures) ... return lilypond_file >>> pairs = [(4, 8), (3, 8), (4, 8), (3, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 4/8 c'2 ~ \time 3/8 c'4. ~ \time 4/8 c'2 ~ \time 3/8 c'4. } } } .. container:: example Ties across every other logical tie: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... nested_music = rmakers.note(durations) ... components = abjad.sequence.flatten(nested_music) ... container = abjad.Container(components) ... logical_ties = abjad.select.logical_ties(container)[:-1] ... logical_ties = abjad.select.get(logical_ties, [0], 2) ... leaves = [abjad.select.leaf(_, -1) for _ in logical_ties] ... rmakers.tie(leaves) ... components = abjad.mutate.eject_contents(container) ... lilypond_file = rmakers.example(components, time_signatures) ... return lilypond_file >>> pairs = [(4, 8), (3, 8), (4, 8), (3, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 4/8 c'2 ~ \time 3/8 c'4. \time 4/8 c'2 ~ \time 3/8 c'4. } } } .. container:: example Strips all ties: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... nested_music = rmakers.note(durations) ... components = abjad.sequence.flatten(nested_music) ... container = abjad.Container(components) ... rmakers.untie(container) ... components = abjad.mutate.eject_contents(container) ... lilypond_file = rmakers.example(components, time_signatures) ... return lilypond_file >>> pairs = [(7, 16), (1, 4), (5, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 7/16 c'4.. \time 1/4 c'4 \time 5/16 c'4 c'16 } } } .. container:: example Spells tuplets as diminutions: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... nested_music = rmakers.note(durations) ... components = abjad.sequence.flatten(nested_music) ... container = abjad.Container(components) ... components = abjad.mutate.eject_contents(container) ... lilypond_file = rmakers.example(components, time_signatures) ... return lilypond_file >>> pairs = [(5, 14), (3, 7)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak edge-height #'(0.7 . 0) \times 8/14 { #(ly:expect-warning "strange time signature found") \time 5/14 c'2 ~ c'8 } \tweak edge-height #'(0.7 . 0) \times 4/7 { #(ly:expect-warning "strange time signature found") \time 3/7 c'2. } } } } .. container:: example Spells tuplets as augmentations: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... nested_music = rmakers.note(durations) ... components = abjad.sequence.flatten(nested_music) ... container = abjad.Container(components) ... rmakers.force_augmentation(container) ... components = abjad.mutate.eject_contents(container) ... lilypond_file = rmakers.example(components, time_signatures) ... return lilypond_file >>> pairs = [(5, 14), (3, 7)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \tweak edge-height #'(0.7 . 0) \times 8/7 { #(ly:expect-warning "strange time signature found") \time 5/14 c'4 ~ c'16 } \tweak text #tuplet-number::calc-fraction-text \tweak edge-height #'(0.7 . 0) \times 8/7 { #(ly:expect-warning "strange time signature found") \time 3/7 c'4. } } } } .. container:: example Forces rest in logical tie 0: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... nested_music = rmakers.note(durations) ... components = abjad.sequence.flatten(nested_music) ... container = abjad.Container(components) ... logical_tie = abjad.select.logical_tie(container, 0) ... rmakers.force_rest(logical_tie) ... components = abjad.mutate.eject_contents(container) ... lilypond_file = rmakers.example(components, time_signatures) ... return lilypond_file >>> pairs = [(5, 8), (2, 8), (2, 8), (5, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 5/8 r2 r8 \time 2/8 c'4 c'4 \time 5/8 c'2 ~ c'8 } } } .. container:: example Forces rests in first two logical ties: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... nested_music = rmakers.note(durations) ... components = abjad.sequence.flatten(nested_music) ... container = abjad.Container(components) ... logical_tie = abjad.select.logical_ties(container)[:2] ... rmakers.force_rest(logical_tie) ... components = abjad.mutate.eject_contents(container) ... lilypond_file = rmakers.example(components, time_signatures) ... return lilypond_file >>> pairs = [(5, 8), (2, 8), (2, 8), (5, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 5/8 r2 r8 \time 2/8 r4 c'4 \time 5/8 c'2 ~ c'8 } } } .. container:: example Forces rests in first and last logical ties: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... nested_music = rmakers.note(durations) ... components = abjad.sequence.flatten(nested_music) ... container = abjad.Container(components) ... logical_ties = abjad.select.logical_ties(container) ... logical_ties = abjad.select.get(logical_ties, [0, -1]) ... rmakers.force_rest(logical_ties) ... components = abjad.mutate.eject_contents(container) ... lilypond_file = rmakers.example(components, time_signatures) ... return lilypond_file >>> pairs = [(5, 8), (2, 8), (2, 8), (5, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 5/8 r2 r8 \time 2/8 c'4 c'4 \time 5/8 r2 r8 } } } .. container:: example Rewrites meter: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... nested_music = rmakers.note(durations) ... components = abjad.sequence.flatten(nested_music) ... voice = rmakers.wrap_in_time_signature_staff(components, time_signatures) ... rmakers.rewrite_meter(voice) ... components = abjad.mutate.eject_contents(voice) ... lilypond_file = rmakers.example(components, time_signatures) ... return lilypond_file >>> pairs = [(3, 4), (6, 16), (9, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 3/4 c'2. \time 6/16 c'4. \time 9/16 c'4. ~ c'8. } } } """ tag = tag or abjad.Tag() tag = tag.append(_function_name(inspect.currentframe())) _assert_are_pairs_durations_or_time_signatures(durations) durations = [abjad.Duration(_) for _ in durations] lists = [] for duration in durations: list_ = abjad.makers.make_leaves( pitches=0, durations=[duration], increase_monotonic=spelling.increase_monotonic, forbidden_note_duration=spelling.forbidden_note_duration, forbidden_rest_duration=spelling.forbidden_rest_duration, tag=tag, ) lists.append(list(list_)) components = abjad.sequence.flatten(lists) assert all(isinstance(_, abjad.Leaf | abjad.Tuplet) for _ in components) return components
[docs]def talea( durations, counts: typing.Sequence[int], denominator: int, *, advance: int = 0, end_counts: typing.Sequence[int] = (), extra_counts: typing.Sequence[int] = (), preamble: typing.Sequence[int] = (), previous_state: dict | None = None, read_talea_once_only: bool = False, spelling: _classes.Spelling = _classes.Spelling(), state: dict | None = None, tag: abjad.Tag | None = None, ) -> list[abjad.Tuplet]: r""" Reads ``counts`` cyclically and makes one tuplet for each duration in ``durations``. Repeats talea of 1/16, 2/16, 3/16, 4/16: .. container:: example >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.talea(durations, [1, 2, 3, 4], 16) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = [(3, 8), (4, 8), (3, 8), (4, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 3/8 c'16 [ c'8 c'8. ] \time 4/8 c'4 c'16 [ c'8 c'16 ] ~ \time 3/8 c'8 c'4 \time 4/8 c'16 [ c'8 c'8. c'8 ] } } } .. container:: example Using ``rmakers.talea()`` with the ``extra_counts`` keyword. >>> def make_lilypond_file(pairs, extra_counts): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.talea( ... durations, ... [1, 2, 3, 4], ... 16, ... extra_counts=extra_counts, ... ) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.swap_trivial(voice) ... return lilypond_file .. container:: example **#1.** Set ``extra_counts=[0, 1]`` to add one extra count to every other tuplet: >>> pairs = [(3, 8), (4, 8), (3, 8), (4, 8)] >>> lilypond_file = make_lilypond_file(pairs, extra_counts=[0, 1]) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { { \time 3/8 c'16 [ c'8 c'8. ] } \times 8/9 { \time 4/8 c'4 c'16 [ c'8 c'8 ] ~ } { \time 3/8 c'16 c'4 c'16 } \times 8/9 { \time 4/8 c'8 [ c'8. ] c'4 } } } } .. container:: example **#2.** Set ``extra_counts=[0, 2]`` to add two extra counts to every other tuplet: >>> pairs = [(3, 8), (4, 8), (3, 8), (4, 8)] >>> lilypond_file = make_lilypond_file(pairs, extra_counts=[0, 2]) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { { \time 3/8 c'16 [ c'8 c'8. ] } \times 4/5 { \time 4/8 c'4 c'16 [ c'8 c'8. ] } { \time 3/8 c'4 c'16 [ c'16 ] ~ } \times 4/5 { \time 4/8 c'16 [ c'8. ] c'4 c'16 [ c'16 ] } } } } .. container:: example **#3.** Set ``extra_counts=[0, -1]`` to remove one count from every other tuplet: >>> pairs = [(3, 8), (4, 8), (3, 8), (4, 8)] >>> lilypond_file = make_lilypond_file(pairs, extra_counts=[0, -1]) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { { \time 3/8 c'16 [ c'8 c'8. ] } \tweak text #tuplet-number::calc-fraction-text \times 8/7 { \time 4/8 c'4 c'16 [ c'8 ] } { \time 3/8 c'8. [ c'8. ] ~ } \tweak text #tuplet-number::calc-fraction-text \times 8/7 { \time 4/8 c'16 [ c'16 c'8 c'8. ] } } } } .. container:: example **Reading talea once only.** Set ``read_talea_once_only=True`` to raise an exception if input durations exceed that of a single reading of talea. The effect is to ensure that a talea is long enough to cover all durations without repeating. Useful when, for example, interpolating from short durations to long durations. .. container:: example Using ``rmakers.talea()`` with the ``preamble`` keyword. .. container:: example Preamble less than total duration: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.talea( ... durations, [8, -4, 8], 32, preamble=[1, 1, 1, 1] ... ) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = [(3, 8), (4, 8), (3, 8), (4, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 3/8 c'32 [ c'32 c'32 c'32 ] c'4 \time 4/8 r8 c'4 c'8 ~ \time 3/8 c'8 r8 c'8 ~ \time 4/8 c'8 c'4 r8 } } } .. container:: example Preamble more than total duration; ignores counts: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.talea( ... durations, [8, -4, 8], 32, preamble=[32, 32, 32, 32] ... ) ... container = abjad.Container(tuplets) ... rmakers.beam(container) ... rmakers.extract_trivial(container) ... components = abjad.mutate.eject_contents(container) ... lilypond_file = rmakers.example(components, time_signatures) ... return lilypond_file >>> pairs = [(3, 8), (4, 8), (3, 8), (4, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 3/8 c'4. ~ \time 4/8 c'2 ~ \time 3/8 c'8 c'4 ~ \time 4/8 c'2 } } } .. container:: example Using ``rmakers.talea()`` with the ``end_counts`` keyword. .. container:: example >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.talea( ... durations, [8, -4, 8], 32, end_counts=[1, 1, 1, 1] ... ) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = [(3, 8), (4, 8), (3, 8), (4, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 3/8 c'4 r8 \time 4/8 c'4 c'4 \time 3/8 r8 c'4 \time 4/8 c'4 r8 c'32 [ c'32 c'32 c'32 ] } } } .. container:: example REGRESSION. End counts leave 5-durated tie in tact: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.talea(durations, [6], 16, end_counts=[1]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = [(3, 8), (3, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \time 3/8 c'4. c'4 ~ c'16 [ c'16 ] } } } """ tag = tag or abjad.Tag() tag = tag.append(_function_name(inspect.currentframe())) _assert_are_pairs_durations_or_time_signatures(durations) durations = [abjad.Duration(_) for _ in durations] talea = _classes.Talea( counts=counts, denominator=denominator, end_counts=end_counts, preamble=preamble, ) talea = talea.advance(advance) previous_state = previous_state or {} if state is None: state = {} tuplets = _make_talea_tuplets( durations, extra_counts, previous_state, read_talea_once_only, spelling, state, talea, tag, ) voice = abjad.Voice(tuplets) logical_ties_produced = len(abjad.select.logical_ties(voice)) new_state = _make_state_dictionary( durations_consumed=len(durations), logical_ties_produced=logical_ties_produced, previous_durations_consumed=previous_state.get("durations_consumed", 0), previous_incomplete_last_note=previous_state.get("incomplete_last_note", False), previous_logical_ties_produced=previous_state.get("logical_ties_produced", 0), state=state, ) tuplets = abjad.mutate.eject_contents(voice) assert all(isinstance(_, abjad.Tuplet) for _ in tuplets), repr(tuplets) state.clear() state.update(new_state) return tuplets
[docs]def tuplet( durations, tuplet_ratios: typing.Sequence[tuple[int, ...]], *, # TODO: is 'denominator' unused? # TODO: remove in favor of dedicated denominator control commands: denominator: int | abjad.Duration | str | None = None, # TODO: is 'spelling' unused? spelling: _classes.Spelling = _classes.Spelling(), tag: abjad.Tag | None = None, ) -> list[abjad.Tuplet]: r""" Makes one tuplet for each duration in ``durations``. Makes tuplets with ``3:2`` ratios: .. container:: example >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(3, 2)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... return lilypond_file >>> pairs = [(1, 2), (3, 8), (5, 16), (5, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 4/5 { \time 1/2 c'4. c'4 } \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'4. c'4 } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 5/16 c'8. [ c'8 ] } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { c'8. [ c'8 ] } } } } .. container:: example Makes tuplets with alternating ``1:-1`` and ``3:1`` ratios: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(1, -1), (3, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... return lilypond_file >>> pairs = [(1, 2), (3, 8), (5, 16), (5, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 1/2 c'4 r4 } \tweak text #tuplet-number::calc-fraction-text \times 3/4 { \time 3/8 c'4. c'8 } \tweak text #tuplet-number::calc-fraction-text \times 5/6 { \time 5/16 c'8. r8. } \tweak text #tuplet-number::calc-fraction-text \times 5/4 { c'8. [ c'16 ] } } } } .. container:: example Beams each tuplet: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(1, 1, 1, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... return lilypond_file >>> pairs = [(5, 8), (3, 8), (6, 8), (4, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \times 5/6 { \time 5/8 c'8. [ c'8. c'8. c'8. ] } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 3/8 c'16. [ c'16. c'16. c'16. ] } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 6/8 c'8. [ c'8. c'8. c'8. ] } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 4/8 c'8 [ c'8 c'8 c'8 ] } } } } .. container:: example Beams each tuplet: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(1, 1, 1, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... return lilypond_file >>> pairs = [(5, 8), (3, 8), (6, 8), (4, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \times 5/6 { \time 5/8 c'8. [ c'8. c'8. c'8. ] } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 3/8 c'16. [ c'16. c'16. c'16. ] } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 6/8 c'8. [ c'8. c'8. c'8. ] } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 4/8 c'8 [ c'8 c'8 c'8 ] } } } } .. container:: example Beams tuplets together: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(1, 1, 2, 1, 1), (3, 1, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... rmakers.beam_groups(tuplets) ... return lilypond_file >>> pairs = [(5, 8), (3, 8), (6, 8), (4, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \times 5/9 { \set stemLeftBeamCount = 0 \set stemRightBeamCount = 1 \time 5/8 c'8. [ \set stemLeftBeamCount = 1 \set stemRightBeamCount = 0 c'8. ] c'4. \set stemLeftBeamCount = 0 \set stemRightBeamCount = 1 c'8. [ \set stemLeftBeamCount = 1 \set stemRightBeamCount = 0 c'8. ] } \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'4. \set stemLeftBeamCount = 0 \set stemRightBeamCount = 1 c'8 [ \set stemLeftBeamCount = 1 \set stemRightBeamCount = 1 c'8 } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \set stemLeftBeamCount = 1 \set stemRightBeamCount = 1 \time 6/8 c'8 \set stemLeftBeamCount = 1 \set stemRightBeamCount = 0 c'8 ] c'4 \set stemLeftBeamCount = 0 \set stemRightBeamCount = 1 c'8 [ \set stemLeftBeamCount = 1 \set stemRightBeamCount = 0 c'8 ] } \times 4/5 { \time 4/8 c'4. \set stemLeftBeamCount = 0 \set stemRightBeamCount = 1 c'8 [ \set stemLeftBeamCount = 1 \set stemRightBeamCount = 0 c'8 ] } } } } .. container:: example Ties nothing: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(2, 3), (1, -2, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... return lilypond_file >>> pairs = [(1, 2), (3, 8), (5, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 4/5 { \time 1/2 c'4 c'4. } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 3/8 c'16. r8. c'16. } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 5/16 c'8 [ c'8. ] } } } } .. container:: example Ties across all tuplets: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(2, 3), (1, -2, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... tuplets = abjad.select.tuplets(voice)[:-1] ... leaves = [abjad.select.leaf(_, -1) for _ in tuplets] ... rmakers.tie(leaves) ... rmakers.beam(voice) ... return lilypond_file >>> pairs = [(1, 2), (3, 8), (5, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 4/5 { \time 1/2 c'4 c'4. ~ } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 3/8 c'16. r8. c'16. ~ } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 5/16 c'8 [ c'8. ] } } } } .. container:: example Ties across every other tuplet: >>> def make_lilypond_file(durations): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(2, 3), (1, -2, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... tuplets = abjad.select.tuplets(voice)[:-1] ... tuplets = abjad.select.get(tuplets, [0], 2) ... leaves = [abjad.select.leaf(_, -1) for _ in tuplets] ... rmakers.tie(leaves) ... rmakers.beam(voice) ... return lilypond_file >>> pairs = [(1, 2), (3, 8), (5, 16), (5, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 4/5 { \time 1/2 c'4 c'4. ~ } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 3/8 c'16. r8. c'16. } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 5/16 c'8 [ c'8. ] ~ } \tweak text #tuplet-number::calc-fraction-text \times 5/6 { c'16. r8. c'16. } } } } .. container:: example Makes diminished tuplets: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(2, 1)]) ... container = abjad.Container(tuplets) ... rmakers.force_diminution(container) ... rmakers.beam(container) ... components = abjad.mutate.eject_contents(container) ... lilypond_file = rmakers.example(components, time_signatures) ... return lilypond_file >>> pairs = [(2, 8), (2, 8), (4, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 2/3 { \time 2/8 c'4 c'8 } \times 2/3 { c'4 c'8 } \times 2/3 { \time 4/8 c'2 c'4 } } } } .. container:: example Makes augmented tuplets: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(2, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.force_augmentation(voice) ... rmakers.beam(voice) ... return lilypond_file >>> pairs = [(2, 8), (2, 8), (4, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \times 4/3 { \time 2/8 c'8 [ c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 4/3 { c'8 [ c'16 ] } \tweak text #tuplet-number::calc-fraction-text \times 4/3 { \time 4/8 c'4 c'8 } } } } .. container:: example Makes diminished tuplets and does not rewrite dots: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(1, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.force_diminution(voice) ... return lilypond_file >>> pairs = [(2, 8), (3, 8), (7, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 2/8 c'8 [ c'8 ] } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 3/8 c'8. [ c'8. ] } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 7/16 c'8.. [ c'8.. ] } } } } .. container:: example Makes diminished tuplets and rewrites dots: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(1, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.rewrite_dots(voice) ... rmakers.force_diminution(voice) ... rmakers.beam(voice) ... return lilypond_file >>> pairs = [(2, 8), (3, 8), (7, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 2/8 c'8 [ c'8 ] } \tweak text #tuplet-number::calc-fraction-text \times 3/4 { \time 3/8 c'4 c'4 } \tweak text #tuplet-number::calc-fraction-text \times 7/8 { \time 7/16 c'4 c'4 } } } } .. container:: example Makes augmented tuplets and does not rewrite dots: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(1, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.force_augmentation(voice) ... return lilypond_file >>> pairs = [(2, 8), (3, 8), (7, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 2/8 c'8 [ c'8 ] } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 3/8 c'8. [ c'8. ] } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 7/16 c'8.. [ c'8.. ] } } } } .. container:: example Makes augmented tuplets and rewrites dots: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(1, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.rewrite_dots(voice) ... rmakers.force_augmentation(voice) ... return lilypond_file >>> pairs = [(2, 8), (3, 8), (7, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 2/8 c'8 [ c'8 ] } \tweak text #tuplet-number::calc-fraction-text \times 3/2 { \time 3/8 c'8 [ c'8 ] } \tweak text #tuplet-number::calc-fraction-text \times 7/4 { \time 7/16 c'8 [ c'8 ] } } } } .. container:: example Leaves trivializable tuplets as-is when ``trivialize`` is false: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(3, -2), (1,), (-2, 3), (1, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.rewrite_dots(voice) ... return lilypond_file >>> pairs = [(3, 8), (3, 8), (3, 8), (3, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'4. r4 } \tweak text #tuplet-number::calc-fraction-text \times 3/2 { c'4 } \tweak text #tuplet-number::calc-fraction-text \times 3/5 { r4 c'4. } \tweak text #tuplet-number::calc-fraction-text \times 3/2 { c'8 [ c'8 ] } } } } .. container:: example Rewrites trivializable tuplets when ``trivialize`` is true. Measures 2 and 4 contain trivial tuplets with 1:1 ratios. To remove these trivial tuplets, set ``extract_trivial`` as shown in the next example: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(3, -2), (1,), (-2, 3), (1, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.trivialize(voice) ... return lilypond_file >>> pairs = [(3, 8), (3, 8), (3, 8), (3, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'4. r4 } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { c'4. } \tweak text #tuplet-number::calc-fraction-text \times 3/5 { r4 c'4. } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { c'8. [ c'8. ] } } } } REGRESSION: Ignores ``trivialize`` and respects ``rewrite_dots`` when both are true. Measures 2 and 4 are first rewritten as trivial but then supplied again with nontrivial prolation when removing dots. The result is that measures 2 and 4 carry nontrivial prolation with no dots: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(3, -2), (1,), (-2, 3), (1, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.trivialize(voice) ... rmakers.rewrite_dots(voice) ... return lilypond_file >>> pairs = [(3, 8), (3, 8), (3, 8), (3, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'4. r4 } \tweak text #tuplet-number::calc-fraction-text \times 3/2 { c'4 } \tweak text #tuplet-number::calc-fraction-text \times 3/5 { r4 c'4. } \tweak text #tuplet-number::calc-fraction-text \times 3/2 { c'8 [ c'8 ] } } } } .. container:: example Leaves trivial tuplets as-is when ``extract_trivial`` is false: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(2, 3), (1, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... tuplets = abjad.select.tuplets(voice)[:-1] ... leaves = [abjad.select.leaf(_, -1) for _ in tuplets] ... rmakers.tie(leaves) ... rmakers.beam(voice) ... return lilypond_file >>> pairs = [(3, 8), (2, 8), (3, 8), (2, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'4 c'4. ~ } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 2/8 c'8 [ c'8 ] ~ } \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'4 c'4. ~ } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 2/8 c'8 [ c'8 ] } } } } .. container:: example Extracts trivial tuplets when ``extract_trivial`` is true. Measures 2 and 4 in the example below now contain only a flat list of notes: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(2, 3), (1, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... tuplets = abjad.select.tuplets(voice)[:-1] ... leaves = [abjad.select.leaf(_, -1) for _ in tuplets] ... rmakers.tie(leaves) ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... return lilypond_file >>> pairs = [(3, 8), (2, 8), (3, 8), (2, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'4 c'4. ~ } \time 2/8 c'8 [ c'8 ] ~ \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'4 c'4. ~ } \time 2/8 c'8 [ c'8 ] } } } .. note:: Flattening trivial tuplets makes it possible subsequently to rewrite the meter of the untupletted notes. .. container:: example REGRESSION: Very long ties are preserved when ``extract_trivial`` is true: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(2, 3), (1, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.extract_trivial(voice) ... notes = abjad.select.notes(voice)[:-1] ... rmakers.tie(notes) ... return lilypond_file >>> pairs = [(3, 8), (2, 8), (3, 8), (2, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'4 ~ c'4. ~ } \time 2/8 c'8 [ ~ c'8 ] ~ \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'4 ~ c'4. ~ } \time 2/8 c'8 [ ~ c'8 ] } } } .. container:: example Force-rests every other tuplet: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(4, 1)]) ... container = abjad.Container(tuplets) ... tuplets = abjad.select.tuplets(container) ... tuplets = abjad.select.get(tuplets, [1], 2) ... rmakers.force_rest(tuplets) ... rmakers.rewrite_rest_filled(container) ... rmakers.extract_trivial(container) ... components = abjad.mutate.eject_contents(container) ... lilypond_file = rmakers.example(components, time_signatures) ... return lilypond_file >>> pairs = [(3, 8), (4, 8), (3, 8), (4, 8)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 4/5 { \time 3/8 c'4. c'16. } \time 4/8 r2 \times 4/5 { \time 3/8 c'4. c'16. } \time 4/8 r2 } } } .. container:: example Tuplet numerators and denominators are reduced to numbers that are relatively prime when ``denominator`` is set to none. This means that ratios like ``6:4`` and ``10:8`` do not arise: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(1, 4)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.rewrite_dots(voice) ... return lilypond_file >>> pairs = [(2, 16), (4, 16), (6, 16), (8, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 4/5 { \time 2/16 c'32 [ c'8 ] } \times 4/5 { \time 4/16 c'16 c'4 } \tweak text #tuplet-number::calc-fraction-text \times 6/5 { \time 6/16 c'16 c'4 } \times 4/5 { \time 8/16 c'8 c'2 } } } } .. container:: example The preferred denominator of each tuplet is set in terms of a unit duration when ``denominator`` is set to a duration. The setting does not affect the first tuplet: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(1, 4)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.rewrite_dots(voice) ... rmakers.denominator(voice, (1, 16)) ... return lilypond_file >>> pairs = [(2, 16), (4, 16), (6, 16), (8, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 4/5 { \time 2/16 c'32 [ c'8 ] } \times 4/5 { \time 4/16 c'16 c'4 } \tweak text #tuplet-number::calc-fraction-text \times 6/5 { \time 6/16 c'16 c'4 } \times 8/10 { \time 8/16 c'8 c'2 } } } } .. container:: example Sets the preferred denominator of each tuplet in terms 32nd notes. The setting affects all tuplets: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(1, 4)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.rewrite_dots(voice) ... rmakers.denominator(voice, (1, 32)) ... return lilypond_file >>> pairs = [(2, 16), (4, 16), (6, 16), (8, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 4/5 { \time 2/16 c'32 [ c'8 ] } \times 8/10 { \time 4/16 c'16 c'4 } \tweak text #tuplet-number::calc-fraction-text \times 12/10 { \time 6/16 c'16 c'4 } \times 16/20 { \time 8/16 c'8 c'2 } } } } .. container:: example Sets the preferred denominator each tuplet in terms 64th notes. The setting affects all tuplets: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(1, 4)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.rewrite_dots(voice) ... rmakers.denominator(voice, (1, 64)) ... return lilypond_file >>> pairs = [(2, 16), (4, 16), (6, 16), (8, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 8/10 { \time 2/16 c'32 [ c'8 ] } \times 16/20 { \time 4/16 c'16 c'4 } \tweak text #tuplet-number::calc-fraction-text \times 24/20 { \time 6/16 c'16 c'4 } \times 32/40 { \time 8/16 c'8 c'2 } } } } .. container:: example The preferred denominator of each tuplet is set directly when ``denominator`` is set to a positive integer. This example sets the preferred denominator of each tuplet to ``8``. Setting does not affect the third tuplet: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(1, 4)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.rewrite_dots(voice) ... rmakers.denominator(voice, 8) ... return lilypond_file >>> pairs = [(2, 16), (4, 16), (6, 16), (8, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 8/10 { \time 2/16 c'32 [ c'8 ] } \times 8/10 { \time 4/16 c'16 c'4 } \tweak text #tuplet-number::calc-fraction-text \times 6/5 { \time 6/16 c'16 c'4 } \times 8/10 { \time 8/16 c'8 c'2 } } } } .. container:: example Sets the preferred denominator of each tuplet to ``12``. Setting affects all tuplets: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(1, 4)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.rewrite_dots(voice) ... rmakers.denominator(voice, 12) ... return lilypond_file >>> pairs = [(2, 16), (4, 16), (6, 16), (8, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 12/15 { \time 2/16 c'32 [ c'8 ] } \times 12/15 { \time 4/16 c'16 c'4 } \tweak text #tuplet-number::calc-fraction-text \times 12/10 { \time 6/16 c'16 c'4 } \times 12/15 { \time 8/16 c'8 c'2 } } } } .. container:: example Sets the preferred denominator of each tuplet to ``13``. Setting does not affect any tuplet: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(1, 4)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... rmakers.rewrite_dots(voice) ... rmakers.denominator(voice, 13) ... return lilypond_file >>> pairs = [(2, 16), (4, 16), (6, 16), (8, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 4/5 { \time 2/16 c'32 [ c'8 ] } \times 4/5 { \time 4/16 c'16 c'4 } \tweak text #tuplet-number::calc-fraction-text \times 6/5 { \time 6/16 c'16 c'4 } \times 4/5 { \time 8/16 c'8 c'2 } } } } .. container:: example >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tag = abjad.Tag("TUPLET_RHYTHM_MAKER") ... tuplets = rmakers.tuplet(durations, [(3, 2)], tag=tag) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice, tag=tag) ... return lilypond_file >>> pairs = [(1, 2), (3, 8), (5, 16), (5, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score, tags=True) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() \times 4/5 %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() { \time 1/2 %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() c'4. %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() c'4 %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() } %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() \tweak text #tuplet-number::calc-fraction-text %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() \times 3/5 %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() { \time 3/8 %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() c'4. %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() c'4 %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() } %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() \tweak text #tuplet-number::calc-fraction-text %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() \times 1/1 %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() { \time 5/16 %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() c'8. %! TUPLET_RHYTHM_MAKER %! rmakers.beam() [ %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() c'8 %! TUPLET_RHYTHM_MAKER %! rmakers.beam() ] %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() } %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() \tweak text #tuplet-number::calc-fraction-text %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() \times 1/1 %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() { %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() c'8. %! TUPLET_RHYTHM_MAKER %! rmakers.beam() [ %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() c'8 %! TUPLET_RHYTHM_MAKER %! rmakers.beam() ] %! TUPLET_RHYTHM_MAKER %! rmakers.tuplet() } } } } .. container:: example Makes tuplets with ``3:2`` ratios: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(3, 2)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... return lilypond_file >>> pairs = [(1, 2), (3, 8), (5, 16), (5, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \times 4/5 { \time 1/2 c'4. c'4 } \tweak text #tuplet-number::calc-fraction-text \times 3/5 { \time 3/8 c'4. c'4 } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 5/16 c'8. [ c'8 ] } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { c'8. [ c'8 ] } } } } .. container:: example Makes tuplets with alternating ``1:-1`` and ``3:1`` ratios: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(1, -1), (3, 1)]) ... lilypond_file = rmakers.example(tuplets, time_signatures) ... voice = lilypond_file["Voice"] ... rmakers.beam(voice) ... return lilypond_file >>> pairs = [(1, 2), (3, 8), (5, 16), (5, 16)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 1/2 c'4 r4 } \tweak text #tuplet-number::calc-fraction-text \times 3/4 { \time 3/8 c'4. c'8 } \tweak text #tuplet-number::calc-fraction-text \times 5/6 { \time 5/16 c'8. r8. } \tweak text #tuplet-number::calc-fraction-text \times 5/4 { c'8. [ c'16 ] } } } } .. container:: example Makes length-1 tuplets: >>> def make_lilypond_file(pairs): ... time_signatures = rmakers.time_signatures(pairs) ... durations = [abjad.Duration(_) for _ in time_signatures] ... tuplets = rmakers.tuplet(durations, [(1,)]) ... container = abjad.Container(tuplets) ... components = abjad.mutate.eject_contents(container) ... lilypond_file = rmakers.example(components, time_signatures) ... return lilypond_file >>> pairs = [(1, 5), (1, 4), (1, 6), (7, 9)] >>> lilypond_file = make_lilypond_file(pairs) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file["Score"] >>> string = abjad.lilypond(score) >>> print(string) \context Score = "Score" { \context RhythmicStaff = "Staff" \with { \override Clef.stencil = ##f } { \context Voice = "Voice" { \tweak edge-height #'(0.7 . 0) \times 4/5 { #(ly:expect-warning "strange time signature found") \time 1/5 c'4 } \tweak text #tuplet-number::calc-fraction-text \times 1/1 { \time 1/4 c'4 } \tweak edge-height #'(0.7 . 0) \times 2/3 { #(ly:expect-warning "strange time signature found") \time 1/6 c'4 } \tweak edge-height #'(0.7 . 0) \times 8/9 { #(ly:expect-warning "strange time signature found") \time 7/9 c'2.. } } } } """ tag = tag or abjad.Tag() tag = tag.append(_function_name(inspect.currentframe())) _assert_are_pairs_durations_or_time_signatures(durations) durations = [abjad.Duration(_) for _ in durations] tuplets = _make_tuplet_rhythm_maker_music( durations, tuplet_ratios, tag=tag, ) assert all(isinstance(_, abjad.Tuplet) for _ in tuplets), repr(tuplets) return tuplets