import { ITransposeCalculator } from "../../MusicalScore/Interfaces" ; import { Pitch , NoteEnum , AccidentalEnum } from "../../Common/DataObjects" ; import { KeyInstruction } from "../../MusicalScore/VoiceData/Instructions" ; /** Calculates transposition of individual notes and keys,
 * which is used by multiple OSMD classes to transpose the whole sheet.
 * Note: This class may not look like much, but a lot of thought has gone into the algorithms,
 * and the exact usage within OSMD classes. */ export class TransposeCalculator implements ITransposeCalculator { private static keyMapping : number [ ] = [ 0 , - 5 , 2 , - 3 , 4 , - 1 , 6 , 1 , - 4 , 3 , - 2 , 5 ] ; private static noteEnums : NoteEnum [ ] = [ NoteEnum . C , NoteEnum . D , NoteEnum . E , NoteEnum . F , NoteEnum . G , NoteEnum . A , NoteEnum . B ] ; public transposePitch ( pitch , currentKeyInstruction , halftones ) { let transposedFundamentalNote = NoteEnum . C ; let transposedOctave = 0 ; let transposedAccidental = AccidentalEnum . NONE ; const result = Pitch . CalculateTransposedHalfTone ( pitch , halftones ) ; let transposedHalfTone = result . halftone ; let octaveChange = result . overflow ; for ( let i = 0 ; i < TransposeCalculator . noteEnums . length ; i ++ ) { const currentValue = < number > TransposeCalculator . noteEnums [ i ] ; if ( currentValue === transposedHalfTone ) { const noteIndex = i ; transposedFundamentalNote = TransposeCalculator . noteEnums [ noteIndex ] ; transposedOctave = < number > ( pitch . Octave + octaveChange ) ; transposedAccidental = AccidentalEnum . NONE ; return new Pitch ( transposedFundamentalNote , transposedOctave , transposedAccidental ) ; } else if ( currentValue > transposedHalfTone ) { break ; } } for ( let i = 0 ; i < TransposeCalculator . noteEnums . length ; i ++ ) { const currentValue = < number > TransposeCalculator . noteEnums [ i ] ; if ( currentValue > transposedHalfTone ) { let noteIndex = i ; const accidentalHalfTones = Pitch . HalfTonesFromAccidental ( pitch . Accidental ) ; if ( accidentalHalfTones > 0 || ( accidentalHalfTones === 0 && currentKeyInstruction . Key >= 0 ) ) { noteIndex -- ; } while ( noteIndex < 0 ) { noteIndex += 7 ; transposedHalfTone += 12 ; octaveChange -- ; } while ( noteIndex >= 7 ) { noteIndex -= 7 ; transposedHalfTone -= 12 ; octaveChange ++ ; } transposedFundamentalNote = TransposeCalculator . noteEnums [ noteIndex ] ; transposedAccidental = Pitch . AccidentalFromHalfTones ( transposedHalfTone - < number > transposedFundamentalNote ) ; transposedOctave = < number > ( pitch . Octave + octaveChange ) ; break ; } } const transposedPitch = new Pitch ( transposedFundamentalNote , transposedOctave , transposedAccidental ) ; return transposedPitch ; } public transposeKey ( keyInstruction , transpose ) { let currentIndex = 0 ; let previousKeyType = 0 ; for ( ; currentIndex < TransposeCalculator . keyMapping . length ; currentIndex ++ ) { previousKeyType = TransposeCalculator . keyMapping [ currentIndex ] ; if ( previousKeyType === keyInstruction . keyTypeOriginal ) { break ; } } let newIndex = ( currentIndex + transpose ) ; while ( newIndex >= 12 ) { newIndex -= 12 ; } while ( newIndex < 0 ) { newIndex += 12 ; } keyInstruction . Key = TransposeCalculator . keyMapping [ newIndex ] ; keyInstruction . isTransposedBy = transpose ; } }