import random
from typing import Optional, Union

import abjad

from .. import get, mutate


class Hocketer:
    r"""A hocket generator that takes an |abjad.Container| (or child class) as
    input and randomly distributes its logical ties among different staves.

    Basic usage:
        Calling the object will return a :obj:`tuple` of |abjad.Selection|
        generated by the hocket process and ready to be assigned to an
        |abjad.Score|. Each call will generate a new random hocket from the
        input container.

        >>> container = abjad.Container(r"c'4 d'4 e'4 f'4")
        >>> abjad.show(container)

        ..  docs::

            {
                c'4
                d'4
                e'4
                f'4
            }

        ..  figure:: ../_images/Hocketer-svcW7YQBUu.png

        >>> hocketer = auxjad.Hocketer(container)
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    r2
                    e'4
                    r4
                }
                \new Staff
                {
                    c'4
                    d'4
                    r4
                    f'4
                }
            >>

        ..  figure:: ../_images/Hocketer-dh5lutbv09v.png

        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    c'4
                    d'4
                    e'4
                    r4
                }
                \new Staff
                {
                    r2.
                    f'4
                }
            >>

        ..  figure:: ../_images/Hocketer-gj278dv7vff.png

    Indexing:
        Alternatively, it is possible to retrieve an |abjad.Selection| for
        each individual voice generated by the process by indexing or slicing
        the the object itself. In the case below, the hocket process is invoked
        in the third line, and the individual selections are retrieved in the
        loop.

        >>> container = abjad.Container(r"c'4 d'4 e'4 f'4")
        >>> hocketer = auxjad.Hocketer(container, n_voices=5, k=3)
        >>> hocketer()
        >>> score = abjad.Score()
        >>> for selection in hocketer[:]:
        ...     staff = abjad.Staff(selection)
        ...     score.append(staff)
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    r2.
                    f'4
                }
                \new Staff
                {
                    c'4
                    r4
                    e'4
                    r4
                }
                \new Staff
                {
                    r4
                    d'4
                    e'4
                    r4
                }
                \new Staff
                {
                    c'4
                    d'4
                    r4
                    f'4
                }
                \new Staff
                {
                    c'4
                    r4
                    e'4
                    r4
                }
            >>

        ..  figure:: ../_images/Hocketer-5r3ybkxhmd4.png

        Individual staves can also be retrieved as shown below.

        >>> staff = abjad.Staff(hocketer[0])
        >>> abjad.show(staff)

        ..  docs::

            \new Staff
            {
                c'4
                r4
                e'4
                f'4
            }

        ..  figure:: ../_images/Hocketer-sodb0btsuhq.png

        >>> partial_score = abjad.Score()
        >>> for selection in hocketer[1:4]:
        ...     staff = abjad.Staff(selection)
        ...     partial_score.append(selection)
        >>> abjad.show(partial_score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    c'4
                    d'4
                    r2
                }
                \new Staff
                {
                    r4
                    d'4
                    e'4
                    r4
                }
                \new Staff
                {
                    R1
                }
            >>

        ..  figure:: ../_images/Hocketer-3gsh3qtl21d.png

    :attr:`current_window`:
        To get the result of the last operation, use the property
        :attr:`current_window`.

        >>> container = abjad.Container(r"c'4 d'4 e'4 f'4")
        >>> hocketer = auxjad.Hocketer(container)
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    c'4
                    r4
                    e'4
                    r4
                }
                \new Staff
                {
                    r4
                    d'4
                    r4
                    f'4
                }
            >>

        ..  figure:: ../_images/Hocketer-i2jt38x28fd.png

        >>> music = hocketer.current_window
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    c'4
                    r4
                    e'4
                    r4
                }
                \new Staff
                {
                    r4
                    d'4
                    r4
                    f'4
                }
            >>

        ..  figure:: ../_images/Hocketer-4291u773dng.png

    Arguments and properties:
        This class has many keyword arguments, all of which can be altered
        after instantiation using properties with the same names as shown
        below. :attr:`weights` set the individual weight of a given voice (must
        be a :obj:`list` of length equal to :attr:`n_voices`). :attr:`k`
        defines the number of times that the process is applied to each logical
        tie. Setting :attr:`force_k_voices` to ``True`` ensure that a single
        logical tie is distributed to exactly :attr:`k` voices. Setting
        :attr:`explode_chords` to ``True`` will distribute individual pitches
        from chords into unique voices. :attr:`pitch_ranges` defines the pitch
        range of each voice; it takes a list of |abjad.PitchRange|'s.
        :attr:`disable_rewrite_meter` disables the
        |abjad.Meter.rewrite_meter()| mutation which is applied to the
        container after every call. Any measure filled with rests will be
        rewritten using a multi-measure rest; set the
        :attr:`use_multimeasure_rests` to ``False`` to disable this behaviour.
        The properties :attr:`boundary_depth`, :attr:`maximum_dot_count`, and
        :attr:`rewrite_tuplets` are passed as arguments to
        |abjad.Meter.rewrite_meter()|, see its documentation for more
        information. Setting the property :attr:`omit_time_signatures` to
        ``True`` will remove all time signatures from the output (``False`` by
        default).

        >>> container = abjad.Container(r"\time 3/4 c'4 d'4 e'4 | f'4 g'4 a'4")
        >>> hocketer = auxjad.Hocketer(container,
        ...                            n_voices=3,
        ...                            weights=[1, 2, 5],
        ...                            k=2,
        ...                            force_k_voices=True,
        ...                            explode_chords=True,
        ...                            pitch_ranges=[
        ...                                abjad.PitchRange("[C4, D6]"),
        ...                                abjad.PitchRange("[C2, A4]"),
        ...                                abjad.PitchRange("[C1, E3]"),
        ...                            ],
        ...                            disable_rewrite_meter=True,
        ...                            use_multimeasure_rests=False,
        ...                            omit_time_signatures=True,
        ...                            boundary_depth=0,
        ...                            maximum_dot_count=1,
        ...                            rewrite_tuplets=False,
        ...                            )
        >>> hocketer.n_voices
        3
        >>> hocketer.weights
        [1, 2, 5]
        >>> hocketer.k
        2
        >>> hocketer.force_k_voices
        True
        >>> hocketer.explode_chords
        True
        >>> hocketer.pitch_ranges
        [PitchRange('[C4, D6]'), PitchRange('[C2, A4]'),
        PitchRange('[C1, E3]')]
        >>> hocketer.disable_rewrite_meter
        True
        >>> not hocketer.use_multimeasure_rests
        False
        >>> hocketer.omit_time_signatures
        True
        >>> hocketer.boundary_depth
        0
        >>> hocketer.maximum_dot_count
        1
        >>> hocketer.rewrite_tuplets
        False

        Use the properties below to change these values after initialisation.

        >>> hocketer.n_voices = 5
        >>> hocketer.weights = [1, 1, 1, 2, 7]
        >>> hocketer.k = 3
        >>> hocketer.force_k_voices = False
        >>> hocketer.explode_chords = False
        >>> hocketer.pitch_ranges = None
        >>> hocketer.disable_rewrite_meter = False
        >>> hocketer.use_multimeasure_rests = True
        >>> hocketer.omit_time_signatures = False
        >>> hocketer.boundary_depth = 1
        >>> hocketer.maximum_dot_count = 2
        >>> hocketer.rewrite_tuplets = True
        >>> hocketer.n_voices
        5
        >>> hocketer.weights
        [1, 1, 1, 2, 7]
        >>> hocketer.k
        3
        >>> not hocketer.force_k_voices
        False
        >>> hocketer.explode_chords
        False
        >>> hocketer.pitch_ranges
        None
        >>> not hocketer.disable_rewrite_meter
        False
        >>> hocketer.use_multimeasure_rests
        True
        >>> hocketer.omit_time_signatures
        False
        >>> hocketer.boundary_depth
        1
        >>> hocketer.maximum_dot_count
        2
        >>> hocketer.rewrite_tuplets
        True

    :attr:`n_voices`:
        Use the optional argument :attr:`n_voices` to set the number of
        different staves in the output (default is 2).

        >>> container = abjad.Container(r"c'8 d'8 e'8 f'8 g'8 a'8 b'8 c''8")
        >>> hocketer = auxjad.Hocketer(container, n_voices=3)
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    c'8
                    r8
                    e'8
                    r8
                    g'8
                    r4.
                }
                \new Staff
                {
                    r8
                    d'8
                    r4
                    r8
                    a'8
                    r4
                }
                \new Staff
                {
                    r4.
                    f'8
                    r4
                    b'8
                    c''8
                }
            >>

        ..  figure:: ../_images/Hocketer-qf9niqf7em.png

    :func:`len()`:
        Applying the :func:`len()` function to the hocketer will return the
        current number of voices to be output by the hocketer.

        >>> container = abjad.Container(r"c'4 d'4 e'4 f'4 ~ | f'2 g'2")
        >>> hocketer = auxjad.Hocketer(container, n_voices=7)
        >>> len(hocketer)
        6

    :attr:`pitch_ranges`:
        The property :attr:`pitch_ranges` defines the pitch range of each
        voice. It takes a list of |abjad.PitchRange|'s.


        >>> container = abjad.Container(r"c' d' e f' g a' b' c''")
        >>> hocketer = auxjad.Hocketer(container,
        ...                            n_voices=3,
        ...                            pitch_ranges=[
        ...                                abjad.PitchRange("[C4, C5]"),
        ...                                abjad.PitchRange("[C4, C5]"),
        ...                                abjad.PitchRange("[C3, B3]"),
        ...                            ],
        ...                            )
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.attach(abjad.Clef('bass'), abjad.select(score[2]).leaf(0))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    c'4
                    d'4
                    r4
                    f'4
                    r4
                    a'4
                    r2
                }
                \new Staff
                {
                    R1
                    r2
                    b'4
                    c''4
                }
                \new Staff
                {
                    \clef "bass"
                    r2
                    e4
                    r4
                    g4
                    r2.
                }
            >>

        ..  figure:: ../_images/Hocketer-akuL9BDgw8.png

        Note that changing :attr:`n_voices` will reset :attr:`pitch_ranges`:

        >>> container = abjad.Container(
        ...     r"\time 3/4 c'4 d'4 e'4 \time 2/4 f'4 g'4"
        ... )
        >>> hocketer = auxjad.Hocketer(container,
        ...                            n_voices=3,
        ...                            pitch_ranges=[
        ...                                abjad.PitchRange("[C4, D6]"),
        ...                                abjad.PitchRange("[C2, A4]"),
        ...                                abjad.PitchRange("[C1, E3]"),
        ...                            ],
        ...                            )
        >>> hocketer.pitch_ranges
        [PitchRange("[C4, D6]"), PitchRange("[C2, A4]"),
        PitchRange("[C1, E3]")]         ]
        >>> hocketer.n_voices = 4
        >>> hocketer.pitch_ranges
        None

    :attr:`weights`:
        Set :attr:`weights` to a :obj:`list` of numbers (either :obj:`float` or
        :obj:`int`) to give different weights to each voice. By default, all
        voices have equal weight. The :obj:`list` in :attr:`weights` must have
        the same length as the number of voices. In the example below,
        :attr:`weights` is a :obj:`list` of length ``2`` (matching the default
        two voices). The second voice has a higher weight to it, and receives
        more notes from the hocket process as expected.

        >>> container = abjad.Container(r"c'8 d'8 e'8 f'8 g'8 a'8 b'8 c''8")
        >>> hocketer = auxjad.Hocketer(container,
        ...                            weights=[2.1, 5.7],
        ...                            )
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    r8
                    d'8
                    r4
                    g'8
                    r4.
                }
                \new Staff
                {
                    c'8
                    r8
                    e'8
                    f'8
                    r8
                    a'8
                    b'8
                    c''8
                }
            >>

        ..  figure:: ../_images/Hocketer-xyecbupzmm.png

    :meth:`reset_weights`:
        Use the method :meth:`reset_weights` to reset the weights back to their
        default values.

        >>> container = abjad.Container(r"c'8 d'8 e'8 f'8 g'8 a'8 b'8 c''8")
        >>> hocketer = auxjad.Hocketer(container,
        ...                            weights=[2.1, 5.7],
        ...                            )
        >>> hocketer.weights
        [2.1, 5.7]
        >>> hocketer.reset_weights()
        >>> hocketer.weights
        [1.0, 1.0]

    :attr:`k`:
        The argument :attr:`k` is an :obj:`int` defining the number of times
        that the process is applied to each logical tie. By default, :attr:`k`
        is set to ``1``, so each logical tie is assigned to a single voice.
        Changing this to a higher value will increase the chance of a logical
        tie appearing for up to :attr:`k` different voices.

        >>> container = abjad.Container(r"c'4 d'4 e'4 f'4")
        >>> hocketer = auxjad.Hocketer(container, n_voices=4, k=2)
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    c'4
                    d'4
                    e'4
                    r4
                }
                \new Staff
                {
                    r2
                    e'4
                    f'4
                }
                \new Staff
                {
                    r2.
                    f'4
                }
                \new Staff
                {
                    r4
                    d'4
                    r2
                }
            >>

        ..  figure:: ../_images/Hocketer-ytjqsp7r2bn.png

    :attr:`force_k_voices`:
        It is important to note that changing :attr:`k` to a higher value does
        not guarantee each logical tie will appear in :attr:`k` different
        voices. By default, :attr:`k` only defines how many times each logical
        tie is processed by the hocket process, which may select the same voice
        more than once. To ensure that each logical tie appears in :attr:`k`
        unique voices, set the optional keyword argument :attr:`force_k_voices`
        to ``True`` as shown below.

        >>> container = abjad.Container(r"c'8 d'8 e'8 f'8 g'8 a'8 b'8 c''8")
        >>> hocketer = auxjad.Hocketer(container,
        ...                            n_voices=3,
        ...                            k=2,
        ...                            force_k_voices=True,
        ...                            )
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    c'8
                    d'8
                    r8
                    f'8
                    g'8
                    a'8
                    b'8
                    c''8
                }
                \new Staff
                {
                    c'8
                    r8
                    e'8
                    f'8
                    r4
                    b'8
                    r8
                }
                \new Staff
                {
                    r8
                    d'8
                    e'8
                    r8
                    g'8
                    a'8
                    r8
                    c''8
                }
            >>

        ..  figure:: ../_images/Hocketer-9limlogk0b8.png

    ..  error::

        Setting :attr:`force_k_voices` to ``True`` when :attr:`k` is larger
        than :attr:`n_voices` will raise a :exc:`ValueError` exception:

        >>> container = abjad.Container(r"c'8 d'8 e'8 f'8 g'8 a'8 b'8 c''8")
        >>> hocketer = auxjad.Hocketer(container, n_voices=4, k=5)
        >>> hocketer.force_k_voices = True
        ValueError: 'force_k_voices' cannot be set to True if 'k' > 'n_voices',
        change 'k' first

    :attr:`explode_chords`:
        If :attr:`explode_chords` is set to ``True``, chords will not be
        considered as a single leaf to be distributed but rather as a
        collection of individual pitches, which are then distributed among the
        voices. Compare:

        >>> container = abjad.Container(
        ...     r"<c' e' g'>4 <d' f' a'>4 <e' g' b'>4 <f' a' c'>4"
        ... )
        >>> hocketer = auxjad.Hocketer(container,
        ...                            n_voices=3,
        ...                            )
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    r2
                    <e' g' b'>4
                    r4
                }
                \new Staff
                {
                    <c' e' g'>4
                    <d' f' a'>4
                    r2
                }
                \new Staff
                {
                    r2.
                    <c' f' a'>4
                }
            >>

        ..  figure:: ../_images/Hocketer-6gwHXAs6IY.png

        >>> container = abjad.Container(
        ...     r"<c' e' g'>4 <d' f' a'>4 <e' g' b'>4 <f' a' c'>4"
        ... )
        >>> hocketer = auxjad.Hocketer(container,
        ...                            n_voices=3,
        ...                            explode_chords=True,
        ...                            )
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    e'4
                    f'4
                    e'4
                    a'4
                }
                \new Staff
                {
                    g'4
                    d'4
                    b'4
                    c'4
                }
                \new Staff
                {
                    c'4
                    a'4
                    g'4
                    f'4
                }
            >>

        ..  figure:: ../_images/Hocketer-gGsBUch6Ai.png

    ..  note::

        It is very important to note that :attr:`explode_chords` does not take
        :attr:`weights` nor :attr:`k` in consideration. It does, however, take
        :attr:`pitch_ranges` into account:

        >>> container = abjad.Container(
        ...     r"<c' e' g'>4 <d' f' a'>4 <e' g' b'>4 <f' a' c'>4"
        ... )
        >>> hocketer = auxjad.Hocketer(container,
        ...                            n_voices=3,
        ...                            explode_chords=True,
        ...                            pitch_ranges=[
        ...                                abjad.PitchRange("[E4, C5]"),
        ...                                abjad.PitchRange("[E4, C5]"),
        ...                                abjad.PitchRange("[C4, F4]"),
        ...                            ],
        ...                            )
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    e'4
                    f'4
                    g'4
                    c''4
                }
                \new Staff
                {
                    g'4
                    a'4
                    b'4
                    a'4
                }
                \new Staff
                {
                    c'4
                    d'4
                    e'4
                    f'4
                }
            >>

        ..  figure:: ../_images/Hocketer-Rycx76se89.png

    ..  warning::

        When setting :attr:`explode_chords` to ``True``, if :attr:`n_voices` is
        less than the number of pitches in a chord then only the first
        :attr:`n_voices`-pitches will be considered in the distribution.

    :attr:`disable_rewrite_meter`:
        By default, this class uses the |abjad.Meter.rewrite_meter()|
        mutation, which is necessary for cleaning up the rests.

        >>> container = abjad.Container(r"c'8 d'8 e'8 f'8 g'8 a'8 b'8 c''8")
        >>> hocketer = auxjad.Hocketer(container)
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    c'8
                    d'8
                    r4
                    r8
                    a'8
                    r4
                }
                \new Staff
                {
                    r4
                    e'8
                    f'8
                    g'8
                    r8
                    b'8
                    c''8
                }
            >>

        ..  figure:: ../_images/Hocketer-qtuvb2zrlz.png

        Set :attr:`disable_rewrite_meter` to ``True`` in order to disable this
        behaviour.

        >>> container = abjad.Container(r"c'8 d'8 e'8 f'8 g'8 a'8 b'8 c''8")
        >>> hocketer = auxjad.Hocketer(container,
        ...                            disable_rewrite_meter=True,
        ...                            )
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    c'8
                    d'8
                    r8
                    r8
                    r8
                    a'8
                    r8
                    r8
                }
                \new Staff
                {
                    r8
                    r8
                    e'8
                    f'8
                    g'8
                    r8
                    b'8
                    c''8
                }
            >>

        ..  figure:: ../_images/Hocketer-l8cn8w7cju.png

    :attr:`use_multimeasure_rests`:
        By default, this class rewrites all measures that are filled with
        rests, replacing the rests by a multi-measure rest.

        >>> container = abjad.Container(r"\time 3/4 c'4 d'4 e'4 f'4 g'4 a'4")
        >>> hocketer = auxjad.Hocketer(container)
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    \time 3/4
                    R1 * 3/4
                    r4
                    g'4
                    a'4
                }
                \new Staff
                {
                    \time 3/4
                    c'4
                    d'4
                    e'4
                    f'4
                    r2
                }
            >>

        ..  figure:: ../_images/Hocketer-ri1ursa6esi.png

        Set :attr:`use_multimeasure_rests` to ``False`` to disable this
        behaviour.

        >>> container = abjad.Container(r"\time 3/4 c'4 d'4 e'4 f'4 g'4 a'4")
        >>> hocketer = auxjad.Hocketer(container,
        ...                            use_multimeasure_rests=False,
        ...                            )
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    \time 3/4
                    r2.
                    r4
                    g'4
                    a'4
                }
                \new Staff
                {
                    \time 3/4
                    c'4
                    d'4
                    e'4
                    f'4
                    r2
                }
            >>

        ..  figure:: ../_images/Hocketer-20idpp518lf.png

    :attr:`contents`:
        Use the property :attr:`contents` to get the input container upon which
        the hocketer operates. Notice that :attr:`contents` remains invariant
        after any shuffling or rotation operations (use :attr:`current_window`
        for the transformed selection of music). :attr:`contents` can be used
        to change the |abjad.Container| to be shuffled.

        >>> container = abjad.Container(r"c'4 d'4 e'4 f'4")
        >>> hocketer = auxjad.Hocketer(container)
        >>> abjad.show(hocketer.contents)

        ..  docs::

            {
                c'4
                d'4
                e'4
                f'4
            }

        ..  figure:: ../_images/Hocketer-t07z297s2e.png

        >>> hocketer()
        >>> abjad.show(hocketer.contents)

        ..  docs::

            {
                c'4
                d'4
                e'4
                f'4
            }

        ..  figure:: ../_images/Hocketer-7g6cbvfgr1j.png

        >>> hocketer.contents = abjad.Container(r"cs2 ds2")
        >>> abjad.show(hocketer.contents)

        ..  docs::

            {
                cs2
                ds2
            }

        ..  figure:: ../_images/Hocketer-2l7eywciib3.png

    Tweaking |abjad.Meter.rewrite_meter()|:
        This function uses the default logical tie splitting algorithm from
        |abjad.Meter.rewrite_meter()|.

        >>> container = abjad.Container(r"c'4. d'8 e'2")
        >>> hocketer = auxjad.Hocketer(container,
        ...                            n_voices=1,
        ...                            )
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    c'4.
                    d'8
                    e'2
                }
            >>

        ..  figure:: ../_images/Hocketer-g3fmvrkd6nw.png

        Set :attr:`boundary_depth` to a different number to change its
        behaviour.

        >>> hocketer = auxjad.Hocketer(container,
        ...                            n_voices=1,
        ...                            boundary_depth=1,
        ...                            )
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(staff)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    c'4
                    ~
                    c'8
                    d'8
                    e'2
                }
            >>

        ..  figure:: ../_images/Hocketer-g7r2oxsx8zc.png

        Other arguments available for tweaking the output of
        |abjad.Meter.rewrite_meter()| are :attr:`maximum_dot_count` and
        :attr:`rewrite_tuplets`, which work exactly as the identically named
        arguments of |abjad.Meter.rewrite_meter()|.

        This class also accepts the arguments ``fuse_across_groups_of_beats``,
        ``fuse_quadruple_meter``, ``fuse_triple_meter``, and
        ``extract_trivial_tuplets``, which are passed on to
        |auxjad.mutate.prettify_rewrite_meter()| (the latter can be disabled
        by setting ``prettify_rewrite_meter`` to ``False``). See the
        documentation of this function for more details on these arguments.

    Time signature changes and nested tuplets:
        This class can handle time signature changes as well as nested tuplets.

        >>> container = abjad.Container(
        ...     r"\time 5/4 r4 \times 2/3 {c'4 d'2} e'4. f'8 "
        ...     r"\times 4/5 {\time 4/4 g'2. \times 2/3 {a'8 r8 b'2}}"
        ... )
        >>> hocketer = auxjad.Hocketer(container,
        ...                            n_voices=4,
        ...                            k=2,
        ...                            )
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    \time 5/4
                    r4
                    \times 2/3
                    {
                        c'4
                        d'2
                    }
                    r4.
                    f'8
                    \times 4/5
                    {
                        \time 4/4
                        r2.
                        \times 2/3
                        {
                            a'8
                            r8
                            r2
                        }
                    }
                }
                \new Staff
                {
                    \time 5/4
                    R1 * 5/4
                    \time 4/4
                    R1
                }
                \new Staff
                {
                    \time 5/4
                    r4
                    \times 2/3
                    {
                        r4
                        d'2
                    }
                    e'4.
                    f'8
                    \times 4/5
                    {
                        \time 4/4
                        r2.
                        \times 2/3
                        {
                            a'8
                            r8
                            b'2
                        }
                    }
                }
                \new Staff
                {
                    \time 5/4
                    r4
                    \times 2/3
                    {
                        c'4
                        r2
                    }
                    r2
                    \times 4/5
                    {
                        \time 4/4
                        g'2.
                        \times 2/3
                        {
                            r4
                            b'2
                        }
                    }
                }
            >>

        ..  figure:: ../_images/Hocketer-seuga1yah9h.png

    :attr:`omit_time_signatures`:
        To disable time signatures altogether, initialise this class with the
        keyword argument :attr:`omit_time_signatures` set to ``True`` (default
        is ``False``), or use the :attr:`omit_time_signatures` property after
        initialisation. It is recommended to also set
        :attr:`use_multimeasure_rests` to ``False``, as those are created
        according to the original time signatures.

        >>> container = abjad.Container(r"\time 3/4 c'4 d'4 e'4 f'4 g'4 a'4")
        >>> hocketer = auxjad.Hocketer(container,
        ...                            omit_time_signatures=True,
        ...                            use_multimeasure_rests=False,
        ...                            )
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    r2.
                    r4
                    g'4
                    a'4
                }
                \new Staff
                {
                    c'4
                    d'4
                    e'4
                    f'4
                    r2
                }
            >>

        ..  figure:: ../_images/Hocketer-6w9r9iicp29.png

    Indicators:
        Dynamics and hairpins are supported.

        >>> container = abjad.Container(
        ...     r"c'2-.\p\< d'2-.\f\> e'1 f'2.\pp\< g'4--\p "
        ...     r"a'2\ff\> b'2\p\> ~ b'2 c''2\ppp"
        ... )
        >>> hocketer = auxjad.Hocketer(container,
        ...                            n_voices=3,
        ...                            k=2,
        ...                            force_k_voices=True,
        ...                            )
        >>> music = hocketer()
        >>> score = abjad.Score()
        >>> for selection in music:
        ...     score.append(abjad.Staff(selection))
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    c'2
                    \p
                    - \staccato
                    \<
                    d'2
                    \f
                    - \staccato
                    \>
                    e'1
                    f'2.
                    \pp
                    \<
                    g'4
                    \p
                    - \tenuto
                    a'2
                    \ff
                    \>
                    r2
                    \p
                    r2
                    c''2
                    \ppp
                }
                \new Staff
                {
                    r2
                    d'2
                    \f
                    - \staccato
                    \>
                    e'1
                    r2.
                    \pp
                    g'4
                    \p
                    - \tenuto
                    r2
                    b'2
                    \>
                    ~
                    b'2
                    r2
                    \ppp
                }
                \new Staff
                {
                    c'2
                    \p
                    - \staccato
                    \<
                    r2
                    \f
                    R1
                    f'2.
                    \pp
                    \<
                    r4
                    \p
                    a'2
                    \ff
                    \>
                    b'2
                    \p
                    \>
                    ~
                    b'2
                    c''2
                    \ppp
                }
            >>

        ..  figure:: ../_images/Hocketer-zel37ga6xob.png

    ..  tip::

        The functions |auxjad.mutate.remove_repeated_dynamics()| and
        |auxjad.mutate.reposition_clefs()| can be used to clean the output
        and remove repeated dynamics and unnecessary clef changes.

    ..  warning::

        Do note that some elements that span multiple notes (such as ottava
        indicators, manual beams, etc.) can become problematic when notes
        containing them are split into two. As a rule of thumb, it is always
        better to attach those to the music after the fading process has ended.
    """

    ### CLASS VARIABLES ###

    __slots__ = (
        "_contents",
        "_n_voices",
        "_weights",
        "_k",
        "_pitch_ranges",
        "_force_k_voices",
        "_explode_chords",
        "_disable_rewrite_meter",
        "_use_multimeasure_rests",
        "_voices",
        "_time_signatures",
        "_boundary_depth",
        "_maximum_dot_count",
        "_rewrite_tuplets",
        "_omit_time_signatures",
        "_prettify_rewrite_meter",
        "_extract_trivial_tuplets",
        "_fuse_across_groups_of_beats",
        "_fuse_quadruple_meter",
        "_fuse_triple_meter",
    )

    ### INITIALISER ###

    def __init__(
        self,
        contents: abjad.Container,
        *,
        n_voices: int = 2,
        pitch_ranges: Optional[list] = None,
        weights: Optional[list] = None,
        k: int = 1,
        force_k_voices: bool = False,
        explode_chords: bool = False,
        disable_rewrite_meter: bool = False,
        use_multimeasure_rests: bool = True,
        omit_time_signatures: bool = False,
        boundary_depth: Optional[int] = None,
        maximum_dot_count: Optional[int] = None,
        rewrite_tuplets: bool = True,
        prettify_rewrite_meter: bool = True,
        extract_trivial_tuplets: bool = True,
        fuse_across_groups_of_beats: bool = True,
        fuse_quadruple_meter: bool = True,
        fuse_triple_meter: bool = True,
    ) -> None:
        self.contents = contents
        self._voices = None
        self._n_voices = n_voices
        self._k = k
        if weights is not None:
            self.weights = weights
        else:
            self.reset_weights()
        self.pitch_ranges = pitch_ranges
        self.force_k_voices = force_k_voices
        self.explode_chords = explode_chords
        self.disable_rewrite_meter = disable_rewrite_meter
        self.use_multimeasure_rests = use_multimeasure_rests
        self.omit_time_signatures = omit_time_signatures
        self.boundary_depth = boundary_depth
        self.maximum_dot_count = maximum_dot_count
        self.rewrite_tuplets = rewrite_tuplets
        self.prettify_rewrite_meter = prettify_rewrite_meter
        self.extract_trivial_tuplets = extract_trivial_tuplets
        self.fuse_across_groups_of_beats = fuse_across_groups_of_beats
        self.fuse_quadruple_meter = fuse_quadruple_meter
        self.fuse_triple_meter = fuse_triple_meter

    ### SPECIAL METHODS ###

    def __repr__(self) -> str:
        r"""Returns interpreter representation of :attr:`contents`."""
        return abjad.lilypond(self._contents)

    def __len__(self) -> int:
        r"""Returns the number of voices of the hocketer."""
        return self._n_voices

    def __call__(self) -> tuple[abjad.Selection]:
        r"""Calls the hocket process, returning a :obj:`tuple` of
        |abjad.Selection|.
        """
        self._make_music()
        return self.current_window

    def __getitem__(self, key: int) -> abjad.Selection:
        r"""Returns one or more voices of the output of the hocketer through
        indexing or slicing.
        """
        output = []
        for voice in self._voices[key]:
            voice_ = abjad.mutate.copy(voice)
            output.append(voice_)
        return tuple(output)

    ### PUBLIC METHODS ###

    def reset_weights(self) -> None:
        r"""Resets the weight vector of all voices to an uniform
        distribution.
        """
        self._weights = [1.0 for _ in range(self.__len__())]

    ### PRIVATE METHODS ###

    def _make_music(self) -> None:
        r"""Runs the hocket process, returning a :obj:`tuple` of
        |abjad.Container()|. It distributes the logical ties from the
        :attr:`contents` into different voices. Voices can have different
        weights, and the process of distributing a same logical tie can be run
        more than once (defined by the attribute :attr:`k`).
        """
        # distributing logical ties into voices
        dummy_voices = self._hocket_process()
        # handling dynamics and slurs
        for voice in dummy_voices:
            mutate.reposition_dynamics(voice[:])
            mutate.reposition_slurs(voice[:])
        # rewriting meter
        if not self._disable_rewrite_meter:
            for voice in dummy_voices:
                mutate.auto_rewrite_meter(
                    voice,
                    meter_list=self._time_signatures,
                    boundary_depth=self._boundary_depth,
                    maximum_dot_count=self._maximum_dot_count,
                    rewrite_tuplets=self._rewrite_tuplets,
                    prettify_rewrite_meter=self._prettify_rewrite_meter,
                    extract_trivial_tuplets=self._extract_trivial_tuplets,
                    fuse_across_groups_of_beats=(self.fuse_across_groups_of_beats),
                    fuse_quadruple_meter=self._fuse_quadruple_meter,
                    fuse_triple_meter=self._fuse_triple_meter,
                )
        # handling empty tuplets and multi-measure rests
        if self._use_multimeasure_rests:
            for voice in dummy_voices:
                mutate.rests_to_multimeasure_rest(voice[:])
        # output
        self._voices = []
        for voice in dummy_voices:
            self._voices.append(voice[:])
            voice[:] = []

    def _hocket_process(self) -> abjad.Container:
        r"""Replaces notes and chords for silences if voice not in the selected
        :obj:`list` for a given logical tie.
        """
        indicators_tuple = (
            abjad.BarLine,
            abjad.Clef,
            abjad.Dynamic,
            abjad.Fermata,
            abjad.KeySignature,
            abjad.LilyPondLiteral,
            abjad.MetronomeMark,
            abjad.Ottava,
            abjad.RehearsalMark,
            abjad.Repeat,
            abjad.StaffChange,
            abjad.StartHairpin,
            abjad.StartMarkup,
            abjad.StartPhrasingSlur,
            abjad.StartSlur,
            abjad.StartTextSpan,
            abjad.StopHairpin,
            abjad.StopPhrasingSlur,
            abjad.StopSlur,
            abjad.StopTextSpan,
            abjad.TimeSignature,
        )
        dummy_voices = [abjad.mutate.copy(self._contents) for _ in range(self._n_voices)]
        selected_voices = self._select_voices()
        for voice_index, voice in enumerate(dummy_voices):
            logical_ties = abjad.select(voice).logical_ties()
            for logical_tie, selected_indeces in zip(
                logical_ties,
                selected_voices,
            ):
                if voice_index not in selected_indeces:
                    for leaf in logical_tie:
                        rest = abjad.Rest(leaf.written_duration)
                        for indicator in abjad.get.indicators(leaf):
                            if isinstance(indicator, indicators_tuple):
                                abjad.attach(indicator, rest)
                        abjad.mutate.replace(leaf, rest)
                elif isinstance(logical_tie.head, abjad.Chord) and self._explode_chords:
                    pitch_number = selected_indeces.index(voice_index)
                    pitch = logical_tie.head.written_pitches[pitch_number]
                    for leaf in logical_tie:
                        note = abjad.Note(pitch, leaf.written_duration)
                        for indicator in abjad.get.indicators(leaf):
                            abjad.attach(indicator, note)
                        abjad.mutate.replace(leaf, note)
        return dummy_voices

    def _select_voices(self) -> list[int]:
        r"""Creates a :obj:`list` of selected voices for each logical tie."""
        selected_voices = []
        if not self._force_k_voices:
            for logical_tie in abjad.select(self._contents).logical_ties():
                # 1st case: exploding chords and ignoring k
                if isinstance(logical_tie.head, abjad.Chord) and self._explode_chords:
                    pitches = logical_tie.head.written_pitches
                    counter = 0
                    while True:
                        if len(pitches) > self._n_voices:
                            sample_k = self._n_voices
                        else:
                            sample_k = len(pitches)
                        voices = random.sample(
                            list(range(self._n_voices)),
                            k=sample_k,
                        )
                        counter += 1
                        if all(
                            self._pitch_in_range(pitch, voice)
                            for voice, pitch in zip(voices, pitches)
                        ):
                            break
                        elif counter >= 1000:
                            raise RuntimeError(
                                "No good distribution of chord "
                                "found, please check the pitch "
                                "ranges or try another seed."
                            )
                    selected_voices.append(voices)
                # 2nd case: distributing leaves into up to k voices, though
                # not enforcing k voices
                else:
                    pitch = self._get_pitch_from_logical_tie(logical_tie)
                    counter = 0
                    while True:
                        voices = random.choices(
                            list(range(self._n_voices)),
                            weights=self._weights,
                            k=self._k,
                        )
                        counter += 1
                        if all(self._pitch_in_range(pitch, voice) for voice in voices):
                            break
                        if counter >= 1000:
                            raise RuntimeError(
                                "No good distribution of notes "
                                "found, please check pitch "
                                "ranges or try another seed."
                            )
                    selected_voices.append(voices)
        # 3rd case: distributing leaves into exactly k voices
        else:
            for logical_tie in abjad.select(self._contents).logical_ties():
                pitch = self._get_pitch_from_logical_tie(logical_tie)
                counter = 0
                voices = []
                while len(voices) < self._k:
                    voice = random.choices(
                        list(range(self._n_voices)),
                        weights=self._weights,
                    )[0]
                    counter += 1
                    if voice in voices:
                        continue
                    if self._pitch_in_range(pitch, voice):
                        voices.append(voice)
                    if counter >= 1000:
                        raise RuntimeError(
                            "No good distribution of notes "
                            "found, please check pitch "
                            "ranges or try another seed."
                        )
                selected_voices.append(voices)
        return selected_voices

    def _pitch_in_range(
        self,
        pitch: Union[abjad.Pitch, abjad.PitchSegment, None],
        voice: int,
    ) -> bool:
        r"""Checks if a pitch is playable by a specific voice."""
        if self._pitch_ranges is None or pitch is None:
            return True
        elif isinstance(pitch, abjad.PitchSegment):
            if min(pitch) in self._pitch_ranges[voice] and max(pitch) in self._pitch_ranges[voice]:
                return True
        if pitch in self._pitch_ranges[voice]:
            return True
        return False

    def _get_lilypond_format(self) -> str:
        r"""Returns interpreter representation of  :attr:`contents`."""
        return self.__repr__()

    @staticmethod
    def _get_pitch_from_logical_tie(
        logical_tie: abjad.LogicalTie,
    ) -> Union[
        abjad.Pitch,
        abjad.PitchSegment,
        None,
    ]:
        r"""Gets the pitch of the first leaf of a logical tie."""
        if isinstance(logical_tie.head, abjad.Note):
            return logical_tie.head.written_pitch
        elif isinstance(logical_tie.head, abjad.Chord):
            return logical_tie.head.written_pitches
        else:
            return None

    @staticmethod
    def _remove_all_time_signatures(
        container: abjad.Container,
    ) -> None:
        r"""Removes all time signatures of an |abjad.Container|."""
        for leaf in abjad.select(container).leaves():
            if abjad.get.effective(leaf, abjad.TimeSignature):
                abjad.detach(abjad.TimeSignature, leaf)

    ### PUBLIC PROPERTIES ###

    @property
    def contents(self) -> abjad.Container:
        r"""The |abjad.Container| to be hocketed."""
        return abjad.mutate.copy(self._contents)

    @contents.setter
    def contents(
        self,
        contents: abjad.Container,
    ) -> None:
        if not isinstance(contents, abjad.Container):
            raise TypeError("'contents' must be 'abjad.Container' or child class")
        if not abjad.select(contents).leaves().are_contiguous_logical_voice():
            raise ValueError("'contents' must be contiguous logical voice")
        if isinstance(contents, abjad.Score):
            self._contents = abjad.mutate.copy(contents[0])
        elif isinstance(contents, abjad.Tuplet):
            self._contents = abjad.Container([abjad.mutate.copy(contents)])
        else:
            self._contents = abjad.mutate.copy(contents)
        self._time_signatures = get.time_signature_list(
            contents,
            do_not_use_none=True,
        )

    @property
    def n_voices(self) -> int:
        r"""Number of individual voices in the output."""
        return self._n_voices

    @n_voices.setter
    def n_voices(
        self,
        n_voices: int,
    ) -> None:
        if not isinstance(n_voices, int):
            raise TypeError("'n_voices' must be 'int'")
        if n_voices < 1:
            raise ValueError("'n_voices' must be greater than zero")
        if self._force_k_voices and self._k > n_voices:
            raise ValueError(
                "'n_voices' cannot be smaller than 'k' when 'force_k_voices' is set to True"
            )
        self._n_voices = n_voices
        self._pitch_ranges = None

    @property
    def weights(self) -> list[Union[float, int]]:
        r"""The :obj:`list` with weights for each voice."""
        return self._weights

    @weights.setter
    def weights(
        self,
        weights: Optional[list[Union[float, int]]],
    ) -> None:
        if weights is not None:
            if not isinstance(weights, list):
                raise TypeError("'weights' must be 'list'")
            if not self.__len__() == len(weights):
                raise ValueError("'weights' must have the same length as 'n_voices'")
            if not all(isinstance(weight, (int, float)) for weight in weights):
                raise TypeError("'weights' elements must be 'int' or 'float'")
            self._weights = weights[:]
        else:
            self.reset_weights()

    @property
    def k(self) -> int:
        r"""Number of random choice operations applied to a logical tie."""
        return self._k

    @k.setter
    def k(
        self,
        k: int,
    ) -> None:
        if not isinstance(k, int):
            raise TypeError("'k' must be 'int'")
        if k < 1:
            raise ValueError("'k' must be greater than zero")
        if self._force_k_voices and k > self._n_voices:
            raise ValueError(
                "'k' cannot be greater than 'n_voices' when 'force_k_voices' is set to True"
            )
        self._k = k

    @property
    def pitch_ranges(self) -> list:
        r"""List of tuples or lists for the pitch ranges of each voice.
        Use the format:

        [(min0, max0), (min1, max1), (min2, max2), ...]

        ... where the indices are the voice numbers.
        """
        return self._pitch_ranges

    @pitch_ranges.setter
    def pitch_ranges(
        self,
        pitch_ranges: Optional[list],
    ) -> None:
        if pitch_ranges is not None:
            if not isinstance(pitch_ranges, list):
                raise TypeError("'pitch_ranges' must be 'list'")
            if len(pitch_ranges) != self._n_voices:
                raise ValueError("'pitch_ranges' must have length 'n_voices'")
            for voice_range in pitch_ranges:
                if not isinstance(voice_range, abjad.PitchRange):
                    raise TypeError("elements of 'pitch_ranges' must be 'abjad.PitchRange'")
        self._pitch_ranges = pitch_ranges

    @property
    def explode_chords(self) -> bool:
        r"""When ``True``, the hocket process will consider each note of a
        chord individually, 'exploding' it into several voices.
        """
        return self._explode_chords

    @explode_chords.setter
    def explode_chords(
        self,
        explode_chords: bool,
    ) -> None:
        if not isinstance(explode_chords, bool):
            raise TypeError("'explode_chords' must be 'bool'")
        self._explode_chords = explode_chords

    @property
    def force_k_voices(self) -> bool:
        r"""When ``True``, the hocket process will ensure that each logical tie
        is distributed among :attr:`k` voices.
        """
        return self._force_k_voices

    @force_k_voices.setter
    def force_k_voices(
        self,
        force_k_voices: bool,
    ) -> None:
        if not isinstance(force_k_voices, bool):
            raise TypeError("'force_k_voices' must be 'bool'")
        if force_k_voices and self._k > self._n_voices:
            raise ValueError(
                "'force_k_voices' cannot be set to True if 'k' > 'n_voices', change 'k' first"
            )
        self._force_k_voices = force_k_voices

    @property
    def omit_time_signatures(self) -> bool:
        r"""When ``True``, all time signatures will be omitted from the
        output.
        """
        return self._omit_time_signatures

    @omit_time_signatures.setter
    def omit_time_signatures(
        self,
        omit_time_signatures: bool,
    ) -> None:
        if not isinstance(omit_time_signatures, bool):
            raise TypeError("'omit_time_signatures' must be 'bool'")
        self._omit_time_signatures = omit_time_signatures

    @property
    def disable_rewrite_meter(self) -> bool:
        r"""When ``True``, the durations of the notes in the output will not be
        rewritten by the |abjad.Meter.rewrite_meter()| mutation. Rests will
        have the same duration as the logical ties they replaced.
        """
        return self._disable_rewrite_meter

    @disable_rewrite_meter.setter
    def disable_rewrite_meter(
        self,
        disable_rewrite_meter: bool,
    ) -> None:
        if not isinstance(disable_rewrite_meter, bool):
            raise TypeError("'disable_rewrite_meter' must be 'bool'")
        self._disable_rewrite_meter = disable_rewrite_meter

    @property
    def use_multimeasure_rests(self) -> bool:
        r"""When ``True``, multi-measure rests will be used for silent
        measures.
        """
        return self._use_multimeasure_rests

    @use_multimeasure_rests.setter
    def use_multimeasure_rests(
        self,
        use_multimeasure_rests: bool,
    ) -> None:
        if not isinstance(use_multimeasure_rests, bool):
            raise TypeError("'use_multimeasure_rests' must be 'bool'")
        self._use_multimeasure_rests = use_multimeasure_rests

    @property
    def boundary_depth(self) -> Union[int, None]:
        r"""Sets the argument ``boundary_depth`` of
        |abjad.Meter.rewrite_meter()|.
        """
        return self._boundary_depth

    @boundary_depth.setter
    def boundary_depth(
        self,
        boundary_depth: Optional[int],
    ) -> None:
        if boundary_depth is not None:
            if not isinstance(boundary_depth, int):
                raise TypeError("'boundary_depth' must be 'int'")
        self._boundary_depth = boundary_depth

    @property
    def maximum_dot_count(self) -> Union[int, None]:
        r"""Sets the argument ``maximum_dot_count`` of
        |abjad.Meter.rewrite_meter()|.
        """
        return self._maximum_dot_count

    @maximum_dot_count.setter
    def maximum_dot_count(
        self,
        maximum_dot_count: Optional[int],
    ) -> None:
        if maximum_dot_count is not None:
            if not isinstance(maximum_dot_count, int):
                raise TypeError("'maximum_dot_count' must be 'int'")
        self._maximum_dot_count = maximum_dot_count

    @property
    def rewrite_tuplets(self) -> bool:
        r"""Sets the argument ``rewrite_tuplets`` of
        |abjad.Meter.rewrite_meter()|.
        """
        return self._rewrite_tuplets

    @rewrite_tuplets.setter
    def rewrite_tuplets(
        self,
        rewrite_tuplets: bool,
    ) -> None:
        if not isinstance(rewrite_tuplets, bool):
            raise TypeError("'rewrite_tuplets' must be 'bool'")
        self._rewrite_tuplets = rewrite_tuplets

    @property
    def prettify_rewrite_meter(self) -> bool:
        r"""Used to enable or disable the mutation
        |auxjad.mutate.prettify_rewrite_meter()| (default ``True``).
        """
        return self._prettify_rewrite_meter

    @prettify_rewrite_meter.setter
    def prettify_rewrite_meter(
        self,
        prettify_rewrite_meter: bool,
    ) -> None:
        if not isinstance(prettify_rewrite_meter, bool):
            raise TypeError("'prettify_rewrite_meter' must be 'bool'")
        self._prettify_rewrite_meter = prettify_rewrite_meter

    @property
    def extract_trivial_tuplets(self) -> bool:
        r"""Sets the argument ``extract_trivial_tuplets`` of
        |auxjad.mutate.prettify_rewrite_meter()|.
        """
        return self._extract_trivial_tuplets

    @extract_trivial_tuplets.setter
    def extract_trivial_tuplets(
        self,
        extract_trivial_tuplets: bool,
    ) -> None:
        if not isinstance(extract_trivial_tuplets, bool):
            raise TypeError("'extract_trivial_tuplets' must be 'bool'")
        self._extract_trivial_tuplets = extract_trivial_tuplets

    @property
    def fuse_across_groups_of_beats(self) -> bool:
        r"""Sets the argument ``fuse_across_groups_of_beats`` of
        |auxjad.mutate.prettify_rewrite_meter()|.
        """
        return self._fuse_across_groups_of_beats

    @fuse_across_groups_of_beats.setter
    def fuse_across_groups_of_beats(
        self,
        fuse_across_groups_of_beats: bool,
    ) -> None:
        if not isinstance(fuse_across_groups_of_beats, bool):
            raise TypeError("'fuse_across_groups_of_beats' must be 'bool'")
        self._fuse_across_groups_of_beats = fuse_across_groups_of_beats

    @property
    def fuse_quadruple_meter(self) -> bool:
        r"""Sets the argument ``fuse_quadruple_meter`` of
        |auxjad.mutate.prettify_rewrite_meter()|.
        """
        return self._fuse_quadruple_meter

    @fuse_quadruple_meter.setter
    def fuse_quadruple_meter(
        self,
        fuse_quadruple_meter: bool,
    ) -> None:
        if not isinstance(fuse_quadruple_meter, bool):
            raise TypeError("'fuse_quadruple_meter' must be 'bool'")
        self._fuse_quadruple_meter = fuse_quadruple_meter

    @property
    def fuse_triple_meter(self) -> bool:
        r"""Sets the argument ``fuse_triple_meter`` of
        |auxjad.mutate.prettify_rewrite_meter()|.
        """
        return self._fuse_triple_meter

    @fuse_triple_meter.setter
    def fuse_triple_meter(
        self,
        fuse_triple_meter: bool,
    ) -> None:
        if not isinstance(fuse_triple_meter, bool):
            raise TypeError("'fuse_triple_meter' must be 'bool'")
        self._fuse_triple_meter = fuse_triple_meter

    @property
    def current_window(self) -> Union[tuple, None]:
        r"""Read-only property, returns the result of the last operation as a
        :obj:`tuple` of |abjad.Selection|..
        """
        if self._voices is not None:
            output = []
            for voice in self._voices:
                voice_ = abjad.mutate.copy(voice)
                if self._omit_time_signatures:
                    self._remove_all_time_signatures(voice_)
                output.append(abjad.select([voice_]))
            return tuple(output[:])
        else:
            return self._voices
