import random
from typing import Optional, Union

import abjad

from .. import mutate
from .Fader import Fader


class CrossFader:
    r"""Takes two |abjad.Container|'s' (or child class) and gradually
    crossfades from one into the other, by fading out the first while fading in
    the second. It makes use of two :class:`auxjad.Fader` for that.

    Basic usage:
        Calling the object will return a :obj:`tuple` of two
        |abjad.Selection|'s generated by the fading process. Each call of the
        object will apply the fading process to one of the two containers of
        the previous results. That is, either a note of the first container is
        removed or a note of the second container is added.

        >>> fade_out_container = abjad.Container(r"fs'4 g'2 bf'4")
        >>> fade_in_container = abjad.Container(r"\times 4/5 {cs''4 d''1}")
        >>> abjad.show(fade_out_container)

        ..  docs::

            {
                fs'4
                g'2
                bf'4
            }

        ..  figure:: ../_images/CrossFader-7yWgnyhyA3.png

        >>> abjad.show(fade_in_container)

        ..  docs::

            {
                \times 4/5 {
                    cs''4
                    d''1
                }
            }

        ..  figure:: ../_images/CrossFader-aS29mS1xIB.png

        >>> fader = auxjad.CrossFader(fade_out_container, fade_in_container)
        >>> selection_a, selection_b = fader()
        >>> score = abjad.Score([
        ...     abjad.Staff(selection_a),
        ...     abjad.Staff(selection_b),
        ... ])
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    \time 4/4
                    fs'4
                    g'2
                    bf'4
                }
                \new Staff
                {
                    \time 4/4
                    R1
                }
            >>

        ..  figure:: ../_images/CrossFader-gdofr6vtutv.png

        >>> selection_a, selection_b = fader()
        >>> score = abjad.Score([
        ...     abjad.Staff(selection_a),
        ...     abjad.Staff(selection_b),
        ... ])
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    \time 4/4
                    fs'4
                    g'2
                    bf'4
                }
                \new Staff
                {
                    \times 4/5
                    {
                        \time 4/4
                        r4
                        d''1
                    }
                }
            >>

        ..  figure:: ../_images/CrossFader-ge0qzrwa7fr.png

        >>> selection_a, selection_b = fader()
        >>> score = abjad.Score([
        ...     abjad.Staff(selection_a),
        ...     abjad.Staff(selection_b),
        ... ])
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    \time 4/4
                    fs'4
                    r2
                    bf'4
                }
                \new Staff
                {
                    \times 4/5
                    {
                        \time 4/4
                        r4
                        d''1
                    }
                }
            >>

        ..  figure:: ../_images/CrossFader-0iynx7xenvmp.png

        The property :attr:`current_window` can be used to access the current
        window without processing it.

        >>> notes = fader.current_window()
        >>> score = abjad.Score([
        ...     abjad.Staff(selection_a),
        ...     abjad.Staff(selection_b),
        ... ])
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    \time 4/4
                    fs'4
                    r2
                    bf'4
                }
                \new Staff
                {
                    \times 4/5
                    {
                        \time 4/4
                        r4
                        d''1
                    }
                }
            >>

        ..  figure:: ../_images/CrossFader-kinei9zncl.png

    :meth:`output_all`:
        To run through the whole process and output it as a :obj:`tuple` of two
        |abjad.Selection|'s, use the method :meth:`output_all`.

        >>> fade_out_container = abjad.Container(r"fs'4 g'2 bf'4")
        >>> fade_in_container = abjad.Container(r"\times 4/5 {cs''4 d'1}")
        >>> fader = auxjad.CrossFader(fade_out_container, fade_in_container)
        >>> selection_a, selection_b = fader.output_all()
        >>> score = abjad.Score([
        ...     abjad.Staff(selection_a),
        ...     abjad.Staff(selection_b),
        ... ])
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    \time 4/4
                    fs'4
                    g'2
                    bf'4
                    fs'4
                    g'2
                    bf'4
                    fs'4
                    r2
                    bf'4
                    fs'4
                    r2
                    bf'4
                    r2.
                    bf'4
                    R1
                }
                \new Staff
                {
                    \time 4/4
                    R1
                    \times 4/5
                    {
                        cs''4
                        r1
                    }
                    \times 4/5
                    {
                        cs''4
                        r1
                    }
                    \times 4/5
                    {
                        cs''4
                        d'1
                    }
                    \times 4/5
                    {
                        cs''4
                        d'1
                    }
                    \times 4/5
                    {
                        cs''4
                        d'1
                    }
                }
            >>

        ..  figure:: ../_images/CrossFader-0t206fb4ycne.png

    :meth:`output_n`:
        To run through just part of the process and output it as a :obj:`tuple`
        of two |abjad.Selection|'s, use the method :meth:`output_n` and pass
        the number of iterations as argument.

        >>> fade_out_container = abjad.Container(r"e'8 fs'4. r2")
        >>> fade_in_container = abjad.Container(r"c''2 ~ c''8 d''4.")
        >>> fader = auxjad.CrossFader(fade_out_container, fade_in_container)
        >>> selection_a, selection_b = fader.output_n(3)
        >>> score = abjad.Score([
        ...     abjad.Staff(selection_a),
        ...     abjad.Staff(selection_b),
        ... ])
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    \time 4/4
                    e'8
                    fs'4.
                    r2
                    e'8
                    fs'4.
                    r2
                    e'8
                    r2..
                }
                \new Staff
                {
                    \time 4/4
                    R1
                    c''2
                    ~
                    c''8
                    r4.
                    c''2
                    ~
                    c''8
                    r4.
                }
            >>

        ..  figure:: ../_images/CrossFader-8o5fjalw1px.png

    Using as iterator:
        The instances of this class can also be used as an iterator, which can
        then be used in a for loop to run through the whole process. Note that
        unlike the methods :meth:`output_n` and :meth:`output_all`, time
        signatures are added to each window returned by the fader. Use the
        function |auxjad.mutate.remove_repeated_time_signatures()| to clean
        the output when using this class in this way.

        >>> fade_out_container = abjad.Container(r"e'8 fs'4. r2")
        >>> fade_in_container = abjad.Container(r"c''2 ~ c''8 d''4.")
        >>> fader = auxjad.CrossFader(fade_out_container, fade_in_container)
        >>> staff_a = abjad.Staff()
        >>> staff_b = abjad.Staff()
        >>> for selection_a, selection_b in fader:
        ...     staff_a.extend(selection_a)
        ...     staff_b.extend(selection_b)
        >>> auxjad.mutate.remove_repeated_time_signatures(staff_a)
        >>> auxjad.mutate.remove_repeated_time_signatures(staff_b)
        >>> score = abjad.Score([staff_a, staff_b])
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    \time 4/4
                    e'8
                    fs'4.
                    r2
                    e'8
                    fs'4.
                    r2
                    e'8
                    r2..
                    e'8
                    r2..
                    R1
                }
                \new Staff
                {
                    \time 4/4
                    R1
                    c''2
                    ~
                    c''8
                    r4.
                    c''2
                    ~
                    c''8
                    r4.
                    c''2
                    ~
                    c''8
                    d''4.
                    c''2
                    ~
                    c''8
                    d''4.
                }
            >>

        ..  figure:: ../_images/CrossFader-3g9fv4ew4h9.png

    Arguments and properties:
        This class can take many optional keyword arguments during its
        creation. Setting :attr:`fade_in_first` to ``True`` will ensure that a
        note from the second container must be faded in before any notes of the
        first container are removed (default ``False``). Setting
        :attr:`fade_out_last` to ``True`` will ensure that all notes from the
        second container must be faded in before the very last note of the
        first container is removed (default ``False``). The arguments
        :attr:`initial_repetitions` and :attr:`final_repetitions` set the
        number of repetitions of the initial and final measures (default ``1``
        for both). :attr:`repetition_chance` sets the chance of a window
        repeating itself, from ``0.0`` to ``1.0`` (default is ``0.0``, i.e. no
        repetitions). Setting :attr:`weighted_duration` to ``True`` will give
        more weight to the larger container (considering both its number of
        notes as well its length), making it more likely that both will fade in
        and out at a similar rate (default value is ``False``).
        :attr:`disable_rewrite_meter` disables the
        |abjad.Meter.rewrite_meter()| mutation which is applied to the
        container after every call, and :attr:`omit_time_signatures` will
        remove all time signatures from the output (both are ``False`` by
        default). 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.

        >>> fade_out_container = abjad.Container(r"fs'4 g'2 bf'4")
        >>> fade_in_container = abjad.Container(r"\times 4/5 {cs''4 d''1}")
        >>> fader = auxjad.CrossFader(fade_out_container,
        ...                           fade_in_container,
        ...                           fade_in_first=True,
        ...                           fade_out_last=True,
        ...                           initial_repetitions=3,
        ...                           final_repetitions=3,
        ...                           repetition_chance=0.7,
        ...                           weighted_duration=True,
        ...                           disable_rewrite_meter=True,
        ...                           omit_time_signatures=True,
        ...                           use_multimeasure_rests=True,
        ...                           boundary_depth=True,
        ...                           maximum_dot_count=True,
        ...                           rewrite_tuplets=True,
        ...                           )
        >>> fader.fade_in_first
        True
        >>> fader.fade_out_last
        True
        >>> fader.initial_repetitions
        3
        >>> fader.final_repetitions
        3
        >>> fader.repetition_chance
        0.7
        >>> fader.weighted_duration
        True
        >>> fader.disable_rewrite_meter
        True
        >>> fader.omit_time_signatures
        True
        >>> fader.use_multimeasure_rests
        True
        >>> fader.boundary_depth
        True
        >>> fader.maximum_dot_count
        True
        >>> fader.rewrite_tuplets
        True

        Use the properties below to change these values after initialisation.

        >>> fader.fade_in_first = False
        >>> fader.fade_out_last = False
        >>> fader.initial_repetitions = 4
        >>> fader.final_repetitions = 7
        >>> fader.repetition_chance = 0.23
        >>> fader.weighted_duration = False
        >>> fader.disable_rewrite_meter = False
        >>> fader.omit_time_signatures = False
        >>> fader.use_multimeasure_rests = False
        >>> fader.boundary_depth = False
        >>> fader.maximum_dot_count = False
        >>> fader.rewrite_tuplets = False
        >>> fader.fade_in_first
        False
        >>> fader.fade_out_last
        False
        >>> fader.initial_repetitions
        4
        >>> fader.final_repetitions
        7
        >>> fader.repetition_chance
        0.23
        >>> fader.weighted_duration
        False
        >>> fader.disable_rewrite_meter
        False
        >>> fader.omit_time_signatures
        False
        >>> fader.use_multimeasure_rests
        False
        >>> fader.boundary_depth
        False
        >>> fader.maximum_dot_count
        False
        >>> fader.rewrite_tuplets
        False

    :meth:`reset`:
        Use the :meth:`reset` method to reset the fader to its initial state.
        This can be used to restart the process at any time.

        >>> fade_out_container = abjad.Container(r"fs'4 g'2 bf'4")
        >>> fade_in_container = abjad.Container(r"\times 4/5 {cs''4 d'1}")
        >>> fader = auxjad.CrossFader(fade_out_container, fade_in_container)
        >>> staff_a = abjad.Staff()
        >>> staff_b = abjad.Staff()
        >>> for _ in range(3):
        ...     selection_a, selection_b = fader()
        ...     staff_a.extend(selection_a)
        ...     staff_b.extend(selection_b)
        >>> fader.reset()
        >>> selection_a, selection_b = fader()
        >>> staff_a.extend(selection_a)
        >>> staff_b.extend(selection_b)
        >>> auxjad.mutate.remove_repeated_time_signatures(staff_a)
        >>> auxjad.mutate.remove_repeated_time_signatures(staff_b)
        >>> score = abjad.Score([staff_a, staff_b])
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    \time 4/4
                    fs'4
                    g'2
                    bf'4
                    fs'4
                    g'2
                    bf'4
                    fs'4
                    r2
                    bf'4
                    fs'4
                    g'2
                    bf'4
                }
                \new Staff
                {
                    \time 4/4
                    R1
                    \times 4/5
                    {
                        cs''4
                        r1
                    }
                    \times 4/5
                    {
                        cs''4
                        r1
                    }
                    R1
                }
            >>

        ..  figure:: ../_images/CrossFader-pauqe26ke8e.png

    Chords:
        This class also support chords. Each of their individual notes are
        removed or added one by one.

        >>> fade_out_container = abjad.Container(r"\times 2/3 {<c' e'>2 g'1}")
        >>> fade_in_container = abjad.Container(r"<d' ef'>2. <bf a'>4")
        >>> fader = auxjad.CrossFader(fade_out_container,
        ...                           fade_in_container,
        ...                           fade_in_first=True,
        ...                           fade_out_last=True,
        ...                           )
        >>> selection_a, selection_b = fader.output_all()
        >>> score = abjad.Score([
        ...     abjad.Staff(selection_a),
        ...     abjad.Staff(selection_b),
        ... ])
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    \times 2/3
                    {
                        \time 4/4
                        <c' e'>2
                        g'1
                    }
                    \times 2/3
                    {
                        <c' e'>2
                        g'1
                    }
                    \times 2/3
                    {
                        <c' e'>2
                        g'1
                    }
                    \times 2/3
                    {
                        <c' e'>2
                        g'1
                    }
                    \times 2/3
                    {
                        c'2
                        g'1
                    }
                    \times 2/3
                    {
                        c'2
                        g'1
                    }
                    \times 2/3
                    {
                        c'2
                        r1
                    }
                    R1
                }
                \new Staff
                {
                    \time 4/4
                    R1
                    ef'2.
                    r4
                    <d' ef'>2.
                    r4
                    <d' ef'>2.
                    bf4
                    <d' ef'>2.
                    bf4
                    <d' ef'>2.
                    <bf a'>4
                    <d' ef'>2.
                    <bf a'>4
                    <d' ef'>2.
                    <bf a'>4
                }
            >>

        ..  figure:: ../_images/CrossFader-lm8byjxoayn.png

    :func:`len()`:
        The function :func:`len()` returns the sum of the number of notes of
        both :attr:`fade_in_contents` and :attr:`fade_out_contents`.

        >>> fade_out_container = abjad.Container(r"c'4 d'4 ~ d'4 r4")
        >>> fade_in_container = abjad.Container(r"r2 c''2")
        >>> fader = auxjad.CrossFader(fade_out_container, fade_in_container)
        >>> len(fader)
        3
        >>> fade_out_container = abjad.Container(r"fs'4 g'2 bf'4")
        >>> fade_in_container = abjad.Container(r"\times 4/5 {cs''4 d''1}")
        >>> fader = auxjad.CrossFader(fade_out_container, fade_in_container)
        >>> len(fader)
        5
        >>> fade_out_container = abjad.Container(r"c'4 d'4 ~ d'4 r4")
        >>> fade_in_container = abjad.Container(r"r2 <c'' e'' g''>2")
        >>> fader = auxjad.CrossFader(fade_out_container, fade_in_container)
        >>> len(fader)
        5

    :attr:`fade_in_first` and :attr:`fade_out_last`:
        Setting the property :attr:`fade_in_first` to ``True`` will ensure that
        a note from second container must be faded in before any note of the
        first container is removed (default ``False``). Setting
        :attr:`fade_out_last` to ``True`` will ensure that all notes from the
        second container must be faded in before the very last note of first
        container is removed (default ``False``).

        >>> fade_out_container = abjad.Container(r"\time 3/4 r4 c'4 d'4")
        >>> fade_in_container = abjad.Container(r"\time 3/4 a''4 g''2")
        >>> fader = auxjad.CrossFader(fade_out_container, fade_in_container)
        >>> selection_a, selection_b = fader.output_all()
        >>> score = abjad.Score([
        ...     abjad.Staff(selection_a),
        ...     abjad.Staff(selection_b),
        ... ])
        >>> abjad.show(score)

        ..  docs::

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

        ..  figure:: ../_images/CrossFader-sm9qcruxat.png

        >>> fader = auxjad.CrossFader(fade_out_container,
        ...                           fade_in_container,
        ...                           fade_out_last=True,
        ...                           )
        >>> selection_a, selection_b = fader.output_all()
        >>> score = abjad.Score([
        ...     abjad.Staff(selection_a),
        ...     abjad.Staff(selection_b),
        ... ])
        >>> abjad.show(score)

        ..  docs::

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

        ..  figure:: ../_images/CrossFader-2a4cyxsyxrg.png

        >>> fader = auxjad.CrossFader(fade_out_container,
        ...                           fade_in_container,
        ...                           fade_in_first=True,
        ...                           fade_out_last=True,
        ...                           )
        >>> selection_a, selection_b = fader.output_all()
        >>> score = abjad.Score([
        ...     abjad.Staff(selection_a),
        ...     abjad.Staff(selection_b),
        ... ])
        >>> abjad.show(score)

        ..  docs::

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

        ..  figure:: ../_images/CrossFader-oap1pnwrfqc.png

    :attr:`weighted_duration`:
        Setting :attr:`weighted_duration` to ``True`` will give more weight to
        the larger container (considering both its number of notes as well its
        length), making it more likely that both will fade in and out at a
        similar rate (default value is ``False``).

        >>> fade_out_container = abjad.Container(r"e'2 c'2")
        >>> fade_in_container = abjad.Container(
        ...     r"c''8 d''8 e''8 f''8 g''8 a''8 b''8 c'''8"
        ... )
        >>> fader = auxjad.CrossFader(fade_out_container, fade_in_container)
        >>> selection_a, selection_b = fader.output_all()
        >>> score = abjad.Score([
        ...     abjad.Staff(selection_a),
        ...     abjad.Staff(selection_b),
        ... ])
        >>> abjad.show(score)

        ..  docs::

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

        ..  figure:: ../_images/CrossFader-o58h79ijsdf.png

        >>> fader = auxjad.CrossFader(fade_out_container,
        ...                           fade_in_container,
        ...                           weighted_duration=True,
        ...                           )
        >>> selection_a, selection_b = fader.output_all()
        >>> score = abjad.Score([
        ...     abjad.Staff(selection_a),
        ...     abjad.Staff(selection_b),
        ... ])
        >>> abjad.show(score)

        ..  docs::

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

        ..  figure:: ../_images/CrossFader-l3dc3vxfpdnsxdym4gql.png

    :attr:`initial_repetitions` and :attr:`final_repetitions`:
        The properties :attr:`initial_repetitions` and
        :attr:`final_repetitions` set the number of repetitions of the initial
        and final measures (default is ``1`` for both).

        >>> fade_out_container = abjad.Container(r"a'4 bf'2 r4")
        >>> fade_in_container = abjad.Container(r"c''2 d''2")
        >>> fader = auxjad.CrossFader(fade_out_container,
        ...                           fade_in_container,
        ...                           initial_repetitions=2,
        ...                           final_repetitions=3,
        ...                           )
        >>> selection_a, selection_b = fader.output_all()
        >>> score = abjad.Score([
        ...     abjad.Staff(selection_a),
        ...     abjad.Staff(selection_b),
        ... ])
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    \time 4/4
                    a'4
                    bf'2
                    r4
                    a'4
                    bf'2
                    r4
                    r4
                    bf'2
                    r4
                    r4
                    bf'2
                    r4
                    r4
                    bf'2
                    r4
                    R1
                    R1
                    R1
                }
                \new Staff
                {
                    \time 4/4
                    R1
                    R1
                    R1
                    r2
                    d''2
                    c''2
                    d''2
                    c''2
                    d''2
                    c''2
                    d''2
                    c''2
                    d''2
                }
            >>

        ..  figure:: ../_images/CrossFader-e480tbrvwg.png

    :attr:`repetition_chance`:
        Use :attr:`repetition_chance` to set the chance of a measure repeating
        itself, ranging from ``0.0`` to ``1.0`` (default is ``0.0``,
        i.e. no repetitions).

        >>> fade_out_container = abjad.Container(r"a'4 bf'2 r4")
        >>> fade_in_container = abjad.Container(r"c''2 d''2")
        >>> fader = auxjad.CrossFader(fade_out_container,
        ...                           fade_in_container,
        ...                           repetition_chance=0.8,
        ...                           )
        >>> selection_a, selection_b = fader.output_n(4)
        >>> score = abjad.Score([
        ...     abjad.Staff(selection_a),
        ...     abjad.Staff(selection_b),
        ... ])
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    \time 4/4
                    a'4
                    bf'2
                    r4
                    a'4
                    bf'2
                    r4
                    a'4
                    bf'2
                    r4
                    a'4
                    bf'2
                    r4
                }
                \new Staff
                {
                    \time 4/4
                    R1
                    r2
                    d''2
                    r2
                    d''2
                    r2
                    d''2
                }
            >>

        ..  figure:: ../_images/CrossFader-743rxr2n02o.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.

        >>> fade_out_container = abjad.Container(r"fs'4 g'2 bf'4")
        >>> fade_in_container = abjad.Container(r"\times 4/5 {cs''4 d''1}")
        >>> fader = auxjad.CrossFader(fade_out_container,
        ...                           fade_in_container,
        ...                           omit_time_signatures=True,
        ...                           )
        >>> selection_a, selection_b = fader.output_n(3)
        >>> score = abjad.Score([
        ...     abjad.Staff(selection_a),
        ...     abjad.Staff(selection_b),
        ... ])
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    fs'4
                    g'2
                    bf'4
                    fs'4
                    g'2
                    r4
                    fs'4
                    g'2
                    r4
                }
                \new Staff
                {
                    R1
                    R1
                    \times 4/5
                    {
                        cs''4
                        r1
                    }
                }
            >>

        ..  figure:: ../_images/CrossFader-aypzofmynwe.png

    ..  tip::

        All methods that return an |abjad.Selection| will add an initial time
        signature to it. The :meth:`output_n` and :meth:`output_all` methods
        automatically remove repeated time signatures. When joining selections
        output by multiple method calls, use
        |auxjad.mutate.remove_repeated_time_signatures()| on the whole
        container after fusing the selections to remove any unecessary time
        signature changes.

    Tweaking or disabling |abjad.Meter.rewrite_meter()|:
        This function uses the default logical tie splitting algorithm from
        |abjad.Meter.rewrite_meter()|. It can be disabled with the property
        :attr:`disable_rewrite_meter`.

        >>> fade_out_container = abjad.Container(r"c'8 d'4 e'8 ~ e'2")
        >>> fade_in_container = abjad.Container(r"c'2 d'2")
        >>> fader = auxjad.CrossFader(fade_out_container,
        ...                           fade_in_container,
        ...                           disable_rewrite_meter=True,
        ...                           )
        >>> selection_a, selection_b = fader.output_n(3)
        >>> score = abjad.Score([
        ...     abjad.Staff(selection_a),
        ...     abjad.Staff(selection_b),
        ... ])
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    \time 4/4
                    c'8
                    d'4
                    e'8
                    ~
                    e'2
                    r8
                    d'4
                    e'8
                    ~
                    e'2
                    r8
                    d'4
                    e'8
                    ~
                    e'2
                }
                \new Staff
                {
                    \time 4/4
                    R1
                    R1
                    r2
                    d'2
                }
            >>

        ..  figure:: ../_images/CrossFader-vprhoh84quk.png

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

    :attr:`fade_in_contents` and :attr:`fade_out_contents`:
        Containers can be switched after initialisation by overwriting the
        properties :attr:`fade_in_contents` or :attr:`fade_out_contents`. This
        will reset the process.

        >>> fade_out_container = abjad.Container(
        ...     r"\time 3/4 e2 \times 2/3 {fs8 gs4}"
        ... )
        >>> fade_in_container = abjad.Container(
        ...     r"\time 3/4 c'8 d' e' f' g' a'"
        ... )
        >>> fader = auxjad.CrossFader(fade_out_container, fade_in_container)
        >>> fader.fade_out_contents = abjad.Container(r"\time 3/4 a4. bf4.")
        >>> print(fader)
        {
            %%% \time 3/4 %%%
            a4.
            bf4.
        }
        {
            %%% \time 3/4 %%%
            c'8
            d'8
            e'8
            f'8
            g'8
            a'8
        }

    Time signature changes:
        This class can handle time signature changes.

        >>> fade_out_container = abjad.Container(
        ...     r"\time 3/4 a'4 bf'2 ~ \time 2/4 bf'4 f'4"
        ... )
        >>> fade_in_container = abjad.Container(
        ...     r"\time 3/4 r16 cs''4.. e''4 \time 2/4 d''2"
        ... )
        >>> fader = auxjad.CrossFader(fade_out_container, fade_in_container)
        >>> selection_a, selection_b = fader.output_n(3)
        >>> score = abjad.Score([
        ...     abjad.Staff(selection_a),
        ...     abjad.Staff(selection_b),
        ... ])
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    \time 3/4
                    a'4
                    bf'2
                    ~
                    \time 2/4
                    bf'4
                    f'4
                    \time 3/4
                    a'4
                    bf'2
                    ~
                    \time 2/4
                    bf'4
                    f'4
                    \time 3/4
                    a'4
                    bf'2
                    ~
                    \time 2/4
                    bf'4
                    r4
                }
                \new Staff
                {
                    \time 3/4
                    R1 * 3/4
                    \time 2/4
                    R1 * 1/2
                    \time 3/4
                    r16
                    cs''4..
                    r4
                    \time 2/4
                    R1 * 1/2
                    \time 3/4
                    r16
                    cs''4..
                    r4
                    \time 2/4
                    R1 * 1/2
                }
            >>

        ..  figure:: ../_images/CrossFader-w99zcui5rj.png

    Indicators:
        This class can also handle dynamics, articulations, chords, and
        tuplets. Hairpins might need manual tweaking if the leaf under which
        they terminate is removed.

        >>> fade_out_container = abjad.Container(r"c'4.\p e'8--\f ~ e'2")
        >>> fade_in_container = abjad.Container(
        ...     r"\times 2/3 {f'4-.\pp r4 d'4->\f ~ } d'2"
        ... )
        >>> fader = auxjad.CrossFader(fade_out_container,
        ...                           fade_in_container,
        ...                           fade_in_first=True,
        ...                           fade_out_last=True,
        ...                           )
        >>> selection_a, selection_b = fader.output_all()
        >>> score = abjad.Score([
        ...     abjad.Staff(selection_a),
        ...     abjad.Staff(selection_b),
        ... ])
        >>> abjad.show(score)

        ..  docs::

            \new Score
            <<
                \new Staff
                {
                    \time 4/4
                    c'4.
                    \p
                    e'8
                    \f
                    - \tenuto
                    ~
                    e'2
                    c'4.
                    \p
                    e'8
                    \f
                    - \tenuto
                    ~
                    e'2
                    r4.
                    e'8
                    - \tenuto
                    ~
                    e'2
                    r4.
                    e'8
                    - \tenuto
                    ~
                    e'2
                    R1
                }
                \new Staff
                {
                    \time 4/4
                    R1
                    \times 2/3
                    {
                        f'4
                        \pp
                        - \staccato
                        r2
                    }
                    r2
                    \times 2/3
                    {
                        f'4
                        - \staccato
                        r2
                    }
                    r2
                    \times 2/3
                    {
                        f'4
                        - \staccato
                        r4
                        d'4
                        \f
                        - \accent
                        ~
                    }
                    d'2
                    \times 2/3
                    {
                        f'4
                        \pp
                        - \staccato
                        r4
                        d'4
                        \f
                        - \accent
                        ~
                    }
                    d'2
                }
            >>

        ..  figure:: ../_images/CrossFader-o0yetbq5wqj.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.

    Using multiple voices:
        The selections output by the fader can also be assigned to
        |abjad.Voice| containers, which can then be displayed simultaneously on
        a single |abjad.Staff|.

        >>> fade_out_container = abjad.Container(r"b'8 c''8 e''2 g''4")
        >>> fade_in_container = abjad.Container(r"\times 2/3 {e'2 d'2 c'2}")
        >>> fader = auxjad.CrossFader(fade_out_container, fade_in_container)
        >>> selection_a, selection_b = fader.output_all()
        >>> literal_voice_one = abjad.LilyPondLiteral(r'\voiceOne')
        >>> literal_voice_two = abjad.LilyPondLiteral(r'\voiceTwo')
        >>> abjad.attach(literal_voice_one, selection_a[0])
        >>> abjad.attach(literal_voice_two, selection_b[0])
        >>> staff = abjad.Staff(
        ...     [abjad.Voice(selection_a), abjad.Voice(selection_b)],
        ...     simultaneous=True,
        ... )
        >>> abjad.show(staff)

        ..  docs::

            \new Staff
            <<
                \new Voice
                {
                    \time 4/4
                    \voiceOne
                    b'8
                    c''8
                    e''2
                    g''4
                    b'8
                    c''8
                    e''2
                    r4
                    b'8
                    c''8
                    e''2
                    r4
                    b'8
                    c''8
                    e''2
                    r4
                    b'8
                    c''8
                    e''2
                    r4
                    b'8
                    c''8
                    r2.
                    b'8
                    r2..
                    R1
                }
                \new Voice
                {
                    \time 4/4
                    \voiceTwo
                    R1
                    R1
                    \times 2/3
                    {
                        r1
                        c'2
                    }
                    \times 2/3
                    {
                        e'2
                        r2
                        c'2
                    }
                    \times 2/3
                    {
                        e'2
                        d'2
                        c'2
                    }
                    \times 2/3
                    {
                        e'2
                        d'2
                        c'2
                    }
                    \times 2/3
                    {
                        e'2
                        d'2
                        c'2
                    }
                    \times 2/3
                    {
                        e'2
                        d'2
                        c'2
                    }
                }
            >>

        ..  figure:: ../_images/CrossFader-rZLSa2kyqM.png

    Using containers of different lengths:
        It is possible to use this class with containers of different lengths
        and time signatures, although this feature is not fully implemented and
        should be considered experimental. LilyPond must be set up to allow
        different simultaneous time signatures, and
        |auxjad.mutate.sync_containers()| can be used to add rests to the end
        of the shorter staff. In order to enable polymetric notation in
        LilyPond, the command ``"\enablePolymeter"`` must be added to the
        layout block. Below is a full example of how this can be accomplished
        using Abjad.

        >>> fade_out_container = abjad.Container(r"\time 3/4 c'4 d'4 e'4")
        >>> fade_in_container = abjad.Container(r"\time 4/4 g'2 a'2")
        >>> fader = auxjad.CrossFader(fade_out_container,
        ...                           fade_in_container,
        ...                           fade_in_first=True,
        ...                           fade_out_last=True,
        ...                           weighted_duration=True,
        ...                           )
        >>> selection_a, selection_b = fader.output_all()
        >>> staff_a = abjad.Staff(selection_a)
        >>> staff_b = abjad.Staff(selection_b)
        >>> abjad.mutate.sync_containers([staff_a, staff_b])
        >>> score = abjad.Score([staff_a, staff_b])
        >>> lilypond_file = abjad.LilyPondFile.new()
        >>> score_block = abjad.Block(name='score')
        >>> layout_block = abjad.Block(name='layout')
        >>> score_block.items.append(score)
        >>> score_block.items.append(layout_block)
        >>> lilypond_file.items.append(score_block)
        >>> layout_block.items.append(r'\enablePolymeter')
        >>> abjad.show(score)

        ..  docs::

            \version "2.19.82"  %! abjad.LilyPondFile._get_format_pieces()
            \language "english" %! abjad.LilyPondFile._get_format_pieces()
            \header { %! abjad.LilyPondFile._get_formatted_blocks()
                tagline = ##f
            } %! abjad.LilyPondFile._get_formatted_blocks()
            \layout {}
            \paper {}
            \score { %! abjad.LilyPondFile._get_formatted_blocks()
                \new Score
                <<
                    \new Staff
                    {
                        \time 3/4
                        c'4
                        d'4
                        e'4
                        c'4
                        d'4
                        e'4
                        c'4
                        r4
                        e'4
                        c'4
                        r2
                        c'4
                        r2
                        R1 * 3/4
                        R1 * 3/4
                        R1 * 3/4
                    }
                    \new Staff
                    {
                        \time 4/4
                        R1
                        r2
                        a'2
                        r2
                        a'2
                        r2
                        a'2
                        g'2
                        a'2
                        g'2
                        a'2
                    }
                >>
                \layout {
                    \enablePolymeter
                }
            } %! abjad.LilyPondFile._get_formatted_blocks()

        ..  figure:: ../_images/CrossFader-5qvaan79w8p.png
    """

    ### CLASS VARIABLES ###

    __slots__ = (
        "_fade_out_contents",
        "_fade_in_contents",
        "_fader_in",
        "_fader_out",
        "_faders",
        "_weights",
        "_weighted_duration",
        "_is_first_window",
        "_is_first_process",
        "_repetition_chance",
        "_initial_repetitions",
        "_final_repetitions",
        "_initial_repetitions_counter",
        "_final_repetitions_counter",
        "_disable_rewrite_meter",
        "_omit_time_signatures",
        "_use_multimeasure_rests",
        "_boundary_depth",
        "_maximum_dot_count",
        "_rewrite_tuplets",
        "_fade_in_first",
        "_fade_out_last",
    )

    ### INITIALISER ###

    def __init__(
        self,
        fade_out_contents: abjad.Container,
        fade_in_contents: abjad.Container,
        *,
        fade_in_first: bool = False,
        fade_out_last: bool = False,
        initial_repetitions: int = 1,
        final_repetitions: int = 1,
        repetition_chance: float = 0.0,
        weighted_duration: bool = False,
        disable_rewrite_meter: bool = False,
        omit_time_signatures: bool = False,
        use_multimeasure_rests: bool = True,
        boundary_depth: Optional[int] = None,
        maximum_dot_count: Optional[int] = None,
        rewrite_tuplets: bool = True,
    ) -> None:
        if not isinstance(fade_out_contents, abjad.Container):
            raise TypeError("'fade_out_contents' must be 'abjad.Container' or child class")
        if not isinstance(fade_in_contents, abjad.Container):
            raise TypeError("'fade_in_contents' must be 'abjad.Container' or child class")
        self._fade_out_contents = fade_out_contents
        self._fade_in_contents = fade_in_contents
        self._fader_out = Fader(self._fade_out_contents, mode="out")
        self._fader_in = Fader(self._fade_in_contents, mode="in")
        self._faders = (self._fader_in, self._fader_out)
        self._is_first_window = True
        self._is_first_process = True
        self._initial_repetitions_counter = 0
        self._final_repetitions_counter = 0
        self.fade_in_first = fade_in_first
        self.fade_out_last = fade_out_last
        self.disable_rewrite_meter = disable_rewrite_meter
        self.omit_time_signatures = omit_time_signatures
        self.use_multimeasure_rests = use_multimeasure_rests
        self.boundary_depth = boundary_depth
        self.maximum_dot_count = maximum_dot_count
        self.rewrite_tuplets = rewrite_tuplets
        self.initial_repetitions = initial_repetitions
        self.final_repetitions = final_repetitions
        self.repetition_chance = repetition_chance
        self.weighted_duration = weighted_duration

    ### SPECIAL METHODS ###

    def __repr__(self) -> str:
        r"""Returns interpreter representation of both contents."""
        strings = (
            abjad.lilypond(self._fader_out),
            abjad.lilypond(self._fader_in),
        )
        return "\n".join(strings)

    def __len__(self) -> int:
        r"""Returns the sum of the number of notes of both contents."""
        return len(self._fader_in) + len(self._fader_out)

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

    def __next__(self) -> tuple[abjad.Selection]:
        r"""Calls the cross fading process for one iteration, returning a
        :obj:`tuple` of |abjad.Selection| objects.
        """
        try:
            return self.__call__()
        except RuntimeError:
            raise StopIteration

    def __iter__(self) -> None:
        r"""Returns an iterator, allowing instances to be used as iterators."""
        return self

    ### PUBLIC METHODS ###

    def output_all(self) -> tuple[abjad.Selection]:
        r"""Goes through the whole fading process and outputs a tuple of two
        |abjad.Selection| objects.
        """
        self.reset()
        dummy_container_a = abjad.Container()
        dummy_container_b = abjad.Container()
        while True:
            try:
                result_a, result_b = self.__call__()
                dummy_container_a.extend(result_a)
                dummy_container_b.extend(result_b)
            except RuntimeError:
                break
        mutate.remove_repeated_time_signatures(dummy_container_a[:])
        mutate.remove_repeated_time_signatures(dummy_container_b[:])
        mutate.remove_repeated_dynamics(dummy_container_a[:])
        mutate.remove_repeated_dynamics(dummy_container_b[:])
        output = (dummy_container_a[:], dummy_container_b[:])
        dummy_container_a[:] = []
        dummy_container_b[:] = []
        return output

    def output_n(
        self,
        n: int,
    ) -> tuple[abjad.Selection]:
        r"""Goes through ``n`` iterations of the fading process and outputs a
        tuple of two |abjad.Selection| objects.
        """
        if not isinstance(n, int):
            raise TypeError("first positional argument must be 'int'")
        if n < 1:
            raise ValueError("first positional argument must be a positive 'int'")
        self.reset()
        dummy_container_a = abjad.Container()
        dummy_container_b = abjad.Container()
        for _ in range(n):
            try:
                result_a, result_b = self.__call__()
                dummy_container_a.extend(result_a)
                dummy_container_b.extend(result_b)
            except RuntimeError:
                break
        mutate.remove_repeated_time_signatures(dummy_container_a[:])
        mutate.remove_repeated_time_signatures(dummy_container_b[:])
        mutate.remove_repeated_dynamics(dummy_container_a[:])
        mutate.remove_repeated_dynamics(dummy_container_b[:])
        output = (dummy_container_a[:], dummy_container_b[:])
        dummy_container_a[:] = []
        dummy_container_b[:] = []
        return output

    def reset(self) -> None:
        r"""Resets to the initial state."""
        self._is_first_window = True
        self._is_first_process = True
        self._initial_repetitions_counter = 0
        self._final_repetitions_counter = 0
        self._fader_in.reset()
        self._fader_out.reset()

    ### PRIVATE METHODS ###

    def _cross_fade_process(self) -> None:
        r"""Processes both faders according to the cross fade process."""
        if self._is_first_window:
            self._fader_out()
            self._fader_in()
            self._initial_repetitions_counter += 1
            self._is_first_window = False
        elif self._initial_repetitions_counter < self._initial_repetitions:
            self._initial_repetitions_counter += 1
        elif self._done:
            if self._final_repetitions_counter < self._final_repetitions - 1:
                self._final_repetitions_counter += 1
            else:
                raise RuntimeError("both faders have been exhausted")
        else:
            if (
                self._is_first_process
                or self._repetition_chance == 0.0
                or random.random() > self._repetition_chance
            ):
                if self._fade_in_first and self._is_first_process:
                    self._fader_in()
                    self._is_first_process = False
                elif (
                    self._fade_out_last
                    and sum(self._fader_out._mask) == 1
                    and not self._fader_in._done
                ):
                    self._fader_in()
                else:
                    try:
                        random_fader = random.choices(
                            self._faders,
                            weights=self._weights,
                        )[0]
                        random_fader()
                    except RuntimeError:
                        other_fader = self._faders[0]
                        if other_fader is random_fader:
                            other_fader = self._faders[1]
                        other_fader()
                    finally:
                        self._is_first_process = False

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

    ### PUBLIC PROPERTIES ###

    @property
    def fade_out_contents(self) -> abjad.Container:
        r"""The |abjad.Container| to be faded out."""
        return abjad.mutate.copy(self._fade_out_contents)

    @fade_out_contents.setter
    def fade_out_contents(
        self,
        fade_out_contents: abjad.Container,
    ) -> None:
        if not isinstance(fade_out_contents, abjad.Container):
            raise TypeError("'fade_out_contents' must be 'abjad.Container' or child class")
        leaves = abjad.select(fade_out_contents).leaves()
        if not leaves.are_contiguous_logical_voice():
            raise ValueError("'fade_out_contents' must be contiguous logical voice")
        self._fade_out_contents = abjad.mutate.copy(fade_out_contents)
        self._fader_out.contents = self._fade_out_contents
        self.reset()

    @property
    def fade_in_contents(self) -> abjad.Container:
        r"""The |abjad.Container| to be faded in."""
        return abjad.mutate.copy(self._fade_in_contents)

    @fade_in_contents.setter
    def fade_in_contents(
        self,
        fade_in_contents: abjad.Container,
    ) -> None:
        if not isinstance(fade_in_contents, abjad.Container):
            raise TypeError("'fade_in_contents' must be 'abjad.Container' or child class")
        leaves = abjad.select(fade_in_contents).leaves()
        if not leaves.are_contiguous_logical_voice():
            raise ValueError("'fade_in_contents' must be contiguous logical voice")
        self._fade_in_contents = abjad.mutate.copy(fade_in_contents)
        self._fader_in.contents = self._fade_in_contents
        self.reset()

    @property
    def current_window(self) -> tuple[abjad.Selection]:
        r"""Read-only property, returns the result of the last operation as a
        :obj:`tuple` of |abjad.Selection| objects.
        """
        return (self._fader_out.current_window, self._fader_in.current_window)

    @property
    def weighted_duration(self) -> bool:
        r"""Weights the choice of fader according to its number of notes and
        total duration.
        """
        return self._weighted_duration

    @weighted_duration.setter
    def weighted_duration(
        self,
        weighted_duration: bool,
    ) -> None:
        if not isinstance(weighted_duration, bool):
            raise TypeError("'weighted_duration' must be 'bool'")
        self._weighted_duration = weighted_duration
        if self._weighted_duration:
            self._weights = []
            for container in [self._fade_in_contents, self._fade_out_contents]:
                notes = abjad.select(container).logical_ties(pitched=True)
                duration = abjad.get.duration(container)
                value = len(notes) * float(duration)
                self._weights.append(value)
        else:
            self._weights = [1.0, 1.0]

    @property
    def repetition_chance(self) -> float:
        r"""The chance of not processing neither :attr:`fade_in_contents` not
        :attr:`fade_out_contents` on a call, thus repeating the previous
        output.
        """
        return self._repetition_chance

    @repetition_chance.setter
    def repetition_chance(
        self,
        repetition_chance: float,
    ) -> None:
        if not isinstance(repetition_chance, float):
            raise TypeError("'repetition_chance' must be 'float'")
        if repetition_chance < 0.0 or repetition_chance > 1.0:
            raise ValueError("'repetition_chance' must be between 0.0 and 1.0")
        self._repetition_chance = repetition_chance

    @property
    def initial_repetitions(self) -> int:
        r"""The number of times the initial containers are repeated before the
        cross fade process starts.
        """
        return self._initial_repetitions

    @initial_repetitions.setter
    def initial_repetitions(
        self,
        initial_repetitions: int,
    ) -> None:
        if not isinstance(initial_repetitions, int):
            raise TypeError("'initial_repetitions' must be 'int'")
        if initial_repetitions < 1:
            raise ValueError("'initial_repetitions' must be greater than zero")
        self._initial_repetitions = initial_repetitions

    @property
    def final_repetitions(self) -> int:
        r"""The number of times the final containers are repeated after the
        cross fade process ends.
        """
        return self._final_repetitions

    @final_repetitions.setter
    def final_repetitions(
        self,
        final_repetitions: int,
    ) -> None:
        if not isinstance(final_repetitions, int):
            raise TypeError("'final_repetitions' must be 'int'")
        if final_repetitions < 1:
            raise ValueError("'final_repetitions' must be greater than zero")
        self._final_repetitions = final_repetitions

    @property
    def initial_repetitions_counter(self) -> int:
        r"""Read-only property, returns the counter of
        :attr:`initial_repetitions`.
        """
        return self._initial_repetitions_counter

    @property
    def final_repetitions_counter(self) -> int:
        r"""Read-only property, returns the counter of
        :attr:`final_repetitions`.
        """
        return self._final_repetitions_counter

    @property
    def fade_in_first(self) -> bool:
        r"""When ``True``, the first note of the fade in content will be added
        before a note from the fade out content is removed.
        """
        return self._fade_in_first

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

    @property
    def fade_out_last(self) -> bool:
        r"""When ``True``, the last note of the fade out content will be
        removed only after the full fade in content is added.
        """
        return self._fade_out_last

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

    @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.
        """
        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
        self._fader_in.disable_rewrite_meter = disable_rewrite_meter
        self._fader_out.disable_rewrite_meter = disable_rewrite_meter

    @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
        self._fader_in.omit_time_signatures = omit_time_signatures
        self._fader_out.omit_time_signatures = omit_time_signatures

    @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
        self._fader_in.use_multimeasure_rests = use_multimeasure_rests
        self._fader_out.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
        self._fader_in.boundary_depth = boundary_depth
        self._fader_out.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
        self._fader_in.maximum_dot_count = maximum_dot_count
        self._fader_out.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
        self._fader_in.rewrite_tuplets = rewrite_tuplets
        self._fader_out.rewrite_tuplets = rewrite_tuplets

    ### PRIVATE PROPERTIES ###

    @property
    def _done(self) -> bool:
        r""":obj:`bool` indicating whether the process is done, which is when
        both faders are done.
        """
        return all(fader._done for fader in self._faders)
