Release notification: Abjad 3.1

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Release notification: Abjad 3.1

Trevor Bača-2
Dear friends,

Abjad 3.1 is now available:


Please note that the old www.projectabjad.org URL has been retired in favor of GitHub doc hosting, as shown above.

There are hundreds of new features in this release; highlights follow below.

Here's to happy composing and to time with friends and family over the holiday season.

We hope you enjoy,

Trevor Bača
* mail: [hidden email]
* home: http://www.trevorbaca.com/

Josiah Wolf Oberholtzer
* mail: [hidden email]
* home: http://josiahwolfoberholtzer.com

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.forbidden_rest_duration

Monotonicity spelling has changed like this:

OLD: abjad.LeafMaker.decrease_monotonic=True
OLD: abjad.Meter.decrease_monotonic=True
OLD: abjad.NoteMaker.decrease_monotonic=True
OLD: abajd.Tuplet.from_duration_and_ratio(..., decrease_monotonic=True)

NEW: abjad.LeafMaker.increase_monotonic=None
NEW: abjad.Meter.increase_monotonic=None
NEW: abjad.NoteMaker.increase_monotonic=None
NEW: abajd.Tuplet.from_duration_and_ratio(..., increase_monotonic=None)

A new abjad.Duration.from_clock_string() constructor is available:

>>> abjad.Duration.from_clock_string("1'59''")
Duration(119, 1)

Durations may now be labeled in seconds:

>>> abjad.label().with_durations(..., in_seconds=None)

The interpreter representation of abjad.Offset has been changed to display grace offsets.

7. GRACE MUSIC

Abjad 3.1 improves the ways grace notes are created, inspected and iterated. The old abjad.GraceContainer class has been renamed abjad.BeforeGraceContainer; the old abjad.AcciaccaturaContainer and abjad.AppoggiaturaContainer classes have been removed; an entirely new abjad.OnBeatGraceContainer class has been added to model Ferneyhough-style on-beat runs of appoggiaturas.

The resulting collection of classes exhibits a 3-way symmetry:

  • abjad.BeforeGraceContainer
  • abjad.OnBeatGraceContainer
  • abjad.AfterGraceContainer

This series of commits closes #1032, #1076, #1104, #1105, #1107, #1120, #1121.

The new on-beat grace container works like this:

>>> music_voice = abjad.Voice("c'4 d' e' f'", name="Music_Voice")
>>> string = "g'8 a' b' c'' d'' c'' b' a' b' c'' d''"
>>> result = abjad.on_beat_grace_container(
...     string, music_voice[1:3], leaf_duration=(1, 30), do_not_slash=True
... )
>>> staff = abjad.Staff([music_voice])
>>> abjad.show(staff)

on-beat-grace-container

All three grace containers work together like this:

>>> music_voice = abjad.Voice("c'4 d' e' f'", name="Music_Voice")
>>> container = abjad.BeforeGraceContainer("cs'16")
>>> abjad.attach(container, music_voice[1])
>>> container = abjad.on_beat_grace_container(
...     "g'16 gs' a' as'", music_voice[2:3], do_not_slash=True,
... )
>>> abjad.attach(abjad.Articulation(">"), container[0])
>>> container = abjad.AfterGraceContainer("fs'16")
>>> abjad.attach(container, music_voice[3])
>>> staff = abjad.Staff([music_voice])
>>> abjad.show(staff)

grace-containers

Refer to this figure for the examples below.

Grace iteration is now controlled by a ternary flag. Set grace=None to iterate grace and nongrace components together:

>>> for component in abjad.iterate(staff).components():
...     component
Staff("c'4 d'4 e'4 f'4")
Note("c'4")
BeforeGraceContainer("cs'16")
Note("cs'16")
Note("d'4")
OnBeatGraceContainer("<g' \\tweak Accidental.stencil ##f e'>16 * 1 gs'16 * 1 a'16 * 1 as'16 * 1")
Note("<g' \\tweak Accidental.stencil ##f e'>16 * 1")
Note("gs'16 * 1")
Note("a'16 * 1")
Note("as'16 * 1")
Note("e'4")
Note("f'4")
AfterGraceContainer("fs'16")
Note("fs'16")

Set grace=True to iterate only grace components:

>>> for component in abjad.iterate(staff).components(grace=True):
...     component
BeforeGraceContainer("cs'16")
Note("cs'16")
OnBeatGraceContainer("<g' \\tweak Accidental.stencil ##f e'>16 * 1 gs'16 * 1 a'16 * 1 as'16 * 1")
Note("<g' \\tweak Accidental.stencil ##f e'>16 * 1")
Note("gs'16 * 1")
Note("a'16 * 1")
Note("as'16 * 1")
AfterGraceContainer("fs'16")
Note("fs'16")

Set grace=False to iterate only nongrace components:

>>> for component in abjad.iterate(staff).components(grace=False):
...     component
Staff("c'4 d'4 e'4 f'4")
Note("c'4")
Note("d'4")
Note("e'4")
Note("f'4")

Use abjad.inspect().leaf() to inspect grace notes immediately before or after any note, rest or chord:

>>> for current_leaf in abjad.select(staff).leaves():
...     previous_leaf = abjad.inspect(current_leaf).leaf(-1)
...     next_leaf = abjad.inspect(current_leaf).leaf(1)
...     print(f"previous leaf: {repr(previous_leaf)}")
...     print(f"current leaf:  {repr(current_leaf)}")
...     print(f"next leaf:     {repr(next_leaf)}")
...     print("---")
previous leaf: None
current leaf:  Note("c'4")
next leaf:     Note("cs'16")
---
previous leaf: Note("c'4")
current leaf:  Note("cs'16")
next leaf:     Note("d'4")
---
previous leaf: Note("cs'16")
current leaf:  Note("d'4")
next leaf:     Chord("<e' g'>16")
---
previous leaf: Note("d'4")
current leaf:  Chord("<e' g'>16")
next leaf:     Note("gs'16")
---
previous leaf: Chord("<e' g'>16")
current leaf:  Note("gs'16")
next leaf:     Note("a'16")
---
previous leaf: Note("gs'16")
current leaf:  Note("a'16")
next leaf:     Note("as'16")
---
previous leaf: Note("a'16")
current leaf:  Note("as'16")
next leaf:     Note("e'4")
---
previous leaf: Note("as'16")
current leaf:  Note("e'4")
next leaf:     Note("f'4")
---
previous leaf: Note("e'4")
current leaf:  Note("f'4")
next leaf:     Note("fs'16")
---
previous leaf: Note("f'4")
current leaf:  Note("fs'16")
next leaf:     None
---

Grace note timespans work like this:

>>> for component in abjad.select(voice).components():
...     timespan = abjad.inspect(component).timespan()
...     print(f"{repr(component):30} {repr(timespan)}")
<Staff{1}>                     Timespan(Offset((0, 1)), Offset((1, 1)))
<Voice-"Music_Voice"{4}>       Timespan(Offset((0, 1)), Offset((1, 1)))
Note("c'4")                    Timespan(Offset((0, 1)), Offset((1, 4)))
BeforeGraceContainer("cs'16")  Timespan(Offset((1, 4), displacement=Duration(-1, 16)), Offset((1, 4)))
Note("cs'16")                  Timespan(Offset((1, 4), displacement=Duration(-1, 16)), Offset((1, 4)))
Note("d'4")                    Timespan(Offset((1, 4)), Offset((1, 2)))
<<<2>>>                        Timespan(Offset((1, 2)), Offset((3, 4)))
OnBeatGraceContainer("<e' g'>16 gs'16 a'16 as'16") Timespan(Offset((1, 2)), Offset((1, 2), displacement=Duration(1, 4)))
Chord("<e' g'>16")             Timespan(Offset((1, 2)), Offset((1, 2), displacement=Duration(1, 16)))
Note("gs'16")                  Timespan(Offset((1, 2), displacement=Duration(1, 16)), Offset((1, 2), displacement=Duration(1, 8)))
Note("a'16")                   Timespan(Offset((1, 2), displacement=Duration(1, 8)), Offset((1, 2), displacement=Duration(3, 16)))
Note("as'16")                  Timespan(Offset((1, 2), displacement=Duration(3, 16)), Offset((1, 2), displacement=Duration(1, 4)))
Voice("e'4", name='Music_Voice') Timespan(Offset((1, 2)), Offset((3, 4)))
Note("e'4")                    Timespan(Offset((1, 2), displacement=Duration(1, 4)), Offset((3, 4)))
Note("f'4")                    Timespan(Offset((3, 4)), Offset((1, 1)))
AfterGraceContainer("fs'16")   Timespan(Offset((1, 1), displacement=Duration(-1, 16)), Offset((1, 1)))
Note("fs'16")                  Timespan(Offset((1, 1), displacement=Duration(-1, 16)), Offset((1, 1)))

Grace notes may now be slurred:

>>> voice = abjad.Voice("c'4 d'4 e'4 f'4")
>>> container = abjad.BeforeGraceContainer("cs'16")
>>> abjad.attach(container, voice[1])
>>> leaves = abjad.select(voice).leaves()
>>> abjad.slur(leaves[1:3])
>>> abjad.show(voice)

grace-note-slur

CHANGED:

OLD: abjad.GraceContainer
NEW: abjad.BeforeGraceContainer

OLD: abjad.inspect().grace_container()
NEW: abjad.inspect().before_grace_container()

OLD: abjad.select().components(grace_notes=True)
NEW: abjad.select().components(grace=True)

OLD: abjad.select().leaves(grace_notes=True)
NEW: abjad.select().leaves(grace=True)

OLD: abjad.inspect().grace_note()
NEW: abjad.inspect().grace()

Also:

  • Fixed abjad.AfterGraceContainer chords. Closes #1074
  • Fixed score-initial grace note measure numbers. Closes #1098
  • Removed do_not_iterate_grace_containers=None keyword
  • Removed abjad.inspect().parentage(grace=None) keyword

8. INSPECTION

  • Removed abjad.inspect().vertical_moment()
  • Removed abjad.inspect().vertical_moment_at()
  • Preserved abjad.iterate().vertical_moments()
  • Removed abjad.inspect().contents(..., include_self=True)
  • Removed abjad.inspect().descendants(..., include_self=True)
  • Removed abjad.inspect().parentage(..., include_self=True)
  • Restricted abjad.inspect().leaf(n) such that n in (-1, 0, 1)

9. IO

  • Added abjad.IOManager.run_lilypond(..., liypond_log_file_path=None) keyword
  • Added abjad.Path.remove_lilypond_warnings()
  • Cleaned up abjad.IOManager Unicode decode handling
  • Removed abjad.ImportManager
  • Set explicit encoding in abjad.IOManager.save_last_ly_as_pdf(). Closes #1090

10. LITERAL MARKUP

Abjad 3.1 adds support for literal markup. Markup with pound signs, double quotes are now possible for the first time with the literal=True keyword. Closes #397:

>>> markup = abjad.Markup(
... r'\markup \with-color #red { \note #"4" #1 }',
... direction=abjad.Up,
... literal=True,
... )
>>> note = abjad.Note("cs'4")
>>> abjad.attach(markup, note)
>>> abjad.show(note)

literal-markup

Fixed tweaked markup bug. Closes #806

11. MATHTOOLS

Abjad 3.1 mathtools functions are now housed in a consolidated mathtools.py file. Closes #1084.

12. MUTATION

  • Fixed now-power-of-two abjad.mutate().split() bug. Closes #1018
  • Removed abjad.mutate().split(..., tie_split_notes=True) keyword. Closes #1021, #1092

13. OBJECT TEMPLATING

Abajd 3.1 extends abjad.new() with support for variable-length *arguments. Closes #1085.

14. PARENT INDEXING

Abjad 3.1 adds support for parent indexing with the new n=0 keyword available in abjad.Parentage.get().

Get the first (innermost), second and last (outermost) voices in the parentage of leaf like this:

>>> abjad.inspect(leaf).parentage().get(prototype=abjad.Voice, n=0)
>>> abjad.inspect(leaf).parentage().get(prototype=abjad.Voice, n=1)
>>> abjad.inspect(leaf).parentage().get(prototype=abjad.Voice, n=-1)

CHANGED:

OLD: abjad.inspect().is_wellformed()
NEW: abjad.inspect().wellformed()

OLD: abjad.parentage().logical_voice property
NEW: abjad.parentage().logical_voice() method

OLD: Parentage.score_index property
NEW: Parentage.score_index() method

OLD: Parentage.get_first()
NEW: Parentage.get(..., n=0)

OLD: abjad.Parentage.depth property
NEW: abjad.Parentage.count() method

OLD: abjad.Parentage.tuplet_depth property
NEW: abjad.Parentage.count(prototype=abjad.Tuplet) method

15. PARSER

  • Fixed parser multimeasure rest multipliers. Closes #1049
  • Fixed parser \breathe. Closes #1119

16. SELECTORS

Abjad 3.1 supports the patterned inclusion of components with the new abjad.select().get() selector.

Gets every other note:

>>> staff = abjad.Staff("c'8 d' e' f' g' a' b' c''")
>>> for note in abjad.select(staff).notes().get([0], 2):
...     print(note)
c'8
e'8
g'8
b'8

Gets notes 2 and 5:

>>> staff = abjad.Staff("c'8 d' e' f' g' a' b' c''")
>>> for note in abjad.select(staff).notes().get([2, 5]):
...     print(note)
e'8
a'8

Abjad 3.1 supports the patterned exclusion of components with the new abjad.select().exclude() selector.

Excludes every other note:

>>> staff = abjad.Staff("c'8 d' e' f' g' a' b' c''")
>>> for note in abjad.select(staff).notes().exclude([0], 2):
...     print(note)
d'8
f'8
a'8
c''8

Excludes notes 2 and 5:

>>> staff = abjad.Staff("c'8 d' e' f' g' a' b' c''")
>>> for note in abjad.select(staff).notes().exclude([2, 5]):
...     print(note)
d'8
f'8
a'8
c''8

Abjad 3.1 supports selector concatenation with __add__(). Closes #1029:

>>> staff = abjad.Staff("c'8 r8 d'8 e'8 r8 f'8 g'8 a'8")
>>> left = abjad.select().leaves()[:2]
>>> right = abjad.select().leaves()[-2:]
>>> selector = left + right
>>> selector(staff)
Selection([Note("c'8"), Rest('r8'), Note("g'8"), Note("a'8")])

Also:

  • Added abjad.select().logical_tie()
  • Added abjad.select().runs() grace note support
  • Added abjad.Selection.filter_by_duration(..., preprolated=None) keyword
  • Replaced abjad.inspect().tuplet() with abjad.select().tuplet()

17. SEQUENCE MANIPULATION

Abjad 3.1 adds a new abjad.Sequence.replace() method:

>>> sequence = abjad.sequence([0, 2, 3, 0, 2, 3, 0, 2, 3])
>>> sequence.replace(0, 1)
Sequence([1, 2, 3, 1, 2, 3, 1, 2, 3])

18. TAGS

Abjad 3.1 adds support for tags. Abjad tags are user-defined strings you can add to the Abjad objects you create. Abjad tags appear as LilyPond comments following the special two-character string %!. Use Abjad tags to help debug complex LilyPond output. Set strict=None to an integer-valued column number to align Abjad tags in LilyPond output.

Tag indicators like this:

>>> note = abjad.Note("c'4")
>>> tag = abjad.Tag("this is a tag")
>>> abjad.attach(abjad.Staccato(), note, tag=tag)
>>> abjad.f(note, strict=20)
c'4
\staccato           %! this is a tag

Tag notes like this:

>>> tag = abjad.Tag("NoteMaker")
>>> maker = abjad.NoteMaker(tag=tag)
>>> notes = maker([0], [(1, 16), (1, 8), (1, 8)])
>>> staff = abjad.Staff(notes)
>>> abjad.f(staff, strict=20)
\new Staff
{
    c'16        %! NoteMaker
    c'8         %! NoteMaker
    c'8         %! NoteMaker
}

Tag tuplets like this:

>>> tag = abjad.Tag("Tuplet")
>>> tuplet = abjad.Tuplet((2, 3), "c'4 d' e'", tag=tag)
>>> abjad.f(tuplet, strict=20)
\times 2/3 {        %! Tuplet
    c'4
    d'4
    e'4
}                   %! Tuplet

Tag contexts like this:

>>> tag = abjad.Tag("Voice")
>>> voice = abjad.Voice("c'4 d' e' f'", tag=tag)
>>> tag = abjad.Tag("Staff")
>>> staff = abjad.Staff([voice], tag=tag)
>>> tag = abjad.Tag("Score")
>>> score = abjad.Score([staff], tag=tag)
>>> abjad.f(score, strict=20)
\new Score          %! Score
<<                  %! Score
    \new Staff      %! Staff
    {               %! Staff
        \new Voice  %! Voice
        {           %! Voice
            c'4
            d'4
            e'4
            f'4
        }           %! Voice
    }               %! Staff
>>                  %! Score

Tag tweaks like this:

>>> staff = abjad.Staff("c'4 d' e' f'")
>>> markup = abjad.Markup("Allegro", direction=abjad.Up).italic()
>>> tag = abjad.tags.ONLY_PARTS
>>> abjad.tweak(markup, tag=tag).color = "red"
>>> abjad.attach(markup, staff[0])
>>> abjad.f(staff)
\new Staff
{
    c'4
    - \tweak color #red %! +PARTS
    ^ \markup {
        \italic
            Allegro
        }
    d'4
    e'4
    f'4
}

Also:

  • abjad.LeafMaker output may be tagged
  • abjad.NoteMaker output may be tagged
  • score templates may be tagged
  • rhythm-makers may be tagged

