Skip to content

Chord.Parse reads "CmMaj7"/"CMaj7" as dominant/minor sevenths and "C°7" as half-diminished #281

Description

@matt-edmondson

What's wrong

Chord.DetermineSeventh (Semantics.Music/Chord.cs ~line 313) only recognizes some spellings of two seventh types that are common in chord charts.

1. The capital-M Maj spelling is not recognized as a major seventh.
hasMaj7 checks for "maj", "M7" or 'Δ', using ordinal comparison. "Maj7" matches none of them, so the chord falls through to SeventhType.Dominant.

Input Actual Expected
Chord.Parse("CmMaj7") Minor / Dominant → formats Cm7, tones 0,3,7,10 Minor / Major → Cmmaj7, tones 0,3,7,11
Chord.Parse("CMaj7") Major / Dominant → formats C7, tones 0,4,7,10 Major / Major → Cmaj7, tones 0,4,7,11

CmMaj7 is already in the ChordRoundTripTests corpus (Semantics.Test/Music/ChordRoundTripTests.cs:13). That test still passes because the wrong chord round-trips consistently: Cm7 → "Cm7" → Cm7. It is the same trap the recent dimmaj7 fix ran into.

2. °7 is recognized for the triad but not for the seventh.
DetermineQuality accepts "dim" or '°' for a diminished triad. The diminished-seventh branch in DetermineSeventh, however, only checks body.Contains("dim").

Input Actual Expected
Chord.Parse("C°7") Diminished / Dominant → formats Cm7b5 (half-diminished), tones 0,3,6,10 Diminished / Diminished → Cdim7, tones 0,3,6,9

Key.ChordFromRomanNumeral rewrites ° to dim before it parses, which is why vii°7 works. A direct Chord.Parse("C°7") does not.

Why it matters

Both failures produce a chord with the wrong pitches, with no exception or other signal. A lead sheet that uses CmMaj7, CMaj7 or C°7 silently plays the wrong notes.

Suggested fix / acceptance criteria

  • In hasMaj7, also match "Maj", e.g. body.Contains("Maj", StringComparison.Ordinal).
  • Change the diminished-seventh condition to (body.Contains("dim", StringComparison.Ordinal) || body.Contains('°')) && hasSeven.
  • Add tests that assert the SeventhType and pitch set, not only the round-trip, for CmMaj7, CMaj7 and C°7.

Confirmed by running the tests against main (8c06aba) on net10.0.

Activity

  1. matt-edmondson commented on Sep 27, 2026

    @matt-edmondson
    ContributorAuthor

    Triage

    Next step: Match "Maj" in hasMaj7 and accept '°' in the diminished-seventh branch. Add tests that assert SeventhType and pitch sets, not just round-trips. It's worth fixing together with #280, since the recurring cause is chord tests that only check round-trips.


    Generated by Claude Code

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

Metadata

Metadata

Labels

bugSomething isn't workingreadyFully specified; implement as written

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions