import abjad
[docs]def merge_hairpins(selection: abjad.Selection) -> None:
r"""Mutates an input |abjad.Selection| in place and has no return value;
this function merges all consecutive hairpins that share a same trend.
Basic usage:
Merging crescendo hairpins:
>>> staff = abjad.Staff(r"c'4\pp\< d'4 e'4\p\< f'4 g'1\mp")
>>> abjad.show(staff)
.. docs::
\new Staff
{
c'4
\pp
\<
d'4
e'4
\p
\<
f'4
g'1
\mp
}
.. figure:: ../_images/merge_hairpins-b4it6YReZ9.png
>>> abjad.mutate.merge_hairpins(staff[:])
>>> abjad.show(staff)
.. docs::
\new Staff
{
c'4
\pp
\<
d'4
e'4
f'4
g'1
\mp
}
.. figure:: ../_images/merge_hairpins-s5cU8PINVO.png
Merging diminuendo hairpins:
>>> staff = abjad.Staff(r"c'4\ff\> d'4 e'4\mf\> f'4 g'1\pp")
>>> abjad.show(staff)
.. docs::
\new Staff
{
c'4
\ff
\>
d'4
e'4
\mf
\>
f'4
g'1
\pp
}
.. figure:: ../_images/merge_hairpins-GUIqXKDXaQ.png
>>> abjad.mutate.merge_hairpins(staff[:])
>>> abjad.show(staff)
.. docs::
\new Staff
{
c'4
\ff
\>
d'4
e'4
f'4
g'1
\pp
}
.. figure:: ../_images/merge_hairpins-adbT777qMg.png
The merge only occurs when hairpins share a trend:
>>> staff = abjad.Staff(r"c'4\pp\< d'4 e'4\p\> f'4 g'1\pp")
>>> abjad.show(staff)
.. docs::
\new Staff
{
c'4
\pp
\<
d'4
e'4
\p
\>
f'4
g'1
\pp
}
.. figure:: ../_images/merge_hairpins-Lvzn2f6PU6.png
>>> abjad.mutate.merge_hairpins(staff[:])
>>> abjad.show(staff)
.. docs::
\new Staff
{
c'4
\pp
\<
d'4
e'4
\p
\>
f'4
g'1
\pp
}
.. figure:: ../_images/merge_hairpins-EJdWJwkUJE.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(staff[:]).merge_hairpins()
>>> abjad.mutate(staff[:]).merge_hairpins()
Gaps:
If there are any gaps between hairpins (i.e. they finish on an earlier
leaf than the start of the new hairpin), they will not be merged even
if they share a trend.
>>> staff = abjad.Staff(
... r"c'1\pp\< d'2\f d'2\< e'1\ff f'1\f\> "
... r"g'2\mp g'2\> a'1\! b'1\ppp"
... )
>>> abjad.show(staff)
.. docs::
\new Staff
{
c'1
\pp
\<
d'2
\f
d'2
\<
e'1
\ff
f'1
\f
\>
g'2
\mp
g'2
\>
a'1
\!
b'1
\ppp
}
.. figure:: ../_images/merge_hairpins-3Bo4GAfHaX.png
>>> auxjad.mutate.merge_hairpins(staff[:])
>>> abjad.show(staff)
.. docs::
\new Staff
{
c'1
\pp
\<
d'2
\f
d'2
\<
e'1
\ff
f'1
\f
\>
g'2
\mp
g'2
\>
a'1
\!
b'1
\ppp
}
.. figure:: ../_images/merge_hairpins-HaF1ZUdqtx.png
Multiple merges:
This function can merge an indefinite number of hairpins:
>>> staff = abjad.Staff(
... r"c'4\pp\< d'4 e'4\p\< f'4 g'4\mp\< a'4 b'4\mf\< c''4"
... r"d''4\f\> c''4 b'4\mf\> a'4 g'4\mp\> f'4 e'4\p\> d'4"
... r"c'1\pp"
... )
>>> abjad.show(staff)
.. docs::
\new Staff
{
c'4
\pp
\<
d'4
e'4
\p
\<
f'4
g'4
\mp
\<
a'4
b'4
\mf
\<
c''4
d''4
\f
\>
c''4
b'4
\mf
\>
a'4
g'4
\mp
\>
f'4
e'4
\p
\>
d'4
c'1
\pp
}
.. figure:: ../_images/merge_hairpins-DrT5XyaGWQ.png
>>> auxjad.mutate.merge_hairpins(staff[:])
>>> abjad.show(staff)
.. docs::
\new Staff
{
c'4
\pp
\<
d'4
e'4
f'4
g'4
a'4
b'4
c''4
d''4
\f
\>
c''4
b'4
a'4
g'4
f'4
e'4
d'4
c'1
\pp
}
.. figure:: ../_images/merge_hairpins-Z2yDxl8dlI.png
"""
if not isinstance(selection, abjad.Selection):
raise TypeError("argument must be 'abjad.Selection'")
active_hairpin = None
for leaf in selection.leaves():
leaf_hairpin = abjad.get.indicator(leaf, abjad.StartHairpin)
if active_hairpin is not None and leaf_hairpin is not None:
if active_hairpin.shape == leaf_hairpin.shape:
abjad.detach(abjad.StartHairpin, leaf)
if abjad.get.indicator(leaf, abjad.Dynamic) is not None:
abjad.detach(abjad.Dynamic, leaf)
if (abjad.get.indicator(leaf, abjad.Dynamic) is not None
or abjad.get.indicator(leaf, abjad.StopHairpin) is not None):
if leaf_hairpin is None:
active_hairpin = None
if leaf_hairpin is not None:
active_hairpin = leaf_hairpin