Skip to content

Read C69, Cadd11 and Cadd13 as added tones, and reject leftover text [patch] - #293

Merged
matt-edmondson merged 3 commits into
mainfrom
fix/chord-parse-69-add11-add13
Sep 28, 2026
Merged

matt-edmondson merged 3 commits into
mainfrom
fix/chord-parse-69-add11-add13

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #280

What was wrong

Chord.TryParse consumed only add9 as an added tone. The bare 9/11/13 left behind by C69, Cadd11 or Cadd13 was read by ApplyExtensions as a stacked extension, which forces a dominant seventh. The leftover add was ignored, so the parse succeeded with the wrong notes: C69 came out as C769, and Cadd11 came out as C711.

Change

  • Six-nine without a slash. RewriteSixNine rewrites a 6 directly followed by a bare 9 in the body to 6add9. This is the same reading TryRewriteSixNine already gives C6/9.
  • add11 / add13. These are now consumed as added tones next to add9, so they no longer imply a seventh. When a chord has no seventh, the formatter writes each natural tension as addN (add9, add11, add13), so these chords round-trip. Chords with a seventh format exactly as before.
  • Leftover text. Once every modifier and extension has been consumed, TryParse fails if the body holds anything besides the quality/seventh vocabulary that DetermineQuality/DetermineSeventh read (maj, min, m, M, -, dim, °, aug, +, Δ, sus/sus2/sus4, 5, 6, 7).

Behaviour change to note

The leftover check means symbols that used to parse leniently into a different chord are now rejected. Examples are Cadd, Cadd4, Cadd2 and unknown suffixes such as Cø7 or C7alt. This is the strictness the issue asked for. If some of these should be supported, each needs its own token.

Tests

  • ChordTones table: C69, Cm69, Cadd11, Cadd13 with the correct tones from the issue.
  • Parse_UnslashedSixNine_IsTheSameChordAsTheSlashedSpelling
  • Parse_AddedEleventhAndThirteenth_DoNotImplyASeventh
  • Parse_UnrecognisedTextLeftInTheBody_Fails
  • The round-trip corpus gains C69, Cm69, Cadd11, Cadd13, Cmadd11.

With Chord.cs reverted, 4 of the Music tests fail. With the change, the full Semantics.Test suite passes: 1336 passed, 8 skipped.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PKmokmgnpkeYgp439Qbthh


Generated by Claude Code

…[patch]

Only "add9" was consumed as an added tone. The bare "9", "11" or "13" left
behind by "C69", "Cadd11" or "Cadd13" was then read as a stacked extension
that implies a dominant seventh, and the leftover "add" was ignored, so the
parse succeeded with the wrong notes.

- Rewrite the unslashed six-nine "69" to "6add9", matching "6/9".
- Consume "add11" and "add13" as added tones, and format a seventh-less
  chord's natural tensions as "addN" so they round-trip.
- Fail the parse when the body still holds anything beyond the quality
  and seventh vocabulary once every token is consumed.

Fixes #280

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PKmokmgnpkeYgp439Qbthh
…erload [patch]

string.Replace(string, string, StringComparison) does not exist on
netstandard2.0, so Semantics.Music failed to build there. Remove each word
with the parser's own ordinal Take instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PKmokmgnpkeYgp439Qbthh
Comment thread Semantics.Music/Chord.cs Fixed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PKmokmgnpkeYgp439Qbthh
@sonarqubecloud

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit 1a6fe4e into main Sep 28, 2026
13 checks passed
@matt-edmondson
matt-edmondson deleted the fix/chord-parse-69-add11-add13 branch September 28, 2026 08:18
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.

Chord.Parse turns "C69", "Cadd11" and "Cadd13" into dominant-seventh chords with an extra b7 instead of rejecting them

2 participants