Skip to content

Releases: Abjad/abjad

v3.9

01 May 13:03
v3.9
Compare
Choose a tag to compare

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

#1453: Changed abjad/_stylesheets to abjad/scm

Users will need to update the way LilyPond is invoked:

OLD: lilypond --include=~/abjad/_stylesheets
NEW: lilypond --include=~/abjad/scm

#1452: Alphabetized all format contributions by format site.

The lexical order of commands in LilyPond output no longer depends on the (dynamic) order in which indicators are attached to leaves.

Alphabetized tags, and offset tags two spaces to the right in LilyPond output.

Added abjad.lilypond(..., site_comments=False) keyword. Set to true to debug the names and contents of every format site.

Diffs of existing scores ported to Abjad 3.9 will likely appear to have changed a lot from Abjad 3.8. But note that no functionality has changed: all that has changed is the order of LilyPond commands in the LilyPond output Abjad creates.

#1447: Cleaned up typings.py.

Removed typing classes from global namespace.

REMOVED:

abjad.typings.DurationSequenceTyping
abjad.typings.IntegerSequence
abjad.typings.Number
abjad.typings.NumberPair
abjad.typings.OffsetSequenceTyping
abjad.typings.RatioSequenceTyping

RENAMED:

OLD: abjad.DurationTyping
NEW: abjad.typings.Duration

OLD: abjad.OffsetTyping
NEW: abjad.typings.Offset

OLD: abjad.PatternTyping
NEW: abjad.typings.Pattern

OLD: abjad.RatioTyping
NEW: abjad.typings.Ratio

v3.8

01 May 12:37
v3.8
Compare
Choose a tag to compare

Abjad 3.8 works with LilyPond 2.23.6, and later.

The functionality of Abjad 3.7 and 3.8 otherwise remains the same.

#1444: Bumped LilyPond to 2.23.6.

LilyPond 2.23 introduces a few breaking changes.

One shows up in stylesheets:

OLD: \on-the-fly #print-page-number-check-first
NEW: \if \should-print-page-number

Another shows up in color quoting:

OLD:

    abjad-color-music = #(
        define-music-function (parser location color music) (symbol? ly:music?)
        #{
        \once \override Accidental.color = #(x11-color #'color)
        ...
        $music #})

NEW:

    abjad-color-music = #(
        define-music-function (parser location color music) (symbol? ly:music?)
        #{
        \once \override Accidental.color = #(x11-color color)
        ...
        $music #})

Run LilyPond's convert-ly script on your scores and stylesheets to locate these changes.

#1442: Added py.typed marker.

Abjad includes inline typehints that can be read by typecheckers like mypy. Users of Abjad 3.7 have to tell mypy where Abjad is installed by setting the MYPYPATH environment variable. But this is silly because mypy already knows the location installed packages, including Abjad. Including an (empty) py.typed file in Abjad's source directory fixes this. Users of Abjad 3.8 no longer need to set MYPYPATH to use mypy with Abjad.

v3.7

06 Apr 13:18
v3.7
Compare
Choose a tag to compare

Changed in Abjad 3.7

Changes to Abjad 3.7 (2020-04-06) since Abjad 3.6 (2020-03-01).