19. TIES

Abjad 3.1 replaces the old tie spanner with two new indicators and a factory function. Closes #1033, #1097:

  • Added abjad.Tie
  • Added abjad.RepeatTie
  • Added abjad.tie()

Abjad 3.1 cleans up repeat-tie handling. Closes #1099:

  • Removed repeat_ties=None keyword from abjad.mutate().rewrite_meter()
  • Removed repeat_ties=None keyword from abjad.mutate().split()
  • Removed repeat_ties=None keyword from abjad.NoteMaker
  • Removed repeat_ties=None keyword from abjad.LeafMaker

20. TIME SIGNATURES

Abjad 3.1 suppresses LilyPond’s “strange time signature” warning for non-power-of-two time signatures like 7/12.

21. TIMESPANS

Frozen timespan expressions are available in Abjad 3.1 with new abjad.timespan() factory function. Empty arguments initialize an expression that can be used as a timespan initializer:

>>> expression = abjad.timespan()
>>> expression(start_offset=0, stop_offset=(1, 4))
Timespan(start_offset=Offset(0, 1), stop_offset=Offset(1, 4))

Abjad 3.1 adds support for abjad.Timespan.__contains__():

>>> timespan = abjad.timespan(0, (1, 4))
>>> -1 in timespan
False
>>> 0 in timespan
True
>>> Offset(1, 8) in timespan
True
>>> Offset(1, 4) in timespan
True
>>> Offset(1, 2) in timespan
False
>>> abjad.timespan(0, (1, 4)) in timespan
True
>>> abjad.timespan((1, 16), (2, 16)) in timespan
True
>>> abjad.timespan(0, (1, 2)) in timespan
False

CHANGED:

OLD: abjad.timespan_2_delays_timespan_1()
NEW: abjad.timespan().delays_timespan()

OLD:

    abjad.timespans.OffsetTimespanTimeRelation
    abjad.timespans.offset_happens_after_timespan_starts()
    abjad.timespans.offset_happens_after_timespan_stops()
    abjad.timespans.offset_happens_before_timespan_starts()
    abjad.timespans.offset_happens_before_timespan_stops()
    abjad.timespans.offset_happens_during_timespan()
    abjad.timespans.offset_happens_when_timespan_starts()
    abjad.timespans.offset_happens_when_timespan_stops()

NEW:

    timespan.start_offset < offset
    timespan.stop_offset < offset
    offset < timespan.start_offset
    offset < timespan.stop_offset
    offset in timespan
    offset == timespan.start_offset
    offset == timespan.stop_offset

REMOVED. Removed timespantools functions. Use abjad.Timespan methods instead.

timespan_2_contains_timespan_1_improperly()
timespan_2_curtails_timespan_1()
timespan_2_happens_during_timespan_1()
timespan_2_intersects_timespan_1()
timespan_2_is_congruent_to_timespan_1()
timespan_2_overlaps_all_of_timespan_1()
timespan_2_overlaps_only_start_of_timespan_1()
timespan_2_overlaps_only_stop_of_timespan_1()
timespan_2_overlaps_start_of_timespan_1()
timespan_2_overlaps_stop_of_timespan_1()
timespan_2_starts_after_timespan_1_starts()
timespan_2_starts_after_timespan_1_stops()
timespan_2_starts_before_timespan_1_starts()
timespan_2_starts_before_timespan_1_stops()
timespan_2_starts_during_timespan_1()
timespan_2_starts_when_timespan_1_starts()
timespan_2_starts_when_timespan_1_stops()
timespan_2_stops_after_timespan_1_starts()
timespan_2_stops_after_timespan_1_stops()
timespan_2_stops_before_timespan_1_starts()
timespan_2_stops_before_timespan_1_stops()
timespan_2_stops_during_timespan_1()
timespan_2_stops_when_timespan_1_starts()
timespan_2_stops_when_timespan_1_stops()
timespan_2_trisects_timespan_1()

Also:

  • Removed abjad.TimeRelation
Reply | Threaded
Open this post in threaded view
|

Abjad maillist? Re: Release notification: Abjad 3.1

padovani-3
Hello,

First of all: thank you Trevor and Josiah for developing Abjad! A great tool!

I would like to know if there is a specific forum/mailist for Abjad (I'm not being allowed by google groups to access the one in http://groups.google.com/group/abjad-user that is linked in the github README.rst file).

Actually I have more questions, but would not like to flood lilypond maillist with them.

Thank you,
José