@@ -653,5 +653,45 @@ class ChordTests: XCTestCase {
653653 assertRankedChord ( [ 65 , 69 , 72 , 74 , 79 ] , expectedDescriptions: [ " F6/9 " , " G9sus4/F " , " G11sus2/F " , " Dm7(add11)/F " ] )
654654 assertRankedChord ( [ 65 , 69 , 72 , 76 , 79 ] , expectedDescriptions: [ " Fmaj9 " , " Am7(add♭13)/F " ] )
655655 }
656-
656+
657+ // MARK: - Octave-Doubled Voicings
658+ //
659+ // A chord must be detected the same regardless of how many times its notes
660+ // are doubled at other octaves — guitar voicings routinely repeat the root,
661+ // third, and fifth across six strings. Detection currently breaks when
662+ // *every* pitch class is doubled (e.g. a full six-string D/F♯): the chord
663+ // search never matches a unison/octave of the root, so `foundNotes` falls
664+ // one short of `pitchSet.count`. The "every note doubled" cases below
665+ // document that bug and should pass once it is fixed.
666+
667+ func testDMajorDetectedInRootPosition( ) {
668+ // D F♯ A
669+ assertRankedChord ( [ 50 , 54 , 57 ] , expectedDescriptions: [ " D " ] )
670+ }
671+
672+ func testDMajorOverFSharpDetectedWithDistinctNotes( ) {
673+ // F♯ A D
674+ assertRankedChord ( [ 42 , 45 , 50 ] , expectedDescriptions: [ " D/F♯ " ] )
675+ }
676+
677+ func testDMajorOverFSharpDetectedWhenFifthAndOctaveDoubled( ) {
678+ // F♯ A D A D — A and D doubled; F♯ is still single so it can root the search
679+ assertRankedChord ( [ 42 , 45 , 50 , 57 , 62 ] , expectedDescriptions: [ " D/F♯ " ] )
680+ }
681+
682+ func testDMajorOverFSharpDetectedWhenEveryNoteDoubled( ) {
683+ // F♯ A D A D F♯ — full six-string voicing, every pitch class doubled
684+ assertRankedChord ( [ 42 , 45 , 50 , 57 , 62 , 66 ] , expectedDescriptions: [ " D/F♯ " ] )
685+ }
686+
687+ func testCMajorDetectedWhenRootAndThirdDoubled( ) {
688+ // C E G C E — G is single so the search can root on G
689+ assertRankedChord ( [ 60 , 64 , 67 , 72 , 76 ] , expectedDescriptions: [ " C " ] )
690+ }
691+
692+ func testCMajorDetectedWhenEveryNoteDoubled( ) {
693+ // C E G C E G — every pitch class doubled
694+ assertRankedChord ( [ 60 , 64 , 67 , 72 , 76 , 79 ] , expectedDescriptions: [ " C " ] )
695+ }
696+
657697}
0 commit comments