import { Note } from "./Note" ; export class Chord { static readonly chordTypeSymbols : any = { "Major Triad" : "" , "Minor Triad" : "m" , "Augmented Triad" : "+" , "Diminished Triad" : "<sup>o</sup>" , "Dominant Seventh" : "<sup>7</sup>" , "Major Seventh" : "maj<sup>7</sup>" , "Minor Seventh" : "min<sup>7</sup>" , "Diminished Seventh" : "<sup>o7</sup>" , "Half Diminished Seventh" : "<sup>ø7</sup>" , "Augmented Seventh" : "+<sup>7</sup>" , "Augmented Major Seventh" : "+<sup>M7</sup>" , "Dominant Ninth" : "<sup>9</sup>" , "Dominant Eleventh" : "<sup>11</sup>" , "Dominant Thirteenth" : "<sup>13</sup>" , "Seventh Augmented Fifth" : "<sup>7♯5</sup>" , "Seventh Minor Ninth" : "<sup>7♭9</sup>" , "Seventh Sharp Ninth" : "<sup>7♯9</sup>" } ; static readonly chordFamilies : any = { "Triads" : { "Major Triad" : [ 0 , 4 , 7 ] , "Minor Triad" : [ 0 , 3 , 7 ] , "Augmented Triad" : [ 0 , 4 , 8 ] , "Diminished Triad" : [ 0 , 3 , 6 ] } , "Sevenths" : { "Dominant Seventh" : [ 0 , 4 , 7 , 10 ] , "Major Seventh" : [ 0 , 4 , 7 , 11 ] , "Minor Seventh" : [ 0 , 3 , 7 , 10 ] , "Diminished Seventh" : [ 0 , 3 , 6 , 9 ] , "Half Diminished Seventh" : [ 0 , 3 , 6 , 10 ] , "Augmented Seventh" : [ 0 , 4 , 8 , 10 ] , "Augmented Major Seventh" : [ 0 , 4 , 8 , 11 ] } , "Extended" : { "Dominant Ninth" : [ 0 , 4 , 7 , 10 , 14 ] , "Dominant Eleventh" : [ 0 , 4 , 7 , 10 , 14 , 16 ] , "Dominant Thirteenth" : [ 0 , 4 , 7 , 10 , 14 , 16 , 20 ] } , "Altered" : { "Seventh Augmented Fifth" : [ 0 , 4 , 8 , 10 ] , "Seventh Minor Ninth" : [ 0 , 4 , 7 , 10 , 13 ] , "Seventh Sharp Ninth" : [ 0 , 4 , 7 , 10 , 15 ] } } ; static readonly letters = [ "A" , "B" , "C" , "D" , "E" , "F" , "G" ] ; public type : string ; public family : string ; public inversionNum : number ; public rootKeyNum : number ; constructor ( rootKeyNum = 48 , type = "Major Triad" , family = "Triads" , inversionNum = 0 ) { this . type = type ; this . rootKeyNum = rootKeyNum ; this . family = family ; this . inversionNum = inversionNum ; } returns public getNotes ( ) { const halfSteps = Chord . chordFamilies [ this . family ] [ this . type ] . slice ( 0 ) ; if ( halfSteps == null ) { throw new Error ( "Cannot get the half steps" ) ; } for ( let i = 0 ; i < this . inversionNum ; i ++ ) { halfSteps [ i ] += 12 ; } let notes = [ ] ; for ( let halfStep of halfSteps ) { const curKeyNum = this . rootKeyNum + halfStep ; const curNote = Note . toNoteName ( curKeyNum ) ; notes . push ( curNote ) ; } return notes ; } param family param type returns static getLen ( family , type ) { const halfSteps = Chord . chordFamilies [ family ] [ type ] . slice ( 0 ) ; if ( halfSteps == [ ] ) { throw new Error ( "Cannot get the half steps" ) ; } else { return halfSteps . length ; } } /**
     * Overwrite toString method
     */ public toString ( ) { const notes = this . getNotes ( ) ; return notes . toString ( ) ; } /**
     * Get the chord name to place in the chord inversion symbol
     */ public getChordName ( ) { const typeSymbol = Chord . chordTypeSymbols [ this . type ] ; let chroma = Note . toChroma ( this . rootKeyNum ) ; const inversionSymbol = this . _getInversionSymbol ( ) ; if ( chroma . indexOf ( "#" ) > - 1 ) { chroma = chroma . replace ( "#" , "♯" ) ; } return `${ chroma }${ typeSymbol }${ inversionSymbol }` ; } private private _getHalfSteps ( ) { const halfSteps = Chord . chordFamilies [ this . family ] [ this . type ] . slice ( 0 ) ; if ( halfSteps == null ) { throw new Error ( "Cannot get the half steps" ) ; } return halfSteps ; } private private _getInversionSymbol ( ) { if ( this . inversionNum == 0 ) { return "" ; } const halfSteps = this . _getHalfSteps ( ) ; const rootKeyNum = this . rootKeyNum ; const rootKeyName = Note . toNoteName ( rootKeyNum ) ; const rootNoteLetter = rootKeyName [ 0 ] ; const rootNoteLetterIndex = Chord . letters . indexOf ( rootNoteLetter ) ; const inversionLetter = Chord . letters [ ( rootNoteLetterIndex + 2 * this . inversionNum ) % 7 ] ; const chromaIDOfLetter = Note . chromas . indexOf ( inversionLetter ) ; const idOfPlayed = rootKeyNum + halfSteps [ this . inversionNum ] ; const nameOfPlayed = Note . toNoteName ( idOfPlayed ) ; const shortNameOfPlayed = nameOfPlayed . substring ( 0 , nameOfPlayed . length - 1 ) ; const chromaIDOfPlayed = Note . chromas . indexOf ( shortNameOfPlayed ) ; let inversionSymbol = inversionLetter ; switch ( ( chromaIDOfLetter - chromaIDOfPlayed ) % Note . chromas . length ) { case - 2 : inversionSymbol = inversionLetter + "♯♯" ; break ; case - 1 : inversionSymbol = inversionLetter + "♯" ; break ; case 0 : inversionSymbol = inversionLetter ; break ; case 1 : inversionSymbol = inversionLetter + "♭" ; break ; case 2 : inversionSymbol = inversionLetter + "♭♭" ; break ; } return `/${ inversionSymbol }` ; } }