Source code for auxjad.mutate.merge_partial_tuplets

import abjad


[docs]def merge_partial_tuplets(selection: abjad.Selection, *, merge_across_barlines: bool = False, ) -> None: r"""Mutates an input |abjad.Selection| in place and has no return value; this function merges all consecutive partial tuplets with the same ratio and which sum up to an assignable duration. Partial tuplets can result from algorithmic manipulations such as phasing or looping, which can slice through a tuplet. Basic usage: Usage is simple: >>> staff = abjad.Staff(r"\times 2/3 {c'1} \times 2/3 {d'2}") >>> abjad.show(staff) .. docs:: \new Staff { \times 2/3 { c'1 } \times 2/3 { d'2 } } .. figure:: ../_images/merge_partial_tuplets-ilr68s15kqb.png >>> auxjad.mutate.merge_partial_tuplets(staff[:]) >>> abjad.show(staff) .. docs:: \new Staff { \times 2/3 { c'1 d'2 } } .. figure:: ../_images/merge_partial_tuplets-qe29etsedx.png .. note:: Auxjad automatically adds this function as an extension function to |abjad.mutate|. It can thus be used from either |auxjad.mutate|_ or |abjad.mutate| namespaces. Therefore, the two lines below are equivalent: >>> auxjad.mutate.merge_partial_tuplets(staff[:]) >>> abjad.mutate.merge_partial_tuplets(staff[:]) Multiple consecutive partial tuplets: This function can also handle several consecutive partial tuplets: >>> staff = abjad.Staff( ... r"\times 2/3 {c'2} \times 2/3 {d'2} \times 2/3 {e'2}" ... ) >>> abjad.show(staff) .. docs:: { \times 2/3 { c'2 } \times 2/3 { d'2 } \times 2/3 { e'2 } } .. figure:: ../_images/merge_partial_tuplets-9rh7vpu208j.png >>> auxjad.mutate.merge_partial_tuplets(staff[:]) >>> abjad.show(staff) .. docs:: \new Staff { \times 2/3 { c'2 d'2 e'2 } } .. figure:: ../_images/merge_partial_tuplets-oy1imqisx2.png ``merge_across_barlines``: By default, partial tuplets are not merged across barlines. >>> staff = abjad.Staff( ... r"\time 3/4 c'2. " ... r"\times 2/3 {d'4} r4 \times 2/3 {e'2} " ... r"\times 2/3 {f'4} r4 \times 2/3 {g'2}" ... ) >>> auxjad.mutate.merge_partial_tuplets(staff[:]) >>> abjad.show(staff) .. docs:: \new Staff { \time 3/4 c'2. \tweak edge-height #'(0.7 . 0) \times 2/3 { d'4 } r4 \tweak edge-height #'(0.7 . 0) \times 2/3 { e'2 } \tweak edge-height #'(0.7 . 0) \times 2/3 { f'4 } r4 \tweak edge-height #'(0.7 . 0) \times 2/3 { g'2 } } .. figure:: ../_images/merge_partial_tuplets-3rjib7pctml.png To change this behaviour, set ``merge_across_barlines`` to ``True``. >>> staff = abjad.Staff( ... r"\time 3/4 c'2. " ... r"\times 2/3 {d'4} r4 \times 2/3 {e'2} " ... r"\times 2/3 {f'4} r4 \times 2/3 {g'2}" ... ) >>> auxjad.mutate.merge_partial_tuplets( ... staff[:], ... merge_across_barlines=True, ... ) >>> abjad.show(staff) .. docs:: \new Staff { \time 3/4 c'2. \tweak edge-height #'(0.7 . 0) \times 2/3 { d'4 } r4 \times 2/3 { e'2 f'4 } r4 \tweak edge-height #'(0.7 . 0) \times 2/3 { g'2 } } .. figure:: ../_images/merge_partial_tuplets-icud1ejcmzc.png Tied partial tuplets: Tied partial tuplets are also handled by this function. >>> staff = abjad.Staff( ... r"\times 2/3 {r4} \times 2/3 {c'2} " ... r"\times 4/5 {d'2~} \times 4/5{d'8}" ... ) >>> abjad.show(staff) .. docs:: \new Staff { \times 2/3 { r4 } \times 2/3 { c'2 } \times 4/5 { d'2 ~ } \times 4/5 { d'8 } } .. figure:: ../_images/merge_partial_tuplets-st4zw38qfce.png >>> auxjad.mutate.merge_partial_tuplets(staff[:]) >>> abjad.show(staff) .. docs:: \new Staff { \times 2/3 { r4 c'2 } \times 4/5 { d'2 ~ d'8 } } .. figure:: ../_images/merge_partial_tuplets-1pky5fsh2nl.png Indicators: Indicators stay the same in the merged tuplet. >>> staff = abjad.Staff( ... r"\times 2/3 {c'2\p\< d'2} \times 2/3 {e'2\ff}" ... ) >>> abjad.show(staff) .. docs:: \new Staff { \times 2/3 { c'2 \p \< d'2 } \times 2/3 { e'2 \ff } } .. figure:: ../_images/merge_partial_tuplets-7cdtafl348h.png >>> auxjad.mutate.merge_partial_tuplets(staff[:]) >>> abjad.show(staff) .. docs:: \new Staff { \times 2/3 { c'2 \p \< d'2 e'2 \ff } } .. figure:: ../_images/merge_partial_tuplets-j9rmdfbawce.png .. tip:: The method |auxjad.mutate.extract_trivial_tuplets()| can be used after merging partial tuplets to further clean the output. The method |auxjad.mutate.auto_rewrite_meter()| can also be used for this purpose, as it will not only rewrite the metric notation of a staff but also apply both |auxjad.mutate.merge_partial_tuplets()| and |auxjad.mutate.extract_trivial_tuplets()| to the output. .. note:: When using |abjad.Container|'s, all time signatures in the output will be commented out with ``%%%.`` This is because Abjad only applies time signatures to containers that belong to a |abjad.Staff|. The present function works with either |abjad.Container| and |abjad.Staff|. >>> container = abjad.Container(r"\time 3/4 c'4 d'4 e'4") >>> abjad.show(container) .. docs:: { %%% \time 3/4 %%% c'4 d'4 e'4 } .. figure:: ../_images/merge_partial_tuplets-945s36mfdn.png >>> staff = abjad.Staff([container]) >>> abjad.show(container) .. docs:: { \time 3/4 c'4 d'4 e'4 } .. figure:: ../_images/merge_partial_tuplets-3b4tyqrnttw.png .. warning:: The input selection must be a contiguous logical voice. When dealing with a container with multiple subcontainers (e.g. a score containing multiple staves), the best approach is to cycle through these subcontainers, applying this function to them individually. """ if not isinstance(selection, abjad.Selection): raise TypeError("argument must be 'abjad.Selection'") if not isinstance(merge_across_barlines, bool): raise TypeError("'merge_across_barlines' must be 'bool'") tuplets = selection.tuplets() if len(tuplets) <= 1: return def _process_tuplets(tuplets): for index in range(len(tuplets[:-1])): for upper_index in range(index, len(tuplets)): if (tuplets[index].multiplier == tuplets[upper_index].multiplier): tuplet_group = tuplets[index:upper_index + 1] else: break if tuplet_group.are_contiguous_logical_voice(): durations = [abjad.get.duration(tuplet) for tuplet in tuplet_group] sum_durations = sum(durations) if (all(duration.implied_prolation != 1 for duration in durations) and sum_durations.implied_prolation == 1): for tuplet in tuplet_group[1:]: tuplet_group[0].extend(tuplet) abjad.mutate.extract(tuplet) if not merge_across_barlines: measures = selection.group_by_measure() for measure in measures: tuplets = abjad.select(measure).tuplets() if len(tuplets) <= 1: continue _process_tuplets(tuplets) else: _process_tuplets(tuplets)