import { Fraction } from "../../Common/DataObjects/Fraction" ; import { Repetition } from "../MusicSource/Repetition" ; import { DynamicsContainer } from "../VoiceData/HelperObjects/DynamicsContainer" ; import { MappingSourceMusicPart } from "../MusicSource/MappingSourceMusicPart" ; import { SourceMeasure } from "../VoiceData/SourceMeasure" ; import { VoiceEntry } from "../VoiceData/VoiceEntry" ; import { Instrument } from "../Instrument" ; import { VerticalSourceStaffEntryContainer } from "../VoiceData/VerticalSourceStaffEntryContainer" ; import { RhythmInstruction } from "../VoiceData/Instructions/RhythmInstruction" ; import { AbstractNotationInstruction } from "../VoiceData/Instructions/AbstractNotationInstruction" ; import { RepetitionInstruction } from "../VoiceData/Instructions/RepetitionInstruction" ; import { ContinuousDynamicExpression } from "../VoiceData/Expressions/ContinuousExpressions/ContinuousDynamicExpression" ; import { InstantaneousDynamicExpression } from "../VoiceData/Expressions/InstantaneousDynamicExpression" ; import { MultiTempoExpression } from "../VoiceData/Expressions/MultiTempoExpression" ; import { AbstractExpression } from "../VoiceData/Expressions/AbstractExpression" ; import log from "loglevel" ; import { MusicSheet } from "../MusicSheet" ; export class MusicPartManagerIterator { constructor ( musicSheet , startTimestamp ? , endTimestamp ? ) { try { this . frontReached = true ; this . musicSheet = musicSheet ; this . currentVoiceEntries = undefined ; this . frontReached = false ; for ( const rep of this . musicSheet . Repetitions ) { this . setRepetitionIterationCount ( rep , 1 ) ; } this . activeDynamicExpressions = new Array ( this . musicSheet . getCompleteNumberOfStaves ( ) ) ; this . currentMeasure = this . musicSheet . SourceMeasures [ 0 ] ; if ( ! startTimestamp ) { return ; } do { this . moveToNext ( ) ; } while ( ( ! this . currentVoiceEntries || this . currentTimeStamp . lt ( startTimestamp ) ) && ! this . endReached ) ; for ( let staffIndex = 0 ; staffIndex < this . activeDynamicExpressions . length ; staffIndex ++ ) { if ( this . activeDynamicExpressions [ staffIndex ] ) { if ( this . activeDynamicExpressions [ staffIndex ] instanceof ContinuousDynamicExpression ) { const continuousDynamic = < ContinuousDynamicExpression > this . activeDynamicExpressions [ staffIndex ] ; this . currentDynamicChangingExpressions . push ( new DynamicsContainer ( continuousDynamic , staffIndex ) ) ; } else { const instantaneousDynamic = < InstantaneousDynamicExpression > this . activeDynamicExpressions [ staffIndex ] ; this . currentDynamicChangingExpressions . push ( new DynamicsContainer ( instantaneousDynamic , staffIndex ) ) ; } } } this . currentTempoChangingExpression = this . activeTempoExpression ; } catch ( err ) { log . info ( "MusicPartManagerIterator: " + err ) ; } } public backJumpOccurred : boolean ; public forwardJumpOccurred : boolean ; private musicSheet : MusicSheet ; private currentMappingPart : MappingSourceMusicPart ; private currentMeasure : SourceMeasure ; private currentMeasureIndex : number = 0 ; private currentPartIndex : number = 0 ; private currentVoiceEntryIndex : number = - 1 ; private currentDynamicEntryIndex : number = 0 ; private currentTempoEntryIndex : number = 0 ; private currentVoiceEntries : VoiceEntry [ ] ; private currentDynamicChangingExpressions : DynamicsContainer [ ] = [ ] ; private currentTempoChangingExpression : MultiTempoExpression ; private repetitionIterationCountDictKeys : Repetition [ ] ; private repetitionIterationCountDictValues : number [ ] ; private currentRepetition : Repetition = undefined ; private endReached : boolean = false ; private frontReached : boolean = false ; public currentTimeStamp : Fraction = new Fraction ( 0 , 1 ) ; private currentEnrolledMeasureTimestamp : Fraction = new Fraction ( 0 , 1 ) ; private currentRelativeInMeasureTimestamp : Fraction = new Fraction ( 0 , 1 ) ; private currentVerticalContainerInMeasureTimestamp : Fraction = new Fraction ( 0 , 1 ) ; private jumpResponsibleRepetition : Repetition = undefined ; private currentBpm : number ; private activeDynamicExpressions : AbstractExpression [ ] = [ ] ; private activeTempoExpression : MultiTempoExpression ; public get EndReached ( ) : boolean { return this . endReached ; } public get FrontReached ( ) : boolean { return this . frontReached ; } public get CurrentMeasure ( ) : SourceMeasure { return this . currentMeasure ; } public get CurrentRepetition ( ) : Repetition { return this . currentRepetition ; } public get CurrentRepetitionIteration ( ) : number { if ( this . CurrentRepetition ) { return this . getRepetitionIterationCount ( this . CurrentRepetition ) ; } return 0 ; } public get CurrentJumpResponsibleRepetitionIterationBeforeJump ( ) : number { if ( this . jumpResponsibleRepetition ) { return this . getRepetitionIterationCount ( this . jumpResponsibleRepetition ) - 1 ; } return 0 ; } public get CurrentBpm ( ) : number { return this . currentBpm ; } public get CurrentVoiceEntries ( ) : VoiceEntry [ ] { return this . currentVoiceEntries ; } public get CurrentMeasureIndex ( ) : number { return this . currentMeasureIndex ; } public get CurrentEnrolledTimestamp ( ) : Fraction { return Fraction . plus ( this . currentEnrolledMeasureTimestamp , this . currentVerticalContainerInMeasureTimestamp ) ; } public get CurrentSourceTimestamp ( ) : Fraction { return this . currentTimeStamp ; } public get CurrentRelativeInMeasureTimestamp ( ) : Fraction { return this . currentRelativeInMeasureTimestamp ; } public get JumpOccurred ( ) : boolean { return this . backJumpOccurred || this . forwardJumpOccurred ; } public get ActiveTempoExpression ( ) : MultiTempoExpression { return this . activeTempoExpression ; } public get ActiveDynamicExpressions ( ) : AbstractExpression [ ] { return this . activeDynamicExpressions ; } public get CurrentTempoChangingExpression ( ) : MultiTempoExpression { return this . currentTempoChangingExpression ; } public get JumpResponsibleRepetition ( ) : Repetition { return this . jumpResponsibleRepetition ; } /**
     * Creates a clone of this iterator which has the same actual position.
     */ public clone ( startTimeStamp = undefined , endTimeStamp = undefined ) { const ret = new MusicPartManagerIterator ( this . musicSheet , startTimeStamp ?? this . currentTimeStamp , endTimeStamp ) ; ret . currentVoiceEntryIndex = this . currentVoiceEntryIndex ; ret . currentMappingPart = this . currentMappingPart ; ret . currentPartIndex = this . currentPartIndex ; ret . currentVoiceEntries = this . currentVoiceEntries ; ret . endReached = this . endReached ; ret . frontReached = this . frontReached ; return ret ; } param instrument public CurrentVisibleVoiceEntries ( instrument ? ) { const voiceEntries = [ ] ; if ( ! this . currentVoiceEntries ) { return voiceEntries ; } if ( instrument ) { for ( const entry of this . currentVoiceEntries ) { if ( entry . ParentVoice . Parent . IdString === instrument . IdString ) { this . getVisibleEntries ( entry , voiceEntries ) ; return voiceEntries ; } } } else { for ( const entry of this . currentVoiceEntries ) { this . getVisibleEntries ( entry , voiceEntries ) ; } } return voiceEntries ; } param instrument public CurrentAudibleVoiceEntries ( instrument ? ) { const voiceEntries = [ ] ; if ( ! this . currentVoiceEntries ) { return voiceEntries ; } if ( instrument ) { for ( const entry of this . currentVoiceEntries ) { if ( entry . ParentVoice . Parent . IdString === instrument . IdString ) { this . getAudibleEntries ( entry , voiceEntries ) ; return voiceEntries ; } } } else { for ( const entry of this . currentVoiceEntries ) { this . getAudibleEntries ( entry , voiceEntries ) ; } } return voiceEntries ; } /**
     * Returns the audible dynamics of the current iterator position.
     * Returns: A List of Dynamics. If there are no entries the List has a Count of 0 (it does not return null).
     */ public getCurrentDynamicChangingExpressions ( ) { return this . currentDynamicChangingExpressions ; } param instrument public CurrentScoreFollowingVoiceEntries ( instrument ? ) { const voiceEntries = [ ] ; if ( ! this . currentVoiceEntries ) { return voiceEntries ; } if ( instrument ) { for ( const entry of this . currentVoiceEntries ) { if ( entry . ParentVoice . Parent . IdString === instrument . IdString ) { this . getScoreFollowingEntries ( entry , voiceEntries ) ; return voiceEntries ; } } } else { for ( const entry of this . currentVoiceEntries ) { this . getScoreFollowingEntries ( entry , voiceEntries ) ; } } return voiceEntries ; } public moveToNext ( ) { this . forwardJumpOccurred = this . backJumpOccurred = false ; if ( this . endReached ) { return ; } if ( this . currentVoiceEntries ) { this . currentVoiceEntries = [ ] ; } this . recursiveMove ( ) ; if ( ! this . currentMeasure ) { this . currentTimeStamp = new Fraction ( 99999 , 1 ) ; } } public moveToNextVisibleVoiceEntry ( notesOnly ) { while ( ! this . endReached ) { this . moveToNext ( ) ; if ( this . checkEntries ( notesOnly ) ) { return ; } } } private resetRepetitionIterationCount ( repetition ) { this . setRepetitionIterationCount ( repetition , 1 ) ; return 1 ; } private incrementRepetitionIterationCount ( repetition ) { if ( this . repetitionIterationCountDictKeys . indexOf ( repetition ) === - 1 ) { return this . setRepetitionIterationCount ( repetition , 1 ) ; } else { return this . setRepetitionIterationCount ( repetition , this . getRepetitionIterationCount ( repetition ) + 1 ) ; } } private setRepetitionIterationCount ( repetition , iterationCount ) { const i = this . repetitionIterationCountDictKeys . indexOf ( repetition ) ; if ( i === - 1 ) { this . repetitionIterationCountDictKeys . push ( repetition ) ; this . repetitionIterationCountDictValues . push ( iterationCount ) ; } else { this . repetitionIterationCountDictValues [ i ] = iterationCount ; } return iterationCount ; } private getRepetitionIterationCount ( rep ) { const i = this . repetitionIterationCountDictKeys . indexOf ( rep ) ; if ( i !== - 1 ) { return this . repetitionIterationCountDictValues [ i ] ; } } private handleRepetitionsAtMeasureBegin ( ) { for ( let idx = 0 , len = this . currentMeasure . FirstRepetitionInstructions . length ; idx < len ; ++ idx ) { const repetitionInstruction = this . currentMeasure . FirstRepetitionInstructions [ idx ] ; if ( ! repetitionInstruction . parentRepetition ) { continue ; } const currentRepetition = repetitionInstruction . parentRepetition ; this . currentRepetition = currentRepetition ; if ( currentRepetition . StartIndex === this . currentMeasureIndex ) { if ( this . JumpResponsibleRepetition !== undefined && currentRepetition !== this . JumpResponsibleRepetition && currentRepetition . StartIndex >= this . JumpResponsibleRepetition . StartIndex && currentRepetition . EndIndex <= this . JumpResponsibleRepetition . EndIndex ) { this . resetRepetitionIterationCount ( currentRepetition ) ; } } } } private handleRepetitionsAtMeasureEnd ( ) { for ( let idx = 0 , len = this . currentMeasure . LastRepetitionInstructions . length ; idx < len ; ++ idx ) { const repetitionInstruction = this . currentMeasure . LastRepetitionInstructions [ idx ] ; const currentRepetition = repetitionInstruction . parentRepetition ; if ( ! currentRepetition ) { continue ; } if ( currentRepetition . BackwardJumpInstructions . indexOf ( repetitionInstruction ) > - 1 ) { if ( this . getRepetitionIterationCount ( currentRepetition ) < currentRepetition . UserNumberOfRepetitions ) { this . doBackJump ( currentRepetition ) ; this . backJumpOccurred = true ; return ; } } if ( repetitionInstruction === currentRepetition . forwardJumpInstruction ) { if ( this . JumpResponsibleRepetition !== undefined && currentRepetition !== this . JumpResponsibleRepetition && currentRepetition . StartIndex >= this . JumpResponsibleRepetition . StartIndex && currentRepetition . EndIndex <= this . JumpResponsibleRepetition . EndIndex ) { this . resetRepetitionIterationCount ( currentRepetition ) ; } const forwardJumpTargetMeasureIndex = currentRepetition . getForwardJumpTargetForIteration ( this . getRepetitionIterationCount ( currentRepetition ) ) ; if ( forwardJumpTargetMeasureIndex >= 0 ) { this . currentMeasureIndex = forwardJumpTargetMeasureIndex ; this . currentMeasure = this . musicSheet . SourceMeasures [ this . currentMeasureIndex ] ; this . currentVoiceEntryIndex = - 1 ; this . jumpResponsibleRepetition = currentRepetition ; this . forwardJumpOccurred = true ; return ; } if ( forwardJumpTargetMeasureIndex === - 2 ) { this . endReached = true ; } } } this . currentMeasureIndex ++ ; if ( this . JumpResponsibleRepetition !== undefined && this . currentMeasureIndex > this . JumpResponsibleRepetition . EndIndex ) { this . jumpResponsibleRepetition = undefined ; } } private doBackJump ( currentRepetition ) { this . currentMeasureIndex = currentRepetition . getBackwardJumpTarget ( ) ; this . currentMeasure = this . musicSheet . SourceMeasures [ this . currentMeasureIndex ] ; this . currentVoiceEntryIndex = - 1 ; this . incrementRepetitionIterationCount ( currentRepetition ) ; this . jumpResponsibleRepetition = currentRepetition ; } private activateCurrentRhythmInstructions ( ) { if ( this . currentMeasure !== undefined && this . currentMeasure . FirstInstructionsStaffEntries . length > 0 && this . currentMeasure . FirstInstructionsStaffEntries [ 0 ] !== undefined ) { const instructions = this . currentMeasure . FirstInstructionsStaffEntries [ 0 ] . Instructions ; for ( let idx = 0 , len = instructions . length ; idx < len ; ++ idx ) { const abstractNotationInstruction = instructions [ idx ] ; if ( abstractNotationInstruction instanceof RhythmInstruction ) { this . musicSheet . SheetPlaybackSetting . rhythm = ( < RhythmInstruction > abstractNotationInstruction ) . Rhythm ; } } } } private activateCurrentDynamicOrTempoInstructions ( ) { const timeSortedDynamics = this . musicSheet . TimestampSortedDynamicExpressionsList ; while ( this . currentDynamicEntryIndex > 0 && ( this . currentDynamicEntryIndex >= timeSortedDynamics . length || this . CurrentSourceTimestamp . lte ( timeSortedDynamics [ this . currentDynamicEntryIndex ] . parMultiExpression ( ) . AbsoluteTimestamp ) ) ) { this . currentDynamicEntryIndex -- ; } while ( this . currentDynamicEntryIndex < timeSortedDynamics . length && timeSortedDynamics [ this . currentDynamicEntryIndex ] . parMultiExpression ( ) . AbsoluteTimestamp . lt ( this . CurrentSourceTimestamp ) ) { this . currentDynamicEntryIndex ++ ; } while ( this . currentDynamicEntryIndex < timeSortedDynamics . length && timeSortedDynamics [ this . currentDynamicEntryIndex ] . parMultiExpression ( ) . AbsoluteTimestamp . Equals ( this . CurrentSourceTimestamp ) ) { const dynamicsContainer = timeSortedDynamics [ this . currentDynamicEntryIndex ] ; const staffIndex = dynamicsContainer . staffNumber ; if ( this . CurrentSourceTimestamp . Equals ( dynamicsContainer . parMultiExpression ( ) . AbsoluteTimestamp ) ) { if ( dynamicsContainer . continuousDynamicExpression ) { this . activeDynamicExpressions [ staffIndex ] = dynamicsContainer . continuousDynamicExpression ; } else if ( dynamicsContainer . instantaneousDynamicExpression ) { this . activeDynamicExpressions [ staffIndex ] = dynamicsContainer . instantaneousDynamicExpression ; } } this . currentDynamicEntryIndex ++ ; } this . currentDynamicChangingExpressions = [ ] ; for ( let staffIndex = 0 ; staffIndex < this . activeDynamicExpressions . length ; staffIndex ++ ) { if ( this . activeDynamicExpressions [ staffIndex ] ) { let startTime ; let endTime ; if ( this . activeDynamicExpressions [ staffIndex ] instanceof ContinuousDynamicExpression ) { const continuousDynamic = < ContinuousDynamicExpression > this . activeDynamicExpressions [ staffIndex ] ; startTime = continuousDynamic . StartMultiExpression . AbsoluteTimestamp ; endTime = continuousDynamic . EndMultiExpression . AbsoluteTimestamp ; if ( startTime . lte ( this . CurrentSourceTimestamp ) && this . CurrentSourceTimestamp . lte ( endTime ) ) { this . currentDynamicChangingExpressions . push ( new DynamicsContainer ( continuousDynamic , staffIndex ) ) ; } } else { const instantaneousDynamic = < InstantaneousDynamicExpression > this . activeDynamicExpressions [ staffIndex ] ; if ( this . CurrentSourceTimestamp . Equals ( instantaneousDynamic . ParentMultiExpression . AbsoluteTimestamp ) ) { this . currentDynamicChangingExpressions . push ( new DynamicsContainer ( instantaneousDynamic , staffIndex ) ) ; } } } } const timeSortedTempoExpressions = this . musicSheet . TimestampSortedTempoExpressionsList ; while ( this . currentTempoEntryIndex > 0 && ( this . currentTempoEntryIndex >= timeSortedTempoExpressions . length || this . CurrentSourceTimestamp . lte ( timeSortedTempoExpressions [ this . currentTempoEntryIndex ] . AbsoluteTimestamp ) ) ) { this . currentTempoEntryIndex -- ; } while ( this . currentTempoEntryIndex < timeSortedTempoExpressions . length && timeSortedTempoExpressions [ this . currentTempoEntryIndex ] . AbsoluteTimestamp . lt ( this . CurrentSourceTimestamp ) ) { this . currentTempoEntryIndex ++ ; } while ( this . currentTempoEntryIndex < timeSortedTempoExpressions . length && timeSortedTempoExpressions [ this . currentTempoEntryIndex ] . AbsoluteTimestamp . Equals ( this . CurrentSourceTimestamp ) ) { this . activeTempoExpression = timeSortedTempoExpressions [ this . currentTempoEntryIndex ] ; this . currentTempoEntryIndex ++ ; } this . currentTempoChangingExpression = undefined ; if ( this . activeTempoExpression ) { let endTime = this . activeTempoExpression . AbsoluteTimestamp ; if ( this . activeTempoExpression . ContinuousTempo ) { endTime = this . activeTempoExpression . ContinuousTempo . AbsoluteEndTimestamp ; } if ( this . activeTempoExpression . AbsoluteTimestamp . lte ( this . CurrentSourceTimestamp ) || this . CurrentSourceTimestamp . lte ( endTime ) ) { this . currentTempoChangingExpression = this . activeTempoExpression ; } } } private recursiveMove ( ) { this . currentVoiceEntryIndex ++ ; if ( this . currentVoiceEntryIndex === 0 ) { this . handleRepetitionsAtMeasureBegin ( ) ; this . activateCurrentRhythmInstructions ( ) ; } if ( this . currentVoiceEntryIndex >= 0 && this . currentVoiceEntryIndex < this . currentMeasure . VerticalSourceStaffEntryContainers . length ) { const currentContainer = this . currentMeasure . VerticalSourceStaffEntryContainers [ this . currentVoiceEntryIndex ] ; this . currentVoiceEntries = this . getVoiceEntries ( currentContainer ) ; this . currentVerticalContainerInMeasureTimestamp = currentContainer . Timestamp ; this . currentTimeStamp = Fraction . plus ( this . currentMeasure . AbsoluteTimestamp , this . currentVerticalContainerInMeasureTimestamp ) ; const selectionEnd = this . musicSheet . SelectionEnd ; if ( selectionEnd && this . currentTimeStamp . gte ( selectionEnd ) ) { this . endReached = true ; } this . activateCurrentDynamicOrTempoInstructions ( ) ; return ; } this . currentEnrolledMeasureTimestamp . Add ( this . currentMeasure . Duration ) ; this . handleRepetitionsAtMeasureEnd ( ) ; if ( this . currentMeasureIndex >= 0 && this . currentMeasureIndex < this . musicSheet . SourceMeasures . length ) { this . currentMeasure = this . musicSheet . SourceMeasures [ this . currentMeasureIndex ] ; this . currentTimeStamp = Fraction . plus ( this . currentMeasure . AbsoluteTimestamp , this . currentVerticalContainerInMeasureTimestamp ) ; this . currentVoiceEntryIndex = - 1 ; this . recursiveMove ( ) ; return ; } this . currentVerticalContainerInMeasureTimestamp = new Fraction ( ) ; this . currentMeasure = undefined ; this . currentVoiceEntries = undefined ; this . endReached = true ; } param notesOnly private checkEntries ( notesOnly ) { const tlist = this . CurrentVisibleVoiceEntries ( ) ; if ( tlist . length > 0 ) { if ( ! notesOnly ) { return true ; } for ( let idx = 0 , len = tlist . length ; idx < len ; ++ idx ) { const entry = tlist [ idx ] ; if ( entry . Notes [ 0 ] . Pitch ) { return true ; } } } return false ; } private getVisibleEntries ( entry , visibleEntries ) { if ( entry . ParentVoice . Visible ) { visibleEntries . push ( entry ) ; } } private getAudibleEntries ( entry , audibleEntries ) { if ( entry . ParentVoice . Audible ) { audibleEntries . push ( entry ) ; } } private getScoreFollowingEntries ( entry , followingEntries ) { if ( entry . ParentVoice . Following && entry . ParentVoice . Parent . Following ) { followingEntries . push ( entry ) ; } } private getVoiceEntries ( container ) { const entries = [ ] ; for ( const sourceStaffEntry of container . StaffEntries ) { if ( ! sourceStaffEntry ) { continue ; } for ( const voiceEntry of sourceStaffEntry . VoiceEntries ) { entries . push ( voiceEntry ) ; } } return entries ; } }