import { Pitch } from "../../Common/DataObjects/Pitch" ; import { KeyInstruction } from "./Instructions/KeyInstruction" ; import { MusicSheetCalculator } from "../Graphical/MusicSheetCalculator" ; import { AccidentalEnum } from "../../Common/DataObjects/Pitch" ; import { EngravingRules } from "../Graphical/EngravingRules" ; export class ChordSymbolContainer { private rootPitch : Pitch ; private chordKind : ChordSymbolEnum ; private bassPitch : Pitch ; private degrees : Degree [ ] ; private rules : EngravingRules ; constructor ( rootPitch , chordKind , bassPitch , chordDegrees , rules ) { this . rootPitch = rootPitch ; this . chordKind = chordKind ; this . bassPitch = bassPitch ; this . degrees = chordDegrees ; this . rules = rules ; } public get RootPitch ( ) : Pitch { return this . rootPitch ; } public get ChordKind ( ) : ChordSymbolEnum { return this . chordKind ; } public get BassPitch ( ) : Pitch { return this . bassPitch ; } public get ChordDegrees ( ) : Degree [ ] { return this . degrees ; } public static calculateChordText ( chordSymbol , transposeHalftones , keyInstruction ) { let transposedRootPitch = chordSymbol . RootPitch ; if ( MusicSheetCalculator . transposeCalculator ) { transposedRootPitch = MusicSheetCalculator . transposeCalculator . transposePitch ( chordSymbol . RootPitch , keyInstruction , transposeHalftones ) ; } if ( chordSymbol . ChordKind === ChordSymbolEnum . none ) { return chordSymbol . getTextFromChordKindEnum ( chordSymbol . ChordKind ) ; } let text = Pitch . getNoteEnumString ( transposedRootPitch . FundamentalNote ) ; if ( transposedRootPitch . Accidental !== AccidentalEnum . NONE ) { text += this . getTextForAccidental ( transposedRootPitch . Accidental ) ; } const degrees = { adds : [ ] , alts : [ ] , subs : [ ] , } ; for ( const chordDegree of chordSymbol . ChordDegrees ) { if ( chordDegree ) { let t = "" ; if ( chordDegree . alteration !== AccidentalEnum . NONE ) { t += this . getTextForAccidental ( chordDegree . alteration ) ; } t += chordDegree . value ; switch ( chordDegree . text ) { case ChordDegreeText . add : degrees . adds . push ( t ) ; break ; case ChordDegreeText . alter : degrees . alts . push ( t ) ; break ; case ChordDegreeText . subtract : degrees . subs . push ( t ) ; break ; default : } } } let chordKind = chordSymbol . getTextFromChordKindEnum ( chordSymbol . ChordKind ) ; const degreeTypeAry = [ "adds" , "alts" , "subs" ] ; const customChords = chordSymbol . rules . CustomChords ; for ( const customChord of customChords ) { if ( customChord . chordKind !== chordSymbol . chordKind ) { continue ; } let hasCustomChordDegrees = true ; for ( const degType of degreeTypeAry ) { for ( const deg of ( customChord . degrees [ degType ] || [ ] ) ) { if ( degrees [ degType ] . indexOf ( deg ) < 0 ) { hasCustomChordDegrees = false ; break ; } } if ( ! hasCustomChordDegrees ) { break ; } } if ( hasCustomChordDegrees ) { for ( const degType of degreeTypeAry ) { for ( const deg of ( customChord . degrees [ degType ] || [ ] ) ) { degrees [ degType ] . splice ( degrees [ degType ] . indexOf ( deg ) , 1 ) ; } } chordKind = customChord . alternateName ; } } text += chordKind ; if ( degrees . adds . length > 0 ) { text += "(" + degrees . adds . join ( "," ) + ")" ; } if ( degrees . alts . length > 0 ) { text += "(alt " + degrees . alts . join ( "," ) + ")" ; } if ( degrees . subs . length > 0 ) { text += "(omit " + degrees . subs . join ( "," ) + ")" ; } if ( chordSymbol . BassPitch ) { let transposedBassPitch = chordSymbol . BassPitch ; if ( MusicSheetCalculator . transposeCalculator ) { transposedBassPitch = MusicSheetCalculator . transposeCalculator . transposePitch ( chordSymbol . BassPitch , keyInstruction , transposeHalftones ) ; } text += "/" ; text += Pitch . getNoteEnumString ( transposedBassPitch . FundamentalNote ) ; text += this . getTextForAccidental ( transposedBassPitch . Accidental ) ; } return text ; } private static getTextForAccidental ( alteration ) { let text = "" ; switch ( alteration ) { case AccidentalEnum . DOUBLEFLAT : text += "bb" ; break ; case AccidentalEnum . FLAT : text += "b" ; break ; case AccidentalEnum . SHARP : text += "#" ; break ; case AccidentalEnum . DOUBLESHARP : text += "x" ; break ; default : } return text ; } private getTextFromChordKindEnum ( kind ) { return this . rules . ChordSymbolLabelTexts . getValue ( kind ) ?? "" ; } } export class Degree { constructor ( value , alteration , text ) { this . value = value ; this . alteration = alteration ; this . text = text ; } public value : number ; public alteration : AccidentalEnum ; public text : ChordDegreeText ; } export interface DegreesInfo { adds ? : string [ ] ; alts ? : string [ ] ; subs ? : string [ ] ; } export class CustomChord { public alternateName : string ; public chordKind : ChordSymbolEnum ; public degrees : DegreesInfo ; constructor ( alternateName , chordKind , degrees ) { this . alternateName = alternateName ; this . chordKind = chordKind ; this . degrees = degrees ; } public static createCustomChord ( altName , chordKind , degrees ) { return new CustomChord ( altName , chordKind , degrees ) ; } public static renameCustomChord ( altName , newAltName , customChords ) { for ( const customChord of customChords ) { if ( customChord . alternateName === altName ) { customChord . alternateName = newAltName ; } } } } export enum ChordDegreeText { add , alter , subtract } export enum ChordSymbolEnum { major , minor , augmented , diminished , dominant , majorseventh , minorseventh , diminishedseventh , augmentedseventh , halfdiminished , majorminor , majorsixth , minorsixth , dominantninth , majorninth , minorninth , dominant11th , major11th , minor11th , dominant13th , major13th , minor13th , suspendedsecond , suspendedfourth , Neapolitan , Italian , French , German , pedal , power , Tristan , none }