spanners

Classes and functions for modeling spanners: beams, hairpins, slurs, etc.


Functions

beam

Attaches beam indicators.

glissando

Attaches glissando indicators.

hairpin

Attaches hairpin indicators.

horizontal_bracket

Attaches group indicators.

ottava

Attaches ottava indicators.

phrasing_slur

Attaches phrasing slur indicators.

piano_pedal

Attaches piano pedal indicators.

slur

Attaches slur indicators.

text_spanner

Attaches text span indicators.

tie

Attaches tie indicators.

trill_spanner

Attaches trill spanner indicators.

abjad.spanners.beam(argument: Component | Sequence[Component], *, beam_lone_notes: bool = False, beam_rests: bool | None = True, direction: Vertical | None = None, durations: Sequence[Duration] | None = None, span_beam_count: int | None = None, start_beam: StartBeam | Bundle | None = None, stemlet_length: int | float | None = None, stop_beam: StopBeam | None = None, tag: Tag | None = None) None[source]

Attaches beam indicators.

>>> voice = abjad.Voice("c'8 d' e' f'")
>>> abjad.beam(voice[:], direction=abjad.UP)
>>> abjad.show(voice)  

Does not beam rests:

>>> voice = abjad.Voice("c'8 r e' f'")
>>> abjad.beam(voice[:], beam_rests=False)
>>> abjad.show(voice)  

Does beam rests:

>>> voice = abjad.Voice("c'8 r e' f'")
>>> abjad.beam(voice[:], beam_rests=True)
>>> abjad.show(voice)  

Beams rests and sets stemlet length:

>>> voice = abjad.Voice("c'8 r e' f'")
>>> abjad.beam(voice[:], beam_rests=True, stemlet_length=1)
>>> abjad.show(voice)  
abjad.spanners.glissando(argument, *tweaks, allow_repeats: bool = False, allow_ties: bool = False, hide_middle_note_heads: bool = False, hide_middle_stems: bool = False, left_broken: bool = False, parenthesize_repeats: bool = False, right_broken: bool = False, right_broken_show_next: bool = False, tag: Tag | None = None, zero_padding: bool = False)[source]

Attaches glissando indicators.

>>> voice = abjad.Voice("c'8 d'8 e'8 f'8", name="Voice")
>>> staff = abjad.Staff([voice], name="Staff")
>>> abjad.glissando(voice[:])
>>> abjad.show(staff)  

Glissando avoids bend-after indicators:

>>> voice = abjad.Voice("c'8 d'8 e'8 f'8", name="Voice")
>>> staff = abjad.Staff([voice], name="Staff")
>>> bend_after = abjad.BendAfter()
>>> abjad.attach(bend_after, voice[1])
>>> abjad.glissando(voice[:])
>>> abjad.show(staff)  

Does not allow repeated pitches:

>>> voice = abjad.Voice("a8 a8 b8 ~ b8 c'8 c'8 d'8 ~ d'8", name="Voice")
>>> staff = abjad.Staff([voice], name="Staff")
>>> abjad.glissando(voice[:], allow_repeats=True)
>>> abjad.show(staff)  

Allows repeated pitches (but not ties):

>>> voice = abjad.Voice("a8 a8 b8 ~ b8 c'8 c'8 d'8 ~ d'8", name="Voice")
>>> staff = abjad.Staff([voice], name="Staff")
>>> abjad.glissando(voice[:], allow_repeats=True)
>>> abjad.show(staff)  

Allows both repeated pitches and ties:

>>> voice = abjad.Voice("a8 a8 b8 ~ b8 c'8 c'8 d'8 ~ d'8", name="Voice")
>>> staff = abjad.Staff([voice], name="Staff")
>>> abjad.glissando(
...     voice[:],
...     allow_repeats=True,
...     allow_ties=True,
... )
>>> abjad.show(staff)  

Ties are excluded when repeated pitches are not allowed because all ties comprise repeated pitches.

Spans and parenthesizes repeated pitches:

>>> voice = abjad.Voice("a8 a8 b8 ~ b8 c'8 c'8 d'8 ~ d'8", name="Voice")
>>> staff = abjad.Staff([voice], name="Staff")
>>> abjad.glissando(
...     voice[:],
...     allow_repeats=True,
...     parenthesize_repeats=True,
... )
>>> abjad.show(staff)  

Parenthesizes (but does not span) repeated pitches:

>>> voice = abjad.Voice("a8 a8 b8 ~ b8 c'8 c'8 d'8 ~ d'8", name="Voice")
>>> staff = abjad.Staff([voice], name="Staff")
>>> abjad.glissando(
...     voice[:],
...     parenthesize_repeats=True,
... )
>>> abjad.show(staff)  

With hide_middle_note_heads=True:

>>> voice = abjad.Voice("c'8 d'8 e'8 f'8", name="Voice")
>>> staff = abjad.Staff([voice], name="Staff")
>>> abjad.glissando(voice[:], hide_middle_note_heads=True)
>>> abjad.show(staff)  

With hide_middle_note_heads=True and hide_middle_stems=True:

>>> voice = abjad.Voice("c'8 d'8 e'8 f'8", name="Voice")
>>> abjad.glissando(
...     voice[:],
...     hide_middle_note_heads=True,
...     hide_middle_stems=True,
... )
>>> abjad.show(voice)  

Note

Respects hide_middle_stems only when hide_middle_note_heads=True.

With right_broken=True:

>>> voice = abjad.Voice("c'8 d'8 e'8 f'8", name="Voice")
>>> abjad.glissando(voice[:], right_broken=True)
>>> abjad.show(voice)  

LilyPond output looks like this:

>>> string = abjad.lilypond(voice, tags=True)
>>> print(string)
\context Voice = "Voice"
{
    c'8
      %! abjad.glissando(7)
    \glissando
    d'8
      %! abjad.glissando(7)
    \glissando
    e'8
      %! abjad.glissando(7)
    \glissando
    f'8
      %! SHOW_TO_JOIN_BROKEN_SPANNERS
      %! abjad.glissando(7)
    %@% \glissando
}

With right_broken=True and hide_middle_note_heads=True:

>>> voice = abjad.Voice("c'8 d'8 e'8 f'8", name="Voice")
>>> abjad.glissando(
...     voice[:],
...     right_broken=True,
...     hide_middle_note_heads=True,
... )
>>> abjad.show(voice)  

LilyPond output looks like this:

>>> string = abjad.lilypond(voice, tags=True)
>>> print(string)
\context Voice = "Voice"
{
    c'8
      %! abjad.glissando(7)
    \glissando
      %! RIGHT_BROKEN
      %! SHOW_TO_JOIN_BROKEN_SPANNERS
      %! abjad.glissando(0)
    \hide NoteHead
      %! RIGHT_BROKEN
      %! SHOW_TO_JOIN_BROKEN_SPANNERS
      %! abjad.glissando(0)
    \override Accidental.stencil = ##f
      %! RIGHT_BROKEN
      %! SHOW_TO_JOIN_BROKEN_SPANNERS
      %! abjad.glissando(0)
    \override NoteColumn.glissando-skip = ##t
      %! RIGHT_BROKEN
      %! SHOW_TO_JOIN_BROKEN_SPANNERS
      %! abjad.glissando(0)
    \override NoteHead.no-ledgers = ##t
    d'8
    e'8
      %! HIDE_TO_JOIN_BROKEN_SPANNERS
      %! RIGHT_BROKEN
      %! abjad.glissando(4)
    \revert Accidental.stencil
      %! HIDE_TO_JOIN_BROKEN_SPANNERS
      %! RIGHT_BROKEN
      %! abjad.glissando(4)
    \revert NoteColumn.glissando-skip
      %! HIDE_TO_JOIN_BROKEN_SPANNERS
      %! RIGHT_BROKEN
      %! abjad.glissando(4)
    \revert NoteHead.no-ledgers
      %! HIDE_TO_JOIN_BROKEN_SPANNERS
      %! RIGHT_BROKEN
      %! abjad.glissando(4)
    \undo \hide NoteHead
    f'8
}

With right_broken=True, hide_middle_note_heads=True and right_broken_show_next=True:

>>> voice = abjad.Voice("c'8 d'8 e'8 f'8", name="Voice")
>>> abjad.glissando(
...     voice[:],
...     hide_middle_note_heads=True,
...     right_broken=True,
...     right_broken_show_next=True,
... )
>>> abjad.show(voice)  

LilyPond output looks like this:

>>> string = abjad.lilypond(voice, tags=True)
>>> print(string)
\context Voice = "Voice"
{
    c'8
      %! abjad.glissando(7)
    \glissando
      %! RIGHT_BROKEN
      %! SHOW_TO_JOIN_BROKEN_SPANNERS
      %! abjad.glissando(0)
    \hide NoteHead
      %! RIGHT_BROKEN
      %! SHOW_TO_JOIN_BROKEN_SPANNERS
      %! abjad.glissando(0)
    \override Accidental.stencil = ##f
      %! RIGHT_BROKEN
      %! SHOW_TO_JOIN_BROKEN_SPANNERS
      %! abjad.glissando(0)
    \override NoteColumn.glissando-skip = ##t
      %! RIGHT_BROKEN
      %! SHOW_TO_JOIN_BROKEN_SPANNERS
      %! abjad.glissando(0)
    \override NoteHead.no-ledgers = ##t
    d'8
    e'8
      %! HIDE_TO_JOIN_BROKEN_SPANNERS
      %! RIGHT_BROKEN
      %! abjad.glissando(4)
    \revert Accidental.stencil
      %! HIDE_TO_JOIN_BROKEN_SPANNERS
      %! RIGHT_BROKEN
      %! abjad.glissando(4)
    \revert NoteColumn.glissando-skip
      %! HIDE_TO_JOIN_BROKEN_SPANNERS
      %! RIGHT_BROKEN
      %! abjad.glissando(4)
    \revert NoteHead.no-ledgers
      %! HIDE_TO_JOIN_BROKEN_SPANNERS
      %! RIGHT_BROKEN
      %! abjad.glissando(4)
    \undo \hide NoteHead
    f'8
      %! RIGHT_BROKEN_SHOW_NEXT
      %! SHOW_TO_JOIN_BROKEN_SPANNERS
      %! abjad.glissando(5)
    %@% \revert Accidental.stencil
      %! RIGHT_BROKEN_SHOW_NEXT
      %! SHOW_TO_JOIN_BROKEN_SPANNERS
      %! abjad.glissando(5)
    %@% \revert NoteColumn.glissando-skip
      %! RIGHT_BROKEN_SHOW_NEXT
      %! SHOW_TO_JOIN_BROKEN_SPANNERS
      %! abjad.glissando(5)
    %@% \revert NoteHead.no-ledgers
      %! RIGHT_BROKEN_SHOW_NEXT
      %! SHOW_TO_JOIN_BROKEN_SPANNERS
      %! abjad.glissando(5)
    %@% \undo \hide NoteHead
}

With left_broken=True (and hide_middle_note_heads=True):

>>> voice = abjad.Voice("c'8 d'8 e'8 f'8", name="Voice")
>>> abjad.glissando(
...     voice[:],
...     left_broken=True,
...     hide_middle_note_heads=True,
... )
>>> abjad.show(voice)  

LilyPond output looks like this:

>>> string = abjad.lilypond(voice, tags=True)
>>> print(string)
\context Voice = "Voice"
{
      %! HIDE_TO_JOIN_BROKEN_SPANNERS
      %! LEFT_BROKEN
      %! abjad.glissando(2)
    \hide NoteHead
      %! HIDE_TO_JOIN_BROKEN_SPANNERS
      %! LEFT_BROKEN
      %! abjad.glissando(2)
    \override Accidental.stencil = ##f
      %! HIDE_TO_JOIN_BROKEN_SPANNERS
      %! LEFT_BROKEN
      %! abjad.glissando(2)
    \override NoteHead.no-ledgers = ##t
    c'8
      %! abjad.glissando(7)
    \glissando
      %! HIDE_TO_JOIN_BROKEN_SPANNERS
      %! LEFT_BROKEN
      %! abjad.glissando(3)
    \override NoteColumn.glissando-skip = ##t
    d'8
    e'8
      %! abjad.glissando(6)
    \revert Accidental.stencil
      %! abjad.glissando(6)
    \revert NoteColumn.glissando-skip
      %! abjad.glissando(6)
    \revert NoteHead.no-ledgers
      %! abjad.glissando(6)
    \undo \hide NoteHead
    f'8
}

