Source code for auxjad.mutate.enforce_time_signature

from typing import Optional, Union

import abjad

from .auto_rewrite_meter import auto_rewrite_meter
from .close_container import close_container as close_container_function
from .fill_with_rests import fill_with_rests as fill_with_rests_function


[docs]def enforce_time_signature(container: abjad.Container, time_signatures: Union[abjad.TimeSignature, tuple, list, ], *, cyclic: bool = False, fill_with_rests: bool = True, close_container: bool = False, disable_rewrite_meter: bool = False, prettify_rewrite_meter: bool = True, boundary_depth: Optional[int] = None, maximum_dot_count: Optional[int] = None, rewrite_tuplets: bool = True, extract_trivial_tuplets: bool = True, fuse_across_groups_of_beats: bool = True, fuse_quadruple_meter: bool = True, fuse_triple_meter: bool = True, split_quadruple_meter: bool = True, ) -> None: r"""Mutates an input container (of type |abjad.Container| or child class) in place and has no return value; this function applies a time signature (or a :obj:`list` of time signatures) to the input container. Basic usage: The function mutates a container in place, applying a time signature to it. >>> staff = abjad.Staff(r"c'1 d'1") >>> abjad.show(staff) .. docs:: \new Staff { c'1 d'1 } .. figure:: ../_images/enforce_time_signature-9bf9zmnm19k.png >>> auxjad.mutate.enforce_time_signature( ... staff, ... abjad.TimeSignature((2, 4)) ... ) >>> abjad.show(staff) .. docs:: \new Staff { \time 2/4 c'2 ~ c'2 d'2 ~ d'2 } .. figure:: ../_images/enforce_time_signature-kerf9uos62i.png .. note:: Auxjad automatically adds this function as an extension function to |abjad.mutate|. It can thus be used from either |auxjad.mutate|_ or |abjad.mutate| namespaces. Therefore, the two lines below are equivalent: >>> auxjad.mutate.enforce_time_signature( ... staff, ... abjad.TimeSignature((2, 4)), ... ) >>> abjad.mutate.enforce_time_signature( ... staff, ... abjad.TimeSignature((2, 4)), ... ) Single value for second positional argument: The second positional argument can take either |abjad.TimeSignature| or a :obj:`tuple` for a single time signature (for multiple time signatures, use a :obj:`list` as shown further below). By default, rests will be appended to the end of the staff if necessary. >>> staff = abjad.Staff(r"c'1 d'1") >>> abjad.show(staff) .. docs:: \new Staff { c'1 d'1 } .. figure:: ../_images/enforce_time_signature-218f65bsco3.png >>> auxjad.mutate.enforce_time_signature(staff, (3, 4)) >>> abjad.show(staff) .. docs:: \new Staff { \time 3/4 c'2. ~ c'4 d'2 ~ d'2 r4 } .. figure:: ../_images/enforce_time_signature-u4p457k6ib7.png ``close_container``: Set the optional keyword argument ``close_container`` to ``True`` in order to adjust the last measure's time signature instead of filling it with rests. >>> staff = abjad.Staff(r"c'1 d'1 e'1 f'1") >>> abjad.show(staff) .. docs:: \new Staff { c'1 d'1 e'1 f'1 } .. figure:: ../_images/enforce_time_signature-tn1l53yimir.png >>> auxjad.mutate.enforce_time_signature( ... staff, ... abjad.TimeSignature((3, 4)), ... close_container=True, ... ) >>> abjad.show(staff) .. docs:: \new Staff { \time 3/4 c'2. ~ c'4 d'2 ~ d'2 e'4 ~ e'2. f'2. ~ \time 1/4 f'4 } .. figure:: ../_images/enforce_time_signature-1uhp08fqlpl.png ``fill_with_rests``: Alternatively, to leave the last measure as it is input (i.e. not filling it with rests nor adjusting the time signature), set the optional keyword argument ``fill_with_rests`` to ``False`` (default value is ``True``). >>> staff = abjad.Staff(r"c'1 d'1 e'1 f'1") >>> abjad.show(staff) .. docs:: \new Staff { c'1 d'1 e'1 f'1 } .. figure:: ../_images/enforce_time_signature-bit2y19hncr.png >>> auxjad.mutate.enforce_time_signature( ... staff, ... abjad.TimeSignature((3, 4)), ... fill_with_rests=False, ... ) >>> abjad.show(staff) .. docs:: \new Staff { \time 3/4 c'2. ~ c'4 d'2 ~ d'2 e'4 ~ e'2. f'2. ~ f'4 } .. figure:: ../_images/enforce_time_signature-xo7fpeqsoek.png Multiple values for second positional argument: The second argument can also take a :obj:`list` of |abjad.TimeSignature| or :obj:`tuple`. >>> staff = abjad.Staff(r"c'1 d'1") >>> abjad.show(staff) .. docs:: \new Staff { c'1 d'1 } .. figure:: ../_images/enforce_time_signature-rl1csjn9osl.png >>> time_signatures = [abjad.TimeSignature((3, 4)), ... abjad.TimeSignature((5, 4)), ... ] >>> auxjad.mutate.enforce_time_signature(staff, time_signatures) >>> abjad.show(staff) .. docs:: \new Staff { \time 3/4 c'2. ~ \time 5/4 c'4 d'1 } .. figure:: ../_images/enforce_time_signature-tqqrqi34bu.png Repeated time signatures: Consecutive identical time signatures are omitted. Also note that time signatures can also be represented as a :obj:`list` of :obj:`tuple`'s. >>> staff = abjad.Staff(r"c'1 d'1 e'1 f'1") >>> abjad.show(staff) .. docs:: \new Staff { c'1 d'1 e'1 f'1 } .. figure:: ../_images/enforce_time_signature-vn9ngz2k6cd.png >>> time_signatures = [(2, 4), ... (2, 4), ... (4, 4), ... ] >>> auxjad.mutate.enforce_time_signature(staff, time_signatures) >>> abjad.show(staff) .. docs:: \new Staff { \time 2/4 c'2 ~ c'2 \time 4/4 d'1 e'1 f'1 } .. figure:: ../_images/enforce_time_signature-nj2c90o0pe.png Alternatively, use ``None`` to indicate repeated time signatures: >>> staff = abjad.Staff(r"c'1 d'1 e'1 f'1") >>> abjad.show(staff) .. docs:: \new Staff { c'1 d'1 e'1 f'1 } .. figure:: ../_images/enforce_time_signature-2og5ld8bkxe.png >>> time_signatures = [(2, 4), ... None, ... None, ... (3, 4), ... None, ... (4, 4), ... ] >>> auxjad.mutate.enforce_time_signature(staff, time_signatures) >>> abjad.show(staff) .. docs:: \new Staff { \time 2/4 c'2 ~ c'2 d'2 ~ \time 3/4 d'2 e'4 ~ e'2. \time 4/4 f'1 } .. figure:: ../_images/enforce_time_signature-3s9h7p1k05x.png Implicit time signature: If the first time signature in a list is ``None``, this function assumes the music is written in 4/4 time signature, although it does not force it in the output. This is similar to LilyPond's behaviour, which fallbacks to a 4/4 time signature when none is present. >>> staff = abjad.Staff(r"c'1 d'1 e'2. f'2.") >>> time_signatures = [None, ... None, ... (3, 4), ... None, ... ] >>> auxjad.mutate.enforce_time_signature(staff, time_signatures) >>> abjad.show(staff) .. docs:: \new Staff { c'1 d'1 \time 3/4 e'2. f'2. } .. figure:: ../_images/enforce_time_signature-cJe2YevEo7.png ``cyclic``: To cycle through the :obj:`list` of time signatures until the container is exhausted, set the optional keyword argument ``cyclic`` to ``True``. >>> staff = abjad.Staff(r"c'1 d'1 e'1 f'1") >>> abjad.show(staff) .. docs:: \new Staff { c'1 d'1 e'1 f'1 } .. figure:: ../_images/enforce_time_signature-vl1bwp21saq.png >>> time_signatures = [abjad.TimeSignature((3, 8)), ... abjad.TimeSignature((2, 8)), ... ] >>> auxjad.mutate.enforce_time_signature( ... staff, ... time_signatures, ... cyclic=True, ... ) >>> abjad.show(staff) .. docs:: \new Staff { \time 3/8 c'4. ~ \time 2/8 c'4 ~ \time 3/8 c'4. \time 2/8 d'4 ~ \time 3/8 d'4. ~ \time 2/8 d'4 ~ \time 3/8 d'8 e'4 ~ \time 2/8 e'4 ~ \time 3/8 e'4. ~ \time 2/8 e'8 f'8 ~ \time 3/8 f'4. ~ \time 2/8 f'4 ~ \time 3/8 f'4 r8 } .. figure:: ../_images/enforce_time_signature-9mq64erlth6.png ``disable_rewrite_meter``: By default, this function applies the mutation |abjad.Meter.rewrite_meter()| to its output. >>> staff = abjad.Staff(r"c'1 ~ c'4 r8 d'4. e'4") >>> time_signatures = [abjad.TimeSignature((5, 4)), ... abjad.TimeSignature((3, 4)), ... ] >>> auxjad.mutate.enforce_time_signature(staff, time_signatures) >>> abjad.show(staff) .. docs:: \new Staff { \time 5/4 c'2. ~ c'2 \time 3/4 r8 d'4. e'4 } .. figure:: ../_images/enforce_time_signature-xsjbr0vnev9.png To disable this, set the keyword argument ``disable_rewrite_meter`` to ``True``. >>> staff = abjad.Staff(r"c'1 ~ c'4 r8 d'4. e'4") >>> time_signatures = [abjad.TimeSignature((5, 4)), ... abjad.TimeSignature((3, 4)), ... ] >>> auxjad.mutate.enforce_time_signature( ... staff, ... time_signatures, ... disable_rewrite_meter=True, ... ) >>> abjad.show(staff) .. docs:: \new Staff { \time 5/4 c'1 ~ c'4 \time 3/4 r8 d'4. e'4 } .. figure:: ../_images/enforce_time_signature-ezjnpwjd3xu.png Tuplets: The function handles tuplets, even if they must be split. >>> staff = abjad.Staff(r"\times 2/3 {c'2 d'2 e'2} f'1") >>> abjad.show(staff) .. docs:: \new Staff { \times 2/3 { c'2 d'2 e'2 } f'1 } .. figure:: ../_images/enforce_time_signature-v4ndqpmqjk.png >>> time_signatures = [abjad.TimeSignature((2, 4)), ... abjad.TimeSignature((3, 4)), ... ] >>> auxjad.mutate.enforce_time_signature(staff, time_signatures) >>> abjad.show(staff) .. docs:: \new Staff { \times 2/3 { \time 2/4 c'2 d'4 ~ } \times 2/3 { \time 3/4 d'4 e'2 } f'4 ~ f'2. } .. figure:: ../_images/enforce_time_signature-5jdoukq2rkd.png Time signatures in the input container: Note that any time signatures in the input container will be ignored. >>> staff = abjad.Staff(r"\time 3/4 c'2. d'2. e'2. f'2.") >>> abjad.show(staff) .. docs:: \new Staff { \time 3/4 c'2. d'2. e'2. f'2. } .. figure:: ../_images/enforce_time_signature-bnnz1hov5bu.png >>> time_signatures = [abjad.TimeSignature((5, 8)), ... abjad.TimeSignature((1, 16)), ... abjad.TimeSignature((2, 4)), ... ] >>> auxjad.mutate.enforce_time_signature( ... staff, ... time_signatures, ... cyclic=True, ... ) >>> abjad.show(staff) .. docs:: \new Staff { \time 5/8 c'4. ~ c'4 ~ \time 1/16 c'16 ~ \time 2/4 c'16 d'4.. ~ \time 5/8 d'4 ~ d'16 e'16 ~ e'4 ~ \time 1/16 e'16 ~ \time 2/4 e'4. f'8 ~ \time 5/8 f'4. ~ f'4 } .. figure:: ../_images/enforce_time_signature-2l289r8sdzl.png Tweaking |abjad.Meter.rewrite_meter()|: This function uses the default logical tie splitting algorithm from |abjad.Meter.rewrite_meter()|. >>> staff = abjad.Staff(r"c'4. d'8 e'2") >>> auxjad.mutate.enforce_time_signature( ... staff, ... abjad.TimeSignature((4, 4)), ... ) >>> abjad.show(staff) .. docs:: \new Staff { \time 4/4 c'4. d'8 e'2 } .. figure:: ../_images/enforce_time_signature-bykbobzx47.png Set ``boundary_depth`` to a different number to change its behaviour. >>> staff = abjad.Staff(r"c'4. d'8 e'2") >>> auxjad.mutate.enforce_time_signature( ... staff, ... abjad.TimeSignature((4, 4)), ... boundary_depth=1, ... ) >>> abjad.show(staff) .. docs:: \new Staff { \time 4/4 c'4 ~ c'8 d'8 e'2 } .. figure:: ../_images/enforce_time_signature-wljhgmjh9c.png Other arguments available for tweaking the output of |abjad.Meter.rewrite_meter()| are ``maximum_dot_count`` and ``rewrite_tuplets``, which work exactly as the identically named arguments of |abjad.Meter.rewrite_meter()|. This function also accepts the arguments ``fuse_across_groups_of_beats``, ``fuse_quadruple_meter``, ``fuse_triple_meter``, ``extract_trivial_tuplets``, and ``split_quadruple_meter``, 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. .. note:: When using |abjad.Container|'s, all time signatures in the output will be commented out with ``%%%.`` This is because Abjad only applies time signatures to containers that belong to a |abjad.Staff|. The present function works with either |abjad.Container| and |abjad.Staff|. >>> container = abjad.Container(r"\time 3/4 c'4 d'4 e'4") >>> abjad.show(container) .. docs:: { %%% \time 3/4 %%% c'4 d'4 e'4 } .. figure:: ../_images/enforce_time_signature-ntl3jgbi7j.png >>> staff = abjad.Staff([container]) >>> abjad.show(container) .. docs:: { \time 3/4 c'4 d'4 e'4 } .. figure:: ../_images/enforce_time_signature-y5sjtx3j0v.png .. warning:: The input container must be a contiguous logical voice. When dealing with a container with multiple subcontainers (e.g. a score containing multiple staves), the best approach is to cycle through these subcontainers, applying this function to them individually. """ if not isinstance(container, abjad.Container): raise TypeError("first argument must be 'abjad.Container' or " "child class") if not abjad.select(container).leaves().are_contiguous_logical_voice(): raise ValueError("first argument must be contiguous logical voice") if isinstance(time_signatures, list): time_signatures_ = time_signatures[:] else: time_signatures_ = [time_signatures] implicit_first_time_signature = False if time_signatures_[0] is None: time_signatures_[0] = abjad.TimeSignature((4, 4)) implicit_first_time_signature = True # converting all elements to abjad.TimeSignature for index, time_signature in enumerate(time_signatures_): if time_signature is None: previous_ts_duration = time_signatures_[index - 1].pair time_signatures_[index] = abjad.TimeSignature(previous_ts_duration) elif not isinstance(time_signature, abjad.TimeSignature): time_signatures_[index] = abjad.TimeSignature(time_signature) partial_time_signature = None if time_signatures_[0].partial is not None: partial_time_signature = time_signatures_[0] time_signatures_[0] = abjad.TimeSignature( partial_time_signature.duration ) partial_element = abjad.TimeSignature(partial_time_signature.partial) time_signatures_.insert(0, partial_element) if not isinstance(cyclic, bool): raise TypeError("'cyclic' must be 'bool'") if not isinstance(fill_with_rests, bool): raise TypeError("'fill_with_rests' must be 'bool'") if not isinstance(close_container, bool): raise TypeError("'close_container' must be 'bool'") if not isinstance(disable_rewrite_meter, bool): raise TypeError("'disable_rewrite_meter' must be 'bool'") if boundary_depth is not None: if not isinstance(boundary_depth, int): raise TypeError("'boundary_depth' must be 'int'") if maximum_dot_count is not None: if not isinstance(maximum_dot_count, int): raise TypeError("'maximum_dot_count' must be 'int'") if not isinstance(rewrite_tuplets, bool): raise TypeError("'rewrite_tuplets' must be 'bool'") if not isinstance(split_quadruple_meter, bool): raise TypeError("'split_quadruple_meter' must be 'bool'") # remove all time signatures from container for leaf in abjad.select(container).leaves(): if abjad.get.indicator(leaf, abjad.TimeSignature): abjad.detach(abjad.TimeSignature, leaf) # slice container at the places where time signatures change durations = [time_signature.duration for time_signature in time_signatures_] if not cyclic: while sum(durations) < abjad.get.duration(container): durations.append(durations[-1]) abjad.mutate.split(container[:], durations, cyclic=cyclic) # attach new time signatures previous_ts = None index = 0 duration = abjad.Duration(0) previous_ts_duration = abjad.Duration(0) for leaf in abjad.select(container).leaves(): if duration == previous_ts_duration: duration = abjad.Duration(0) previous_ts_duration = durations[index] if partial_time_signature is not None and index in (0, 1): ts = partial_time_signature else: ts = time_signatures_[index] if ts != previous_ts: abjad.attach(ts, leaf) previous_ts = ts index += 1 if index == len(time_signatures_): if cyclic: index = 0 else: break duration += abjad.get.duration(leaf) # filling with rests or closing container if close_container: close_container_function(container) elif fill_with_rests: fill_with_rests_function( container, disable_rewrite_meter=disable_rewrite_meter, ) # removing first time signature if implicit if implicit_first_time_signature: abjad.detach(abjad.TimeSignature, abjad.select(container).leaf(0)) # rewrite meter if not disable_rewrite_meter: measures = abjad.select(container[:]).group_by_measure() if cyclic: pattern = time_signatures_[:] while len(time_signatures_) < len(measures): time_signatures_ += pattern[:] else: while len(time_signatures_) < len(measures): time_signatures_.append(time_signatures_[-1]) auto_rewrite_meter( container, meter_list=time_signatures_, boundary_depth=boundary_depth, maximum_dot_count=maximum_dot_count, rewrite_tuplets=rewrite_tuplets, prettify_rewrite_meter=prettify_rewrite_meter, extract_trivial_tuplets=extract_trivial_tuplets, fuse_across_groups_of_beats=fuse_across_groups_of_beats, fuse_quadruple_meter=fuse_quadruple_meter, fuse_triple_meter=fuse_triple_meter, split_quadruple_meter=split_quadruple_meter, )