v3.17
Abjad 3.17 works with Python 3.10 (and 3.11) and LilyPond 2.23.6 (and later).
#1522. CHANGED. Cleaned up context initializers. This forces keyword parameters to be keyword-only:
OLD:
abjad.Score(
components=None,
lilypond_type: str = "Score",
simultaneous: bool = True,
name: str | None = None,
tag: _tag.Tag | None = None,
*,
language: str = "english",
)
abjad.Staff(
components=None,
lilypond_type: str = "Staff",
simultaneous: bool = False,
name: str | None = None,
tag: _tag.Tag | None = None,
*,
language: str = "english",
)
abjad.StaffGroup(
components=None,
lilypond_type: str = "StaffGroup",
simultaneous: bool = True,
name: str | None = None,
tag: _tag.Tag | None = None,
*,
language: str = "english",
)
abjad.Voice(
components=None,
lilypond_type: str = "Voice",
simultaneous: bool = False,
name: str | None = None,
tag: _tag.Tag | None = None,
*,
language: str = "english",
)
NEW:
abjad.Score(
components=None,
*,
language: str = "english",
lilypond_type: str = "Score",
name: str | None = None,
simultaneous: bool = True,
tag: _tag.Tag | None = None,
)
abjad.Staff(
components=None,
*,
language: str = "english",
lilypond_type: str = "Staff",
name: str | None = None,
simultaneous: bool = False,
tag: _tag.Tag | None = None,
)
abjad.StaffGroup(
components=None,
*,
language: str = "english",
lilypond_type: str = "StaffGroup",
name: str | None = None,
simultaneous: bool = True,
tag: _tag.Tag | None = None,
)
abjad.Voice(
components=None,
*,
language: str = "english",
lilypond_type: str = "Voice",
name: str | None = None,
simultaneous: bool = False,
tag: _tag.Tag | None = None,
)
#1523. CHANGED. Container input must now be flat:
OLD. Nested lists of components were allowed as container input through Abjad 3.16:
abjad.Staff(
[abjad.Note("c'4"), [abjad.Note("d'4")]]
)
NEW. Starting in Abjad 3.17, container input must be a flat list of components:
abjad.Staff(
[abjad.Note("c'4"), abjad.Note("d'4")]
)
#1525 CHANGED abjad.illustrators.selection()
to abjad.illustrators.components()
:
OLD: abjad.illustrators.selection()
NEW: abjad.illustrators.components()
OLD: abjad.illustrators.selection_to_score_markup_string()
NEW: abjad.illustrators.components_to_score_markup_string()
#1527. Cleaned up abjad.on_beat_grace_container()
:
CHANGED. Changed abjad.on_beat_grace_container()
parameter names:
OLD: abjad.on_beat_grace_container(..., anchor_voice_number=2)
NEW: abjad.on_beat_grace_container(..., nongrace_polyphony_command=r"\voiceTwo")
OLD: abjad.on_beat_grace_container(..., grace_voice_number=1)
NEW: abjad.on_beat_grace_container(..., grace_polyphony_command=r"\voiceOne")
OLD: abjad.on_beat_grace_container(..., font_size=-3)
NEW: abjad.on_beat_grace_container(..., grace_font_size=-3)
OLD: abjad.on_beat_grace_container(..., leaf_duration=None)
NEW: abjad.on_beat_grace_container(..., grace_leaf_duration=None)
CHANGED. Changed abjad.activate()
, abjad.deactivate()
return types:
OLD:
* both functions returned (text, count) pair when skipped=False
* both functions returned (text, count, skipped) triple when skipped=True
NEW:
* both functions return (text, count, skipped) triple
NEW. Added abjad.parse(..., tag=None)
keyword.
NEW. Added abjad.wf.check_overlapping_beams()
.
NEW. Added abjad.wf.check_beamed_lone_notes()
.
BUGFIX. Taught abjad.ForbidUpdate
to update indicators on entrance. Indicators need to be updated after swap; context manager updates indicators before forbidding further updates:
>>> staff = abjad.Staff(r"\times 1/1 { c'4 d' }")
>>> abjad.attach(abjad.Clef("alto"), staff[0][0])
>>> container = abjad.Container()
>>> abjad.mutate.swap(staff[0], container)
>>> with abjad.ForbidUpdate(staff):
... for note in staff[0]:
... print(note)
... print(abjad.get.effective(note, abjad.Clef))
...
Note("c'4")
Clef(name='alto', hide=False)
Note("d'4")
Clef(name='alto', hide=False)
Users encountered this bug (up to Abjad 3.16) only if using abjad.ForbidContext
immediately after some type of score mutatation, like in the example above.
#1528. NEW. Added abjad.VoiceNumber
indicator:
Set n to 1, 2, 3, 4 or none. Models LilyPond \voiceOne
, \voiceTwo
, \voiceThree
, \voiceFour
, \oneVoice
commands.
def make_staff():
staff = abjad.Staff()
voice_1 = abjad.Voice("g'8 a' b' c''")
command = abjad.VoiceNumber(n=1)
abjad.attach(command, voice_1[0])
voice_2 = abjad.Voice("e'8 f' g' a'")
command = abjad.VoiceNumber(n=2)
abjad.attach(command, voice_2[0])
container = abjad.Container([voice_1, voice_2], simultaneous=True)
staff.append(container)
voice = abjad.Voice("c''4 a'")
command = abjad.VoiceNumber()
abjad.attach(command, voice[0])
staff.append(voice)
>>> staff = make_staff()
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
<<
\new Voice
{
\voiceOne
g'8
a'8
b'8
c''8
}
\new Voice
{
\voiceTwo
e'8
f'8
g'8
a'8
}
>>
\new Voice
{
\oneVoice
c''4
a'4
}
}
The abjad.VoiceNumber indicator is contexted at the level of abjad.Voice. Use abjad.get.effective() to get the abjad.VoiceNumber indicator in effect for any leaf:
>>> for leaf in abjad.select.leaves(staff):
... command = abjad.get.effective(leaf, abjad.VoiceNumber)
... print(f"{leaf}, {command}")
Note("g'8"), VoiceNumber(n=1)
Note("a'8"), VoiceNumber(n=1)
Note("b'8"), VoiceNumber(n=1)
Note("c''8"), VoiceNumber(n=1)
Note("e'8"), VoiceNumber(n=2)
Note("f'8"), VoiceNumber(n=2)
Note("g'8"), VoiceNumber(n=2)
Note("a'8"), VoiceNumber(n=2)
Note("c''4"), VoiceNumber(n=None)
Note("a'4"), VoiceNumber(n=None)
#1529. CHANGED abjad.LilyPondLiteral
format site from "opening"
to "before"
:
Abjad leaves should only format "before" and "after" sites. (Though Abjad containers can format "before", "after", "opening" and "closing" sites.) Because abjad.LilyPondLiteral
objects almost always get attached to leaves (instead of containers), it makes sense to change the default format site of LilyPond literals from (container-like) "opening" to (leaf-like) "before".
#1534. CHANGED abjad.TimeSignature
context from "Staff"
to "Score"
:
Through Abjad 3.16, time signature application was most commonly abjad.attach(time_signature, note, context="Score")
.
Beginning in Abjad 3.17, abjad.attach(time_signature, note)
binds to the score context automatically.
#1537. Made abjad.TimeSignature
, abjad.MetronomeMark
initializers strict. That is, these initializers no longer coerce input:
Intialize metronome marks like this:
OLD:
* abjad.MetronomeMark(abjad.Duration(1, 4), 72)
* abjad.MetronomeMark((1, 4), 72)
NEW:
* abjad.MetronomeMark(abjad.Duration(1, 4), 72)
Initialize time signatures like this:
OLD:
* abjad.TimeSignature(pair)
* abjad.TimeSignature(duration)
* abjad.TimeSignature(time_signature)
NEW:
* abjad.TimeSignature(pair)
CHANGED. Moved LilyPond stop-hairpin \!
from articulations site to spanner-stops site in LilyPond output.
#1540. Cleaned up indicators:
CHANGED. The "site" argument to abjad.LilyPondLiteral
is now keyword-only:
OLD: abjad.LilyPondLiteral(..., site)
NEW: abjad.LilyPondLiteral(..., *, site="before")
CHANGED. Made abjad.MetricModulation
into frozen dataclass.
CHANGED. Renamed abjad.StaffChange
parameter:
OLD: abjad.StaffChange.staff
NEW: abjad.StaffChange.staff_name
REMOVED remove_ly keyword
from these:
* abjad.persist.as_midi()
* abjad.persist.as_pdf()
* abjad.persist.as_png()
#1542. Fixed abjad.beam(..., stemlet_length=None)
formatting:
EXAMPLE.
>>> voice = abjad.Voice("c'8 d' e' f'")
>>> abjad.beam(voice[:], stemlet_length=0.75)
>>> string = abjad.lilypond(voice)
OLD:
>>> print(string)
\new Voice
{
\override Staff.Stem.stemlet-length = 0.75
c'8
[
d'8
e'8
\revert Staff.Stem.stemlet-length
f'8
]
}
NEW:
>>> print(string)
\new Voice
{
\override Staff.Stem.stemlet-length = 0.75
c'8
[
d'8
e'8
f'8
]
\revert Staff.Stem.stemlet-length
}
CHANGED. abjad.illustrators.make_piano_score()
now includes explicit voices:
OLD:
>>> score = abjad.illustrators.make_piano_score()
>>> string = abjad.lilypond(score)
>>> print(string)
\context Score = "Score"
<<
\context PianoStaff = "Piano_Staff"
<<
\context Staff = "Treble_Staff"
{
}
\context Staff = "Bass_Staff"
{
}
>>
>>
NEW:
>>> score = abjad.illustrators.make_piano_score()
>>> string = abjad.lilypond(score)
>>> print(string)
\context Score = "Score"
<<
\context PianoStaff = "Piano_Staff"
<<
\context Staff = "Treble_Staff"
{
\context Voice = "Treble_Voice"
{
}
}
\context Staff = "Bass_Staff"
{
\context Voice = "Bass_Voice"
{
}
}
>>
>>
#1543. Added an explicit abjad.Voice context to the output created by abjad.illustrators.components()
:
EXAMPLE:
def main():
components = [abjad.Note("c'4")]
lilypond_file = abjad.illustrators.components(components)
string = abjad.lilypond(lilypond_file["Score"])
print(string)
OLD:
\context Score = "Score"
<<
\context Staff = "Staff"
{
\time 1/4
c'4
}
>>
NEW:
\context Score = "Score"
<<
\context Staff = "Staff"
{
\context Voice = "Voice"
{
\time 1/4
c'4
}
}
>>