import abjad
[docs]def respell_augmented_unisons(selection: abjad.Selection,
*,
include_multiples: bool = False,
respell_by_pitch_class: bool = False,
) -> None:
r"""Mutates an input |abjad.Selection| in place and has no return value;
this function changes the accidentals of individual pitches of all chords
in a container in order to avoid augmented unisons.
Basic usage:
To use this function, apply it to a selection that contains chords that
have augmented unisons.
>>> container = abjad.Container(r"c'4 r4 <ef' e'>4 g'4 <c' cs'>4 r2.")
>>> abjad.show(container)
.. docs::
{
c'4
r4
<ef' e'>4
g'4
<c' cs'>4
r2.
}
.. figure:: ../_images/respell_augmented_unisons-OXnGvQzGT2.png
>>> auxjad.mutate.respell_augmented_unisons(container[:])
>>> abjad.show(container)
.. docs::
{
c'4
r4
<ds' e'>4
g'4
<c' df'>4
r2.
}
.. figure:: ../_images/respell_augmented_unisons-x33afbbamt.png
This can be useful when using tuples of integers to create chords that
contain minor seconds:
>>> pitches = [(0, 1), (8, 9, 12), (0, 4, 5, 6), (-1, 5, 6)]
>>> durations = [(1, 8), (3, 8), (7, 16), (1, 16)]
>>> maker = abjad.LeafMaker()
>>> chords = maker(pitches, durations)
>>> staff = abjad.Staff(chords)
>>> literal = abjad.LilyPondLiteral(r'\accidentalStyle dodecaphonic')
>>> abjad.attach(literal, staff)
>>> abjad.show(staff)
.. docs::
\new Staff
{
\accidentalStyle dodecaphonic
<c' cs'>8
<af' a' c''>4.
<c' e' f' fs'>4..
<b f' fs'>16
}
.. figure:: ../_images/respell_augmented_unisons-mWVWwV9uBx.png
>>> auxjad.mutate.respell_augmented_unisons(staff[:])
>>> abjad.show(staff)
.. docs::
\new Staff
{
\accidentalStyle dodecaphonic
<c' df'>8
<gs' a' c''>4.
<c' e' f' gf'>4..
<b f' gf'>16
}
.. figure:: ../_images/respell_augmented_unisons-IfzaseW4oS.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.respell_augmented_unisons(staff[:])
>>> abjad.mutate.respell_augmented_unisons(staff[:])
2-note chords:
The example below shows first the default spelling of 2-note chords in
Abjad followed by the respelt 2-note chords.
>>> staff = abjad.Staff()
>>> for pitch in range(12):
... staff.append(abjad.Chord([pitch, pitch + 1], (1, 16)))
>>> literal = abjad.LilyPondLiteral(r'\accidentalStyle dodecaphonic')
>>> abjad.attach(literal, staff)
>>> abjad.show(staff)
.. docs::
\new Staff
{
\accidentalStyle dodecaphonic
<c' cs'>16
<cs' d'>16
<d' ef'>16
<ef' e'>16
<e' f'>16
<f' fs'>16
<fs' g'>16
<g' af'>16
<af' a'>16
<a' bf'>16
<bf' b'>16
<b' c''>16
}
.. figure:: ../_images/respell_augmented_unisons-qQduIqCRpz.png
>>> auxjad.mutate.respell_augmented_unisons(staff[:])
>>> abjad.show(staff)
.. docs::
\new Staff
{
\accidentalStyle dodecaphonic
<c' df'>16
<cs' d'>16
<d' ef'>16
<ds' e'>16
<e' f'>16
<f' gf'>16
<fs' g'>16
<g' af'>16
<gs' a'>16
<a' bf'>16
<as' b'>16
<b' c''>16
}
.. figure:: ../_images/respell_augmented_unisons-jvg032q24il.png
augmented unissons in chords with 3 or more pitches:
The function looks for all augmented unissons in chords of 3 or more
pitches:
>>> staff = abjad.Staff(r"<a c' cs' f'>1")
>>> abjad.show(staff)
.. docs::
\new Staff
{
<a c' cs' f'>1
}
.. figure:: ../_images/respell_augmented_unisons-IklJO81q1E.png
>>> auxjad.mutate.respell_augmented_unisons(staff[:])
>>> abjad.show(staff)
.. docs::
\new Staff
{
<a c' df' f'>1
}
.. figure:: ../_images/respell_augmented_unisons-gyficck05p.png
``include_multiples``:
By default, this function only changes spelling for pitches that are
1 semitone apart.
>>> staff = abjad.Staff(r"<c' cs''>1")
>>> abjad.show(staff)
.. docs::
\new Staff
{
<c' cs''>1
}
.. figure:: ../_images/respell_augmented_unisons-HPqFrADjeh.png
>>> auxjad.mutate.respell_augmented_unisons(staff[:])
>>> abjad.show(staff)
.. docs::
\new Staff
{
<c' cs''>1
}
.. figure:: ../_images/respell_augmented_unisons-uszf11qb72d.png
To consider pitches in different octaves (thus including augmented
unisons, augmented octaves, augmented fifteenths, etc.), call this
function with the keyword argument ``include_multiples`` set to
``True``.
>>> staff = abjad.Staff(r"<c' cs''>1")
>>> auxjad.mutate.respell_augmented_unisons(
... staff[:],
... include_multiples=True,
... )
.. docs::
\new Staff
{
<c' df''>1
}
.. figure:: ../_images/respell_augmented_unisons-8am8cu2rmgi.png
``respell_by_pitch_class``:
By default, when this function changes the spelling of a pitch, it does
not change the spelling of all other pitches with the same pitch-class.
>>> staff = abjad.Staff(r"<c' cs' cs''>1")
>>> abjad.show(staff)
.. docs::
\new Staff
{
<c' cs' cs''>1
}
.. figure:: ../_images/respell_augmented_unisons-eWixL7iCEq.png
>>> auxjad.mutate.respell_augmented_unisons(staff[:])
>>> abjad.show(staff)
.. docs::
\new Staff
{
<c' df' cs''>1
}
.. figure:: ../_images/respell_augmented_unisons-47d16xk6gvs.png
To alter all pitch-classes, call this function with the keyword
argument ``respell_by_pitch_class`` set to ``True``.
>>> staff = abjad.Staff(r"<c' cs' cs''>1")
>>> auxjad.mutate.respell_augmented_unisons(
... staff[:],
... respell_by_pitch_class=True,
... )
>>> abjad.show(staff)
.. docs::
\new Staff
{
<c' df' df''>1
}
.. figure:: ../_images/respell_augmented_unisons-kobft0oq9sl.png
"""
if not isinstance(selection, abjad.Selection):
raise TypeError("argument must be 'abjad.Selection'")
if not isinstance(respell_by_pitch_class, bool):
raise TypeError("'respell_by_pitch_class' must be 'bool'")
if not isinstance(include_multiples, bool):
raise TypeError("'include_multiples' must be 'bool'")
for leaf in selection.leaves():
if isinstance(leaf, abjad.Chord):
accidentals = [pitch.accidental for pitch in leaf.written_pitches]
original_accidentals = accidentals[:]
if not include_multiples:
# dealing only with intervals of size equal to 1 semitone
for i in range(len(leaf.written_pitches) - 1):
p1 = leaf.written_pitches[i]
p2 = leaf.written_pitches[i + 1]
interval12 = p1 - p2
try:
p3 = leaf.written_pitches[i + 2]
interval23 = p2 - p3
except IndexError:
p3 = None
interval23 = None
if (interval12 == abjad.NamedInterval('+A1')
and interval23 != abjad.NamedInterval('+A1')
and interval23 != abjad.NamedInterval('+m2')):
if not respell_by_pitch_class:
# respelling only one single note
if p1.accidental == abjad.Accidental('f'):
accidentals[i] = abjad.Accidental('s')
elif p1.accidental == abjad.Accidental(''):
accidentals[i + 1] = abjad.Accidental('f')
else:
# respelling all matching pitch-classes
if p1.accidental == abjad.Accidental('f'):
for j, p in enumerate(leaf.written_pitches):
if p.pitch_class == p1.pitch_class:
accidentals[j] = abjad.Accidental('s')
elif p1.accidental == abjad.Accidental(''):
for j, p in enumerate(leaf.written_pitches):
if p.pitch_class == p2.pitch_class:
accidentals[j] = abjad.Accidental('f')
else:
# dealing with augmented unisons as well as augmented 8as,
# 15ths, etc.
for i in range(len(leaf.written_pitches) - 1):
for j in range(i + 1, len(leaf.written_pitches)):
# no p3 this time since p1 and p2 are not necessary
# consecutive pitches in the chord
p1 = leaf.written_pitches[i]
p2 = leaf.written_pitches[j]
interval = abjad.NamedIntervalClass(p1 - p2)
if (interval in (abjad.NamedIntervalClass('+A1'),
abjad.NamedIntervalClass('-d1'),
)):
# no need for respell_by_pitch_class since this
# will go through all notes in the chord anyway
if p1.accidental == abjad.Accidental('f'):
accidentals[i] = abjad.Accidental('s')
if p1.accidental == abjad.Accidental('s'):
accidentals[i] = abjad.Accidental('f')
elif p1.accidental == abjad.Accidental(''):
if p2.accidental == abjad.Accidental('s'):
accidentals[j] = abjad.Accidental('f')
elif p2.accidental == abjad.Accidental('f'):
accidentals[j] = abjad.Accidental('s')
# rewritting chord with new spelling
respelt_pitches = []
for pitch, accidental, original_accidental in zip(
leaf.written_pitches,
accidentals,
original_accidentals,
):
if (accidental != original_accidental
and accidental == abjad.Accidental('f')):
respelt_pitches.append(pitch._respell(accidental='flats'))
elif (accidental != original_accidental
and accidental == abjad.Accidental('s')):
respelt_pitches.append(pitch._respell(accidental='sharps'))
else:
respelt_pitches.append(pitch)
leaf.written_pitches = respelt_pitches