import dataclasses
import typing
from . import _getlib
from . import bind as _bind
from . import get as _get
from . import indicators as _indicators
from . import instruments as _instruments
from . import iterate as _iterate
from . import pcollections as _pcollections
from . import pitch as _pitch
from . import score as _score
[docs]def iterate_out_of_range(argument) -> typing.Iterator[_score.Leaf]:
r"""
Iterates out-of-range notes and chords in ``argument``.
.. container:: example
>>> staff = abjad.Staff("c'8 r8 <d fs>8 r8")
>>> violin = abjad.Violin()
>>> abjad.attach(violin, staff[0])
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
c'8
r8
<d fs>8
r8
}
>>> for leaf in abjad.iterpitches.iterate_out_of_range(staff):
... leaf
...
Chord('<d fs>8')
"""
for leaf in _iterate.leaves(argument, pitched=True):
instrument = _getlib._get_effective(leaf, _instruments.Instrument)
if instrument is None:
raise ValueError("no instrument found.")
if not sounding_pitches_are_in_range(leaf, instrument.pitch_range):
yield leaf
[docs]def respell_with_flats(argument) -> None:
r"""
Respells pitches in ``argument`` with flats.
.. container:: example
>>> staff = abjad.Staff("cs'8 ds' es' fs' gs' as' bs'4")
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
cs'8
ds'8
es'8
fs'8
gs'8
as'8
bs'4
}
>>> abjad.iterpitches.respell_with_flats(staff)
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
df'8
ef'8
f'8
gf'8
af'8
bf'8
c''4
}
"""
for leaf in _iterate.leaves(argument):
if isinstance(leaf, _score.Note):
assert leaf.written_pitch is not None
leaf.written_pitch = leaf.written_pitch.respell(accidental="flats")
elif isinstance(leaf, _score.Chord):
for note_head in leaf.note_heads:
pitch = note_head.written_pitch.respell(accidental="flats")
note_head.written_pitch = pitch
[docs]def respell_with_sharps(argument) -> None:
r"""
Respells pitches in ``argument`` with sharps.
.. container:: example
>>> staff = abjad.Staff("cf'8 df' ef' ff' gf' af' bf'4")
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
cf'8
df'8
ef'8
ff'8
gf'8
af'8
bf'4
}
>>> abjad.iterpitches.respell_with_sharps(staff)
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
b8
cs'8
ds'8
e'8
fs'8
gs'8
as'4
}
"""
for leaf in _iterate.leaves(argument):
if isinstance(leaf, _score.Note):
assert leaf.written_pitch is not None
leaf.written_pitch = leaf.written_pitch.respell(accidental="sharps")
elif isinstance(leaf, _score.Chord):
for note_head in leaf.note_heads:
pitch = note_head.written_pitch.respell(accidental="sharps")
note_head.written_pitch = pitch
[docs]def sounding_pitches_are_in_range(argument, pitch_range) -> bool:
"""
Returns true when all pitches in ``argument`` sound within ``pitch_range``.
"""
assert isinstance(pitch_range, _pcollections.PitchRange), repr(pitch_range)
if isinstance(argument, int | float):
pitch = _pitch.NamedPitch(argument)
return pitch in pitch_range
if isinstance(argument, _pitch.Pitch):
return argument in pitch_range
if hasattr(argument, "written_pitch"):
sounding_pitch = _getlib._get_sounding_pitch(argument)
return sounding_pitch in pitch_range
if hasattr(argument, "written_pitches"):
sounding_pitches = _getlib._get_sounding_pitches(argument)
return all(_ in pitch_range for _ in sounding_pitches)
pitches = list(_iterate.pitches(argument))
if pitches:
return all(_ in pitch_range for _ in pitches)
else:
try:
return all(_ in pitch_range for _ in argument)
except TypeError:
return False
return False
[docs]def transpose_from_sounding_pitch(argument) -> None:
r"""
Transpose notes and chords in ``argument`` from sounding pitch to written pitch.
.. container:: example
>>> staff = abjad.Staff("<c' e' g'>4 d'4 r4 e'4")
>>> clarinet = abjad.ClarinetInBFlat()
>>> abjad.attach(clarinet, staff[0])
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
<c' e' g'>4
d'4
r4
e'4
}
>>> abjad.iterpitches.transpose_from_sounding_pitch(staff)
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
<d' fs' a'>4
e'4
r4
fs'4
}
"""
for leaf in _iterate.leaves(argument, pitched=True):
instrument = _getlib._get_effective(leaf, _instruments.Instrument)
if not instrument:
continue
sounding_pitch = instrument.middle_c_sounding_pitch
interval = _pitch.NamedPitch("C4") - sounding_pitch
interval *= -1
if hasattr(leaf, "written_pitch"):
pitch = leaf.written_pitch
pitch = interval.transpose(pitch)
leaf.written_pitch = pitch
elif hasattr(leaf, "written_pitches"):
pitches = [interval.transpose(pitch) for pitch in leaf.written_pitches]
leaf.written_pitches = pitches
wrapper = _get.indicator(leaf, _indicators.StartTrillSpan, unwrap=False)
if wrapper is not None:
start_trill_span = wrapper.unbundle_indicator()
new_pitch = interval.transpose(start_trill_span.pitch)
new_start_trill_span = dataclasses.replace(
start_trill_span, pitch=new_pitch
)
wrapper_tag = wrapper.tag
_bind.detach(wrapper, leaf)
if wrapper.bundled():
new_bundle = dataclasses.replace(
wrapper.get_item(), indicator=new_start_trill_span
)
_bind.attach(new_bundle, leaf, tag=wrapper_tag)
else:
_bind.attach(new_start_trill_span, leaf, tag=wrapper_tag)
[docs]def transpose_from_written_pitch(argument) -> None:
r"""
Transposes notes and chords in ``argument`` from sounding pitch to written pitch.
.. container:: example
>>> staff = abjad.Staff("<c' e' g'>4 d'4 r4 e'4")
>>> clarinet = abjad.ClarinetInBFlat()
>>> abjad.attach(clarinet, staff[0])
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
<c' e' g'>4
d'4
r4
e'4
}
>>> abjad.iterpitches.transpose_from_written_pitch(staff)
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
<bf d' f'>4
c'4
r4
d'4
}
"""
for leaf in _iterate.leaves(argument, pitched=True):
instrument = _getlib._get_effective(leaf, _instruments.Instrument)
if not instrument:
continue
sounding_pitch = instrument.middle_c_sounding_pitch
interval = _pitch.NamedPitch("C4") - sounding_pitch
if hasattr(leaf, "written_pitch"):
written_pitch = leaf.written_pitch
written_pitch = interval.transpose(written_pitch)
leaf.written_pitch = written_pitch
elif hasattr(leaf, "written_pitches"):
pitches = [interval.transpose(pitch) for pitch in leaf.written_pitches]
leaf.written_pitches = pitches
wrapper = _get.indicator(leaf, _indicators.StartTrillSpan, unwrap=False)
if wrapper is not None:
start_trill_span = wrapper.unbundle_indicator()
new_pitch = interval.transpose(start_trill_span.pitch)
new_start_trill_span = dataclasses.replace(
start_trill_span, pitch=new_pitch
)
_bind.detach(wrapper, leaf)
if wrapper.bundled():
new_bundle = dataclasses.replace(
wrapper.get_item, indicator=new_start_trill_span
)
_bind.attach(new_bundle, leaf)
else:
_bind.attach(new_start_trill_span, leaf)