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