import { describe, it, expect, beforeEach, } from 'vitest'; import { ChordBase, ChordComponent, ChordExtensionType, ChordModificationType, constructChord, analyzeIntervals, getChordName, } from '../src'; describe('constructChord', () => { it('works', () => { const chord = constructChord({ pitchClass: 0 }); expect(chord).toEqual([0, 4, 7]); }); }); describe('analyzeChord', () => { describe('building', () => { let chord: number[]; beforeEach(() => { chord = []; }); describe('root', () => { beforeEach(() => { chord.push(0); }); describe('major third', () => { beforeEach(() => { chord.push(4); }); describe('perfect fifth', () => { beforeEach(() => { chord.push(7); }); it('determines major chord', () => { expect(analyzeIntervals(chord)).toEqual({ base: ChordBase.MAJOR, }); }); describe('major sixth', () => { beforeEach(() => { chord.push(9); }); it('describes major sixth chord', () => { expect(analyzeIntervals(chord)).toEqual({ base: ChordBase.MAJOR, extensions: [{ type: ChordExtensionType.MAJOR, component: ChordComponent.SIXTH, }], }); }); }); describe('minor seventh', () => { beforeEach(() => { chord.push(10); }); it('describes dominant seventh chord', () => { expect(analyzeIntervals(chord)).toEqual({ base: ChordBase.MAJOR, extensions: [{ type: ChordExtensionType.DOMINANT, component: ChordComponent.SEVENTH, }], }); }); }); describe('major seventh', () => { beforeEach(() => { chord.push(11); }); it('describes major seventh chord', () => { expect(analyzeIntervals(chord)).toEqual({ base: ChordBase.MAJOR, extensions: [{ type: ChordExtensionType.MAJOR, component: ChordComponent.SEVENTH, }], }); }); }); }); describe('diminished fifth', () => { beforeEach(() => { chord.push(6); }); describe('minor seventh', () => { beforeEach(() => { chord.push(10); }); it('describes dominant seventh lowered fifth chord', () => { expect(analyzeIntervals(chord)).toEqual({ base: ChordBase.MAJOR, modifications: [{ type: ChordModificationType.LOWERED, component: ChordComponent.FIFTH, }], extensions: [{ type: ChordExtensionType.DOMINANT, component: ChordComponent.SEVENTH, }], }); }); }); describe('major seventh', () => { beforeEach(() => { chord.push(11); }); it('describes major seventh lowered fifth chord', () => { expect(analyzeIntervals(chord)).toEqual({ base: ChordBase.MAJOR, modifications: [{ type: ChordModificationType.LOWERED, component: ChordComponent.FIFTH, }], extensions: [{ type: ChordExtensionType.MAJOR, component: ChordComponent.SEVENTH, }], }); }); }); }); describe('augmented fifth', () => { beforeEach(() => { chord.push(8); }); it('determines augmented chord', () => { expect(analyzeIntervals(chord)).toEqual({ base: ChordBase.AUGMENTED, }); }); describe('minor seventh', () => { beforeEach(() => { chord.push(10); }); it('describes augmented dominant seventh chord', () => { expect(analyzeIntervals(chord)).toEqual({ base: ChordBase.AUGMENTED, extensions: [{ type: ChordExtensionType.DOMINANT, component: ChordComponent.SEVENTH, }], }); }); }); describe('major seventh', () => { beforeEach(() => { chord.push(11); }); it('describes augmented major seventh chord', () => { expect(analyzeIntervals(chord)).toEqual({ base: ChordBase.AUGMENTED, extensions: [{ type: ChordExtensionType.MAJOR, component: ChordComponent.SEVENTH, }], }); }); }); }); }); describe('minor third', () => { beforeEach(() => { chord.push(3); }); describe('perfect fifth', () => { beforeEach(() => { chord.push(7); }); it('determines minor chord', () => { expect(analyzeIntervals(chord)).toEqual({ base: ChordBase.MINOR, }); }); describe('major sixth', () => { beforeEach(() => { chord.push(9); }); it('describes minor sixth chord', () => { expect(analyzeIntervals(chord)).toEqual({ base: ChordBase.MINOR, extensions: [{ type: ChordExtensionType.MAJOR, component: ChordComponent.SIXTH, }], }); }); }); describe('minor seventh', () => { beforeEach(() => { chord.push(10); }); it('describes minor seventh chord', () => { expect(analyzeIntervals(chord)).toEqual({ base: ChordBase.MINOR, extensions: [{ type: ChordExtensionType.DOMINANT, component: ChordComponent.SEVENTH, }], }); }); }); describe('major seventh', () => { beforeEach(() => { chord.push(11); }); it('describes minor major seventh chord', () => { expect(analyzeIntervals(chord)).toEqual({ base: ChordBase.MINOR, extensions: [{ type: ChordExtensionType.MAJOR, component: ChordComponent.SEVENTH, }], }); }); }); }); describe('diminished fifth', () => { beforeEach(() => { chord.push(6); }); it('determines diminished chord', () => { expect(analyzeIntervals(chord)).toEqual({ base: ChordBase.DIMINISHED, }); }); describe('diminished seventh', () => { beforeEach(() => { chord.push(9); }); it('describes diminished seventh chord', () => { expect(analyzeIntervals(chord)).toEqual({ base: ChordBase.DIMINISHED, extensions: [{ type: ChordExtensionType.DIMINISHED, component: ChordComponent.SEVENTH, }], }); }); }); describe('minor seventh', () => { beforeEach(() => { chord.push(10); }); it('describes diminished dominant seventh (half-diminished) chord', () => { expect(analyzeIntervals(chord)).toEqual({ base: ChordBase.DIMINISHED, extensions: [{ type: ChordExtensionType.DOMINANT, component: ChordComponent.SEVENTH, }], }); }); }); describe('major seventh', () => { beforeEach(() => { chord.push(11); }); it('describes diminished major seventh chord', () => { expect(analyzeIntervals(chord)).toEqual({ base: ChordBase.DIMINISHED, extensions: [{ type: ChordExtensionType.MAJOR, component: ChordComponent.SEVENTH, }], }); }); }); }); }); }); }); describe('extensions', () => { it('analyzes complete ninth chords', () => { expect(analyzeIntervals([0, 4, 7, 10, 14])).toEqual({ base: ChordBase.MAJOR, extensions: [ { type: ChordExtensionType.DOMINANT, component: ChordComponent.SEVENTH, }, { type: ChordExtensionType.MAJOR, component: ChordComponent.NINTH, }, ], }); }); it('analyzes incomplete ninth chords', () => { expect(analyzeIntervals([0, 4, 7, 14])).toEqual({ base: ChordBase.MAJOR, extensions: [ { type: ChordExtensionType.MAJOR, component: ChordComponent.NINTH, }, ], omissions: [ChordComponent.SEVENTH], }); expect(analyzeIntervals([0, 4, 14])).toEqual({ base: ChordBase.MAJOR, extensions: [ { type: ChordExtensionType.MAJOR, component: ChordComponent.NINTH, }, ], omissions: [ChordComponent.FIFTH, ChordComponent.SEVENTH], }); }); }); describe('naming', () => { it('names major chords', () => { expect(getChordName(analyzeIntervals([0, 4, 7]))).toBe(''); }); it('names minor chords', () => { expect(getChordName(analyzeIntervals([0, 3, 7]))).toBe('minor'); }); it('names augmented chords', () => { expect(getChordName(analyzeIntervals([0, 4, 8]))).toBe('augmented'); }); it('names diminished chords', () => { expect(getChordName(analyzeIntervals([0, 3, 6]))).toBe('diminished'); }); it('names major seventh chords', () => { expect(getChordName(analyzeIntervals([0, 4, 7, 11]))).toBe('major seventh'); }); it('names minor seventh chords', () => { expect(getChordName(analyzeIntervals([0, 3, 7, 10]))).toBe('minor seventh'); }); it('names dominant seventh chords', () => { expect(getChordName(analyzeIntervals([0, 4, 7, 10]))).toBe('seventh'); }); it('names major ninth chords', () => { expect(getChordName(analyzeIntervals([0, 4, 7, 11, 14]))).toBe('major seventh ninth'); }); it('names minor ninth chords', () => { expect(getChordName(analyzeIntervals([0, 3, 7, 10, 14]))).toBe('minor seventh ninth'); }); it('names dominant ninth chords', () => { expect(getChordName(analyzeIntervals([0, 4, 7, 10, 14]))).toBe('seventh ninth'); }); it('names major eleventh chords', () => { expect(getChordName(analyzeIntervals([0, 4, 7, 11, 14, 18]))).toBe('major seventh ninth eleventh'); }); it('names minor eleventh chords', () => { expect(getChordName(analyzeIntervals([0, 3, 7, 10, 14, 18]))).toBe('minor seventh ninth eleventh'); }); it('names dominant eleventh chords', () => { expect(getChordName(analyzeIntervals([0, 4, 7, 10, 14, 18]))).toBe('seventh ninth eleventh'); }); it('names major thirteenth chords', () => { expect(getChordName(analyzeIntervals([0, 4, 7, 11, 14, 18, 21]))).toBe('major seventh ninth eleventh thirteenth'); }); it('names minor thirteenth chords', () => { expect(getChordName(analyzeIntervals([0, 3, 7, 10, 14, 18, 21]))).toBe('minor seventh ninth eleventh thirteenth'); }); it('names dominant thirteenth chords', () => { expect(getChordName(analyzeIntervals([0, 4, 7, 10, 14, 18, 21]))).toBe('seventh ninth eleventh thirteenth'); }); }); });