Note

Respects left-broken only with hide_middle_note_heads=True.

Tweaks apply to every glissando:

>>> voice = abjad.Voice("c'8 d'8 e'8 f'8", name="Voice")
>>> abjad.glissando(
...     voice[:],
...     abjad.Tweak(r"- \tweak style #'trill"),
... )
>>> abjad.show(voice)  

With zero_padding=True on fixed pitch:

>>> voice = abjad.Voice("d'8 d'4. d'4. d'8", name="Voice")
>>> abjad.glissando(
...     voice[:],
...     allow_repeats=True,
...     zero_padding=True,
... )
>>> for note in voice[1:]:
...     abjad.override(note).NoteHead.transparent = True
...     abjad.override(note).NoteHead.X_extent = "#'(0 . 0)"
... 
>>> lilypond_file = abjad.LilyPondFile([r'\include "abjad.ily"', voice])
>>> abjad.show(lilypond_file)  

With zero_padding=True on changing pitches:

>>> voice = abjad.Voice("c'8. d'8. e'8. f'8.", name="Voice")
>>> abjad.glissando(voice[:], zero_padding=True)
>>> for note in voice[1:-1]:
...     abjad.override(note).NoteHead.transparent = True
...     abjad.override(note).NoteHead.X_extent = "#'(0 . 0)"
... 
>>> lilypond_file = abjad.LilyPondFile([r'\include "abjad.ily"', voice])
>>> abjad.show(lilypond_file)  

With indexed tweaks:

>>> voice = abjad.Voice("d'4 d' d' d'", name="Voice")
>>> abjad.glissando(
...     voice[:],
...     abjad.Tweak(r"- \tweak color #red", i=0),
...     abjad.Tweak(r"- \tweak color #red", i=-1),
...     allow_repeats=True,
...     zero_padding=True,
... )
>>> for note in voice[1:-1]:
...     abjad.override(note).NoteHead.transparent = True
...     abjad.override(note).NoteHead.X_extent = "#'(0 . 0)"
... 
>>> lilypond_file = abjad.LilyPondFile([r'\include "abjad.ily"', voice])
>>> abjad.show(lilypond_file)  
abjad.spanners.hairpin(descriptor: str, argument: Component | Sequence[Component], *, direction: Vertical | None = None, tag: Tag | None = None) None[source]

Attaches hairpin indicators.

With three-part string descriptor:

>>> voice = abjad.Voice("c'4 d' e' f'")
>>> abjad.hairpin("p < f", voice[:], direction=abjad.UP)
>>> abjad.override(voice[0]).DynamicLineSpanner.staff_padding = 4
>>> abjad.show(voice)  

With two-part string descriptor:

>>> voice = abjad.Voice("c'4 d' e' f'")
>>> abjad.hairpin("< !", voice[:])
>>> abjad.override(voice[0]).DynamicLineSpanner.staff_padding = 4
>>> abjad.show(voice)  

With dynamic objects:

>>> voice = abjad.Voice("c'4 d' e' f'")
>>> start_hairpin = abjad.StartHairpin("o<|")
>>> bundle = abjad.bundle(start_hairpin, r"- \tweak color #blue")
>>> stop_dynamic = abjad.Dynamic('"f"')
>>> abjad.hairpin([bundle, stop_dynamic], voice[:])
>>> abjad.override(voice[0]).DynamicLineSpanner.staff_padding = 4
>>> lilypond_file = abjad.LilyPondFile([r'\include "abjad.ily"', voice])
>>> abjad.show(lilypond_file)  
abjad.spanners.horizontal_bracket(argument: Component | Sequence[Component], *, start_group: StartGroup | Bundle | None = None, stop_group: StopGroup | None = None, tag: Tag | None = None) None[source]

Attaches group indicators.

>>> voice = abjad.Voice("c'4 d' e' f'")
>>> voice.consists_commands.append("Horizontal_bracket_engraver")
>>> abjad.horizontal_bracket(voice[:])
>>> abjad.show(voice)  

Bundle start-group indicators to tweak the padding and outside-staff priority of nested analysis brackets:

>>> voice = abjad.Voice("c'4 d' e' f' c' d' e' f'")
>>> voice.consists_commands.append("Horizontal_bracket_engraver")
>>> bundle = abjad.bundle(
...     abjad.StartGroup(),
...     r"- \tweak color #red",
...     r"- \tweak padding 1.5",
...     comment="% lexical order 1",
... )
>>> abjad.horizontal_bracket(voice[:4], start_group=bundle)
>>> bundle = abjad.bundle(
...     abjad.StartGroup(),
...     r"- \tweak color #red",
...     r"- \tweak padding 1.5",
...     comment="% lexical order 1",
... )
>>> abjad.horizontal_bracket(voice[4:], start_group=bundle)
>>> bundle = abjad.bundle(
...     abjad.StartGroup(),
...     r"- \tweak color #blue",
...     r"- \tweak outside-staff-priority 801",
...     r"- \tweak padding 1.5",
...     comment="% lexical order 0",
... )
>>> abjad.horizontal_bracket(voice[:], start_group=bundle)
>>> abjad.show(voice)  
abjad.spanners.ottava(argument: Component | Sequence[Component], *, start_ottava: Ottava = Ottava(n=1, site='before'), stop_ottava: Ottava = Ottava(n=0, site='after'), tag: Tag | None = None) None[source]

Attaches ottava indicators.

>>> staff = abjad.Staff("c'4 d' e' f'")
>>> abjad.ottava(staff[:])
>>> abjad.show(staff)  
abjad.spanners.phrasing_slur(argument: Component | Sequence[Component], *, direction: Vertical | None = None, start_phrasing_slur: StartPhrasingSlur | Bundle | None = None, stop_phrasing_slur: StopPhrasingSlur | None = None, tag: Tag | None = None) None[source]

Attaches phrasing slur indicators.

>>> voice = abjad.Voice("c'4 d' e' f'")
>>> abjad.phrasing_slur(voice[:], direction=abjad.UP)
>>> abjad.show(voice)  
abjad.spanners.piano_pedal(argument: Component | Sequence[Component], *, context: str | None = None, start_piano_pedal: StartPianoPedal | Bundle | None = None, stop_piano_pedal: StopPianoPedal | None = None, tag: Tag | None = None) None[source]

Attaches piano pedal indicators.

>>> staff = abjad.Staff("c'4 d' e' f'")
>>> abjad.piano_pedal(staff[:], context="Staff")
>>> abjad.setting(staff).pedalSustainStyle = "#'mixed"
>>> abjad.override(staff).SustainPedalLineSpanner.staff_padding = 5
>>> abjad.show(staff)  
abjad.spanners.slur(argument: Component | Sequence[Component], *, direction: Vertical | None = None, start_slur: StartSlur | Bundle | None = None, stop_slur: StopSlur | None = None, tag: Tag | None = None) None[source]

Attaches slur indicators.

>>> voice = abjad.Voice("c'4 d' e' f'")
>>> abjad.slur(voice[:], direction=abjad.UP)
>>> abjad.show(voice)  
abjad.spanners.text_spanner(argument: Component | Sequence[Component], *, direction: Vertical | None = None, start_text_span: StartTextSpan | Bundle | None = None, stop_text_span: StopTextSpan | None = None, tag: Tag | None = None) None[source]

Attaches text span indicators.

Single spanner:

>>> voice = abjad.Voice("c'4 d' e' f'")
>>> start_text_span = abjad.StartTextSpan(
...     left_text=abjad.Markup(r"\upright pont."),
...     right_text=abjad.Markup(r"\markup \upright tasto"),
...     style=r"\abjad-solid-line-with-arrow",
... )
>>> abjad.text_spanner(
...     voice[:], direction=abjad.UP, start_text_span=start_text_span
... )
>>> abjad.override(voice[0]).TextSpanner.staff_padding = 4
>>> lilypond_file = abjad.LilyPondFile([r'\include "abjad.ily"', voice])
>>> abjad.show(lilypond_file)  

Enchained spanners:

>>> voice = abjad.Voice("c'4 d' e' f' r")
>>> start_text_span = abjad.StartTextSpan(
...     left_text=abjad.Markup(r"\upright pont."),
...     style=r"\abjad-dashed-line-with-arrow",
... )
>>> abjad.text_spanner(voice[:3], start_text_span=start_text_span)
>>> start_text_span = abjad.StartTextSpan(
...     left_text=abjad.Markup(r"\upright tasto"),
...     right_text=abjad.Markup(r"\markup \upright pont."),
...     style=r"\abjad-dashed-line-with-arrow",
... )
>>> abjad.text_spanner(voice[-3:], start_text_span=start_text_span)
>>> abjad.override(voice).TextSpanner.staff_padding = 4
>>> lilypond_file = abjad.LilyPondFile([r'\include "abjad.ily"', voice])
>>> abjad.show(lilypond_file)  
>>> voice = abjad.Voice("c'4 d' e' f' r")
>>> start_text_span = abjad.StartTextSpan(
...     left_text=abjad.Markup(r"\upright pont."),
...     style=r"\abjad-dashed-line-with-arrow",
... )
>>> abjad.text_spanner(voice[:3], start_text_span=start_text_span)
>>> start_text_span = abjad.StartTextSpan(
...     left_text=abjad.Markup(r"\upright tasto"),
...     style=r"\abjad-solid-line-with-hook",
... )
>>> abjad.text_spanner(voice[-3:], start_text_span=start_text_span)
>>> abjad.override(voice).TextSpanner.staff_padding = 4
>>> lilypond_file = abjad.LilyPondFile([r'\include "abjad.ily"', voice])
>>> abjad.show(lilypond_file)  
abjad.spanners.tie(argument: Component | Sequence[Component], *, direction: Vertical | None = None, repeat: bool | tuple[int, int] | Callable = False, tag: Tag | None = None) None[source]

Attaches tie indicators.

>>> staff = abjad.Staff("c'4 c' c' c'")
>>> abjad.tie(staff[:], direction=abjad.UP)
>>> abjad.show(staff)  

With repeat ties:

>>> voice = abjad.Voice("c'4 c' c' c'", name="Voice")
>>> abjad.tie(voice[:], repeat=True)
>>> abjad.show(voice)  

Removes any existing ties before attaching new tie:

>>> voice = abjad.Voice("c'4 ~ c' ~ c' ~ c'", name="Voice")
>>> abjad.tie(voice[:])
>>> abjad.show(voice)  

Ties consecutive chords if all adjacent pairs have at least one pitch in common:

>>> voice = abjad.Voice("<c'>4 <c' d'>4 <d'>4", name="Voice")
>>> abjad.tie(voice[:])
>>> abjad.show(voice)  

Enharmonics are allowed:

>>> voice = abjad.Voice("c'4 bs c' dff'", name="Voice")
>>> abjad.tie(voice[:])
>>> abjad.show(voice)  

Repeat tie threshold works like this:

>>> voice = abjad.Voice("d'4. d'2 d'4. d'2", name="Voice")
>>> abjad.tie(voice[:], repeat=(4, 8))
>>> abjad.show(voice)  

Detaches ties before attach:

>>> voice = abjad.Voice("d'2 ~ d'8 ~ d'8 ~ d'8 ~ d'8", name="Voice")
>>> abjad.show(voice)  
>>> abjad.tie(voice[:], repeat=(4, 8))
>>> abjad.show(voice)  
abjad.spanners.trill_spanner(argument: Component | Sequence[Component], *, start_trill_span: StartTrillSpan | Bundle | None = None, stop_trill_span: StopTrillSpan | None = None, tag: Tag | None = None) None[source]

Attaches trill spanner indicators.

>>> voice = abjad.Voice("c'4 d' e' f'")
>>> abjad.trill_spanner(voice[:])
>>> abjad.show(voice)