Figured Bass in Abjad

41 views
Skip to first unread message

Andrew Rickards

unread,
Apr 2, 2025, 8:31:50 AMApr 2
to abjad-user
I'm sorry if I am missing something obvious (I have searched the docs and the conversations in this group but nothing I have managed to find has quite worked).
Is there a recommended way to insert a figured bass line below a score in Abjad? I've managed to put figured bass symbols in by attaching markups to notes/chords with a custom font but that has its limitations and is a bit of a work around.
If someone could point me in the right direction I'd be very grateful.
Thanks you.

Gregory Evans

unread,
Apr 2, 2025, 9:50:51 AMApr 2
to abjad...@googlegroups.com

Hi Andrew,
As you are probably aware, there are usually a few ways a particular notation can be achieved in Lilypond. This can be both a good thing (many short-term solutions are available) and a bad thing (sometimes the preferred method is difficult to discover). For your needs it is entirely possible that downward markups are the most efficient method for you to use. However, looking at the Lilypond documentation it appears that the preferred method is to use a FiguredBass context (see: https://lilypond.org/doc/v2.23/Documentation/notation/figured-bass).

This context is not currently modeled in Abjad, nor is the Lyrics context. This is not because it is not possible or even undesirable to have these contexts available. More likely, it is just a byproduct of the fact that until now most Abjad contributors and/or users have not wanted them. I wrote a piece a few years back where I needed to model the Lyrics context so let me suggest something for FiguredBass based on that experience:

class FiguredBass(
    abjad.Context
):

    ### CLASS VARIABLES ###

    __documentation_section__ = "Contexts"

    __slots__ = ()

    _default_lilypond_type = "FiguredBass"

    ### INITIALIZER ###

    def __init__(
        self,
        components=None,
        lilypond_type: str = "FiguredBass",
        figures: str = r"\figuremode",
        simultaneous: bool = False,
        name: str = None,
        tag: abjad.Tag = None,
        *,
        language: str = "english",
    ) -> None:
        abjad.Context.__init__(
            self,
            components=components,
            language=language,
            lilypond_type=lilypond_type,
            simultaneous=simultaneous,
            name=name,
            tag=tag,
        )
        lyrics_literal = abjad.LilyPondLiteral(fr"\figuremode {{ {figures} }}")
        abjad.attach(lyrics_literal, self)

    ### PUBLIC PROPERTIES ###

    @property
    def tag(self):
        return super().tag

As seen above, this FiguredBass context inherits from Abjad’s native Context object. This should allow it to be accepted when inserted into an abjad.Score or another object like it. The use case would look something like this:

figure_context = FiguredBass(figures=r"<6>4 <7\+>8 <6+ [_!]> <6>4")

where the figure notation as seen in the Lilypond docs are written as a string. The figures can then be placed in a staff set to simultaneous and the figures will be rendered below the staff.

score = abjad.Score([abjad.Staff([abjad.Voice("c'4 c'8 c'8 c'4"), figure_context], simultaneous=True)])
abjad.show(score)

see the attached image
lilypond_figures.png
hope this helps,
Gregory Evans



--
You received this message because you are subscribed to the Google Groups "abjad-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to abjad-user+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/abjad-user/1a45b52d-45fa-496e-a082-959e6b30bc34n%40googlegroups.com.


--

Andrew Rickards

unread,
Apr 3, 2025, 2:36:34 AMApr 3
to abjad-user
Thank you SO much! That pointed me in just the right direction. Initially the figures where appearing above the staff but after playing around with it I managed to fine a solution. Here is a small snippet for anyone else who is interested;

`import abjad

# Create a bass line
bass_voice = abjad.Voice("c1 d2 e2 f1", name="BassVoice")

# Create a separate voice/context for the figured bass
# The voice can't be empty it seems so use a 'skip' to put something in the voice.
figures_voice = abjad.Voice("s1", lilypond_type="FiguredBass", name="Figures")

# Create the figured bass literal
figures_literal = abjad.LilyPondLiteral(
    r"\figuremode { \bassFigureExtendersOn <6 4>2 <6 3>2 <_>2 <6\! 4\!>2 <6- _!>1 }",
    site="before", # Attach before the first skip
)

# Attach the literal block to the beginning of the figures_voice
abjad.attach(figures_literal, abjad.select.leaf(figures_voice, 0))

# Create a staff containing ONLY the bass voice
staff = abjad.Staff([bass_voice], name="BassStaff")

# Set bass clef for the bass staff
bass_clef = abjad.Clef("bass")
abjad.attach(bass_clef, abjad.select.leaf(bass_voice, 0))

# Create a score containing the staff and the figures voice
score = abjad.Score([staff, figures_voice], name="Score")

# Show the result
abjad.show(score)`
Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted

Andrew Rickards

unread,
Aug 28, 2025, 2:41:13 PM (11 days ago) Aug 28
to abjad-user
Why are my messages getting deleted? Are images not allowed? Have I broken some guidelines? Were my code example bad? What's happening?

Andrew Rickards

unread,
Aug 28, 2025, 2:41:18 PM (11 days ago) Aug 28
to abjad-user
I've tried to post this twice but the messages kept getting deleted (I think I was using the wrong google account). Anyway, here is an updated version of how to do figured bass in abjad based on some things I've learned recently (sorry if this is obvious to everyone already).

There are two ways to include figured bass. First, you can attach the figures directly to a staff. In this case the vertical positioning of the figures is affected by the notes and you can change the position of the figured in relation to the staff, placing the above or below. You can change the position back and forth too.

Screenshot 2025-08-22 at 5.32.01 pm.jpgScreenshot 2025-08-22 at 5.32.17 pm.jpg
import abjad

# Create the figures
# This defaults to showing the figures above the staff.
# Setting the site argument to 'opening' also seems necessary.
figures = abjad.LilyPondLiteral(fr"\figuremode {{ <6>4 <7\+>8 <6+ [_!]> <6>4 }}", site='opening')

# To display them below use \bassFigureStaffAlignmentDown like this;
# figures = abjad.LilyPondLiteral(fr"\figuremode {{ \bassFigureStaffAlignmentDown <6>4 <7\+>8 <6+ [_!]> <6>4 }}", site='opening')

# Create the staves
tre = abjad.Staff([abjad.Voice("c'4 c'8 c'8 c'4")], simultaneous=True)
bass = abjad.Staff([abjad.Voice("c4 c8 c,8 e,4")], simultaneous=True)
abjad.attach(abjad.Clef('bass'), abjad.select.leaf(bass, 0))

piano = abjad.StaffGroup([tre, bass], lilypond_type='PianoStaff')

# Attach figures to bass staff
abjad.attach(figures, bass)

score = abjad.Score([piano])
abjad.show(score)


Or you can create an independent FiguredBass context which will always show the figures below the staff and the vertical positioning of the figures is independent of the notes.
Screenshot 2025-08-22 at 5.32.53 pm.jpg
 
import abjad

# Create the figures
figures = abjad.LilyPondLiteral(fr"\figuremode {{ <6>4 <7\+>8 <6+ [_!]> <6>4 }}", site='opening')

# Create a FiguredBass context
figure_context = abjad.Context(lilypond_type='FiguredBass', simultaneous=True)

# Attach the figures to the context
abjad.attach(figures, figure_context)

# Create the staves
tre = abjad.Staff([abjad.Voice("c'4 c'8 c'8 c'4")], simultaneous=True)

# Include the FiguredBass context in the components list of the staff
bass = abjad.Staff([abjad.Voice("c4 c8 c,8 e,4"), figure_context], simultaneous=True)
abjad.attach(abjad.Clef('bass'), abjad.select.leaf(bass, 0))

piano = abjad.StaffGroup([tre, bass], lilypond_type='PianoStaff')

score = abjad.Score([piano])
abjad.show(score)


You can do both simultaneously too.
Screenshot 2025-08-22 at 5.32.38 pm.jpg
On Thursday, April 3, 2025 at 3:36:34 PM UTC+9 Andrew Rickards wrote:

Andrew Rickards

unread,
Aug 28, 2025, 2:41:24 PM (11 days ago) Aug 28
to abjad-user
I just wanted to update this because I have learned a few things since I posted that last message and I thought it might be helpful for anyone else needing figured bass in their scores.

It seems there are two ways to include figured bass. The first way is to attach it directly to a staff. In this case you can set and change whether the figures appear above or below the staff and the vertical positioning of the figures will be affected by the notes.
(I know these figures make no sense. It's just for testing)
Screenshot 2025-08-22 at 5.32.01 pm.jpgScreenshot 2025-08-22 at 5.32.17 pm.jpg
Here is the code that made these;

import abjad

# Create the figures
# This defaults to showing the figures above the staff.
# Setting the site argument to 'opening' also seems necessary.
figures = abjad.LilyPondLiteral(fr"\figuremode {{ <6>4 <7\+>8 <6+ [_!]> <6>4 }}", site='opening')

# To display them below use \bassFigureStaffAlignmentDown like this;
# figures = abjad.LilyPondLiteral(fr"\figuremode {{ \bassFigureStaffAlignmentDown <6>4 <7\+>8 <6+ [_!]> <6>4 }}", site='opening')

# Create the staves
tre = abjad.Staff([abjad.Voice("c'4 c'8 c'8 c'4")], simultaneous=True)
bass = abjad.Staff([abjad.Voice("c4 c8 c,8 e,4")], simultaneous=True)
abjad.attach(abjad.Clef('bass'), abjad.select.leaf(bass, 0))

piano = abjad.StaffGroup([tre, bass], lilypond_type='PianoStaff')

# Attach figures to bass staff
abjad.attach(figures, bass)

score = abjad.Score([piano])
abjad.show(score)


The next way is to create a dedicated FiguredBass context. Here the vertical position of the figures is independent of the notes;
Screenshot 2025-08-22 at 5.32.53 pm.jpg
 
import abjad

# Create the figures
figures = abjad.LilyPondLiteral(fr"\figuremode {{ <6>4 <7\+>8 <6+ [_!]> <6>4 }}", site='opening')

# Create a FiguredBass context
figure_context = abjad.Context(lilypond_type='FiguredBass', simultaneous=True)

# Attach the figures to the context
abjad.attach(figures, figure_context)

# Create the staves
tre = abjad.Staff([abjad.Voice("c'4 c'8 c'8 c'4")], simultaneous=True)

# Include the FiguredBass context in the components list of the staff
bass = abjad.Staff([abjad.Voice("c4 c8 c,8 e,4"), figure_context], simultaneous=True)
abjad.attach(abjad.Clef('bass'), abjad.select.leaf(bass, 0))

piano = abjad.StaffGroup([tre, bass], lilypond_type='PianoStaff')

score = abjad.Score([piano])
abjad.show(score)


You can do both simultaneously;
Screenshot 2025-08-22 at 5.32.38 pm.jpg
Anyway, I hope someone finds this helpful.
On Thursday, April 3, 2025 at 3:36:34 PM UTC+9 Andrew Rickards wrote:

Andrew Rickards

unread,
Aug 28, 2025, 2:41:30 PM (11 days ago) Aug 28
to abjad-user
I just wanted to update this because I have learnt a couple of things since I posted that last message and thought it might be helpful of anyone else needing to use figured bass in abjad.

It seems there are two ways to add figured bass (that I know of) in Lilypond. First, you can attach the figures directly to a staff. In this case the vertical position of the figures will be affected by any notes outside of the staff, so the figures may not align horizontally. On the plus side you can change the position of the figures above or below the staff using \bassFigureStaffAlignmentDown\bassFigureStaffAlignmentUp\bassFigureStaffAlignmentNeutral (see docs). Here is a simple example of how to attach bass figures to the staff of a piano staff;

 
import abjad

# Create the figures
# This defaults to showing the figures above the staff.
# Setting the site argument to 'opening' also seems necessary.
figures = abjad.LilyPondLiteral(fr"\figuremode {{ <6>4 <7\+>8 <6+ [_!]> <6>4 }}", site='opening')

# To display them below use \bassFigureStaffAlignmentDown like this;
# figures = abjad.LilyPondLiteral(fr"\figuremode {{ \bassFigureStaffAlignmentDown <6>4 <7\+>8 <6+ [_!]> <6>4 }}", site='opening')

# Create the staves
tre = abjad.Staff([abjad.Voice("c'4 c'8 c'8 c'4")], simultaneous=True)
bass = abjad.Staff([abjad.Voice("c4 c8 c,8 e,4")], simultaneous=True)
abjad.attach(abjad.Clef('bass'), abjad.select.leaf(bass, 0))

piano = abjad.StaffGroup([tre, bass], lilypond_type='PianoStaff')

# Attach figures to bass staff
abjad.attach(figures, bass)

score = abjad.Score([piano])
abjad.show(score)


Here is an example above and below the staff (I know the figures make no sense. ;
Screenshot 2025-08-22 at 5.32.01 pm.jpgScreenshot 2025-08-22 at 5.32.17 pm.jpg
The other way is to create a seperate FiguredBass context. In this case the figures will always appear below the staff and the vertical positioning will be independent of the notes, which means the figures will always be horizontally aligned. Here is an example;


import abjad

# Create the figures
figures = abjad.LilyPondLiteral(fr"\figuremode {{ <6>4 <7\+>8 <6+ [_!]> <6>4 }}", site='opening')

# Create a FiguredBass context
figure_context = abjad.Context(lilypond_type='FiguredBass', simultaneous=True)

# Attach the figures to the context
abjad.attach(figures, figure_context)

# Create the staves
tre = abjad.Staff([abjad.Voice("c'4 c'8 c'8 c'4")], simultaneous=True)

# Include the FiguredBass context in the components list of the staff
bass = abjad.Staff([abjad.Voice("c4 c8 c,8 e,4"), figure_context], simultaneous=True)
abjad.attach(abjad.Clef('bass'), abjad.select.leaf(bass, 0))

piano = abjad.StaffGroup([tre, bass], lilypond_type='PianoStaff')

score = abjad.Score([piano])
abjad.show(score)


Here is an example with a seperate FiguredBass context;
Screenshot 2025-08-22 at 5.32.53 pm.jpg
You can even do both at the same time;
Screenshot 2025-08-22 at 5.32.38 pm.jpg
Hope that helps someone in the future.
On Thursday, April 3, 2025 at 3:36:34 PM UTC+9 Andrew Rickards wrote:
Reply all
Reply to author
Forward
0 new messages