Skip to content

Chord.Parse rejects "C+7" and "C+13" and reads "C+9"/"C+11" as a major triad with #9/#11 (regression from #362) #378

Description

@matt-edmondson

What's wrong

The chord grammar in Semantics.Music/README.md:91-93 (and #360 §3.1) lets the augmented mark + act as the quality and be followed by an extension number:

body      = [ quality ] [ extension ] [ suspension ] { modifier }
quality   = minor [ "aug" | "+" ] | "dim" | "°" | "ø" | "aug" | "+" | majorWord
extension = [ majorWord ] number | ...

Under that grammar C+7 is an augmented seventh, and Cm+7 is Cm7#5.

The reader doesn't follow it. ReadAugmentedQuality in Semantics.Music/ChordSymbolReader.cs:112 takes + as the quality only when the next character is not a digit:

if (TryTake("aug") || (Peek('+') && !IsDigit(PeekNext()) && TryTake("+")))

When a digit follows, the + is left for the modifier loop. There TryReadAlteration reads it as a sharp, and it accepts only 5, 9 or 11 after a sharp. So:

  • +7 and +13 are not valid alterations, and the whole symbol is rejected.
  • +9 and +11 are read as #9 or #11 added to a plain major triad with no seventh.

Before #362, C+7, C+9, C+11 and C+13 all parsed as augmented chords. Neither ChordGrammarTests nor ChordRoundTripTests covers a leading + followed by a number; the corpus has only C+, C7+ and C7+5.

Reproduction

Chord.TryParse / ToString() / ChordTones() against the built library at 022c8a4, compared with a build at 268a90e, the commit before #362:

Input Main today Before #362 Intended
C+7 rejected Caug7 [0,4,8,10] Caug7
C+13 rejected aug13 Caug13
Cm+7 rejected Caug7 (wrong third, #340) Cm7#5 [0,3,8,10]
C+9 C(#9) [0,4,7,15] Caug9 [0,4,8,10,14] Caug9 [0,4,8,10,14]
C+11 C(#11) [0,4,7,18] aug11 Caug11

These spellings work today:

  • C+ → Caug
  • C+maj7 → Caugmaj7
  • C9+ → Caug9
  • C7+ → Caug7
  • C-7 → Cm7
  • C-13 → Cm13

So a body-start - followed by a number is read as a quality, but a body-start + followed by a number is not.

Why it matters

Suggested fix / acceptance criteria

  • At the start of the body, after the optional minor mark, read + as the augmented mark whether or not a digit follows, the same way a body-start - is already handled. Keep + as a sharp only in modifier position, after the extension.
  • These must parse as follows:
    • C+7 → Caug7 [0,4,8,10]
    • C+9 → Caug9 [0,4,8,10,14]
    • C+11 and C+13 → augmented 11th and 13th chords
    • Cm+7 → Cm7#5 [0,3,8,10]
  • These must not change: C+, C+5 → Caug, C7+, C7+5, C7+9 → C7#9, C9+ → Caug9, Cadd9(#11).
  • Add the rows above to Parse_GrammarSpellings_KeepTheirMeaning. The existing exhaustive round-trip test should still pass.

Related: #345 covers + after a digit (C7+9), and #340 covers the third in Cm+. Neither covers a leading + before a number.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions