コード例 #1
0
def prettify_rewrite_meter(
    selection: abjad.Selection,
    meter: Union[abjad.Meter, abjad.TimeSignature],
    *,
    fuse_across_groups_of_beats: bool = True,
    fuse_quadruple_meter: bool = True,
    fuse_triple_meter: bool = True,
    extract_trivial_tuplets: bool = True,
    split_quadruple_meter: bool = True,
) -> None:
    r"""Mutates an input |abjad.Selection| in place and has no return value;
    this function fuses pitched leaves according to the rules shown below,
    improving the default output of |abjad.mutate().rewrite_meter()|.

    Basic usage:
        Meters whose denominators are a crotchet or longer get tied notes
        within a beat after |abjad.mutate().rewrite_meter()| when they are at
        an offset ``denominator / 4``, so a rhythm such as  ``denominator / 4``
        ``denominator / 2`` ``denominator / 4`` becomes ``denominator / 4``
        ``denominator / 4`` ``~`` ``denominator / 4`` ``denominator / 4``. This
        function looks for those specific cases and fuses them, generating an
        output which is often more readable.

        >>> staff = abjad.Staff(
        ...     r"\time 3/4 c'16 d'8 e'16 f'16 g'16 a'8 b'8 c''16 d''16"
        ... )
        >>> meter = abjad.Meter((3, 4))
        >>> abjad.mutate(staff[:]).rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            \time 3/4
            c'16
            d'16
            ~
            d'16
            e'16
            f'16
            g'16
            a'8
            b'8
            c''16
            d''16
        }

        .. figure:: ../_images/prettify_rewrite_meter-vlnd7l5fb7s.png

        >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            \time 3/4
            c'16
            d'8
            e'16
            f'16
            g'16
            a'8
            b'8
            c''16
            d''16
        }

        .. figure:: ../_images/prettify_rewrite_meter-e7vfnese0ut.png

    .. note::

        Auxjad automatically adds this function as an extension method to
        |abjad.mutate()|. It can thus be used from either
        :func:`auxjad.mutate()` or |abjad.mutate()|. Therefore, the two lines
        below are equivalent:

        >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(meter)
        >>> abjad.mutate(staff[:]).prettify_rewrite_meter(meter)

    Other examples:
        The rhythm of the leaves just before and after the two leaves to be
        fused can be different than ``denominator / 4``, as the function
        searches for logical ties of specific length and offset, and its
        surroundings do not matter.

        >>> staff = abjad.Staff(r"\time 3/4 c'32 d'32 e'8 f'16 "
        ...                     r"\times 2/3 {g'32 a'32 b'32} c''8 "
        ...                     r"r16 r32. d''64 e''8 f''32 g''32"
        ...                     )
        >>> meter = abjad.Meter((3, 4))
        >>> abjad.mutate(staff[:]).rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            \time 3/4
            c'32
            d'32
            e'16
            ~
            e'16
            f'16
            \times 2/3 {
                g'32
                a'32
                b'32
            }
            c''16
            ~
            c''16
            r16
            r32.
            d''64
            e''16
            ~
            e''16
            f''32
            g''32
        }

        .. figure:: ../_images/prettify_rewrite_meter-kw09gse2zxj.png

        >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            \time 3/4
            c'32
            d'32
            e'8
            f'16
            \times 2/3 {
                g'32
                a'32
                b'32
            }
            c''8
            r16
            r32.
            d''64
            e''8
            f''32
            g''32
        }

        .. figure:: ../_images/prettify_rewrite_meter-u5gmtdippsa.png

    ``fuse_across_groups_of_beats``:
        By default, this function also fuses rhythms of type
        ``denominator / 2`` ``denominator / 2`` ``~`` ``denominator / 2``
        ``denominator / 2``, becoming ``denominator / 2`` ``denominator``
        ``denominator / 2``. This is only applied when the meter's structure
        has a depth of 2, which is the case for meters with numerators equal to
        or larger than ``5``.

        >>> staff = abjad.Staff(r"\time 6/4 c'8 d'4 e'4 f'4 g'4 a'4 b'8")
        >>> meter = abjad.Meter((6, 4))
        >>> abjad.mutate(staff[:]).rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            \time 6/4
            c'8
            d'8
            ~
            d'8
            e'8
            ~
            e'8
            f'8
            ~
            f'8
            g'8
            ~
            g'8
            a'8
            ~
            a'8
            b'8
        }

        .. figure:: ../_images/prettify_rewrite_meter-tqi4p0u8qog.png

        >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            \time 6/4
            c'8
            d'4
            e'4
            f'8
            ~
            f'8
            g'4
            a'4
            b'8
        }

        .. figure:: ../_images/prettify_rewrite_meter-riif1glyqpo.png

        to disable this behaviour, set the optional keyword argument
        ``fuse_across_groups_of_beats`` to ``False``.

        >>> staff = abjad.Staff(r"\time 6/4 c'8 d'4 e'4 f'4 g'4 a'4 b'8")
        >>> meter = abjad.Meter((6, 4))
        >>> abjad.mutate(staff[:]).rewrite_meter(meter)
        >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(
        ...     meter,
        ...     fuse_across_groups_of_beats=False,
        ... )
        >>> abjad.f(staff)
        \new Staff
        {
            \time 6/4
            c'8
            d'8
            ~
            d'8
            e'8
            ~
            e'8
            f'8
            ~
            f'8
            g'8
            ~
            g'8
            a'8
            ~
            a'8
            b'8
        }

        .. figure:: ../_images/prettify_rewrite_meter-ki5xbiteij.png

    |abjad.Meter| with ``increase_monotonic=True``:
        The fused notes will respect the beat structures of such meters, even
        when ``increase_monotonic`` is set to the non-default value ``True``.
        Compare the outputs below.

        >>> staff = abjad.Staff(r"\time 7/4 c'8 d'4 e'4 f'4 g'4 a'4 b'4 c''8")
        >>> meter = abjad.Meter((7, 4))
        >>> abjad.mutate(staff[:]).rewrite_meter(meter)
        >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            \time 7/4
            c'8
            d'4
            e'4
            f'8
            ~
            f'8
            g'4
            a'8
            ~
            a'8
            b'4
            c''8
        }

        .. figure:: ../_images/prettify_rewrite_meter-bud0jhkvvl.png

        >>> staff = abjad.Staff(r"\time 7/4 c'8 d'4 e'4 f'4 g'4 a'4 b'4 c''8")
        >>> meter = abjad.Meter((7, 4), increase_monotonic=True)
        >>> abjad.mutate(staff[:]).rewrite_meter(meter)
        >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            \time 7/4
            c'8
            d'4
            e'8
            ~
            e'8
            f'4
            g'8
            ~
            g'8
            a'4
            b'4
            c''8
        }

        .. figure:: ../_images/prettify_rewrite_meter-47y86pbwwv5.png

    Multiple measures at once:
        This function can take handle multiple measures at once, as long as
        they share the same meter.

        >>> staff = abjad.Staff(r"\time 5/8 c'16 d'8 e'8 f'8 g'8 a'16 ~ "
        ...                     r"a'16 b'8 c''8 d''8 e''8 f''16"
        ...                     )
        >>> meter = abjad.Meter((5, 8))
        >>> for measure in abjad.select(staff[:]).group_by_measure():
        ...     abjad.mutate(staff[:]).rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            \time 5/8
            c'16
            d'16
            ~
            d'16
            e'16
            ~
            e'16
            f'16
            ~
            f'16
            g'16
            ~
            g'16
            a'16
            ~
            a'16
            b'16
            ~
            b'16
            c''16
            ~
            c''16
            d''16
            ~
            d''16
            e''16
            ~
            e''16
            f''16
        }

        .. figure:: ../_images/prettify_rewrite_meter-8jdzmvf9yl.png

        >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            \time 5/8
            c'16
            d'8
            e'8
            f'16
            ~
            f'16
            g'8
            a'16
            ~
            a'16
            b'8
            c''8
            d''16
            ~
            d''16
            e''8
            f''16
        }

        .. figure:: ../_images/prettify_rewrite_meter-pcn8x9hr6bb.png

    Multiple measures:
        Similarly to |abjad.mutate().rewrite_meter()|, this function accepts
        selections of multiple measures:

        >>> staff = abjad.Staff(r"\time 4/4 c'8 d'4 e'4 f'4 g'8 | "
        ...                     r"a'8 b'4 c''8 d''16 e''4 f''8.")
        >>> meter = abjad.Meter((4, 4))
        >>> for measure in abjad.select(staff[:]).group_by_measure():
        ...     abjad.mutate(measure).rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            \time 4/4
            c'8
            d'8
            ~
            d'8
            e'8
            ~
            e'8
            f'8
            ~
            f'8
            g'8
            a'8
            b'8
            ~
            b'8
            c''8
            d''16
            e''8.
            ~
            e''16
            f''8.
        }

        .. figure:: ../_images/prettify_rewrite_meter-s8fg7a2k0tr.png

        >>> for measure in abjad.select(staff[:]).group_by_measure():
        ...     auxjad.mutate(measure).prettify_rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            \time 4/4
            c'8
            d'4
            e'8
            ~
            e'8
            f'4
            g'8
            a'8
            b'4
            c''8
            d''16
            e''8.
            ~
            e''16
            f''8.
        }

        .. figure:: ../_images/prettify_rewrite_meter-rgd7ok7fkq.png

    Multiple measures with different meters:
        If the measures have different meters, they can be passed on
        individually using :func:`zip()` as shown below.

        >>> staff = abjad.Staff(r"\time 3/4 c'8 d'4 e'4 f'16 g'16 | "
        ...                     r"\time 4/4 a'8 b'4 c''8 d''16 e''4 f''8.")
        >>> meters = [abjad.Meter((3, 4)), abjad.Meter((4, 4))]
        >>> for meter, measure in zip(
        ...     meters,
        ...     abjad.select(staff[:]).group_by_measure(),
        ... ):
        ...     abjad.mutate(measure).rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            \time 3/4
            c'8
            d'8
            ~
            d'8
            e'8
            ~
            e'8
            f'16
            g'16
            \time 4/4
            a'8
            b'8
            ~
            b'8
            c''8
            d''16
            e''8.
            ~
            e''16
            f''8.
        }

        .. figure:: ../_images/prettify_rewrite_meter-o2izz0m7s9k.png

        >>> for meter, measure in zip(
        ...     meters,
        ...     abjad.select(staff[:]).group_by_measure(),
        ... ):
        ...     auxjad.mutate(measure).prettify_rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            \time 3/4
            c'8
            d'4
            e'4
            f'16
            g'16
            \time 4/4
            a'8
            b'4
            c''8
            d''16
            e''8.
            ~
            e''16
            f''8.
        }

        .. figure:: ../_images/prettify_rewrite_meter-zh89kk66zon.png

    ``fuse_quadruple_meter``:
        This function also takes care of two special cases, namely quadruple
        and triple meters. By default, it will fuse leaves in quadruple meters
        across beats 1 and 2, and across beats 3 and 4 (as long as they fulfil
        the other requirements of duration and offset).

        >>> staff = abjad.Staff(r"\time 4/4 c'8 d'4 e'4 f'4 g'8")
        >>> meter = abjad.Meter((4, 4))
        >>> abjad.mutate(staff[:]).rewrite_meter(meter)
        >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            \time 4/4
            c'8
            d'4
            e'8
            ~
            e'8
            f'4
            g'8
        }

        .. figure:: ../_images/prettify_rewrite_meter-nap4bbf7mxe.png

        Set ``fuse_quadruple_meter`` to ``False`` to disable this behaviour.

        >>> staff = abjad.Staff(r"\time 4/4 c'8 d'4 e'4 f'4 g'8")
        >>> meter = abjad.Meter((4, 4))
        >>> abjad.mutate(staff[:]).rewrite_meter(meter)
        >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(
        ...     meter,
        ...     fuse_quadruple_meter=False,
        ... )
        >>> abjad.f(staff)
        \new Staff
        {
            \time 4/4
            c'8
            d'8
            ~
            d'8
            e'8
            ~
            e'8
            f'8
            ~
            f'8
            g'8
        }

        .. figure:: ../_images/prettify_rewrite_meter-juipg9nzna.png

    ``fuse_triple_meter``:
        In the case of triple meters, it will fuse leaves across any beat as
        long as the previously mentioned conditions of offset and duration are
        met.

        >>> staff = abjad.Staff(r"\time 3/4 c'8 d'4 e'4 f'8")
        >>> meter = abjad.Meter((3, 4))
        >>> abjad.mutate(staff[:]).rewrite_meter(meter)
        >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            \time 3/4
            c'8
            d'4
            e'4
            f'8
        }

        .. figure:: ../_images/prettify_rewrite_meter-4wg3grpb94p.png

        Similarly to the example before, set ``fuse_triple_meter`` to ``False``
        to disable this behaviour.

        >>> staff = abjad.Staff(r"\time 3/4 c'8 d'4 e'4 f'8")
        >>> meter = abjad.Meter((3, 4))
        >>> abjad.mutate(staff[:]).rewrite_meter(meter)
        >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(
        ...     meter,
        ...     fuse_triple_meter=False,
        ... )
        >>> abjad.f(staff)
        \new Staff
        {
            \time 3/4
            c'8
            d'8
            ~
            d'8
            e'8
            ~
            e'8
            f'8
        }

        .. figure:: ../_images/prettify_rewrite_meter-l16ostzscta.png

    ``extract_trivial_tuplets``:
        By default, this function extracts the contents of tuples that consist
        solely of rests, or solely of tied notes and chords.

        >>> staff = abjad.Staff(
        ...     r"\times 2/3 {c'4 ~ c'8} \times 2/3 {d'8 r4} "
        ...     r"\times 2/3 {r8 r8 r8} \times 2/3 {<e' g'>8 ~ <e' g'>4}"
        ... )
        >>> meter = abjad.Meter((4, 4))
        >>> abjad.mutate(staff[:]).rewrite_meter(meter)
        >>> abjad.mutate(staff[:]).prettify_rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            c'4
            \times 2/3 {
                d'8
                r4
            }
            r4
            <e' g'>4
        }

        .. figure:: ../_images/prettify_rewrite_meter-a72jx4fc1xd.png

        Set ``extract_trivial_tuplets`` to ``False`` to disable this behaviour.

        >>> staff = abjad.Staff(
        ...     r"\times 2/3 {c'4 ~ c'8} \times 2/3 {d'8 r4} "
        ...     r"\times 2/3 {r8 r8 r8} \times 2/3 {<e' g'>8 ~ <e' g'>4}"
        ... )
        >>> meter = abjad.Meter((4, 4))
        >>> abjad.mutate(staff[:]).rewrite_meter(meter)
        >>> abjad.mutate(staff[:]).prettify_rewrite_meter(
        ...     meter,
        ...     extract_trivial_tuplets=False,
        ... )
        >>> abjad.f(staff)
        \new Staff
        {
            \times 2/3 {
                c'4.
            }
            \times 2/3 {
                d'8
                r4
            }
            \times 2/3 {
                r4.
            }
            \times 2/3 {
                <e' g'>4.
            }
        }

        .. figure:: ../_images/prettify_rewrite_meter-v9q0ka94qcd.png

    ``split_quadruple_meter``
        When applying |abjad.mutate().rewrite_meter()| to a selection with
        quadruple meter and without using a deeper ``boundary_depth`` than the
        default, the resulting notation will often have leaves crossing the
        third beat of the measure, as shown below.

        >>> staff = abjad.Staff(
        ...     r"c'4 d'2 r4"
        ...     r"e'4. f'2 g'8"
        ...     r"a'4. b'4. c''4"
        ...     r"d''16 e''8. f''4. g''4 a''8"
        ... )
        >>> meter = abjad.Meter((4, 4))
        >>> for measure in abjad.select(staff[:]).group_by_measure():
        ...     abjad.mutate(measure).rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            c'4
            d'2
            r4
            e'4.
            f'8
            ~
            f'4.
            g'8
            a'4.
            b'4.
            c''4
            d''16
            e''8.
            f''4.
            g''8
            ~
            g''8
            a''8
        }

        .. figure:: ../_images/prettify_rewrite_meter-1wvhrjife1i.png

        This function tests those leaves against a series of rules, splitting
        them when the tests fails. In the case shown above, the first two bars
        are very easy to read rhythmically, but the third and fourth are less
        so. This is due to the dotted crotchet, which starts off a beat,
        crossing the third beat of the measure. This function will split these
        sort of leaves as shown below.

        >>> abjad.mutate(staff[:]).prettify_rewrite_meter(meter)
        >>> abjad.f(staff)
        \new Staff
        {
            c'4
            d'2
            r4
            e'4.
            f'8
            ~
            f'4.
            g'8
            a'4.
            b'8
            ~
            b'4
            c''4
            d''16
            e''8.
            f''4
            ~
            f''8
            g''4
            a''8
        }
        .. figure:: ../_images/prettify_rewrite_meter-56dy04wjzg.png

        Set ``split_quadruple_meter`` to ``False`` to disable this behaviour.

        >>> staff = abjad.Staff(
        ...     r"c'4 d'2 r4"
        ...     r"e'4. f'2 g'8"
        ...     r"a'4. b'4. c''4"
        ...     r"d''16 e''8. f''4. g''4 a''8"
        ... )
        >>> meter = abjad.Meter((4, 4))
        >>> for measure in abjad.select(staff[:]).group_by_measure():
        ...     abjad.mutate(measure).rewrite_meter(meter)
        >>> abjad.mutate(staff[:]).prettify_rewrite_meter(
        ...     meter,
        ...     split_quadruple_meter=False,
        ... )
        >>> abjad.f(staff)
        \new Staff
        {
            c'4
            d'2
            r4
            e'4.
            f'8
            ~
            f'4.
            g'8
            a'4.
            b'4.
            c''4
            d''16
            e''8.
            f''4.
            g''4
            a''8
        }

        .. figure:: ../_images/prettify_rewrite_meter-ww1x0zsxlnd.png

    .. tip::

        Use :func:`auxjad.auto_rewrite_meter()` to automatically apply
        |abjad.mutate().rewrite_meter()| and
        |auxjad.mutate().prettify_rewrite_meter()| to a container with multiple
        time signatures.

    .. warning::

        The input selection must be a contiguous logical voice. When dealing
        with a container with multiple subcontainers (e.g. a score containing
        multiple staves), the best approach is to cycle through these
        subcontainers, applying this function to them individually.
    """
    if not isinstance(selection, abjad.Selection):
        raise TypeError("first argument must be 'abjad.Selection'")
    if not selection.leaves().are_contiguous_logical_voice():
        raise ValueError("first argument must be contiguous logical voice")
    if not isinstance(meter, (abjad.Meter, abjad.TimeSignature)):
        raise TypeError("argument must be 'abjad.Meter' or "
                        "'abjad.TimeSignature'")
    if not isinstance(fuse_across_groups_of_beats, bool):
        raise TypeError("'fuse_across_groups_of_beats' must be 'bool'")
    if not isinstance(fuse_quadruple_meter, bool):
        raise TypeError("'fuse_quadruple_meter' must be 'bool'")
    if not isinstance(fuse_triple_meter, bool):
        raise TypeError("'fuse_triple_meter' must be 'bool'")
    if not isinstance(extract_trivial_tuplets, bool):
        raise TypeError("'extract_trivial_tuplets' must be 'bool'")
    if not isinstance(split_quadruple_meter, bool):
        raise TypeError("'split_quadruple_meter' must be 'bool'")

    if isinstance(meter, abjad.TimeSignature):
        meter = abjad.Meter(meter.pair)

    logical_ties = selection.logical_ties(pitched=True)
    if len(logical_ties) == 0:
        return

    first_leaf = selection.leaf(0)
    initial_offset = abjad.inspect(first_leaf).timespan().start_offset
    base = 1 / meter.denominator

    def _merge_indicators_then_fuse(logical_tie):
        last_indicators = abjad.inspect(logical_tie[-1]).indicators()
        initial_indicators = abjad.inspect(logical_tie[0]).indicators()
        initial_indicators_types = tuple(
            type(indicator) for indicator in initial_indicators)
        abjad.mutate(logical_tie).fuse()
        for indicator in last_indicators:
            if isinstance(indicator, (
                    abjad.Dynamic,
                    abjad.StopSlur,
                    abjad.StopGroup,
                    abjad.StopHairpin,
                    abjad.StopTextSpan,
                    abjad.StopTrillSpan,
                    abjad.StopPianoPedal,
                    abjad.StopPhrasingSlur,
            )):
                if not isinstance(indicator, initial_indicators_types):
                    abjad.attach(indicator, logical_tie[0])

    for logical_tie in logical_ties.filter_duration("==", base / 2):
        offset = abjad.inspect(logical_tie).timespan().start_offset
        offset -= initial_offset
        offset %= base
        if offset == base / 4:
            _merge_indicators_then_fuse(logical_tie)

    if fuse_across_groups_of_beats:
        for logical_tie in logical_ties.filter_duration("==", base):
            offset = abjad.inspect(logical_tie).timespan().start_offset
            offset -= initial_offset
            offset %= meter.duration
            offset_mod = offset % base
            if offset_mod == base / 2:
                if (not offset + base / 2
                        in meter.depthwise_offset_inventory[1]):
                    _merge_indicators_then_fuse(logical_tie)

    if fuse_quadruple_meter and meter.numerator == 4:
        for logical_tie in logical_ties.filter_duration("==", base):
            offset = abjad.inspect(logical_tie).timespan().start_offset
            offset -= initial_offset
            offset %= meter.duration
            offset_mod = offset % base
            if offset_mod == base / 2:
                if not offset + base / 2 in (
                        abjad.Offset(0, 1),
                        abjad.Offset(2 * base),
                        abjad.Offset(4 * base),
                ):
                    _merge_indicators_then_fuse(logical_tie)

    if fuse_triple_meter and meter.numerator == 3:
        for logical_tie in logical_ties.filter_duration("==", base):
            offset = abjad.inspect(logical_tie).timespan().start_offset
            offset -= initial_offset
            offset %= meter.duration
            offset_mod = offset % base
            if offset_mod == base / 2:
                if not offset + base / 2 in (
                        abjad.Offset(0, 1),
                        abjad.Offset(3 * base),
                ):
                    _merge_indicators_then_fuse(logical_tie)

    logical_ties = selection.logical_ties()  # splitting not only pitched
    if split_quadruple_meter and meter.numerator == 4:
        half_point_offset = abjad.Offset(2 * base)
        for logical_tie in logical_ties:
            offset0 = abjad.inspect(logical_tie).timespan().start_offset
            offset0 -= initial_offset
            offset0 %= meter.duration
            if offset0 == abjad.Offset(0, 1):
                # do not split things like c'1, c'2.. r8, c'2. r4, etc.
                continue
            offset1 = abjad.inspect(logical_tie).timespan().stop_offset
            offset1 -= initial_offset
            offset1 %= meter.duration
            if offset1 == abjad.Offset(0, 1):
                offset1 = abjad.Offset(meter.duration)
            if (offset0 % abjad.Offset(base) == abjad.Offset(0, 1)
                    and offset1 % abjad.Offset(base) == abjad.Offset(0, 1)):
                # do not split things like r4 c'2.
                continue
            if offset0 < half_point_offset < offset1:
                if (offset1 == abjad.Offset(meter.duration)
                        and len(logical_tie) == 1):
                    # do not split r8 c'2.., r16 c'2..., etc.
                    break
                if any(
                        abjad.inspect(leaf).duration() == abjad.Duration(2 *
                                                                         base)
                        for leaf in logical_tie):
                    # do not split r8 c'8~c'2 r4, r16 c'8.~c'2~c'8 r8, etc.
                    break
                # do not split tuplets
                getter = abjad.select().logical_ties()
                result = selection.tuplets().map(getter).flatten()
                if logical_tie in result:
                    break
                duration = abjad.Duration(half_point_offset - offset0)
                abjad.mutate(logical_tie).split([duration])

    if extract_trivial_tuplets:
        extract_trivial_tuplets_function(selection)
コード例 #2
0
def merge_partial_tuplets(
    selection: abjad.Selection,
    *,
    merge_across_barlines: bool = False,
) -> None:
    r"""Mutates an input |abjad.Selection| in place and has no return value;
    this function merges all consecutive partial tuplets with the same ratio
    and which sum up to an assignable duration. Partial tuplets can result from
    algorithmic manipulations such as phasing or looping, which can slice
    through a tuplet.

    Basic usage:
        Usage is simple:

        >>> staff = abjad.Staff(r"\times 2/3 {c'1} \times 2/3 {d'2}")
        >>> abjad.show(staff)

        ..  docs::

            \new Staff
            {
                \times 2/3
                {
                    c'1
                }
                \times 2/3
                {
                    d'2
                }
            }

        ..  figure:: ../_images/merge_partial_tuplets-ilr68s15kqb.png

        >>> auxjad.mutate.merge_partial_tuplets(staff[:])
        >>> abjad.show(staff)

        ..  docs::

            \new Staff
            {
                \times 2/3
                {
                    c'1
                    d'2
                }
            }

        ..  figure:: ../_images/merge_partial_tuplets-qe29etsedx.png

    ..  note::

        Auxjad automatically adds this function as an extension function to
        |abjad.mutate|. It can thus be used from either |auxjad.mutate|_ or
        |abjad.mutate| namespaces. Therefore, the two lines below are
        equivalent:

        >>> auxjad.mutate.merge_partial_tuplets(staff[:])
        >>> abjad.mutate.merge_partial_tuplets(staff[:])

    Multiple consecutive partial tuplets:
        This function can also handle several consecutive partial tuplets:

        >>> staff = abjad.Staff(
        ...     r"\times 2/3 {c'2} \times 2/3 {d'2} \times 2/3 {e'2}"
        ... )
        >>> abjad.show(staff)

        ..  docs::

            {
                \times 2/3
                {
                    c'2
                }
                \times 2/3
                {
                    d'2
                }
                \times 2/3
                {
                    e'2
                }
            }

        ..  figure:: ../_images/merge_partial_tuplets-9rh7vpu208j.png

        >>> auxjad.mutate.merge_partial_tuplets(staff[:])
        >>> abjad.show(staff)

        ..  docs::

            \new Staff
            {
                \times 2/3
                {
                    c'2
                    d'2
                    e'2
                }
            }

        ..  figure:: ../_images/merge_partial_tuplets-oy1imqisx2.png

    ``merge_across_barlines``:
        By default, partial tuplets are not merged across barlines.

        >>> staff = abjad.Staff(
        ...     r"\time 3/4 c'2. "
        ...     r"\times 2/3 {d'4} r4 \times 2/3 {e'2} "
        ...     r"\times 2/3 {f'4} r4 \times 2/3 {g'2}"
        ... )
        >>> auxjad.mutate.merge_partial_tuplets(staff[:])
        >>> abjad.show(staff)

        ..  docs::

            \new Staff
            {
                \time 3/4
                c'2.
                \tweak edge-height #'(0.7 . 0)
                \times 2/3
                {
                    d'4
                }
                r4
                \tweak edge-height #'(0.7 . 0)
                \times 2/3
                {
                    e'2
                }
                \tweak edge-height #'(0.7 . 0)
                \times 2/3
                {
                    f'4
                }
                r4
                \tweak edge-height #'(0.7 . 0)
                \times 2/3
                {
                    g'2
                }
            }

        ..  figure:: ../_images/merge_partial_tuplets-3rjib7pctml.png

        To change  this behaviour, set ``merge_across_barlines`` to ``True``.

        >>> staff = abjad.Staff(
        ...     r"\time 3/4 c'2. "
        ...     r"\times 2/3 {d'4} r4 \times 2/3 {e'2} "
        ...     r"\times 2/3 {f'4} r4 \times 2/3 {g'2}"
        ... )
        >>> auxjad.mutate.merge_partial_tuplets(
        ...     staff[:],
        ...     merge_across_barlines=True,
        ... )
        >>> abjad.show(staff)

        ..  docs::

            \new Staff
            {
                \time 3/4
                c'2.
                \tweak edge-height #'(0.7 . 0)
                \times 2/3
                {
                    d'4
                }
                r4
                \times 2/3
                {
                    e'2
                    f'4
                }
                r4
                \tweak edge-height #'(0.7 . 0)
                \times 2/3
                {
                    g'2
                }
            }

        ..  figure:: ../_images/merge_partial_tuplets-icud1ejcmzc.png

    Tied partial tuplets:
        Tied partial tuplets are also handled by this function.

        >>> staff = abjad.Staff(
        ...     r"\times 2/3 {r4} \times 2/3 {c'2} "
        ...     r"\times 4/5 {d'2~} \times 4/5{d'8}"
        ... )
        >>> abjad.show(staff)

        ..  docs::

            \new Staff
            {
                \times 2/3
                {
                    r4
                }
                \times 2/3
                {
                    c'2
                }
                \times 4/5
                {
                    d'2
                    ~
                }
                \times 4/5
                {
                    d'8
                }
            }

        ..  figure:: ../_images/merge_partial_tuplets-st4zw38qfce.png

        >>> auxjad.mutate.merge_partial_tuplets(staff[:])
        >>> abjad.show(staff)

        ..  docs::

            \new Staff
            {
                \times 2/3
                {
                    r4
                    c'2
                }
                \times 4/5
                {
                    d'2
                    ~
                    d'8
                }
            }

        ..  figure:: ../_images/merge_partial_tuplets-1pky5fsh2nl.png

    Indicators:
        Indicators stay the same in the merged tuplet.

        >>> staff = abjad.Staff(
        ...     r"\times 2/3 {c'2\p\< d'2} \times 2/3 {e'2\ff}"
        ... )
        >>> abjad.show(staff)

        ..  docs::

            \new Staff
            {
                \times 2/3
                {
                    c'2
                    \p
                    \<
                    d'2
                }
                \times 2/3
                {
                    e'2
                    \ff
                }
            }

        ..  figure:: ../_images/merge_partial_tuplets-7cdtafl348h.png

        >>> auxjad.mutate.merge_partial_tuplets(staff[:])
        >>> abjad.show(staff)

        ..  docs::

            \new Staff
            {
                \times 2/3
                {
                    c'2
                    \p
                    \<
                    d'2
                    e'2
                    \ff
                }
            }

        ..  figure:: ../_images/merge_partial_tuplets-j9rmdfbawce.png

    ..  tip::

        The method |auxjad.mutate.extract_trivial_tuplets()| can be used
        after merging partial tuplets to further clean the output. The method
        |auxjad.mutate.auto_rewrite_meter()| can also be used for this
        purpose, as it will not only rewrite the metric notation of a staff but
        also apply both |auxjad.mutate.merge_partial_tuplets()| and
        |auxjad.mutate.extract_trivial_tuplets()| to the output.

    ..  note::

        When using |abjad.Container|'s, all time signatures in the output will
        be commented out with ``%%%.`` This is because Abjad only applies time
        signatures to containers that belong to a |abjad.Staff|. The present
        function works with either |abjad.Container| and |abjad.Staff|.

        >>> container = abjad.Container(r"\time 3/4 c'4 d'4 e'4")
        >>> abjad.show(container)

        ..  docs::

            {
                %%% \time 3/4 %%%
                c'4
                d'4
                e'4
            }

        ..  figure:: ../_images/merge_partial_tuplets-945s36mfdn.png

        >>> staff = abjad.Staff([container])
        >>> abjad.show(container)

        ..  docs::

            {
                \time 3/4
                c'4
                d'4
                e'4
            }

        ..  figure:: ../_images/merge_partial_tuplets-3b4tyqrnttw.png

    ..  warning::

        The input selection must be a contiguous logical voice. When dealing
        with a container with multiple subcontainers (e.g. a score containing
        multiple staves), the best approach is to cycle through these
        subcontainers, applying this function to them individually.
    """
    if not isinstance(selection, abjad.Selection):
        raise TypeError("argument must be 'abjad.Selection'")
    if not isinstance(merge_across_barlines, bool):
        raise TypeError("'merge_across_barlines' must be 'bool'")

    tuplets = selection.tuplets()
    if len(tuplets) <= 1:
        return

    def _process_tuplets(tuplets):
        for index in range(len(tuplets[:-1])):
            for upper_index in range(index, len(tuplets)):
                if (tuplets[index].multiplier ==
                        tuplets[upper_index].multiplier):
                    tuplet_group = tuplets[index:upper_index + 1]
                else:
                    break
                if tuplet_group.are_contiguous_logical_voice():
                    durations = [
                        abjad.get.duration(tuplet) for tuplet in tuplet_group
                    ]
                    sum_durations = sum(durations)
                    if (all(duration.implied_prolation != 1
                            for duration in durations)
                            and sum_durations.implied_prolation == 1):
                        for tuplet in tuplet_group[1:]:
                            tuplet_group[0].extend(tuplet)
                            abjad.mutate.extract(tuplet)

    if not merge_across_barlines:
        measures = selection.group_by_measure()
        for measure in measures:
            tuplets = abjad.select(measure).tuplets()
            if len(tuplets) <= 1:
                continue
            _process_tuplets(tuplets)
    else:
        _process_tuplets(tuplets)
