Skip to content

Releases: Abjad/abjad

v3.19

02 Aug 14:40
v3.19
Compare
Choose a tag to compare

Abjad 3.19 works with Python 3.10 (and 3.11) and LilyPond 2.23.6 (and later).

Abjad 3.19 is a maintenance release that makes only the following three changes.

#1554: FIXED: duplicated dynamics corner case.

#1556: CHANGED: lexical position of \tweaks in LilyPond output.

#1559: CHANGED: names of abjad.StartTextSpan.style strings.

v3.18

01 Jun 16:47
v3.18
Compare
Choose a tag to compare

Abjad 3.18 works with Python 3.10 (and 3.11) and LilyPond 2.23.6 (and later).

Abjad 3.18 is a maintenance release that preserves the functionality of Abjad 3.17 without significant changes.

v3.17

25 Apr 22:13
v3.17
Compare
Choose a tag to compare

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"
    <<

...

Read more

v3.16

24 Feb 21:41
v3.16
88ee265
Compare
Choose a tag to compare

Abjad 3.16 works with Python 3.10 (and 3.11) and LilyPond 2.23.6 (and later).

BREAKING CHANGES. Abjad 3.16 will break existing code. But the changes should be easy to follow. Removed abjad.Multiplier, abjad.Ratio, abjad.NonreducedFraction, abjad.NonreducedRatio in favor of built-in fractions.Fraction and (int, int) pairs. Also the types of abjad.Tuplet.multiplier, abjad.Leaf.multiplier and preprolated durations in the rhtyhmtrees module are all now more tightly constrained.

This release contains primarily #1515

OLD: abjad.Multiplier
NEW: use built-in fractions.Fraction instead

OLD: abjad.NonreducedFraction
NEW: use (int, int) pair instead

OLD: abjad.NonreducedRatio
NEW: use (int, ...) tuple instead

OLD: abjad.Ratio
NEW: use (int, ...) tuple instead

BREAKING CHANGE. Leaf multiplier now returns a nonreduced fraction.

OLD: Leaf.multiplier could be either multiplier or nonreduced multiplier.
NEW: Leaf.multiplier is always an (int, int) pair.

BREAKING CHANGE. abjad.Tuplet.multiplier has changed:

OLD: abjad.Tuplet.multiplier accepted the following:
     string, pair, duration, fraction, multiplier, nonreduced fraction
NEW: abjad.Tuplet.multiplier accepts only string and pair

OLD: abjad.Tuplet.multiplier returned nonreduced fraction (or none)
NEW: abjad.Tuplet.multiplier returns pair (or none)

OLD:

    >>> abjad.Tuplet("3:2", "c'4 d' e'")
    >>> abjad.Tuplet((2, 3), "c'4 d' e'")
    >>> abjad.Tuplet(abjad.Multiplier(2, 3), "c'4 d' e'")
    >>> abjad.Tuplet(abjad.Fraction(2, 3), "c'4 d' e'")
    >>> abjad.Tuplet(abjad.NonreducedFraction(2, 3), "c'4 d' e'")

NEW:

    >>> abjad.Tuplet("3:2", "c'4 d' e'")
    >>> abjad.Tuplet((2, 3), "c'4 d' e'")

OLD: tuplet.multplier == 1
NEW: tuplet.multplier == (1, 1)
NEW: abjad.Fraction(*tuplet.multplier) == 1

CHANGED. Replaced abjad.Duration.with_denominator().

OLD:
    >>> abjad.Duration(1, 4).with_denominator(16)
    NonreducedFraction(4, 16)

NEW:
    >>> duration = abjad.Duration(1, 4)
    >>> pair = abjad.duration.with_denominator(duration, 16)
    >>> pair
    (4, 16)

    >>> abjad.NonreducedFraction(pair)
    NonreducedFraction(4, 16)

CHANGED. Constrained rhythmtree preprolated duration.

