Skip to content

Tuplet and Parenthesis Handling Issues in ABC converter (abcFormat) #1798

@guang-yng

Description

@guang-yng

music21 version

9.7.1

Operating System(s) checked
MacOS 15.5

Problem summary

Hi music21 developers! Thank you for maintaining such a great project!

While working with the ABC converter in music21/abcFormat, I noticed some issues related to how tuplets and parentheses (used for slurs and cresc./dim.) are handled. Here’s what I’ve found:

  • ABC tuplet symbols like (3 are tokenized and applied to following notes via the lastTupletToken variable. However, at the same time, the string "Tuplet" is pushed onto the self.activeParens stack and only removed upon encountering an ABCParenStop token. This is problematic because in ABC notation, tuplets are not structured like slurs—they don’t require a closing parenthesis.
  • Slur stops and crescendo/diminuendo stops are all tokenized as ABCParenStop, without distinguishing their types. This could cause issues when these constructs appear in alternating patterns. One possible fix is to use separate token types and maintain separate stacks for each construct.

I’m happy to help address these issues! I actually have already done some work to support ABC v2.1 (like multi-voice and inline clef/key/meter change)—but I’m still refining it.

Additionally, the current ABC parsing logic is quite complex. Have we considered building on top of existing tools like abc2xml.py, which already provides a fairly complete ABC parser?

Steps to reproduce

Here is an example:

from music21 import converter
abc_str="""X:1
M:4/4
K:C
L:1/4
(C(3DEF)G|"""
score = converter.parse(abc_str)
score.show('text')

Expected vs. actual behavior

Actual behavior:

{0.0} <music21.metadata.Metadata object at 0x14a13ffee480>
{0.0} <music21.stream.Part 0x14a13fe47b30>
    {0.0} <music21.clef.TrebleClef>
    {0.0} <music21.key.Key of C major>
    {0.0} <music21.meter.TimeSignature 4/4>
    {0.0} <music21.spanner.Slur <music21.note.Note C><music21.note.Note D><music21.note.Note E><music21.note.Note F><music21.note.Note G>>
    {0.0} <music21.note.Note C>
    {1.0} <music21.note.Note D>
    {1.6667} <music21.note.Note E>
    {2.3333} <music21.note.Note F>
    {3.0} <music21.note.Note G>

Expected behavior:

{0.0} <music21.metadata.Metadata object at 0x14a13ffee480>
{0.0} <music21.stream.Part 0x14a13fe47b30>
    {0.0} <music21.clef.TrebleClef>
    {0.0} <music21.key.Key of C major>
    {0.0} <music21.meter.TimeSignature 4/4>
    {0.0} <music21.spanner.Slur <music21.note.Note C><music21.note.Note D><music21.note.Note E><music21.note.Note F>>
    {0.0} <music21.note.Note C>
    {1.0} <music21.note.Note D>
    {1.6667} <music21.note.Note E>
    {2.3333} <music21.note.Note F>
    {3.0} <music21.note.Note G>

The closing parenthesis) should end the slur that starts before C. However, due to interaction with the tuplet parsing, it incorrectly includes the note G in the slur.

More information

I’d be happy to help with:

  • Introducing distinct close tokens and separate stacks for each construct (tuplets, slurs, etc.)
  • Add new features to support ABC v2.1
  • Refactoring or rewriting parts of the ABC parser to improve clarity and modularity if needed

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions