Skip to content

Fix: Correctly parse slurs and triplets preceding grace notes#1137

Open
leedale30 wants to merge 1 commit intopaulrosen:mainfrom
leedale30:fix-slur-grace-parsing
Open

Fix: Correctly parse slurs and triplets preceding grace notes#1137
leedale30 wants to merge 1 commit intopaulrosen:mainfrom
leedale30:fix-slur-grace-parsing

Conversation

@leedale30
Copy link

This PR addresses the issue where slurs (and triplets) are incorrectly parsed when they immediately precede a grace note block (e.g., ({BcB}G)).

Root Cause

In MusicParser.prototype.parseMusic, the "prefix gathering" loop (which collects chords, accents, and grace notes) would exit if it encountered a ( character because letter_to_open_slurs_and_triplets was called after this loop. When a slur start ( precedes a grace note block {...}, the loop would see the ( and break, preventing letter_to_grace from being called.

Fix

Integrated the gathering of open slurs and triplets directly into the prefix gathering loop. Specifically:

  1. Added a call to letter_to_open_slurs_and_triplets within the loop, after letter_to_grace returns 0.
  2. Removed the redundant call to letter_to_open_slurs_and_triplets that followed the loop.
  3. Updated the character skip at the end of the loop to ensure it doesn't bypass valid prefix characters.

This ensures slurs and triplets are correctly associated with the following note/chord even if grace notes are interspersed.

Fixes #1136 (if applicable) or relates to the reported slur parsing issue.

@leedale30
Copy link
Author

leedale30 commented Jan 19, 2026

hey Paul,

so its 5am here in China and i couldnt sleep so i decided to run those tests you asked for :D

Checked the nested slurs and the ones with notes in between, seems to work grait.

Heres the ABC file i used:

X:1
T:Paul Rosen Slur Tests
C:leedale30
M:4/4
L:1/8
K:G
%%STAVES (1 2)
V:1
GAG ({BcB}G) AB cd | (C(D) E) F G4 | (Cggg(D)ggg) | (C({g}D)E) F G4 |
V:2
K:HP
({g}A) B c d e4 | (A({g}B)c) d e4 | GAG ({BcB}G) AB cd | A4 A4 |

And the MusicXML output:
paul_rosen_test_render

Click to see full XML output
<?xml version='1.0' encoding='utf-8'?>
<?xml-model href="https://www.w3.org/2021/06/musicxml40/musicxml.xsd" type="application/xml" schematypens="http://www.w3.org/2001/XMLSchema"?>
<score-partwise>
  <work>
    <work-title>Paul Rosen Slur Tests</work-title>
  </work>
  <identification>
    <creator type="composer">leedale30</creator>
    <encoding>
      <encoder>abc2xml version 239</encoder>
      <encoding-date>2026-01-20</encoding-date>
    </encoding>
  </identification>
  <part-list>
    <score-part id="P1">
      <part-name />
    </score-part>
    <score-part id="P2">
      <part-name />
    </score-part>
  </part-list>
  <part id="P1">
    <measure number="1">
      <attributes>
        <divisions>120</divisions>
        <key>
          <fifths>1</fifths>
          <mode>major</mode>
        </key>
        <time>
          <beats>4</beats>
          <beat-type>4</beat-type>
        </time>
      </attributes>
      <note>
        <pitch>
          <step>G</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">begin</beam>
      </note>
      <note>
        <pitch>
          <step>A</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">continue</beam>
      </note>
      <note>
        <pitch>
          <step>G</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">end</beam>
      </note>
      <note>
        <grace />
        <pitch>
          <step>B</step>
          <octave>4</octave>
        </pitch>
        <voice>1</voice>
        <type>eighth</type>
        <notations>
          <slur number="1" type="start" />
        </notations>
      </note>
      <note>
        <grace />
        <pitch>
          <step>C</step>
          <octave>5</octave>
        </pitch>
        <voice>1</voice>
        <type>eighth</type>
      </note>
      <note>
        <grace />
        <pitch>
          <step>B</step>
          <octave>4</octave>
        </pitch>
        <voice>1</voice>
        <type>eighth</type>
      </note>
      <note>
        <pitch>
          <step>G</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <notations>
          <slur number="1" type="stop" />
        </notations>
      </note>
      <note>
        <pitch>
          <step>A</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">begin</beam>
      </note>
      <note>
        <pitch>
          <step>B</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">end</beam>
      </note>
      <note>
        <pitch>
          <step>C</step>
          <octave>5</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">begin</beam>
      </note>
      <note>
        <pitch>
          <step>D</step>
          <octave>5</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">end</beam>
      </note>
    </measure>
    <measure number="2">
      <note>
        <pitch>
          <step>C</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">begin</beam>
        <notations>
          <slur number="1" type="start" />
        </notations>
      </note>
      <note>
        <pitch>
          <step>D</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">end</beam>
        <notations>
          <slur number="1" type="stop" />
          <slur number="1" type="start" />
        </notations>
      </note>
      <note>
        <pitch>
          <step>E</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <notations>
          <slur number="1" type="stop" />
        </notations>
      </note>
      <note>
        <pitch>
          <step>F</step>
          <alter>1</alter>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        </note>
      <note>
        <pitch>
          <step>G</step>
          <octave>4</octave>
        </pitch>
        <duration>240</duration>
        <voice>1</voice>
        <type>half</type>
      </note>
    </measure>
    <measure number="3">
      <note>
        <pitch>
          <step>C</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">begin</beam>
        <notations>
          <slur number="1" type="start" />
        </notations>
      </note>
      <note>
        <pitch>
          <step>G</step>
          <octave>5</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">continue</beam>
      </note>
      <note>
        <pitch>
          <step>G</step>
          <octave>5</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">continue</beam>
      </note>
      <note>
        <pitch>
          <step>G</step>
          <octave>5</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">continue</beam>
      </note>
      <note>
        <pitch>
          <step>D</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">continue</beam>
        <notations>
          <slur number="1" type="stop" />
          <slur number="1" type="start" />
        </notations>
      </note>
      <note>
        <pitch>
          <step>G</step>
          <octave>5</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">continue</beam>
      </note>
      <note>
        <pitch>
          <step>G</step>
          <octave>5</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">continue</beam>
      </note>
      <note>
        <pitch>
          <step>G</step>
          <octave>5</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">end</beam>
        <notations>
          <slur number="1" type="stop" />
        </notations>
      </note>
    </measure>
    <measure number="4">
      <note>
        <pitch>
          <step>C</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">begin</beam>
        <notations>
          <slur number="1" type="start" />
        </notations>
      </note>
      <note>
        <grace />
        <pitch>
          <step>G</step>
          <octave>5</octave>
        </pitch>
        <voice>1</voice>
        <type>eighth</type>
        <notations>
          <slur number="2" type="start" />
        </notations>
      </note>
      <note>
        <pitch>
          <step>D</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">continue</beam>
        <notations>
          <slur number="2" type="stop" />
        </notations>
      </note>
      <note>
        <pitch>
          <step>E</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">end</beam>
        <notations>
          <slur number="1" type="stop" />
        </notations>
      </note>
      <note>
        <pitch>
          <step>F</step>
          <alter>1</alter>
          <octave>4</octave>
          </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
      </note>
      <note>
        <pitch>
          <step>G</step>
          <octave>4</octave>
        </pitch>
        <duration>240</duration>
        <voice>1</voice>
        <type>half</type>
      </note>
    </measure>
  </part>
  <part id="P2">
    <measure number="1">
      <attributes>
        <divisions>120</divisions>
        <key>
          <fifths>1</fifths>
          <mode>major</mode>
        </key>
        <time>
          <beats>4</beats>
          <beat-type>4</beat-type>
        </time>
      </attributes>
      <note>
        <grace />
        <pitch>
          <step>G</step>
          <octave>5</octave>
        </pitch>
        <voice>1</voice>
        <type>eighth</type>
        <notations>
          <slur number="1" type="start" />
        </notations>
      </note>
      <note>
        <pitch>
          <step>A</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <notations>
          <slur number="1" type="stop" />
        </notations>
      </note>
      <note>
        <pitch>
          <step>B</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
      </note>
      <note>
        <pitch>
          <step>C</step>
          <octave>5</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
      </note>
      <note>
        <pitch>
          <step>D</step>
          <octave>5</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
      </note>
      <note>
        <pitch>
          <step>E</step>
          <octave>5</octave>
        </pitch>
        <duration>240</duration>
        <voice>1</voice>
        <type>half</type>
      </note>
    </measure>
    <measure number="2">
      <note>
        <pitch>
          <step>A</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">begin</beam>
        <notations>
          <slur number="1" type="start" />
        </notations>
      </note>
      <note>
        <grace />
        <pitch>
          <step>G</step>
          <octave>5</octave>
        </pitch>
        <voice>1</voice>
        <type>eighth</type>
        <notations>
          <slur number="2" type="start" />
        </notations>
      </note>
      <note>
        <pitch>
          <step>B</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">continue</beam>
        <notations>
          <slur number="2" type="stop" />
        </notations>
      </note>
      <note>
        <pitch>
          <step>C</step>
          <octave>5</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">end</beam>
        <notations>
          <slur number="1" type="stop" />
        </notations>
      </note>
      <note>
        <pitch>
          <step>D</step>
          <octave>5</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
      </note>
      <note>
        <pitch>
          <step>E</step>
          <octave>5</octave>
        </pitch>
        <duration>240</duration>
        <voice>1</voice>
        <type>half</type>
      </note>
    </measure>
    <measure number="3">
      <note>
        <pitch>
          <step>G</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">begin</beam>
      </note>
      <note>
        <pitch>
          <step>A</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">continue</beam>
      </note>
      <note>
        <pitch>
          <step>G</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">end</beam>
      </note>
      <note>
        <grace />
        <pitch>
          <step>B</step>
          <octave>4</octave>
        </pitch>
        <voice>1</voice>
        <type>eighth</type>
        <notations>
          <slur number="1" type="start" />
        </notations>
      </note>
      <note>
        <grace />
        <pitch>
          <step>C</step>
          <octave>5</octave>
        </pitch>
        <voice>1</voice>
        <type>eighth</type>
      </note>
      <note>
        <grace />
        <pitch>
          <step>B</step>
          <octave>4</octave>
        </pitch>
        <voice>1</voice>
        <type>eighth</type>
      </note>
      <note>
        <pitch>
          <step>G</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <notations>
          <slur number="1" type="stop" />
        </notations>
      </note>
      <note>
        <pitch>
          <step>A</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">begin</beam>
      </note>
      <note>
        <pitch>
          <step>B</step>
          <octave>4</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">end</beam>
      </note>
      <note>
        <pitch>
          <step>C</step>
          <octave>5</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">begin</beam>
      </note>
      <note>
        <pitch>
          <step>D</step>
          <octave>5</octave>
        </pitch>
        <duration>60</duration>
        <voice>1</voice>
        <type>eighth</type>
        <beam number="1">end</beam>
      </note>
    </measure>
    <measure number="4">
      <note>
        <pitch>
          <step>A</step>
          <octave>4</octave>
        </pitch>
        <duration>240</duration>
        <voice>1</voice>
        <type>half</type>
      </note>
      <note>
        <pitch>
          <step>A</step>
          <octave>4</octave>
        </pitch>
        <duration>240</duration>
        <voice>1</voice>
        <type>half</type>
      </note>
    </measure>
  </part>
</score-partwise>

Seems like the logic holds up!

I also verified with a local rendering that the visual output matches.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Slurs around graces cause issues

1 participant