OLD: int, pair, duration, nonreduced fraction
NEW: pair, duration, nonreduced fraction

CHANGED. Set several sequence.py parameters keyword-only.

NEW. Added abjad.duration.pair():

>>> abjad.duration.pair((3, 6))
(3, 6)

>>> abjad.duration.pair(abjad.Fraction(3, 6))
(1, 2)

>>> abjad.duration.pair(abjad.Duration(3, 6))
(1, 2)

>>> abjad.duration.pair(abjad.Offset((3, 6)))
(1, 2)

>>> abjad.duration.pair(abjad.TimeSignature((3, 6)))
(3, 6)

NEW. Added abjad.duration.add_pairs().

v3.15

14 Jan 19:29
v3.15
Compare
Choose a tag to compare

Abjad 3.15 works with Python 3.10 (and 3.11) and LilyPond 2.23.6 (and later).

Abjad 3.15 is a maintenance release that preserves the functionality of Abjad 3.14 without significant changes.

v3.14

01 Nov 21:33
v3.14
Compare
Choose a tag to compare

Abjad 3.14 works with Python 3.10 (and 3.11) and LilyPond 2.23.6 (and later).

NEW: use python -m pip install abjad[dev] to install Abjad's development dependencies. See #1483.

REMOVED: natural-language inequalities have been removed from abjad.Timespan. See #1491.

REMOVED: replaced third-party quicktions with built-in fractions. See #1489.

REMOVED: abjad.NoteMaker, abjad.LeafMaker; use abjad.makers.make_notes(), abjad.makers.make_leaves() instead. See #1478.

FIXED: abjad.MetronomeMark.textual_indication is now formatted exactly as entered by the user. See #1498.

v3.13

24 Sep 20:23
v3.13
Compare
Choose a tag to compare

Abjad 3.13 works with Python 3.10 and LilyPond 2.23.6 (and later).

Abjad 3.13 completes the migration of Abjad rhythm-makers that began in Abjad 3.12. Users of Abjad's rhythm-makers should migrate to Abjad 3.12 first, and then migrate to Abjad 3.13. No other changes are included in this release.

REMOVED:

rmakers.accelerando()
rmakers.after_grace_container()
rmakers.beam()
rmakers.beam_groups()
rmakers.before_grace_container()
rmakers.denominator()
rmakers.duration_bracket()
rmakers.even_division()
rmakers.example()
rmakers.extract_trivial()
rmakers.feather_beam()
rmakers.force_augmentation()
rmakers.force_diminution()
rmakers.force_fraction()
rmakers.force_note()
rmakers.force_repeat_tie()
rmakers.force_rest()
rmakers.incised()
rmakers.interpolate()
rmakers.invisible_music()
rmakers.multiplied_duration()
rmakers.nongrace_leaves_in_each_tuplet()
rmakers.note()
rmakers.on_beat_grace_container()
rmakers.reduce_multiplier()
rmakers.repeat_tie()
rmakers.rewrite_dots()
rmakers.rewrite_meter()
rmakers.rewrite_rest_filled()
rmakers.rewrite_sustained()
rmakers.split_measures()
rmakers.talea()
rmakers.tie()
rmakers.tremolo_container()
rmakers.trivialize()
rmakers.tuplet()
rmakers.unbeam()
rmakers.untie()
rmakers.wrap_in_time_signature_staff()
rmakers.written_duration()
rmakers.AccelerandoRhythmMaker
rmakers.EvenDivisionRhythmMaker
rmakers.MultipliedDurationRhythmMaker
rmakers.NoteRhythmMaker
rmakers.TaleaRhythmMaker
rmakers.TupletRhythmMaker
rmakers.assign()
rmakers.bind()
rmakers.stack()
rmakers.Assign
rmakers.Bind
rmakers.Stack

RENAMED:

OLD:

    rmakers.accelerando_function()
    rmakers.after_grace_container_function()
    rmakers.beam_function()
    rmakers.beam_groups_function()
    rmakers.before_grace_container_function()
    rmakers.denominator_function()
    rmakers.duration_bracket_function()
    rmakers.even_division_function()
    rmakers.example_function()
    rmakers.extract_trivial_function()
    rmakers.feather_beam_function()
    rmakers.force_augmentation_function()
    rmakers.force_diminution_function()
    rmakers.force_fraction_function()
    rmakers.force_note_function()
    rmakers.force_repeat_tie_function()
    rmakers.force_rest_function()
    rmakers.incised_function()
    rmakers.interpolate_function()
    rmakers.invisible_music_function()
    rmakers.multiplied_duration_function()
    rmakers.nongrace_leaves_in_each_tuplet_function()
    rmakers.note_function()
    rmakers.on_beat_grace_container_function()
    rmakers.reduce_multiplier_function()
    rmakers.repeat_tie_function()
    rmakers.rewrite_dots_function()
    rmakers.rewrite_meter_function()
    rmakers.rewrite_rest_filled_function()
    rmakers.rewrite_sustained_function()
    rmakers.split_measures_function()
    rmakers.talea_function()
    rmakers.tie_function()
    rmakers.tremolo_container_function()
    rmakers.trivialize_function()
    rmakers.tuplet_function()
    rmakers.unbeam_function()
    rmakers.untie_function()
    rmakers.wrap_in_time_signature_staff_function()
    rmakers.written_duration_function()

NEW:

    rmakers.accelerando()
    rmakers.after_grace_container()
    rmakers.beam()
    rmakers.beam_groups()
    rmakers.before_grace_container()
    rmakers.denominator()
    rmakers.duration_bracket()
    rmakers.even_division()
    rmakers.example()
    rmakers.extract_trivial()
    rmakers.feather_beam()
    rmakers.force_augmentation()
    rmakers.force_diminution()
    rmakers.force_fraction()
    rmakers.force_note()
    rmakers.force_repeat_tie()
    rmakers.force_rest()
    rmakers.incised()
    rmakers.interpolate()
    rmakers.invisible_music()
    rmakers.multiplied_duration()
    rmakers.nongrace_leaves_in_each_tuplet()
    rmakers.note()
    rmakers.on_beat_grace_container()
    rmakers.reduce_multiplier()
    rmakers.repeat_tie()
    rmakers.rewrite_dots()
    rmakers.rewrite_meter()
    rmakers.rewrite_rest_filled()
    rmakers.rewrite_sustained()
    rmakers.split_measures()
    rmakers.talea()
    rmakers.tie()
    rmakers.tremolo_container()
    rmakers.trivialize()
    rmakers.tuplet()
    rmakers.unbeam()
    rmakers.untie()
    rmakers.wrap_in_time_signature_staff()
    rmakers.written_duration()

Abjad 3.12

22 Sep 14:36
v3.12
Compare
Choose a tag to compare

Abjad 3.12 works with Python 3.10 and LilyPond 2.23.6 (and later).

Abjad 3.12 is a bridge release that helps users of Abjad's rhythm-makers migrate from Abjad 3.11 to Abjad 3.13. No other changes are included in the release.

In Abjad 3.11, the usual way of working with Abjad's rhythm-makers is through defining an (object-oriented and persistent) stack of (object-oriented and persistent) command objects. This is done with a collection of factory functions, and the resulting stack is then called (like a function) on a list of divisions to make notes, rests and tuplets:

stack = rmakers.stack(
    rmakers.even_division([8], extra_counts=[1]),
    rmakers.force_fraction(),
    rmakers.beam(),
)
divisions = [(2, 8), (2, 8), (2, 8)]
stack(divisions)
[Tuplet('3:2', "c'8 c'8 c'8"), Tuplet('3:2', "c'8 c'8 c'8"), Tuplet('3:2', "c'8 c'8 c'8")]