BREAKING CHANGE (#1440). Cleaned up tweaks.

Removed tweaks from all indicators. Use the new abjad.bundle() function to create indicators "bundled" with tweaks. Then attach the resulting abjad.Bundle to a note, rest or chord:

OLD: arpeggio = abjad.Arpeggio()
     abjad.tweak(arpeggio).color = "#red"
     abjad.attach(arpeggio, ...)
NEW: arpeggio = abjad.Arpeggio()
     bundle = abjad.bundle(arpeggio, r"- \tweak color #red")
     abjad.attach(bundle, ...)

OLD: articulation = abjad.Articulation(".")
     abjad.tweak(articulation).color = "#red"
     abjad.attach(articulation, ...)
NEW: articulation = abjad.Articulation(".")
     bundle = abjad.bundle(articulation, r"- \tweak color #red")
     abjad.attach(bundle, ...)

OLD: bend_after = abjad.BendAfter()
     abjad.tweak(bend_after).color = "#red"
     abjad.attach(bend_after, ...)
NEW: bend_after = abjad.BendAfter()
     bundle = abjad.bundle(bend_after, r"- \tweak color #red")
     abjad.attach(bundle, ...)

etc.

Two new frozen dataclasses are included in this commit. These are abjad.Bundle and abjad.Tweak:

>>> articulation = abjad.Articulation(".")
>>> bundle = abjad.bundle(
    articulation,
    r"- \tweak color #red",
    r"- \tweak padding 1.25",
)

>>> bundle.indicator
Articulation(name='.')

>>> for _ in bundle.tweaks: _
...
Tweak(string='- \\tweak color #red', tag=None)
Tweak(string='- \\tweak padding 1.25', tag=None)

Inspect tweak properties like this:

>>> tweak = bundle.tweaks[0]
>>> tweak
Tweak(string='- \\tweak color #red', tag=None)

>>> tweak.string
'- \\tweak color #red'

>>> tweak.attribute()
'color'

>>> tweak.post_event()
True

>>> tweak.value()
'#red'

abjad.get.indicator() knows about bundled indicators:

>>> note = abjad.Note("c'4")
>>> abjad.attach(bundle, note)
>>> abjad.get.indicator(note, abjad.Articulation)
Articulation(name='.')

Use wrapper properties to work with the bundle itself:

>>> wrapper = abjad.get.wrapper(note, abjad.Articulation)
>>> bundle = wrapper.indicator
>>> bundle.indicator
Articulation(name='.')

>>> for _ in bundle.tweaks: _
...
Tweak(string='- \\tweak color #red', tag=None)
Tweak(string='- \\tweak padding 1.25', tag=None)

Continue to use the old abjad.tweak() function to tweak note-heads and tuplets. But note that you must now pass a tweak object to the function:

>>> note = abjad.Note("c'4")
>>> tweak = abjad.Tweak(r"\tweak color #red")
>>> abjad.tweak(note.note_head, tweak)
>>> for _ in note.note_head.tweaks: _
...
Tweak(string='\\tweak color #red', tag=None)

Additionally, removing the (mutable) tweaks means that almost all Abjad indicators are now dataclasses decorated with frozen=True:

abjad.Arpeggio
abjad.Articulation
abjad.BarLine
abjad.BeamCount
abjad.BendAfter
abjad.BreathMark
abjad.Clef
abjad.ColorFingering
abjad.Fermata
abjad.Glissando
abjad.KeyCluster
abjad.LilyPondLiteral
abjad.Mode
abjad.KeySignature
abjad.LaissezVibrer
abjad.MarginMarkup
abjad.Markup
abjad.Ottava
abjad.RehearsalMark
abjad.Repeat
abjad.RepeatTie
abjad.StaffChange
abjad.StartBeam
abjad.StartGroup
abjad.StartHairpin
abjad.StartMarkup
abjad.StartPhrasingSlur
abjad.StartPianoPedal
abjad.StartSlur
abjad.StartTextSpan
abjad.StartTrillSpan
abjad.StemTremolo
abjad.StopBeam
abjad.StopGroup
abjad.StopHairpin
abjad.StopPhrasingSlur
abjad.StopPianoPedal
abjad.StopSlur
abjad.StopTextSpan
abjad.StopTrillSpan
abjad.Tie

Objects created from these classes can not be changed after you create them, but otherwise behave the same as before. Note, however, that abjad.KeySignature objects must now be initialized with explicit pitch-class and mode objects:

OLD: abjad.KeySignature("e", "major")
NEW: abjad.KeySignature(abjad.NamedPitchClass("e"), abjad.Mode("major"))

The abjad.Dynamic, abjad.MetricModulation, abjad.MetronomeMark, abjad.TimeSignature and instrument classes will be frozen in Abjad 3.8 but remain mutable in Abjad 3.7.

This commit also changes the order that articulations, spanners and other items appear in the LilyPond output that Abjad produces. Previous versions of Abjad relied in part on the (dynamic) order in which users attached such objects to score components. Abjad 3.7 sorts these elements by class name to better standardize the (lexical) order of such commands in LilyPond output.

BREAKING CHANGE (#1429). Moved direction from indicators to attach.

The 10 indicators that previously implemented a direction attribute no longer implement that attribute. Use the new abjad.attach(..., direction=None) keyword instead:

OLD: articulation = abjad.Articulation(".", direction=abjad.Up)
     abjad.attach(articulation, note)
NEW: articulation = abjad.Articulation(".")
     abjad.attach(articulation, note, direction=abjad.UP)

OLD: dynamic = abjad.Dynamic("f", direction=abjad.Up)
     abjad.attach(dynamic, note)
NEW: dynamic = abjad.Dynamic("f")
     abjad.attach(dynamic, note, direction=abjad.UP)

OLD: markup = abjad.Markup(r"\markup Allegro", direction=abjad.Up)
     abjad.attach(markup, note)
NEW: markup = abjad.Markup(r"\markup Allegro")
     abjad.attach(dynamic, markup, direction=abjad.UP)

OLD: repeat_tie = abjad.RepeatTie(direction=abjad.Up)
     abjad.attach(repeat_tie, note)
NEW: repeat_tie = abjad.RepeatTie()
     abjad.attach(repeat_tie, note, direction=abjad.UP)

OLD: start_beam = abjad.StartBeam(direction=abjad.Up)
     abjad.attach(start_beam, note)
NEW: articulation = abjad.Articulation(".")
     abjad.attach(articulation, note, direction=abjad.UP)

OLD: start_hairpin = abjad.StartHairpin(direction=abjad.Up)
     abjad.attach(start_hairpin, note)
NEW: start_hairpin = abjad.StartHairping()
     abjad.attach(start_hairpin, note, direction=abjad.UP)

OLD: start_phrasing_slur = abjad.StartPhrasingSlur(direction=abjad.Up)
     abjad.attach(start_phrasing_slur, note)
NEW: start_phrasing_slur = abjad.StartPhrasingSlur()
     abjad.attach(start_phrasing_slur, note, direction=abjad.UP)

OLD: start_slur = abjad.StartSlur(direction=abjad.Up)
     abjad.attach(start_slur, note)
NEW: start_slur = abjad.StartSlur()
     abjad.attach(start_slur, note, direction=abjad.UP)

OLD: start_text_span = abjad.StartTextSpan(direction=abjad.Up)
     abjad.attach(start_text_span, note)
NEW: start_text_span = abjad.StartTextSpan()
     abjad.attach(start_text_span, note, direction=abjad.UP)

OLD: tie = abjad.Tie(direction=abjad.Up)
     abjad.attach(tie, note)
NEW: tie = abjad.Tie()
     abjad.attach(tie, note, direction=abjad.UP)

Additionally, abjad.ColorFingering and abjad.KeyCluster should now also be directed with the abjad.attach(..., direction=None) keyword:

OLD: fingering = abjad.ColorFingering(1)
     abjad.attach(fingering, note)
NEW: fingering = abjad.ColorFingering(1)
     abjad.attach(fingering, note, direction=abjad.UP)

OLD: cluster = abjad.KeyCluster()
     abjad.attach(cluster, note)
NEW: cluster = abjad.KeyCluster()
     abjad.attach(cluster, note, direction=abjad.UP)

Closes #748, from August 2016, Abjad's oldest open issue.

BREAKING CHANGE (#1428, #1409). Removed abjad.Selection.

Abjad 3.6 (2020-03-01) deprecated the abjad.Selection class. Abjad 3.7 now removes abjad.Selection from the system. The old abjad.select() factory function has been replaced by the vanilla functions housed in select.py:

OLD:

abjad.select(...).chord(n)
abjad.select(...).chords()
abjad.select(...).components()
abjad.select(...).exclude([0], 2)
abjad.select(...).filter(lambda _: len(_) == 2)
abjad.select(...).get([0], 2)
abjad.select(...).group_by(lambda _: getattr(_, "foo"))
abjad.select(...).group_by_contiguity()
abjad.select(...).group_by_duration()
abjad.select(...).group_by_length()
abjad.select(...).group_by_measure()
abjad.select(...).group_by_pitch()
abjad.select(...).leaf(n)
abjad.select(...).leaves()
abjad.select(...).logical_tie(n)
abjad.select(...).logical_ties()
abjad.select(...).nontrivial()
abjad.select(...).note(n)
abjad.select(...).notes()
abjad.select(...).partition_by_counts([4, 4, 2], cyclic=True)
abjad.select(...).partition_by_ratio((2, 1))
abjad.select(...).rest(n)
abjad.select(...).rests()
abjad.select(...).run(n)
abjad.select(...).runs()
abjad.select(...).top()
abjad.select(...).tuplet(n)
abjad.select(...).tuplets()
abjad.select(...).with_next_leaf()
abjad.select(...).with_previous_leaf()

NEW:

abjad.select.chord(..., n)
abjad.select.chords(..., )
abjad.select.components(..., )
abjad.select.exclude(..., [0], 2)
abjad.select.filter(..., lambda _: len(_) == 2)
abjad.select.get(..., [0], 2)
abjad.select.group_by(..., lambda _: getattr(_, "foo"))
abjad.select.group_by_contiguity(..., )
abjad.select.group_by_duration(..., )
abjad.select.group_by_length(..., )
abjad.select.group_by_measure(..., )
abjad.select.group_by_pitch(..., )
abjad.select.leaf(..., n)
abj...
Read more

v3.6

01 Mar 16:22
v3.6
Compare
Choose a tag to compare

Changed in Abjad 3.6

Changes to Abjad 3.6 (2022-03-01) since Abjad 3.5 (2022-02-01).

PERFORMANCE INCREASES. Abjad 3.6 runs significantly faster than previous versions of the system: user code rendering two or more pages of music runs 200% to 800% faster than before. Performance increases came from removing inspect-heavy functions, and from optimizing score updates. Total performance increase depends on the number of context indicators (like clefs and time signatures) used, and on the amount of looping used to find indicators in a score.

BREAKING CHANGE (#1407): The abjad.Selection class is deprecated will be completely removed in Abjad 3.7.

CHANGED. In general, remove all `isinstance(..., abjad.Selection)` from your code:
Abjad 3.6 now passes built-in lists of components instead of custom selection
objects. Container slices now return a list:

OLD:

    staff = abjad.Staff("c'4 d' e' f'")[:]
    abjad.Selection(items=[Note("c'4"), Note("d'4"), Note("e'4"), Note("f'4")])

NEW:

    staff = abjad.Staff("c'4 d' e' f'")[:]
    [Note("c'4"), Note("d'4"), Note("e'4"), Note("f'4")]

CHANGED. `abjad.select.foo(...)` and `abjad.iterate.foo(...)` now match.

Selecting components means calling functions; class creation is no longer required:

OLD:

    abjad.select(...).chord(n)
    abjad.select(...).chords()
    abjad.select(...).components()
    abjad.select(...).exclude([0], 2)
    abjad.select(...).filter(lambda _: len(_) == 2)
    abjad.select(...).get([0], 2)
    abjad.select(...).group_by(lambda _: getattr(_, "foo"))
    abjad.select(...).group_by_contiguity()
    abjad.select(...).group_by_duration()
    abjad.select(...).group_by_length()
    abjad.select(...).group_by_measure()
    abjad.select(...).group_by_pitch()
    abjad.select(...).leaf(n)
    abjad.select(...).leaves()
    abjad.select(...).logical_tie(n)
    abjad.select(...).logical_ties()
    abjad.select(...).nontrivial()
    abjad.select(...).note(n)
    abjad.select(...).notes()
    abjad.select(...).partition_by_counts([4, 4, 2], cyclic=True)
    abjad.select(...).partition_by_ratio((2, 1))
    abjad.select(...).rest(n)
    abjad.select(...).rests()
    abjad.select(...).run(n)
    abjad.select(...).runs()
    abjad.select(...).top()
    abjad.select(...).tuplet(n)
    abjad.select(...).tuplets()
    abjad.select(...).with_next_leaf()
    abjad.select(...).with_previous_leaf()

NEW:

    abjad.select.chord(..., n)
    abjad.select.chords(..., )
    abjad.select.components(..., )
    abjad.select.exclude(..., [0], 2)
    abjad.select.filter(..., lambda _: len(_) == 2)
    abjad.select.get(..., [0], 2)
    abjad.select.group_by(..., lambda _: getattr(_, "foo"))
    abjad.select.group_by_contiguity(..., )
    abjad.select.group_by_duration(..., )
    abjad.select.group_by_length(..., )
    abjad.select.group_by_measure(..., )
    abjad.select.group_by_pitch(..., )
    abjad.select.leaf(..., n)
    abjad.select.leaves(..., )
    abjad.select.logical_tie(..., n)
    abjad.select.logical_ties(..., )
    abjad.select.nontrivial(..., )
    abjad.select.note(..., n)
    abjad.select.notes(..., )
    abjad.select.partition_by_counts(..., [4, 4, 2], cyclic=True)
    abjad.select.partition_by_ratio(..., (2, 1))
    abjad.select.rest(..., n)
    abjad.select.rests(..., )
    abjad.select.run(..., n)
    abjad.select.runs(..., )
    abjad.select.top(..., )
    abjad.select.tuplet(..., n)
    abjad.select.tuplets(..., )
    abjad.select.with_next_leaf(..., )
    abjad.select.with_previous_leaf(..., )

Dot-chained syntax continues to be allowed in Abjad 3.6 but will be removed in Abjad
3.7. Rewrite dot-chained method calls like this:

Example 1:

    OLD:

        result = abjad.select(...).tuplets()[:4].leaves()

    NEW:

        result = abjad.select.tuplets(...)[:4]
        result = abjad.select.leaves(result)

Example 2:

    OLD:

        result = abjad.select(...).leaves().group_by_measure().get([0], 2)

    NEW:

        result = abjad.select.leaves(...)
        result = abjad.select.group_by_measure(result)
        result = abjad.select.get(result, [0], 2)

BREAKING CHANGE (#1415): Replaced abjad.Sequence with sequence.py module:

OLD:

    abjad.Sequence(...).filter()
    abjad.Sequence(...).flatten()
    abjad.Sequence(...).group_by()
    abjad.Sequence(...).is_decreasing()
    abjad.Sequence(...).is_increasing()
    abjad.Sequence(...).is_permutation()
    abjad.Sequence(...).is_repetition_free()
    abjad.Sequence(...).join()
    abjad.Sequence(...).map()
    abjad.Sequence(...).nwise()
    abjad.Sequence(...).partition_by_counts()
    abjad.Sequence(...).partition_by_ratio_of_lengths()
    abjad.Sequence(...).partition_by_ratio_of_weights()
    abjad.Sequence(...).partition_by_weights()
    abjad.Sequence(...).permute()
    abjad.Sequence(...).remove()
    abjad.Sequence(...).remove_repeats()
    abjad.Sequence(...).repeat()
    abjad.Sequence(...).repeat_to_length()
    abjad.Sequence(...).repeat_to_weight()
    abjad.Sequence(...).replace()
    abjad.Sequence(...).replace_at()
    abjad.Sequence(...).retain()
    abjad.Sequence(...).retain_pattern()
    abjad.Sequence(...).reverse()
    abjad.Sequence(...).rotate()
    abjad.Sequence(...).sort()
    abjad.Sequence(...).split()
    abjad.Sequence(...).sum()
    abjad.Sequence(...).sum_by_sign()
    abjad.Sequence(...).truncate()
    abjad.Sequence(...).weight()
    abjad.Sequence(...).zip()

NEW:

    abjad.sequence.filter(...)
    abjad.sequence.flatten(...)
    abjad.sequence.group_by(...)
    abjad.sequence.is_decreasing(...)
    abjad.sequence.is_increasing(...)
    abjad.sequence.is_permutation(...)
    abjad.sequence.is_repetition_free(...)
    abjad.sequence.join(...)
    abjad.sequence.map(...)
    abjad.sequence.nwise(...)
    abjad.sequence.partition_by_counts(...)
    abjad.sequence.partition_by_ratio_of_lengths(...)
    abjad.sequence.partition_by_ratio_of_weights(...)
    abjad.sequence.partition_by_weights(...)
    abjad.sequence.permute(...)
    abjad.sequence.remove(...)
    abjad.sequence.remove_repeats(...)
    abjad.sequence.repeat(...)
    abjad.sequence.repeat_to_length(...)
    abjad.sequence.repeat_to_weight(...)
    abjad.sequence.replace(...)
    abjad.sequence.replace_at(...)
    abjad.sequence.retain(...)
    abjad.sequence.retain_pattern(...)
    abjad.sequence.reverse(...)
    abjad.sequence.rotate(...)
    abjad.sequence.sort(...)
    abjad.sequence.split(...)
    abjad.sequence.sum(...)
    abjad.sequence.sum_by_sign(...)
    abjad.sequence.truncate(...)
    abjad.sequence.weight(...)
    abjad.sequence.zip(...)

BREAKING CHANGE (#1394): Replaced abjad.String with string.py module:

OLD:

    abjad.String("text").capitalize_start()
    abjad.String("text").delimit_words()
    abjad.String("text").from_roman()
    abjad.String("text").is_lilypond_identifier()
    abjad.String("text").is_roman()
    abjad.String("text").is_shout_case()
    abjad.String("text").pluralize()
    abjad.String("text").strip_roman()
    abjad.String("text").to_shout_case()
    abjad.String("text").to_upper_camel_case()
    abjad.String.normalize("text")
    abjad.String.sort_roman(["PartI", "PartII", "PartIII"])
    abjad.String.to_tridirectional_lilypond_symbol("text")
    abjad.String.to_tridirectional_ordinal_constant("text")

NEW:

    abjad.string.capitalize_start("text")
    abjad.string.delimit_words("text")
    abjad.string.from_roman("text")
    abjad.string.is_lilypond_identifier("text")
    abjad.string.is_roman("text")
    abjad.string.is_shout_case("text")
    abjad.string.pluralize("text")
    abjad.string.strip_roman("text")
    abjad.string.to_shout_case("text")
    abjad.string.to_upper_camel_case("text")
    abjad.string.normalize("text")
    abjad.string.sort_roman(["PartI", "PartII", "PartIII"])
    abjad.string.to_tridirectional_lilypond_symbol("text")
    abjad.string.to_tridirectional_ordinal_constant("text")

REMOVED:

    abjad.String("text").base_26()
    abjad.String("text").is_build_directory_name()
    abjad.String("text").is_classfile_name()
    abjad.String("text").is_dash_case()
    abjad.String("text").is_lower_camel_case()
    abjad.String("text").is_lowercase_file_name()
    abjad.String("text").is_module_file_name()
    abjad.String("text").is_package_name()
    abjad.String("text").is_public_python_file_name()
    abjad.String("text").is_rehearsal_mark()
    abjad.String("text").is_snake_case()
    abjad.String("text").is_snake_case_file_name()
    abjad.String("text").is_snake_case_file_name_with_extension()
    abjad.String("text").is_snake_case_package_name()
    abjad.String("text").is_space_delimited_lowercase()
    abjad.String("text").is_string()
    abjad.String("text").is_stylesheet_name()
    abjad.String("text").is_tools_file_name()
    abjad.String("text").is_upper_camel_case()
    abjad.String("text").match_strings()
    abjad.String("text").m...
Read more

v3.5

01 Feb 19:51
v3.5
Compare
Choose a tag to compare

Changed in Abjad 3.5

Changes to Abjad 3.5 (2022-02-01) since Abjad 3.4 (2021-05-01).

Abjad 3.5 requires Python 3.10.

#1384 <https://github.com/Abjad/abjad/issues/1384>_. Moved abjad.ily from
abjad/docs/_stylesheets to abjad/abjad/_stylesheets.

#1372 <https://github.com/Abjad/abjad/issues/1372>_. Refactored all indicators as
dataclasses. Added new indicators.py module.

#1370 <https://github.com/Abjad/abjad/issues/1370>_. Fixed definition of Forte SC 4-25.

#1368 <https://github.com/Abjad/abjad/issues/1368>_. Gutted abjad.Markup. Markup is
no longer parsed:

OLD::

    abjad.Markup('\italic "Allegro moderato"', literal=True)

NEW::

    abjad.Markup(r'\markup \italic "Allegro moderator"')

REMOVED::

    * abjad.Postscript; use strings instead
    * abjad.PostscriptOperator; use strings instead
    * abjad.Markup.__add__(), __radd__()
    * abjad.Markup.postscript()
    * abjad.markups.abjad_metronome_mark()

#1366 <https://github.com/Abjad/abjad/issues/1366>_. Removed abjad.OrderedDict. Use
dict() instead.

#1360 <https://github.com/Abjad/abjad/issues/1360>_. Replaced
abjad.StorageFormatManager with format.py module.

#1359 <https://github.com/Abjad/abjad/issues/1359>_. Changed abjad.iterate() to
iterate.py module:

OLD::

    abjad.iterate(argument).components()
    abjad.iterate(argument).leaves()
    abjad.iterate(argument).logical_ties()
    abjad.iterate(argument).pitches()

NEW::

    abjad.iterate.components(argument)
    abjad.iterate.leaves(argument)
    abjad.iterate.logical_ties(argument)
    abjad.iterate.pitches(argument)

#1357 <https://github.com/Abjad/abjad/issues/1357>_. Changed abjad.Label to
label.py module:

OLD::

    abjad.Label(argument).by_selector()
    abjad.Label(argument).color_container()
    abjad.Label(argument).color_leaves()
    abjad.Label(argument).color_note_heads()
    abjad.Label(argument).remove_markup()
    abjad.Label(argument).vertical_moments()
    abjad.Label(argument).with_durations()
    abjad.Label(argument).with_indices()
    abjad.Label(argument).with_intervals()
    abjad.Label(argument).with_pitches()
    abjad.Label(argument).with_set_classes()
    abjad.Label(argument).with_start_offsets()

NEW::

    abjad.label.by_selector(argument)
    abjad.label.color_container(argument)
    abjad.label.color_leaves(argument)
    abjad.label.color_note_heads(argument)
    abjad.label.remove_markup(argument)
    abjad.label.vertical_moments(argument)
    abjad.label.with_durations(argument)
    abjad.label.with_indices(argument)
    abjad.label.with_intervals(argument)
    abjad.label.with_pitches(argument)
    abjad.label.with_set_classes(argument)
    abjad.label.with_start_offsets(argument)

#1303 <https://github.com/Abjad/abjad/issues/1303>_. Removed default.ily stylesheet.

#1293 <https://github.com/Abjad/abjad/issues/1293>_. Gutted abjad.LilyPondFile:

Removed abjad.ContextBlock; use abjad.Block instead::

    >>> string = r"""\Staff
    ...     \name FluteStaff
    ...     \type Engraver_group
    ...     \alias Staff
    ...     \remove Forbid_line_break_engraver
    ...     \consists Horizontal_bracket_engraver
    ...     \accepts FluteUpperVoice
    ...     \accepts FluteLowerVoice
    ...     \override Beam.positions = #'(-4 . -4)
    ...     \override Stem.stem-end-position = -6
    ...     autoBeaming = ##f
    ...     tupletFullLength = ##t
    ...     \accidentalStyle dodecaphonic"""
    >>> block = abjad.Block(name="context")
    >>> block.items.append(string)

    >>> string = abjad.lilypond(block)
    >>> print(string)
    \context
    {
        \Staff
        \name FluteStaff
        \type Engraver_group
        \alias Staff
        \remove Forbid_line_break_engraver
        \consists Horizontal_bracket_engraver
        \accepts FluteUpperVoice
        \accepts FluteLowerVoice
        \override Beam.positions = #'(-4 . -4)
        \override Stem.stem-end-position = -6
        autoBeaming = ##f
        tupletFullLength = ##t
        \accidentalStyle dodecaphonic
    }

Removed ``abjad.Block.__setattr__()``. Use ``abjad.Block.items`` instead.

REMOVED::

    * abjad.DateTimeToken
    * abjad.LilyPondDimension
    * abjad.LilyPondLanguageToken
    * abjad.LilyPondVersionToken
    * abjad.PackageGitCommitToken
    * abjad.LilyPondFile.comments
    * abjad.LilyPondFile.includes
    * abjad.LilyPondFile.use_relative_includes
    * Removed courtesy blank lines from abjad.LilyPondFile output
    * abjad.LilyPondFile.default_paper_size
    * abjad.LilyPondFile.global_staff_size:

OLD::

    * abjad.LilyPondFile.default_paper_size = ("a4", "letter")
    * abjad.LilyPondFile.global_staff_size = 16

NEW::

    preamble = r"""
        #(set-default-paper-size "a4" 'letter)
        #(set-global-staff-size 16)"""

    * abjad.LilyPondFile(items=[preamble, ...])

OLD::

    * abjad.LilyPondFile.header_block
    * abjad.LilyPondFile.layout_block
    * abjad.LilyPondFile.paper_block

NEW::

    * abjad.LilyPondFile["header"]
    * abjad.LilyPondFile["layout"]
    * abjad.LilyPondFile["paper"]

Limited ``abjad.LilyPondFile.__getitem__()`` to strings:

OLD::

    * lilypond_file["My_Staff"]
    * lilypond_file[abjad.Staff]

NEW::

    * lilypond_file["My_Staff"]

#1136 <https://github.com/Abjad/abjad/issues/1136>_. Collapsed
abjad.AnnotatedTimespan into abjad.Timespan.

CONFIGURATION::

* Removed abjad.AbjadConfiguration.composer_email
* Removed abjad.AbjadConfiguration.composer_full_name
* Removed abjad.AbjadConfiguration.composer_github_username
* Removed abjad.AbjadConfiguration.composer_last_name
* Removed abjad.AbjadConfiguration.composer_scores_directory
* Removed abjad.AbjadConfiguration.composer_uppercase_name
* Removed abjad.AbjadConfiguration.composer_website
* Added abjad.AbjadConfiguration.sphinx_stylesheets_directory colon-delimited paths

ENUMERATION: `abjad.enumerate.yield_outer_product()previously returned a generator ofabjad.Sequence`` objects. The function now returns a list of list.

I/O::

* Taught abjad.persist.as_ly() to write file-terminal newline.
* Cleaned up abjad.persist.as_midi().
* Cleaned up abjad.run_lilypond():
    OLD: abjad.run_lilypond() returned true or false.
    NEW: abjad.run_lilypond() returns integer exit code.
* Cleaned up abjad.io.profile():
    * removed print_to_terminal=True keyword
    * function now always returns a string

LABEL: Taught abjad.Label.color_note_heads() to color accidentals.

SELECTION: Changed abjad.select() to a true synonym for abjad.Selection().

Deprecated abjad.SegmentMaker. Define scores as a linear sequence of function calls
instead.

Deprecated all score templates. Define make_empty_score() function instead.

v3.4

01 May 23:17
v3.4
91f4f46
Compare
Choose a tag to compare

Changed in Abjad 3.4

Changes to Abjad 3.4 (2021-05-01) since Abjad 3.3 (2021-03-01).

Removed support for IPython.

#1338 Cleaned up tuplet formatting and block formatting. Opening brace now appears on its own line in LilyPond output:

OLD:

>>> tuplet = abjad.Tuplet("3:2", "c'4 d' e'")
>>> string = abjad.lilypond(tuplet)
>>> print(string)
\times 2/3 {
    c'4
    d'4
    e'4
}

>>> staff = abjad.Staff("c'4 d' e' f'")
>>> block = abjad.Block(name="score")
>>> block.items.append(staff)
>>> string = abjad.lilypond(block)
>>> print(string)
\score {
    \new Staff
    {
        c'4
        d'4
        e'4
        f'4
    }
}

NEW:

>>> tuplet = abjad.Tuplet("3:2", "c'4 d' e'")
>>> string = abjad.lilypond(tuplet)
>>> print(string)
\times 2/3
{
    c'4
    d'4
    e'4
}

>>> staff = abjad.Staff("c'4 d' e' f'")
>>> block = abjad.Block(name="score")
>>> block.items.append(staff)
>>> string = abjad.lilypond(block)
>>> print(string)
\score
{
    \new Staff
    {
        c'4
        d'4
        e'4
        f'4
    }
}

#1299. Removed deprecated stravinsky keyword from pitch classes. The function of the keyword was to transpose sets and segments such that the first element was set equal to 0 (after operations like inversion or rotation). Transpose sets and segments separately (after inversion or rotation) when required instead.

v3.3

02 Mar 01:04
v3.3
172f3fc
Compare
Choose a tag to compare

Changed in Abjad 3.3

Changes to Abjad 3.3 (2021-03-01) since Abjad 3.2 (2021-01-19).

#1328. Removed abjad.WoodwindFingering. Use LilyPond \woodwind-fingering instead.

#1323. Removed abjad.f(). Use abjad.lilypond() instead:

OLD:

    >>> abjad.f(score)

NEW:

    >>> string = abjad.lilypond(score)
    >>> print(string)

#1293. Removed abjad.LilyPondFile.new() constructor. Use abjad.LilyPondFile initializer instead:

OLD:

    >>> abjad.LilyPondFile.new(score)

NEW:

    >>> block = abjad.Block(name="score")
    >>> block.items.append(score)
    >>> abjad.LilyPondFile(items=[block])

#1086. Gutted markup interface. Externalize markup in a LilyPond stylesheet and set literal=True instead:

REMOVED:

    abjad.Markup.bold()
    abjad.Markup.center_column()
    abjad.Markup.hcenter_in()
    abjad.Markup.italic()
    abjad.Markup.with_dimensions()
    ...

OLD:

    >>> markup = abjad.Markup("Allegro assai")
    >>> markup = markup.bold()

NEW:

    Create a markup library in an external LilyPond file;
    assign each new piece of markup to a LilyPond variable:

        allegro-assai = \markup \bold { Allegro assai }

    Then initialize in Abjad like this:

        >>> abjad.Markup(r"\allegro-assai", literal=True)

    Markup can still be initialized locally in Abjad;
    type markup exactly as in LilyPond:

    >>> string = r"\markup \bold { Allegro assai }"
    >>> abjad.Markup(string, literal=True)

(The literal=True keyword will be removed in a future release of Abjad. All markup will then initialize as though literal=True.)

#1086. Removed Scheme proxy classes. Type Scheme settings as literal LilyPond code instead:

REMOVED:

    abjad.SchemeMoment
    abjad.SchemeAssociativeList
    abjad.SchemeColor
    abjad.SchemePair
    abjad.SpacingVector
    abjad.SchemeSymbol
    abjad.SchemeVector
    abjad.SchemeVectorConstant

CHANGED:

    >>> scheme_moment = abjad.SchemeMoment((1, 24))
    >>> abjad.override(score).proportional_notation_duration = scheme_moment

    >>> abjad.override(score).proportionalNotationDuration = "#(ly:make-moment 1 24)"

CHANGED:

    >>> abjad.override(voice).note_head.color = abjad.SchemeColor("red")

    >>> abjad.override(voice).NoteHead.color = "#red"

CHANGED:

    >>> abjad.override(voice).note_head.style = abjad.SchemeSymbol("harmonic")

    >>> abjad.override(voice).NoteHead.style = "#'harmonic"

CHANGED:

    >>> spacing_vector = abjad.SpacingVector(0, 10, 10, 0)
    >>> abjad.override(score).staff_grouper.staff_staff_spacing = spacing_vector

    >>> string = "#'((basic-distance . 10) (minimum-distance . 10))
    >>> abjad.override(score).StaffGrouper.staff_staff_spacing = string

CHANGED:

    >>> string = "tuplet-number::calc-denominator-text"
    >>> abjad.override(score).tuplet_number.text = string

    >>> string = "#tuplet-number::calc-denominator-text"
    >>> abjad.override(score).TupletNumber.text = string

Fixed in Abjad 3.3

#1319. Taught the auxilliary note in pitched trills to transpose (Tsz Kiu Pang).

#1309. Taught abjad.Meter.rewrite_meter() more about handling grace notes (Tsz Kiu Pang).

#1129. Taught tweaked note heads to copy correctly (Tsz Kiu Pang).

#1174. Taught abjad.Selection.group_by_measure() to respect pick-measures created at the beginning
of a score with abjad.TimeSignature.partial (Tsz Kiu Pang).

v3.2

19 Jan 21:30
v3.2
Compare
Choose a tag to compare

Abjad 3.2

Changes to Abjad 3.2 (2021-01-19) since Abjad 3.1 (2019-12-19).


#1244. Taught tuplets to preserve input ratios without reducing terms of fraction:

NEW. Taught abjad.Tuplet to preserve tuplet ratio without reducing:

    >>> tuplet = abjad.Tuplet("6:4", "c'4 d' e'")
    >>> abjad.f(tuplet)
    \times 4/6 {
        c'4
        d'4
        e'4
    }

    >>> tuplet = abjad.Tuplet((4, 6), "c'4 d' e'")
    >>> abjad.f(tuplet)
    \times 4/6 {
        c'4
        d'4
        e'4
    }
NEW. Taught Abjad about LilyPond \tuplet command:

    >>> voice = abjad.Voice(r"\tuplet 6/4 { c'4 d' e' }")
    >>> string = abjad.lilypond(voice)
    >>> print(string)
    \new Voice
    {
        \times 4/6 {
            c'4
            d'4
            e'4
        }
    }
Tuplet multiplier now returns a nonreduced fraction:

    OLD: abjad.Tuplet.multiplier returns abjad.Multiplier
    NEW: abjad.Tuplet.multiplier returns abjad.NonreducedFraction
Tuplet interpreter representation now shows colon string:

    OLD:

        >>> abjad.Tuplet("6:4", "c'4 d' e'")
        Tuplet(Multiplier(4, 6), "c'4 d'4 e'4")

    NEW:

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

#1231. Changed abjad.mathtools to abjad.math:

OLD:

    abjad.mathtools.all_are_equal()
    abjad.mathtools.all_are_integer_equivalent()
    abjad.mathtools.all_are_integer_equivalent_numbers()
    abjad.mathtools.all_are_nonnegative_integer_equivalent_numbers()
    abjad.mathtools.all_are_nonnegative_integer_powers_of_two()
    abjad.mathtools.all_are_nonnegative_integers()
    abjad.mathtools.all_are_pairs_of_types()
    abjad.mathtools.all_are_positive_integers()
    abjad.mathtools.are_relatively_prime()
    abjad.mathtools.arithmetic_mean()
    abjad.mathtools.binomial_coefficient()
    abjad.mathtools.cumulative_products()
    abjad.mathtools.cumulative_sums()
    abjad.mathtools.difference_series()
    abjad.mathtools.divisors()
    abjad.mathtools.factors()
    abjad.mathtools.fraction_to_proper_fraction()
    abjad.mathtools.greatest_common_divisor()
    abjad.mathtools.greatest_power_of_two_less_equal()
    abjad.mathtools.integer_equivalent_number_to_integer()
    abjad.mathtools.integer_to_base_k_tuple()
    abjad.mathtools.integer_to_binary_string()
    abjad.mathtools.is_assignable_integer()
    abjad.mathtools.is_integer_equivalent()
    abjad.mathtools.is_integer_equivalent_n_tuple()
    abjad.mathtools.is_integer_equivalent_number()
    abjad.mathtools.is_nonnegative_integer()
    abjad.mathtools.is_nonnegative_integer_equivalent_number()
    abjad.mathtools.is_nonnegative_integer_power_of_two()
    abjad.mathtools.is_positive_integer()
    abjad.mathtools.is_positive_integer_equivalent_number()
    abjad.mathtools.is_positive_integer_power_of_two()
    abjad.mathtools.least_common_multiple()
    abjad.mathtools._least_common_multiple_helper()
    abjad.mathtools.partition_integer_into_canonic_parts()
    abjad.mathtools.sign()
    abjad.mathtools.weight()
    abjad.mathtools.yield_all_compositions_of_integer()

NEW:

    abjad.math.all_are_equal()
    abjad.math.all_are_integer_equivalent()
    abjad.math.all_are_integer_equivalent_numbers()
    abjad.math.all_are_nonnegative_integer_equivalent_numbers()
    abjad.math.all_are_nonnegative_integer_powers_of_two()
    abjad.math.all_are_nonnegative_integers()
    abjad.math.all_are_pairs_of_types()
    abjad.math.all_are_positive_integers()
    abjad.math.are_relatively_prime()
    abjad.math.arithmetic_mean()
    abjad.math.binomial_coefficient()
    abjad.math.cumulative_products()
    abjad.math.cumulative_sums()
    abjad.math.difference_series()
    abjad.math.divisors()
    abjad.math.factors()
    abjad.math.fraction_to_proper_fraction()
    abjad.math.greatest_common_divisor()
    abjad.math.greatest_power_of_two_less_equal()
    abjad.math.integer_equivalent_number_to_integer()
    abjad.math.integer_to_base_k_tuple()
    abjad.math.integer_to_binary_string()
    abjad.math.is_assignable_integer()
    abjad.math.is_integer_equivalent()
    abjad.math.is_integer_equivalent_n_tuple()
    abjad.math.is_integer_equivalent_number()
    abjad.math.is_nonnegative_integer()
    abjad.math.is_nonnegative_integer_equivalent_number()
    abjad.math.is_nonnegative_integer_power_of_two()
    abjad.math.is_positive_integer()
    abjad.math.is_positive_integer_equivalent_number()
    abjad.math.is_positive_integer_power_of_two()
    abjad.math.least_common_multiple()
    abjad.math._least_common_multiple_helper()
    abjad.math.partition_integer_into_canonic_parts()
    abjad.math.sign()
    abjad.math.weight()
    abjad.math.yield_all_compositions_of_integer()

#1214. Changed abjad.mutate() constructor to abjad.mutate module:

OLD:

    abjad.mutate(argument).copy()
    abjad.mutate(argument).eject_contents()
    abjad.mutate(argument).extract()
    abjad.mutate(argument).fuse()
    abjad.mutate(argument).logical_tie_to_tuplet()
    abjad.mutate(argument).replace()
    abjad.mutate(argument).scale()
    abjad.mutate(argument).swap()
    abjad.mutate(argument).transpose()
    abjad.mutate(argument).wrap()

NEW:

    abjad.mutate.copy(argument)
    abjad.mutate.eject_contents(argument)
    abjad.mutate.extract(argument)
    abjad.mutate.fuse(argument)
    abjad.mutate.logical_tie_to_tuplet(argument)
    abjad.mutate.replace(argument)
    abjad.mutate.scale(argument)
    abjad.mutate.swap(argument)
    abjad.mutate.transpose(argument)
    abjad.mutate.wrap(argument)

#1213. Changed abjad.IOManager class to abjad.io module:

OLD:

    abjad.IOManager.compare_files()
    abjad.IOManager.execute_file()
    abjad.IOManager.execute_string()
    abjad.IOManager.find_executable()
    abjad.IOManager.make_subprocess()
    abjad.IOManager.open_file()
    abjad.IOManager.open_last_log()
    abjad.IOManager.profile()
    abjad.IOManager.run_command()
    abjad.IOManager.run_lilypond()
    abjad.IOManager.spawn_subprocess()

NEW:

    abjad.io.compare_files()
    abjad.io.execute_file()
    abjad.io.execute_string()
    abjad.io.find_executable()
    abjad.io.make_subprocess()
    abjad.io.open_file()
    abjad.io.open_last_log()
    abjad.io.profile()
    abjad.io.run_command()
    abjad.io.run_lilypond()
    abjad.io.spawn_subprocess()

#1212. Changed abjad.persist() constructor to abjad.persist module:

OLD:

    abjad.persist(argument).as_ly()
    abjad.persist(argument).as_midi()
    abjad.persist(argument).as_pdf()
    abjad.persist(argument).as_png()

NEW:

    abjad.persist.as_ly(argument)
    abjad.persist.as_midi(argument)
    abjad.persist.as_pdf(argument)
    abjad.persist.as_png(argument)

You must now pass an explicit path to the following:

abjad.persist.as_ly(argument)
abjad.persist.as_midi(argument)
abjad.persist.as_pdf(argument)
abjad.persist.as_png(argument)

#1196. Changed abjad.inspect() constructor to abjad.get module:

OLD:

    abjad.inspect(argument)after_grace_container()
    abjad.inspect(argument)annotation()
    abjad.inspect(argument)annotation_wrappers()
    abjad.inspect(argument)bar_line_crossing()
    abjad.inspect(argument)before_grace_container()
    abjad.inspect(argument)contents()
    abjad.inspect(argument)descendants()
    abjad.inspect(argument)duration()
    abjad.inspect(argument)effective()
    abjad.inspect(argument)effective_staff()
    abjad.inspect(argument)effective_wrapper()
    abjad.inspect(argument)grace()
    abjad.inspect(argument)has_effective_indicator()
    abjad.inspect(argument)has_indicator()
    abjad.inspect(argument)indicator()
    abjad.inspect(argument)indicators()
    abjad.inspect(argument)leaf()
    abjad.inspect(argument)lineage()
    abjad.inspect(argument)logical_tie()
    abjad.inspect(argument)markup()
    abjad.inspect(argument)measure_number()
    abjad.inspect(argument)parentage()
    abjad.inspect(argument)pitches()
    abjad.inspect(argument)report_modifications()
    abjad.inspect(argument)sounding_pitch()
    abjad.inspect(argument)sounding_pitches()
    abjad.inspect(argument)sustained()
    abjad.inspect(argument)timespan()

NEW:

    abjad.get.after_grace_container(argument)
    abjad.get.annotation(argument)
    abjad.get.annotation_wrappers(argument)
    abjad.get.bar_line_crossing(argument)
    abjad.get.before_grace_container(argument)
    abjad.get.contents(argument)
    abjad.get.descendants(argument)
    abjad.get.duration(argument)
    abjad.get.effective(argument)
    abjad.get.effective_staff(argument)
    abjad.get.effective_wrapper(argument)
    abjad.get.grace(argument)
    abjad.get.has_effective_indicator(argument)
    abjad.get.has_indicator(argument)
    abjad.get.indicator(argument)
    abjad.get.indicators(argument)
    abjad.get.leaf(argument)
    abjad.get.lineage(argument)
    abjad.get.logical_tie(argument)
    abjad.get.markup(argument)
    abjad.get.measure_number(argument)
    abjad.get.parentage(argument)
    abjad.get.pitches(argument)
    abjad.get.report_modifications(argument)
    abjad.get.sounding_pitch(argument)
    abjad.get.sounding_pitches(argument)
    abjad.get.sustained(argument)
    abjad.get.timespan(argument)

#1191. Removed abjad.Infinity, abjad.NegativeInfinity "singletons." Previously abjad.Infinity was an instance of the abjad.mathtools.Infinity class. This was confusing. Because abjad.Infinity looked like a class but wasn't:

OLD:

    foo is abjad.Infinity
    foo is not abjad.Infinity

NEW:

    foo == abjad.Infinity()
    foo != abjad.Infinity()

Moved four fancy iteration functions to t...

Read more

Abjad 3.1

18 Dec 21:55
315a137
Compare
Choose a tag to compare

ABJAD 3.1 RELEASE NOTES

Abjad 3.1 includes a large number of new features and three important changes.

Changes:

  • Respelled abjad.Container.is_simultaneous as abjad.Container.simultaneous
  • Removed abjad.Measure
  • Replaced old spanner classes with new factory functions

Select new features:

  • Annotated iteration
  • Attribute testing
  • Literal markup
  • Selector concatenation
  • Selector inclusion / exclusion
  • Tagged component, indicator, tweak output
  • Timespan expressions

Details appear below.

CHANGES

1. RESPELLED ABJAD.CONTAINER.IS_SIMULTANEOUS AS ABJAD.CONTAINER.SIMULTANEOUS

OLD: Container.is_simultaneous
NEW: Container.simultaneous

Example:

>>> voice_1 = abjad.Voice(r"a''4 \flageolet ( df'''16 )")
>>> literal = abjad.LilyPondLiteral(r"\voiceOne", "opening")
>>> abjad.attach(literal, voice_1[0])
>>> voice_2 = abjad.Voice(r"<a' a''>4 \flageolet ( <bf' f''>16 )")
>>> literal = abjad.LilyPondLiteral(r"\voiceTwo", "opening")
>>> abjad.attach(literal, voice_2[0])
>>> container = abjad.Container([voice_1, voice_2], simultaneous=True)
>>> staff = abjad.Staff("r2 r8.")
>>> staff.insert(1, container)
>>> markup = abjad.Markup("div. in 3", direction=abjad.Up)
>>> abjad.attach(markup, staff[0])
>>> abjad.override(staff[0]).text_script.self_alignment_X = -0.25
>>> abjad.override(staff[0]).text_script.staff_padding = 2
>>> abjad.show(staff)

container-simultaneous

Users should change is_simultaneous to simultaneous everywhere in existing scores. Closes #1103.

2. REMOVED ABJAD.MEASURE

LilyPond does not model measures explicitly. This is now true in Abjad 3.1, too. Attach abjad.TimeSignature indicators wherever you would call the LilyPond \time command.

Recall that in Abjad you can iterate notes, rests and chords grouped together by the measure that contains them:

>>> time_signature = abjad.TimeSignature((9, 8))
>>> staff = abjad.Staff("f''4. gf'' f'' gf'' f'' c''' c''' a'' fs''")
>>> first_leaf = staff[0]
>>> abjad.attach(time_signature, first_leaf)
>>> abjad.show(staff)

staff

>>> for group in groups:
...     print(group)
Selection([Note("f''4."), Note("gf''4."), Note("f''4.")])
Selection([Note("gf''4."), Note("f''4."), Note("c'''4.")])
Selection([Note("c'''4."), Note("a''4."), Note("fs''4.")])
>>> last_group = groups[-1]
>>> for note in last_group:
...     abjad.attach(abjad.Marcato(), note)
...
>>> abjad.show(staff)

last-measure-articulations

Also:

  • Removed abjad.Measure
  • Removed abjad.MeasureMaker
  • Removed abjad.Mutation.replace_measure_contents()

3. REPLACED SPANNERS WITH FACTORY FUNCTIONS

LilyPond models beams, hairpins, slurs and other spanners with matching start- and stop-commands. This is now true in Abjad 3.1, too. The spanners.py module implements 12 factory functions to help you work with spanners. These new factory functions are implemented in terms of matching pairs of start and stop indicators: abjad.text_spanner() works by attaching instances of the new abjad.StartTextSpan and abjad.StopTextSpan indicators (which format as LilyPond \startTextSpan and \stopTextSpan). Closes #1033:

  • abjad.beam()
  • abjad.bow_contact_spanner()
  • abjad.glissando()
  • abjad.hairpin()
  • abjad.horizontal_bracket()
  • abjad.ottava()
  • abjad.phrasing_slur()
  • abjad.piano_pedal()
  • abjad.slur()
  • abjad.text_spanner()
  • abjad.tie()
  • abjad.trill_spanner()

CHANGED:

OLD: abjad.BowContactSpanner
NEW: abjad.bow_contact_spanner()

OLD: abjad.Glissando
NEW: abjad.glissando()

OLD: abjad.HorizontalBracket
NEW: abjad.horizontal_bracket()

OLD: abjad.OctavationSpanner
NEW: abjad.ottava()

OLD: abjad.PianoPedalSpanner
NEW: abjad.piano_pedal()

OLD: abjad.TrillSpanner
NEW: abjad.trill_spanner()

OLD: abjad.HairpinIndicator
NEW: abjad.StartHairpin

Also:

  • Added abjad.glissando(..., hide_stem_selector=None) keyword
  • Added abjad.glissando(..., left_broken=None) keyword
  • Added abjad.glissando(..., right_broken_show_next=None) keyword
  • Added abjad.glissando(..., hide_middle_stems=None) keyword
  • Removed abjad.mutate().splice()
  • Removed fracture_spanners=None keyword in all functions

NEW FUNCTIONALITY

1. ANNOTATED ITERATION

Abjad 3.1 allows you to exclude annotated leaves from iteration.

Excludes leaves with "RED" or "BLUE" annotations:

>>> staff = abjad.Staff()
>>> staff.extend("<c' bf'>8 <g' a'>8")
>>> staff.extend("af'8 r8")
>>> staff.extend("r8 gf'8")
>>> abjad.attach(abjad.TimeSignature((2, 8)), staff[0])
>>> abjad.annotate(staff[0], "RED", True)
>>> abjad.annotate(staff[1], "BLUE", True)
>>> abjad.annotate(staff[2], "GREEN", True)
>>> abjad.annotate(staff[3], "RED", True)
>>> abjad.annotate(staff[4], "BLUE", True)
>>> abjad.annotate(staff[5], "GREEN", True)
>>> abjad.show(staff)

annotated-exclusions

>>> for leaf in abjad.iterate(staff).leaves(
...     exclude=["RED", "BLUE"],
...     ):
...     leaf
...
Note("af'8")
Note("gf'8")

2. ARTICULATIONS

Abjad 3.1 cleans up the direction-handling of four indicators. Closes #1064:

  • abjad.Dynamic.direction
  • abjad.Staccato.direction
  • abjad.RepeatTie.direction
  • abjad.Staccatissimo.direction

Without direction:

>>> staff = abjad.Staff("g' a' b' c''")
>>> for note in staff:
...     staccato = abjad.Staccato()
...     abjad.attach(staccato, note)
...
>>> abjad.show(staff)

staccato-without-direction

Forced up:

>>> staff = abjad.Staff("g' a' b' c''")
>>> for note in staff:
...     staccato = abjad.Staccato(direction=abjad.Up)
...     abjad.attach(staccato, note)
...
>>> abjad.show(staff)

staccato-forced-up

Forced down:

>>> staff = abjad.Staff("g' a' b' c''")
>>> for note in staff:
...     staccato = abjad.Staccato(direction=abjad.Down)
...     abjad.attach(staccato, note)
...
>>> abjad.show(staff)

staccato-forced-down

Abjad 3.1 adds support for the LilyPond halfopen and snappizzicato articulation types.

Abjad 3.1 cleans up woodwind diagrams. Closes #1061

3. ATTRIBUTE TESTING

Abjad 3.1 adds support for attribute testing with the new attributes=None keyword:

  • abjad.inspect().effective(..., attributes=None)
  • abjad.inspect().effective_wrapper(..., attributes=None)
  • abjad.inspect().has_effective_indicator(..., attributes=None)
  • abjad.inspect().has_indicator(..., attributes=None)
  • abjad.inspect().indicator(..., attributes=None)
  • abjad.inspect().indicators(..., attributes=None)
  • abjad.inspect().wrapper(..., attributes=None)
  • abjad.inspect().wrappers(..., attributes=None)

Example:

>>> voice = abjad.Voice("c'4 d' e' f'")
>>> start_text_span = abjad.StartTextSpan()
>>> abjad.attach(start_text_span, voice[0])
>>> stop_text_span = abjad.StopTextSpan()
>>> abjad.attach(stop_text_span, voice[2])
>>> abjad.f(voice)
\new Voice
{
    c'4
    \startTextSpan
    d'4
    e'4
    \stopTextSpan
    f'4
}
>>> for note in voice:
...     note, abjad.inspect(note).effective(abjad.StartTextSpan)
...
(Note("c'4"), StartTextSpan(command='\\startTextSpan', concat_hspace_left=0.5))
(Note("d'4"), StartTextSpan(command='\\startTextSpan', concat_hspace_left=0.5))
(Note("e'4"), StartTextSpan(command='\\startTextSpan', concat_hspace_left=0.5))
(Note("f'4"), StartTextSpan(command='\\startTextSpan', concat_hspace_left=0.5))
>>> for note in voice:
...     note, abjad.inspect(note).effective(abjad.StopTextSpan)
...
(Note("c'4"), None)
(Note("d'4"), None)
(Note("e'4"), StopTextSpan(command='\\stopTextSpan'))
(Note("f'4"), StopTextSpan(command='\\stopTextSpan'))
>>> attributes = {'parameter': 'TEXT_SPANNER'}
>>> for note in voice:
...     indicator = abjad.inspect(note).effective(
...         object,
...         attributes=attributes,
...         )
...     note, indicator
...
(Note("c'4"), StartTextSpan(command='\\startTextSpan', concat_hspace_left=0.5))
(Note("d'4"), StartTextSpan(command='\\startTextSpan', concat_hspace_left=0.5))
(Note("e'4"), StopTextSpan(command='\\stopTextSpan'))
(Note("f'4"), StopTextSpan(command='\\stopTextSpan'))

4. CLEFS

Abjad 3.1 adds support for LilyPond varC and tenorvarC clef types.

5. DOCS

  • Cleaned up Ligeti example. Closes #896
  • Corrected assignability docs. Closes #897
  • Cleaned up Bartók example. Closes #1059
  • Added support for cropped PNGs. Closes #1066

6. DURATIONS

Duration multipliers are now implemented as an explicit property on notes, rests and chords in Abjad 3.1. Closes #902:

OLD: abjad.attach(abjad.Multiplier((1, 2)), note)
NEW: note.multiplier = (1, 2)

Forbidden duration spelling has changed like this:

OLD: abjad.LeafMaker.forbidden_duration
NEW: abjad.LeafMaker.forbidden_note_duration
NEW: abjad.LeafMaker.forbidde...
Read more

Abjad 3.0.0

29 Jul 04:03
98b8f92
Compare
Choose a tag to compare

NEW CONFIGURATION FUNCTIONALITY:

* Added AbjadConfiguration.composer_scores_directory

* Added composer template data to AbjadConfiguration

* Integrated pathlib into abjad.Configuration

    The four main abjad.Configuration properties now return path objects
    instead of strings:

        * abjad.Configuration.configuration_directory
        * abjad.Configuration.configuration_file_path
        * abjad.Configuration.home_directory
        * abjad.Configuration.temp_directory

* Changed 'directory_path' to just 'directory' in abjad.Configuration

OLD: Configuration.configuration_file_name
NEW: Configuration.file_path

OLD: Configuration.configuration_directory_name
NEW: Configuration.configuration_directory

NEW CONTAINER FUNCTIONALITY:

* Added bracket comments to measure-open, measure-close.

    OLD:

        >>> measure = abjad.Measure((3, 4), "c'4 d' e'")
        >>> abjad.f(measure)
        {
            \time 3/4
            c'4
            d'4
            e'4
        }

    NEW:

        >>> measure = abjad.Measure((3, 4), "c'4 d' e'")
        >>> abjad.f(measure)
        { % measure
            \time 3/4
            c'4
            d'4
            e'4
        } % measure

* Removed Container.reverse(); no longer supported

* Removed Component.name; preserved Container.name

* Taught containers to initialize from collections of strings:

    staff = abjad.Staff([
        r"\times 9/10 { r8 c'16 c'16 bf'4 ~ bf'16 r16 }",
        r"\times 9/10 { bf'16 e''16 e''4 ~ e''16 r16 fs''16 af''16 }",
        r"\times 4/5 { a'16 r4 }",
        ])

    abjad.f(staff)
    \new Staff {
        {
            \tweak text #tuplet-number::calc-fraction-text
            \times 9/10 {
                r8
                c'16
                c'16
                bf'4 ~
                bf'16
                r16
            }
        }
        {
            \tweak text #tuplet-number::calc-fraction-text
            \times 9/10 {
                bf'16
                e''16
                e''4 ~
                e''16
                r16
                fs''16
                af''16
            }
        }
        {
            \times 4/5 {
                a'16
                r4
            }
        }
    }

* Taught simultaneous containers to accept vanilla containers
  (in addition to contexts)

OLD: abjad.Container.music
NEW: abjad.Container.components

NEW CONTEXT FUNCTIONALITY:

OLD: abjad.Context.context_name
NEW: abjad.Context.lilypond_type

    * Closes #895

NEW DATA STRUCTURE FUNCTIONALITY:

* Removed abjad.ClefList; use list instead
* Removed abjad.PerformerList; use list instead
* Removed abjad.PitchRangeList; use list instead

* Removed abjad.InstrumentDictionary; use abjad.OrderedDict instead
* Removed abjad.MetronomeMarkDictionary; use abjad.OrderedDict instead

OLD: abjad.TypedOrderedDict
NEW: abjad.OrderedDict

    * Closes #909

NEW FORMAT FUNCTIONALITY:

* Added abjad.Container.identifier property. Use to set parse handles on any
  Abjad container:

    >>> container = abjad.Container("c'4 d' e' f'")
    >>> container.identifier = '%*% AB'

    >>> abjad.f(container)
    {   %*% AB
        c'4
        d'4
        e'4
        f'4
    }   %*% AB

* Changed context open-statement formatting to strictly one-per-line:

    OLD:

        \new Score \with {
            \override BarLine.stencil = ##f
            \override BarNumber.transparent = ##t
            \override SpanBar.stencil = ##f
            \override TimeSignature.stencil = ##f
        } <<
            \new PianoStaff <<
                \context Staff = "Treble Staff" {
                    \clef "treble"
                    r16
                    r16
                    r16
                    r16
                    r16
                    c'16
                    d'16
                    e'16
                    f'16
                    g'16
                }
                \context Staff = "Bass Staff" {
                    \clef "bass"
                    c16
                    d16
                    e16
                    f16
                    g16
                    r16
                    r16
                    r16
                    r16
                    r16
                }
            >>
        >>

    NEW:

        \new Score
        \with
        {
            \override BarLine.stencil = ##f
            \override BarNumber.transparent = ##t
            \override SpanBar.stencil = ##f
            \override TimeSignature.stencil = ##f
        }
        <<
            \new PianoStaff
            <<
                \context Staff = "Treble Staff"
                {
                    \clef "treble"
                    r16
                    r16
                    r16
                    r16
                    r16
                    c'16
                    d'16
                    e'16
                    f'16
                    g'16
                }
                \context Staff = "Bass Staff"
                {
                    \clef "bass"
                    c16
                    d16
                    e16
                    f16
                    g16
                    r16
                    r16
                    r16
                    r16
                    r16
                }
            >>
        >>

    MODEL. Note that this makes lexical postprocessing incredibly easy. Any chunk
    of anything can be parsed out of Abjad's LilyPond output as a sequence of
    consecutive lines. Target application might be anything from assignment to
    variables (for externalization in complex scores) or tagging parts of LilyPond
    files on and off.

* Removed 'right' format slot

NEW INDICATOR FUNCTIONALITY:

* Added abjad.hairpin() factory function:

    With three-part string descriptor:

        >>> staff = abjad.Staff("c'4 d' e' f'")
        >>> abjad.hairpin('p < f', staff[:])
        >>> abjad.override(staff[0]).dynamic_line_spanner.staff_padding = 4

        >>> abjad.f(staff)
        \new Staff
        {
            \once \override DynamicLineSpanner.staff-padding = #4
            c'4
            \p
            \<
            d'4
            e'4
            f'4
            \f
        }

    With dynamic objects:

        >>> staff = abjad.Staff("c'4 d' e' f'")
        >>> start = abjad.Dynamic('niente', command=r'\!')
        >>> trend = abjad.DynamicTrend('o<')
        >>> abjad.tweak(trend).color = 'blue'
        >>> stop = abjad.Dynamic('"f"')
        >>> abjad.hairpin([start, trend, stop], staff[:])
        >>> abjad.override(staff[0]).dynamic_line_spanner.staff_padding = 4

        >>> abjad.f(staff)
        \new Staff
        {
            \once \override DynamicLineSpanner.staff-padding = #4
            c'4
            \!
            - \tweak color #blue
            - \tweak circled-tip ##t
            - \tweak stencil #abjad-flared-hairpin
            \<
            d'4
            e'4
            f'4
            _ #(make-dynamic-script
                (markup
                    #:whiteout
                    #:line (
                        #:general-align Y -2 #:normal-text #:larger "“"
                        #:hspace -0.4
                        #:dynamic "f"
                        #:hspace -0.2
                        #:general-align Y -2 #:normal-text #:larger "”"
                        )
                    )
                )
        }

    * Closes #991

    * Added abjad.HairpinStart:

        >>> staff = abjad.Staff("c'4 d' e' f' c' d' e' r4")
        >>> abjad.attach(abjad.Dynamic('p'), staff[0])
        >>> abjad.attach(abjad.HairpinStart('<|'), staff[0])
        >>> abjad.attach(abjad.Dynamic('f'), staff[3])
        >>> abjad.attach(abjad.Dynamic('f'), staff[4])
        >>> abjad.attach(abjad.HairpinStart('|>o'), staff[4])
        >>> abjad.attach(abjad.Dynamic('niente', command=r'\!'), staff[-1])
        >>> abjad.override(staff).dynamic_line_spanner.staff_padding = 4.5

        >>> abjad.f(staff)
        \new Staff
        \with
        {
            \override DynamicLineSpanner.staff-padding = #4.5
        }
        {
            c'4
            \p
            - \tweak stencil #abjad-flared-hairpin
            \<
            d'4
            e'4
            f'4
            \f
            c'4
            \f
            - \tweak circled-tip ##t
            - \tweak stencil #abjad-flared-hairpin
            \>
            d'4
            e'4
            r4
            \!
        }

    * Added abjad-flared-hairpin to docs/source/_stylesheets/default.ily

* Added abjad.text_spanner...
Read more