import abjad
from .. import get
[docs]def close_container(container: abjad.Container) -> None:
r"""Mutates an input container (of type |abjad.Container| or child class)
in place and has no return value; this function changes the time signature
of the last measure of an underfull in order to make it full.
Basic usage:
Returns the missing duration of the last measure of any container or
child class. If no time signature is encountered, it uses LilyPond's
convention and considers the container as in 4/4.
>>> container1 = abjad.Staff(r"c'4 d'4 e'4 f'4")
>>> container2 = abjad.Staff(r"c'4 d'4 e'4")
>>> container3 = abjad.Staff(r"c'4 d'4 e'4 f'4 | c'4")
>>> container4 = abjad.Staff(r"c'4 d'4 e'4 f'4 | c'4 d'4 e'4 f'4")
>>> auxjad.mutate.close_container(container1)
>>> auxjad.mutate.close_container(container2)
>>> auxjad.mutate.close_container(container3)
>>> auxjad.mutate.close_container(container4)
>>> abjad.show(container1)
.. docs::
\new Staff
{
c'4
d'4
e'4
f'4
}
.. figure:: ../_images/close_container-nfnk06s90x.png
>>> abjad.show(container2)
.. docs::
\new Staff
{
\time 3/4
c'4
d'4
e'4
}
.. figure:: ../_images/close_container-swyxwiup8pm.png
>>> abjad.show(container3)
.. docs::
\new Staff
{
c'4
d'4
e'4
f'4
\time 1/4
c'4
}
.. figure:: ../_images/close_container-mms5hiysbwe.png
>>> abjad.show(container4)
.. docs::
\new Staff
{
c'4
d'4
e'4
f'4
c'4
d'4
e'4
f'4
}
.. figure:: ../_images/close_container-aky7avbla4w.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.close_containers(staff)
>>> abjad.mutate.close_containers(staff)
Time signature changes:
Handles any time signatures as well as changes of time signature.
>>> container1 = abjad.Staff(r"\time 4/4 c'4 d'4 e'4 f'4 g'")
>>> container2 = abjad.Staff(r"\time 3/4 a2. \time 2/4 c'4")
>>> container3 = abjad.Staff(r"\time 5/4 g1 ~ g4 \time 4/4 af'2")
>>> auxjad.mutate.close_container(container1)
>>> auxjad.mutate.close_container(container2)
>>> auxjad.mutate.close_container(container3)
>>> abjad.show(container1)
.. docs::
\new Staff
{
\time 4/4
c'4
d'4
e'4
f'4
\time 1/4
g'4
}
.. figure:: ../_images/close_container-3tgyty245cq.png
>>> abjad.show(container2)
.. docs::
\new Staff
{
\time 3/4
a2.
\time 1/4
c'4
}
.. figure:: ../_images/close_container-st5d89zofoh.png
>>> abjad.show(container3)
.. docs::
\new Staff
{
\time 5/4
g1
~
g4
\time 2/4
af'2
}
.. figure:: ../_images/close_container-wd5irlm76l.png
.. 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/close_container-xrwkorhtl5.png
>>> staff = abjad.Staff([container])
>>> abjad.show(container)
.. docs::
{
\time 3/4
c'4
d'4
e'4
}
.. figure:: ../_images/close_container-ys6pcdlywy.png
Partial time signatures:
Correctly handles partial time signatures.
>>> container = abjad.Staff(r"c'4 d'4 e'4 f'4 g'4")
>>> time_signature = abjad.TimeSignature((3, 4), partial=(1, 4))
>>> abjad.attach(time_signature, container[0])
>>> auxjad.mutate.close_container(container)
>>> abjad.show(container)
.. docs::
\new Staff
{
\partial 4
\time 3/4
c'4
d'4
e'4
f'4
\time 1/4
g'4
}
.. figure:: ../_images/close_container-rfskjbbfnu.png
.. error::
If a container is malformed, i.e. it has an underfilled measure before
a time signature change, the function raises a :exc:`ValueError`
exception.
>>> container = abjad.Container(r"\time 5/4 g''1 \time 4/4 f'4")
>>> auxjad.mutate.close_container(container)
ValueError: 'container' is malformed, with an underfull measure
preceding a time signature change
.. 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("argument must be 'abjad.Container' or child class")
if not abjad.select(container).leaves().are_contiguous_logical_voice():
raise ValueError("argument must be contiguous logical voice")
try:
if not get.selection_is_full(container[:]):
missing_duration = get.underfull_duration(container[:])
leaves = abjad.select(container).leaves()
for leaf in leaves[::-1]:
time_signature = abjad.get.effective(leaf, abjad.TimeSignature)
if time_signature is not None:
last_time_signature = time_signature
break
else:
last_time_signature = abjad.TimeSignature((4, 4))
last_bar_duration = last_time_signature.duration - missing_duration
final_bar_time_signature = abjad.TimeSignature(last_bar_duration)
final_bar_time_signature.simplify_ratio()
duration = 0
for leaf in leaves[::-1]:
duration += abjad.get.duration(leaf)
if duration == last_bar_duration:
if abjad.get.indicator(leaf, abjad.TimeSignature):
abjad.detach(abjad.TimeSignature, leaf)
abjad.attach(final_bar_time_signature, leaf)
break
except ValueError as err:
raise ValueError("'container' is malformed, with an underfull measure "
"preceding a time signature change") from err