In Abjad 3.12, this is no longer necessary. The package's command objects can be avoided in favor of pure functions. No object-oriented framework is required, and the output of each line of code can be examined after it runs. This makes rhythms easier to design and debug; it also makes it much easier to mix the functionality of Abjad's rhythm-makers with user-defined custom functions:

>>> divisions = [(2, 8), (2, 8), (2, 8)]
>>> music = rmakers.even_division_function(divisions, [8], extra_counts=[1])
>>> rmakers.force_fraction_function(music)
>>> rmakers.beam_function(music)

Rhythms designed to be used throughout a score can be encapsulated in function. And it makes sense to use a temporary Abjad container when building rhythms because Abjad recognizes tied notes only when they are housed in an Abjad container. The 200+ examples in the abjad-ext-rmakers package have been rewritten according to a basic pattern that looks like this:

def make_rhythm(divisions):
    music = rmakers.even_division_function(divisions, [8], extra_counts=[1])
    container = abjad.Container(music)
    rmakers.force_fraction_function(container)
    rmakers.beam_function(container)
    music = abjad.mutate.eject_contents(container)
    return music
divisions = [(2, 8), (2, 8), (2, 8)]
make_rhythm(divisions)
[Tuplet('3:2', "c'8 c'8 c'8"), Tuplet('3:2', "c'8 c'8 c'8"), Tuplet('3:2', "c'8 c'8 c'8")]

How to migrate existing rhythm-maker code? Abjad 3.12 provides a shadow interface to facilitate migration. The old factory functions remain in the package but are deprecated in favor of a new set of pure functions, named in parallel:

DEPRECATED IN ABJAD 3.12:

rmakers.accelerando()
rmakers.after_grace_container()
rmakers.assign()
rmakers.beam()
rmakers.beam_groups()
rmakers.before_grace_container()
rmakers.bind()
rmakers.cache_state()
rmakers.denominator()
rmakers.duration_bracket()
rmakers.even_division()
rmakers.example()
rmakers.extract_trivial()
rmakers.feather_beam()
rmakers.force_augmentation()
rmakers.force_diminution()
rmakers.force_fraction()
rmakers.force_note()
rmakers.force_repeat_tie()
rmakers.force_rest()
rmakers.incised()
rmakers.invisible_music()
rmakers.multiplied_duration()
rmakers.note()
rmakers.on_beat_grace_container()
rmakers.reduce_multiplier()
rmakers.repeat_tie()
rmakers.rewrite_dots()
rmakers.rewrite_meter()
rmakers.rewrite_rest_filled()
rmakers.rewrite_sustained()
rmakers.split_measures()
rmakers.stack()
rmakers.talea()
rmakers.tie()
rmakers.tremolo_container()
rmakers.trivialize()
rmakers.tuplet()
rmakers.unbeam()
rmakers.untie()
rmakers.written_duration()

NEW IN ABJAD 3.12:

rmakers.accelerando_function()
rmakers.after_grace_container_function()
rmakers.beam_function()
rmakers.beam_groups_function()
rmakers.before_grace_container_function()
rmakers.denominator_function()
rmakers.duration_bracket_function()
rmakers.even_division_function()
rmakers.extract_trivial_function()
rmakers.feather_beam_function()
rmakers.force_augmentation_function()
rmakers.force_diminution_function()
rmakers.force_fraction_function()
rmakers.force_note_function()
rmakers.force_repeat_tie_function()
rmakers.force_rest_function()
rmakers.incised_function()
rmakers.invisible_music_function()
rmakers.multiplied_duration_function()
rmakers.note_function()
rmakers.on_beat_grace_container_function()
rmakers.reduce_multiplier_function()
rmakers.repeat_tie_function()
rmakers.rewrite_dots_function()
rmakers.rewrite_meter_function()
rmakers.rewrite_rest_filled_function()
rmakers.rewrite_sustained_function()
rmakers.split_measures_function()
rmakers.talea_function()
rmakers.tie_function()
rmakers.tremolo_container_function()
rmakers.trivialize_function()
rmakers.tuplet_function()
rmakers.unbeam_function()
rmakers.untie_function()
rmakers.written_duration_function()