コード例 #3
0
def extract_trivial_tuplets(selection: abjad.Selection) -> None:
    r"""Mutates an input |abjad.Selection| in place and has no return value;
    this function looks for tuplets filled with rests or with tied notes or
    chords and replaces them with a single leaf.

    Basic usage:
        Usage is simple:

        >>> staff = abjad.Staff(
        ...     r"\times 2/3 {r4 r2} \times 2/3 {c'8 ~ c'8 ~ c'2}"
        ... )
        >>> abjad.f(container)
        {
            \times 2/3 {
                r4
                r2
            }
            \times 2/3 {
                c'8
                ~
                c'8
                ~
                c'2
            }
        }

        .. figure:: ../_images/extract_trivial_tuplets-4htz2xebxwf.png

        >>> auxjad.mutate(container[:]).extract_trivial_tuplets()
        >>> abjad.f(container)
        {
            r2
            c'2
        }

        .. figure:: ../_images/extract_trivial_tuplets-2dbuwo4erhb.png

        It also works with containers with tuplets within tuplets.

        >>> container = abjad.Container(r"\times 4/5 {r2. \times 2/3 {r2 r4}}")
        >>> abjad.f(container)
        {
            \times 4/5 {
                r2.
                \times 2/3 {
                    r2
                    r4
                }
            }
        }

        .. figure:: ../_images/extract_trivial_tuplets-8d5bcyxcmhc.png

        >>> auxjad.mutate(container[:]).extract_trivial_tuplets()
        >>> abjad.f(container)
        {
            r1
        }

        .. figure:: ../_images/extract_trivial_tuplets-2a2fvwimyrx.png

        >>> container = abjad.Container(
        ...     r"\times 4/5 {c'2. ~ \times 2/3 {c'2 ~ c'4}}"
        ... )
        >>> abjad.f(container)
        {
            \times 4/5 {
                c'2.
                ~
                \times 2/3 {
                    c'2
                    ~
                    c'4
                }
            }
        }

        .. figure:: ../_images/extract_trivial_tuplets-xka6r5iyo4l.png

        >>> auxjad.mutate(staff[:]).extract_trivial_tuplets()
        >>> abjad.f(container)
        {
            c'1
        }

        .. figure:: ../_images/extract_trivial_tuplets-f1qxi44xcsw.png

    .. note::

        Auxjad automatically adds this function as an extension method to
        |abjad.mutate()|. It can thus be used from either
        :func:`auxjad.mutate()` or |abjad.mutate()|. Therefore, the two lines
        below are equivalent:

        >>> auxjad.mutate(staff[:]).extract_trivial_tuplets()
        >>> abjad.mutate(staff[:]).extract_trivial_tuplets()

    Partial extraction:
        This function also extracts tuplets within tuplets.

        >>> container = abjad.Container(
        ...     r"r2 \times 2/3 {r2 r4} \times 4/5 {c'2. \times 2/3 {r2 r4}}"
        ... )
        >>> abjad.f(container)
        {
            r2
            \times 2/3 {
                r2
                r4
            }
            \times 4/5 {
                c'2.
                \times 2/3 {
                    r2
                    r4
                }
            }
        }

        .. figure:: ../_images/extract_trivial_tuplets-adibnkb1mbs.png

        >>> auxjad.mutate(container[:]).extract_trivial_tuplets()
        >>> abjad.f(container)
        {
            r2
            r2
            \times 4/5 {
                c'2.
                r2
            }
        }

        .. figure:: ../_images/extract_trivial_tuplets-xldohyedqs.png

    .. tip::

        Use |auxjad.mutate().rests_to_multimeasure_rest()| to replace measures
        filled with rests by a single multi-measure rest. That function makes
        use of |auxjad.mutate().extract_trivial_tuplets()|, so it is not
        necessary to flatten the empty tuplets beforehand.

    Time signature changes:
        Works with measures with any time signature.

        >>> container = abjad.Staff(r"\time 3/4 r2. \times 3/2 {r4 r4}")
        >>> auxjad.mutate(container[:]).extract_trivial_tuplets()
        >>> abjad.f(container)
        \new Staff
        {
            \time 3/4
            r2.
            r2.
        }

        .. figure:: ../_images/extract_trivial_tuplets-sa1tqmvtkx.png

    Non-assignable durations:
        This function also extracts tuplets which sum up to a non-assignable
        duration. In this case, it creates multiple leaves and substitutes them
        for the original tuplet. Indicators are passed on to the first leaf of
        the new leaves.

        >>> staff = abjad.Staff(r"\time 6/4 c'4\f \times 5/6 {g1.\p}")
        >>> abjad.f(staff)
        \new Staff
        {
            \time 6/4
            c'4
            \f
            \tweak text #tuplet-number::calc-fraction-text
            \times 5/6 {
                g1.
                \p
            }
        }

        .. figure:: ../_images/extract_trivial_tuplets-l4kp9g5v7m.png

        >>> abjad.mutate(staff[:]).extract_trivial_tuplets()
        >>> abjad.f(staff)
        \new Staff
        {
            \time 6/4
            c'4
            \f
            g1
            \p
            ~
            g4
        }

        .. figure:: ../_images/extract_trivial_tuplets-8r40ndemvpn.png

    .. note::

        When using |abjad.Container|'s, all time signatures in the output will
        be commented out with ``%%%.`` This is because Abjad only applies time
        signatures to containers that belong to a |abjad.Staff|. The present
        function works with either |abjad.Container| and |abjad.Staff|.

        >>> container = abjad.Container(r"\time 3/4 c'4 d'4 e'4")
        >>> abjad.f(container)
        {
            %%% \time 3/4 %%%
            c'4
            d'4
            e'4
        }

        .. figure:: ../_images/extract_trivial_tuplets-6wymsb7z1n4.png

        >>> staff = abjad.Staff([container])
        >>> abjad.f(container)
        {
            \time 3/4
            c'4
            d'4
            e'4
        }

        .. figure:: ../_images/extract_trivial_tuplets-moavfyqtxza.png

    .. warning::

        The input selection must be a contiguous logical voice. When dealing
        with a container with multiple subcontainers (e.g. a score containing
        multiple staves), the best approach is to cycle through these
        subcontainers, applying this function to them individually.
    """
    if not isinstance(selection, abjad.Selection):
        raise TypeError("argument must be 'abjad.Selection'")

    tuplets = selection.tuplets()
    if len(tuplets) == 0:
        return

    for tuplet in tuplets:
        leaves = abjad.select(tuplet).leaves()
        if (all(isinstance(leaf, abjad.Rest) for leaf in leaves)
                and len(leaves) > 1):
            duration = tuplet.multiplied_duration
            rests = abjad.LeafMaker()(None, duration)
            time_signature = abjad.inspect(leaves[0]).indicator(
                abjad.TimeSignature)
            if time_signature is not None:
                abjad.attach(time_signature, rests[0])
            abjad.mutate(tuplet).replace(rests)
        if tuplet.sustained():
            duration = tuplet.multiplied_duration
            n_elements = len(tuplet)
            after_tie = abjad.inspect(leaves[-1]).indicator(abjad.Tie)
            for _ in range(n_elements - 1):
                tuplet.pop(-1)
            if not after_tie:
                abjad.detach(abjad.Tie(), leaves[0])
            if duration.is_assignable:
                leaves[0].written_duration = duration
                abjad.mutate(tuplet).extract()
            elif duration.has_power_of_two_denominator:
                if isinstance(leaves[0], abjad.Note):
                    pitch = leaves[0].written_pitch
                elif isinstance(leaves[0], abjad.Chord):
                    pitch = leaves[0].written_pitches
                else:
                    pitch = None
                notes = abjad.LeafMaker()(pitch, duration)
                indicators = abjad.inspect(leaves[0]).indicators()
                for indicator in indicators:
                    abjad.attach(indicator, notes[0])
                abjad.mutate(leaves[0]).replace(notes)
                abjad.mutate(tuplet).extract()
            else:
                continue
    for tuplet in tuplets:
        if tuplet.trivializable():
            tuplet.trivialize()
            abjad.mutate(tuplet).extract()