import { Fraction } from "../../Common/DataObjects/Fraction" ; import { Voice } from "./Voice" ; import { SourceStaffEntry } from "./SourceStaffEntry" ; import { Note } from "./Note" ; import { Pitch } from "../../Common/DataObjects/Pitch" ; import { LyricsEntry } from "./Lyrics/LyricsEntry" ; import { TechnicalInstruction } from "./Instructions/TechnicalInstruction" ; import { OrnamentContainer } from "./OrnamentContainer" ; import { KeyInstruction } from "./Instructions/KeyInstruction" ; import { OrnamentEnum } from "./OrnamentContainer" ; import { AccidentalEnum } from "../../Common/DataObjects/Pitch" ; import { Dictionary } from "typescript-collections" ; import { Arpeggio } from "./Arpeggio" ; import { SourceMeasure } from "./SourceMeasure" ; import { Articulation } from "./Articulation" ; /**
 * A [[VoiceEntry]] contains the notes in a voice at a timestamp.
 */ export class VoiceEntry { param timestamp param parentVoice param parentSourceStaffEntry param isGrace param graceNoteSlash constructor ( timestamp , parentVoice , parentSourceStaffEntry , isGrace = false , graceNoteSlash = false , graceSlur = false ) { this . timestamp = timestamp ; this . parentVoice = parentVoice ; this . parentSourceStaffEntry = parentSourceStaffEntry ; this . isGrace = isGrace ; this . graceAfterMainNote = false ; this . graceNoteSlash = graceNoteSlash ; this . graceSlur = graceSlur ; if ( parentSourceStaffEntry !== undefined ) { const list = parentSourceStaffEntry . VoiceEntries ; if ( list . indexOf ( this ) === - 1 ) { list . push ( this ) ; } } } private parentVoice : Voice ; private parentSourceStaffEntry : SourceStaffEntry ; private timestamp : Fraction ; private notes : Note [ ] = [ ] ; private isGrace : boolean ; /** States whether the grace notes come after a main note (at end of measure). */ private graceAfterMainNote : boolean ; private graceNoteSlash : boolean ; private graceSlur : boolean ; private articulations : Articulation [ ] = [ ] ; private technicalInstructions : TechnicalInstruction [ ] = [ ] ; private lyricsEntries : Dictionary < number , LyricsEntry > = new Dictionary < number , LyricsEntry > ( ) ; /** The Arpeggio consisting of this VoiceEntry's notes. Undefined if no arpeggio exists. */ private arpeggio : Arpeggio ; private ornamentContainer : OrnamentContainer ; private wantedStemDirection : StemDirectionType = StemDirectionType . Undefined ; /** Stem direction specified in the xml stem element. */ private stemDirectionXml : StemDirectionType = StemDirectionType . Undefined ; private stemDirection : StemDirectionType = StemDirectionType . Undefined ; /** Color of the stem given in XML. RGB Hexadecimal, like #00FF00. */ private stemColorXml : string ; /** Color of the stem currently set. RGB Hexadecimal, like #00FF00. */ private stemColor : string ; public get ParentSourceStaffEntry ( ) : SourceStaffEntry { return this . parentSourceStaffEntry ; } public get ParentVoice ( ) : Voice { return this . parentVoice ; } public get Timestamp ( ) : Fraction { return this . timestamp ; } public set Timestamp ( value ) { this . timestamp = value ; } public get Notes ( ) : Note [ ] { return this . notes ; } public get IsGrace ( ) : boolean { return this . isGrace ; } public set IsGrace ( value ) { this . isGrace = value ; } public get GraceAfterMainNote ( ) : boolean { return this . graceAfterMainNote ; } public set GraceAfterMainNote ( value ) { this . graceAfterMainNote = value ; } public get GraceNoteSlash ( ) : boolean { return this . graceNoteSlash ; } public set GraceNoteSlash ( value ) { this . graceNoteSlash = value ; } public get GraceSlur ( ) : boolean { return this . graceSlur ; } public set GraceSlur ( value ) { this . graceSlur = value ; } public get Articulations ( ) : Articulation [ ] { return this . articulations ; } public get TechnicalInstructions ( ) : TechnicalInstruction [ ] { return this . technicalInstructions ; } public get LyricsEntries ( ) : Dictionary < number , LyricsEntry > { return this . lyricsEntries ; } public get Arpeggio ( ) : Arpeggio { return this . arpeggio ; } public set Arpeggio ( value ) { this . arpeggio = value ; } public get OrnamentContainer ( ) : OrnamentContainer { return this . ornamentContainer ; } public set OrnamentContainer ( value ) { this . ornamentContainer = value ; } public set WantedStemDirection ( value ) { this . wantedStemDirection = value ; } public get WantedStemDirection ( ) : StemDirectionType { return this . wantedStemDirection ; } public set StemDirectionXml ( value ) { this . stemDirectionXml = value ; } public get StemDirectionXml ( ) : StemDirectionType { return this . stemDirectionXml ; } public set StemDirection ( value ) { this . stemDirection = value ; } public get StemDirection ( ) : StemDirectionType { return this . stemDirection ; } public get StemColorXml ( ) : string { return this . stemColorXml ; } public set StemColorXml ( value ) { this . stemColorXml = value ; } public get StemColor ( ) : string { return this . stemColor ; } public set StemColor ( value ) { this . stemColor = value ; } public hasArticulation ( articulation ) { for ( const existingArticulation of this . articulations ) { if ( existingArticulation . Equals ( articulation ) ) { return true ; } } return false ; } public static isSupportedArticulation ( articulation ) { switch ( articulation ) { case ArticulationEnum . accent : case ArticulationEnum . strongaccent : case ArticulationEnum . invertedstrongaccent : case ArticulationEnum . staccato : case ArticulationEnum . staccatissimo : case ArticulationEnum . spiccato : case ArticulationEnum . tenuto : case ArticulationEnum . fermata : case ArticulationEnum . invertedfermata : case ArticulationEnum . breathmark : case ArticulationEnum . caesura : case ArticulationEnum . lefthandpizzicato : case ArticulationEnum . naturalharmonic : case ArticulationEnum . snappizzicato : case ArticulationEnum . upbow : case ArticulationEnum . downbow : case ArticulationEnum . bend : return true ; default : return false ; } } public hasTie ( ) { for ( let idx = 0 , len = this . Notes . length ; idx < len ; ++ idx ) { const note = this . Notes [ idx ] ; if ( note . NoteTie ) { return true ; } } return false ; } public hasSlur ( ) { for ( let idx = 0 , len = this . Notes . length ; idx < len ; ++ idx ) { const note = this . Notes [ idx ] ; if ( note . NoteSlurs . length > 0 ) { return true ; } } return false ; } public isStaccato ( ) { for ( const articulation of this . Articulations ) { if ( articulation . articulationEnum === ArticulationEnum . staccato ) { return true ; } } return false ; } public isAccent ( ) { for ( const articulation of this . Articulations ) { if ( articulation . articulationEnum === ArticulationEnum . accent || articulation . articulationEnum === ArticulationEnum . strongaccent ) { return true ; } } return false ; } public getVerseNumberForLyricEntry ( lyricsEntry ) { let verseNumber = 1 ; this . lyricsEntries . forEach ( ( key , value ) : void => { if ( lyricsEntry === value ) { verseNumber = key ; } } ) ; return verseNumber ; } public createVoiceEntriesForOrnament ( voiceEntryWithOrnament , activeKey ) { if ( ! voiceEntryWithOrnament ) { voiceEntryWithOrnament = this ; } const voiceEntries = [ ] ; if ( ! voiceEntryWithOrnament . ornamentContainer ) { return ; } const baseNote = this . notes [ 0 ] ; const baselength = baseNote . Length ; const baseVoice = voiceEntryWithOrnament . ParentVoice ; const baseTimestamp = voiceEntryWithOrnament . Timestamp ; let currentTimestamp = Fraction . createFromFraction ( baseTimestamp ) ; switch ( voiceEntryWithOrnament . ornamentContainer . GetOrnament ) { case OrnamentEnum . Trill : { const length = new Fraction ( baselength . Numerator , baselength . Denominator * 8 ) ; const higherPitch = baseNote . Pitch . getTransposedPitch ( 1 ) ; let alteration = activeKey . getAlterationForPitch ( higherPitch ) ; if ( voiceEntryWithOrnament . OrnamentContainer . AccidentalAbove !== AccidentalEnum . NONE ) { alteration = voiceEntryWithOrnament . ornamentContainer . AccidentalAbove ; } for ( let i = 0 ; i < 8 ; i ++ ) { currentTimestamp = Fraction . plus ( baseTimestamp , new Fraction ( i * length . Numerator , length . Denominator ) ) ; if ( ( i % 2 ) === 0 ) { this . createBaseVoiceEntry ( currentTimestamp , length , baseVoice , baseNote , voiceEntries ) ; } else { this . createAlteratedVoiceEntry ( currentTimestamp , length , baseVoice , baseNote . SourceMeasure , higherPitch , alteration , voiceEntries ) ; } } break ; } case OrnamentEnum . Turn : { const length = new Fraction ( baselength . Numerator , baselength . Denominator * 4 ) ; const lowerPitch = baseNote . Pitch . getTransposedPitch ( - 1 ) ; const lowerAlteration = activeKey . getAlterationForPitch ( lowerPitch ) ; const higherPitch = baseNote . Pitch . getTransposedPitch ( 1 ) ; const higherAlteration = activeKey . getAlterationForPitch ( higherPitch ) ; this . createAlteratedVoiceEntry ( currentTimestamp , length , baseVoice , baseNote . SourceMeasure , higherPitch , higherAlteration , voiceEntries ) ; currentTimestamp . Add ( length ) ; this . createBaseVoiceEntry ( currentTimestamp , length , baseVoice , baseNote , voiceEntries ) ; currentTimestamp . Add ( length ) ; this . createAlteratedVoiceEntry ( currentTimestamp , length , baseVoice , baseNote . SourceMeasure , lowerPitch , lowerAlteration , voiceEntries ) ; currentTimestamp . Add ( length ) ; this . createBaseVoiceEntry ( currentTimestamp , length , baseVoice , baseNote , voiceEntries ) ; break ; } case OrnamentEnum . InvertedTurn : { const length = new Fraction ( baselength . Numerator , baselength . Denominator * 4 ) ; const lowerPitch = baseNote . Pitch . getTransposedPitch ( - 1 ) ; const lowerAlteration = activeKey . getAlterationForPitch ( lowerPitch ) ; const higherPitch = baseNote . Pitch . getTransposedPitch ( 1 ) ; const higherAlteration = activeKey . getAlterationForPitch ( higherPitch ) ; this . createAlteratedVoiceEntry ( currentTimestamp , length , baseVoice , baseNote . SourceMeasure , lowerPitch , lowerAlteration , voiceEntries ) ; currentTimestamp . Add ( length ) ; this . createBaseVoiceEntry ( currentTimestamp , length , baseVoice , baseNote , voiceEntries ) ; currentTimestamp . Add ( length ) ; this . createAlteratedVoiceEntry ( currentTimestamp , length , baseVoice , baseNote . SourceMeasure , higherPitch , higherAlteration , voiceEntries ) ; currentTimestamp . Add ( length ) ; this . createBaseVoiceEntry ( currentTimestamp , length , baseVoice , baseNote , voiceEntries ) ; break ; } case OrnamentEnum . DelayedTurn : { const length = new Fraction ( baselength . Numerator , baselength . Denominator * 2 ) ; const lowerPitch = baseNote . Pitch . getTransposedPitch ( - 1 ) ; const lowerAlteration = activeKey . getAlterationForPitch ( lowerPitch ) ; const higherPitch = baseNote . Pitch . getTransposedPitch ( 1 ) ; const higherAlteration = activeKey . getAlterationForPitch ( higherPitch ) ; this . createBaseVoiceEntry ( currentTimestamp , length , baseVoice , baseNote , voiceEntries ) ; currentTimestamp = Fraction . plus ( baseTimestamp , length ) ; length . Denominator = baselength . Denominator * 8 ; this . createAlteratedVoiceEntry ( currentTimestamp , length , baseVoice , baseNote . SourceMeasure , higherPitch , higherAlteration , voiceEntries ) ; currentTimestamp . Add ( length ) ; this . createBaseVoiceEntry ( currentTimestamp , length , baseVoice , baseNote , voiceEntries ) ; currentTimestamp . Add ( length ) ; this . createAlteratedVoiceEntry ( currentTimestamp , length , baseVoice , baseNote . SourceMeasure , lowerPitch , lowerAlteration , voiceEntries ) ; currentTimestamp . Add ( length ) ; this . createBaseVoiceEntry ( currentTimestamp , length , baseVoice , baseNote , voiceEntries ) ; break ; } case OrnamentEnum . DelayedInvertedTurn : { const length = new Fraction ( baselength . Numerator , baselength . Denominator * 2 ) ; const lowerPitch = baseNote . Pitch . getTransposedPitch ( - 1 ) ; const lowerAlteration = activeKey . getAlterationForPitch ( lowerPitch ) ; const higherPitch = baseNote . Pitch . getTransposedPitch ( 1 ) ; const higherAlteration = activeKey . getAlterationForPitch ( higherPitch ) ; this . createBaseVoiceEntry ( currentTimestamp , length , baseVoice , baseNote , voiceEntries ) ; currentTimestamp = Fraction . plus ( baseTimestamp , length ) ; length . Denominator = baselength . Denominator * 8 ; this . createAlteratedVoiceEntry ( currentTimestamp , length , baseVoice , baseNote . SourceMeasure , lowerPitch , lowerAlteration , voiceEntries ) ; currentTimestamp . Add ( length ) ; this . createBaseVoiceEntry ( currentTimestamp , length , baseVoice , baseNote , voiceEntries ) ; currentTimestamp . Add ( length ) ; this . createAlteratedVoiceEntry ( currentTimestamp , length , baseVoice , baseNote . SourceMeasure , higherPitch , higherAlteration , voiceEntries ) ; currentTimestamp . Add ( length ) ; this . createBaseVoiceEntry ( currentTimestamp , length , baseVoice , baseNote , voiceEntries ) ; break ; } case OrnamentEnum . Mordent : { const length = new Fraction ( baselength . Numerator , baselength . Denominator * 4 ) ; const higherPitch = baseNote . Pitch . getTransposedPitch ( 1 ) ; const alteration = activeKey . getAlterationForPitch ( higherPitch ) ; this . createBaseVoiceEntry ( currentTimestamp , length , baseVoice , baseNote , voiceEntries ) ; currentTimestamp . Add ( length ) ; this . createAlteratedVoiceEntry ( currentTimestamp , length , baseVoice , baseNote . SourceMeasure , higherPitch , alteration , voiceEntries ) ; length . Denominator = baselength . Denominator * 2 ; currentTimestamp = Fraction . plus ( baseTimestamp , length ) ; this . createBaseVoiceEntry ( currentTimestamp , length , baseVoice , baseNote , voiceEntries ) ; break ; } case OrnamentEnum . InvertedMordent : { const length = new Fraction ( baselength . Numerator , baselength . Denominator * 4 ) ; const lowerPitch = baseNote . Pitch . getTransposedPitch ( - 1 ) ; const alteration = activeKey . getAlterationForPitch ( lowerPitch ) ; this . createBaseVoiceEntry ( currentTimestamp , length , baseVoice , baseNote , voiceEntries ) ; currentTimestamp . Add ( length ) ; this . createAlteratedVoiceEntry ( currentTimestamp , length , baseVoice , baseNote . SourceMeasure , lowerPitch , alteration , voiceEntries ) ; length . Denominator = baselength . Denominator * 2 ; currentTimestamp = Fraction . plus ( baseTimestamp , length ) ; this . createBaseVoiceEntry ( currentTimestamp , length , baseVoice , baseNote , voiceEntries ) ; break ; } default : throw new RangeError ( ) ; } return voiceEntries ; } private createBaseVoiceEntry ( currentTimestamp , length , baseVoice , baseNote , voiceEntries ) { const voiceEntry = new VoiceEntry ( currentTimestamp , baseVoice , baseNote . ParentStaffEntry ) ; const pitch = new Pitch ( baseNote . Pitch . FundamentalNote , baseNote . Pitch . Octave , baseNote . Pitch . Accidental ) ; const note = new Note ( voiceEntry , undefined , length , pitch , baseNote . SourceMeasure ) ; voiceEntry . Notes . push ( note ) ; voiceEntries . push ( voiceEntry ) ; } private createAlteratedVoiceEntry ( currentTimestamp , length , baseVoice , sourceMeasure , higherPitch , alteration , voiceEntries ) { const voiceEntry = new VoiceEntry ( currentTimestamp , baseVoice , undefined ) ; const pitch = new Pitch ( higherPitch . FundamentalNote , higherPitch . Octave , alteration ) ; const note = new Note ( voiceEntry , undefined , length , pitch , sourceMeasure ) ; voiceEntry . Notes . push ( note ) ; voiceEntries . push ( voiceEntry ) ; } } export enum ArticulationEnum { accent , strongaccent , marcatoup , marcatodown , invertedstrongaccent , staccato , staccatissimo , spiccato , tenuto , fermata , invertedfermata , breathmark , caesura , lefthandpizzicato , naturalharmonic , snappizzicato , upbow , downbow , scoop , plop , doit , falloff , stress , unstress , detachedlegato , otherarticulation , bend } export enum StemDirectionType { Undefined = - 1 , Up = 0 , Down = 1 , None = 2 , Double = 3 }