Source code for auxjad.mutate.reposition_clefs

import abjad


[docs]def reposition_clefs(selection: abjad.Selection, *, shift_clef_to_notes: bool = True, implicit_clef: abjad.Clef = abjad.Clef('treble'), ) -> None: r"""Mutates an input |abjad.Selection| in place and has no return value; this function removes all consecutive repeated clefs. It can also be used to shift clefs from rests to pitched leaves. Basic usage: When consecutive clefs are the same, the second one is removed: >>> staff = abjad.Staff(r"c'1 | d'1") >>> abjad.attach(abjad.Clef('treble'), staff[0]) >>> abjad.attach(abjad.Clef('treble'), staff[1]) >>> string = abjad.lilypond(staff) >>> print(string) \new Staff { \clef "treble" c'1 \clef "treble" d'1 } >>> abjad.show(staff) .. docs:: \new Staff { \clef "treble" c'1 \clef "treble" d'1 } .. figure:: ../_images/reposition_clefs-ve7c2iykuyb.png >>> auxjad.mutate.reposition_clefs(staff[:]) >>> string = abjad.lilypond(staff) >>> print(string) \new Staff { \clef "treble" c'1 d'1 } >>> abjad.show(staff) .. docs:: \new Staff { \clef "treble" c'1 d'1 } .. figure:: ../_images/reposition_clefs-w6sbmg4iihr.png .. note:: As seen above, LilyPond automatically omits repeated clefs unless the first clef is omitted. In that case, it uses a treble clef as fallback, although it won't then remove a subsequent repeated treble clef: >>> staff = abjad.Staff(r"c'1 | d'1") >>> abjad.attach(abjad.Clef('treble'), staff[1]) >>> abjad.show(staff) .. docs:: \new Staff { c'1 \clef "treble" d'1 } .. figure:: ../_images/reposition_clefs-ozr2sz3jugc.png This function handles fallback clefs too: >>> auxjad.mutate.reposition_clefs(staff[:]) >>> abjad.show(staff) .. docs:: \new Staff { c'1 d'1 } .. figure:: ../_images/reposition_clefs-0620w7q00lsr.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.reposition_clefs(staff[:]) >>> abjad.mutate.reposition_clefs(staff[:]) Clef structure: The function also removes clefs that are separated by an arbitrary number of leaves without clefs: >>> staff = abjad.Staff(r"c'1 | d'2 e'4 r4 | f'1") >>> abjad.attach(abjad.Clef('treble'), staff[4]) >>> abjad.show(staff) .. docs:: \new Staff { c'1 d'2 e'4 r4 \clef "treble" f'1 } .. figure:: ../_images/reposition_clefs-1dwpu3agebe.png >>> auxjad.mutate.reposition_clefs(staff[:]) >>> abjad.show(staff) .. docs:: \new Staff { c'1 d'2 e'4 r4 f'1 } .. figure:: ../_images/reposition_clefs-wjmmwbhtaq.png Inputs with optimal clef structure: The function will not alter the container if the clef changes are already optimal. >>> staff = abjad.Staff(r"c'1 | a,2 bf,4 r4 | f'1") >>> abjad.attach(abjad.Clef('bass'), staff[1]) >>> abjad.attach(abjad.Clef('treble'), staff[4]) >>> abjad.show(staff) .. docs:: \new Staff { c'1 \clef "bass" a,2 bf,4 r4 \clef "treble" f'1 } .. figure:: ../_images/reposition_clefs-ooacruvoibr.png >>> auxjad.mutate.reposition_clefs(staff[:]) >>> abjad.show(staff) .. docs:: \new Staff { c'1 \clef "bass" a,2 bf,4 r4 \clef "treble" f'1 } .. figure:: ../_images/reposition_clefs-8z0s96frl4x.png Multi-measure rests: The function handles rests and multi-measure rests. >>> staff = abjad.Staff(r"c'1 | d'2 r2 | R1 | e'1") >>> abjad.attach(abjad.Clef('treble'), staff[0]) >>> abjad.attach(abjad.Clef('treble'), staff[4]) >>> abjad.show(staff) .. docs:: \new Staff { c'1 d'2 r2 R1 \clef "treble" e'1 } .. figure:: ../_images/reposition_clefs-wpuzqrszs7i.png >>> auxjad.mutate.reposition_clefs(staff[:]) >>> abjad.show(staff) .. docs:: \new Staff { c'1 d'2 r2 R1 e'1 } .. figure:: ../_images/reposition_clefs-os7dqkh11vl.png ``shift_clef_to_notes``: By default, clefs attached to rests are shifted to the first pitched leaf. >>> staff = abjad.Staff(r"c'1 | d'2 r2 | fs1") >>> abjad.attach(abjad.Clef('treble'), staff[0]) >>> abjad.attach(abjad.Clef('bass'), staff[2]) >>> abjad.show(staff) .. docs:: \new Staff { \clef "treble" c'1 d'2 \clef "bass" r2 fs1 } .. figure:: ../_images/reposition_clefs-jft5tljn0ni.png >>> auxjad.mutate.reposition_clefs(staff[:]) >>> abjad.show(staff) .. docs:: \new Staff { \clef "treble" c'1 d'2 r2 \clef "bass" fs1 } .. figure:: ../_images/reposition_clefs-pirrrq3p6di.png Set ``shift_clef_to_notes`` to ``False`` to disable this behaviour. >>> staff = abjad.Staff(r"c'1 | d'2 r2 | fs1") >>> abjad.attach(abjad.Clef('treble'), staff[0]) >>> abjad.attach(abjad.Clef('bass'), staff[2]) >>> auxjad.mutate.reposition_clefs(staff[:], shift_clef_to_notes=False) >>> abjad.show(staff) .. docs:: \new Staff { \clef "treble" c'1 d'2 \clef "bass" r2 fs1 } .. figure:: ../_images/reposition_clefs-srrb69k33oe.png Multiple multi-measure rests: Clefs are shifted even if the container has multiple multi-measure rests. >>> staff = abjad.Staff(r"\time 3/4 c'2. | d'4 r2 | R1 * 3/4 | e'2.") >>> abjad.attach(abjad.Clef('treble'), staff[0]) >>> abjad.attach(abjad.Clef('bass'), staff[2]) >>> abjad.show(staff) .. docs:: \new Staff { \time 3/4 \clef "treble" c'2. d'4 \clef "bass" r2 R1 * 3/4 e'2. } .. figure:: ../_images/reposition_clefs-1l1ws1tqqt5.png >>> auxjad.mutate.reposition_clefs(staff[:]) >>> abjad.show(staff) .. docs:: \new Staff { \time 3/4 \clef "treble" c'2. d'4 r2 R1 * 3/4 \clef "bass" e'2. } .. figure:: ../_images/reposition_clefs-gmh7uqxjjrf.png Subcontainers: The container from which the selection is made can also have subcontainers, including cases in which the clefs are attached to leaves of subcontainers: >>> staff = abjad.Staff([abjad.Note("c'2"), ... abjad.Chord("<d' f'>2"), ... abjad.Tuplet((2, 3), "g'2 a'2 b'2"), ... ]) >>> abjad.attach(abjad.Clef('treble'), staff[2][1]) >>> abjad.show(staff) .. docs:: \new Staff { c'2 <d' f'>2 \times 2/3 { g'2 \clef "treble" a'2 b'2 } } .. figure:: ../_images/reposition_clefs-vwygykrmjd.png >>> auxjad.mutate.reposition_clefs(staff[:]) >>> abjad.show(staff) .. docs:: \new Staff { c'2 <d' f'>2 \times 2/3 { g'2 a'2 b'2 } } .. figure:: ../_images/reposition_clefs-9gaqlf92kc.png ``implicit_clef``: By default, when the first leaf doesn't have a clef the function assumes that the music is written in treble clef (which is the default fallback clef in LilyPond). >>> staff = abjad.Staff(r"c'1 | d'1") >>> abjad.attach(abjad.Clef('treble'), staff[1]) >>> abjad.show(staff) .. docs:: \new Staff { c'1 \clef "treble" d'1 } .. figure:: ../_images/reposition_clefs-tuxicnsglgk.png >>> auxjad.mutate.reposition_clefs(staff[:]) >>> abjad.show(staff) .. docs:: \new Staff { c'1 d'1 } .. figure:: ../_images/reposition_clefs-co27o4xxato.png Set the argument ``implicit_clef`` to a different |abjad.Clef| to change the implicit clef. >>> staff = abjad.Staff(r"c1 | d1") >>> abjad.attach(abjad.Clef('bass'), staff[1]) >>> abjad.show(staff) .. docs:: \new Staff { c1 \clef "bass" d1 } .. figure:: ../_images/reposition_clefs-jyp5xd92vgi.png >>> auxjad.mutate.reposition_clefs( ... staff[:], ... implicit_clef=abjad.Clef('bass'), ... ) >>> abjad.show(staff) .. docs:: \new Staff { c1 d1 } .. figure:: ../_images/reposition_clefs-o7bi4n2n58.png This can be useful when extending a container that already has a specific clef. >>> music = abjad.Staff(r"\clef bass c4 d4 e4 f4") >>> music.extend(staff) >>> abjad.show(music) .. docs:: \new Staff { \clef "bass" c4 d4 e4 f4 c1 d1 } .. figure:: ../_images/reposition_clefs-7y32wepotnf.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 selection.leaves().are_contiguous_logical_voice(): raise ValueError("argument must be contiguous logical voice") if not isinstance(shift_clef_to_notes, bool): raise TypeError("'shift_clef_to_notes' must be 'bool'") if not isinstance(implicit_clef, abjad.Clef): raise TypeError("'implicit_clef' must be 'abjad.Clef'") leaves = selection.leaves() # shifting clefs from rests to notes if shift_clef_to_notes: shifted_clef = None for leaf in leaves[1:]: clef = abjad.get.indicator(leaf, abjad.Clef) if isinstance(leaf, (abjad.Rest, abjad.MultimeasureRest)): if abjad.get.indicator(leaf, abjad.Clef) is not None: shifted_clef = abjad.get.indicator(leaf, abjad.Clef) abjad.detach(abjad.Clef, leaf) else: if (abjad.get.indicator(leaf, abjad.Clef) is None and shifted_clef is not None): abjad.attach(shifted_clef, leaf) shifted_clef = None # removing repeated clefs previous_clef = abjad.get.indicator(leaves[0], abjad.Clef) if previous_clef is None: previous_clef = implicit_clef for leaf in leaves[1:]: clef = abjad.get.indicator(leaf, abjad.Clef) if clef == previous_clef: abjad.detach(abjad.Clef, leaf) elif clef is not None: previous_clef = clef