Note that the pure functions introduced in Abjad 3.12 are suffixed in _function() for only one release. In Abjad 3.13, the old factory functions will be removed, and the pure functions will lose their suffix. The Abjad 3.13 version of the pattern shown above will look like this:

def make_rhythm(divisions):
    music = rmakers.even_division(divisions, [8], extra_counts=[1])
    container = abjad.Container(music)
    rmakers.force_fraction(container)
    rmakers.beam(container)
    music = abjad.mutate.eject_contents(container)
    return music

TL;DR Abjad 3.12 implements two different interfaces to the functionality of Abjad's rhythm-makers. Use Abjad 3.12 to port existing rhythm-maker code from Abjad 3.11 to Abjad 3.13.

Abjad 3.11

10 Sep 15:27
v3.11
Compare
Choose a tag to compare

Abjad 3.11 works with Python 3.10 and LilyPond 2.23.6 (and later).

Abjad 3.11 is a maintenance release that preserves the functionality of Abjad 3.10 without significant changes.

3.10

02 Jun 14:22
v3.10
Compare
Choose a tag to compare

Abjad 3.10 works with Python 3.10 and LilyPond 2.23.6 (and later).

#1460: Cleaned up instrument classes

Abjad 3.10 reimplements Abjad's instrument classes as frozen data classes, removes four properties from all instrument classes, and changes the name of one property.

REMOVED:

    * abjad.Instrument.markup
    * abjad.Instrument.name
    * abjad.Instrument.short_markup
    * abjad.Instrument.short_name

CHANGED:

    OLD: abjad.Instrument.allowable_clefs=("treble", "bass")
    NEW: abjad.Instrument.clefs==("treble", "bass")

This means that instrument classes are left with four basic properties:

 >>> abjad.Flute()
Flute(clefs=('treble',), context='Staff', middle_c_sounding_pitch=NamedPitch("c'"), pitch_range=PitchRange(range_string='[C4, D7]'))

Use abjad.InstrumentName and abjad.ShortInstrumentName to handle those properties independently.

#1459 : Cleaned up instrument name, short instrument name

LilyPond uses \instrumentName to print markup to the left of the first system of a score. It makes no sense to change \instrumentName after it is first set because the value of \instrumentName is printed only once.

LilyPond uses \shortInstrumentName to print markup to left the of nonfirst systems of a score. Changing \shortInstrumentName is necessary whenever instrument changes (for example, from flute to piccolo) should be reflected to the left of each system. (Whether, and how, scores use left-positioned directives to reflective instrument changes seems to vary over time, and by publisher.)

Abjad 3.9 (and earlier) implemented abjad.StartMarkup and abjad.MarginMarkup classes to handle these two types of markup. Abjad 3.10 replaces these with abjad.InstrumentName and abjad.ShortInstrumentName classes that match LilyPond's \instrumentName and \shortInstrumentName commands.

OLD: abjad.StartMarkup(markup=abjad.Markup(r"\markup Cello"))
NEW: abjad.InstrumentName(r"\markup Cello")

OLD: abjad.MarginMarkup(markup=abjad.Markup(r"\markup Vc."))
NEW: abjad.ShortInstrumentName(r"\markup Vc.")

#1457 Cleaned up abjad.Octave initializer

OLD. Octave objects are usually initialized by octave number. But the abjad.Octave initialzer allowed for undocumented initialization by tick string:

>>> abjad.Octave("'")
Octave(number=4)

NEW. Use the new abjad.Octave.from_ticks() constructor instead:

abjad.Octave.from_ticks("'")
Octave(number=4)