import { Fraction } from "../../Common/DataObjects/Fraction" ; import { VerticalSourceStaffEntryContainer } from "./VerticalSourceStaffEntryContainer" ; import { SourceStaffEntry } from "./SourceStaffEntry" ; import { RepetitionInstruction , RepetitionInstructionEnum , AlignmentType } from "./Instructions/RepetitionInstruction" ; import { Staff } from "./Staff" ; import { VoiceEntry } from "./VoiceEntry" ; import { Voice } from "./Voice" ; import { MusicSheet } from "../MusicSheet" ; import { MultiExpression } from "./Expressions/MultiExpression" ; import { MultiTempoExpression } from "./Expressions/MultiTempoExpression" ; import { RehearsalExpression } from "./Expressions/RehearsalExpression" ; import { AbstractNotationInstruction } from "./Instructions/AbstractNotationInstruction" ; import { ClefInstruction } from "./Instructions/ClefInstruction" ; import { KeyInstruction } from "./Instructions/KeyInstruction" ; import { Repetition } from "../MusicSource/Repetition" ; import { SystemLinesEnum } from "../Graphical/SystemLinesEnum" ; import { EngravingRules } from "../Graphical/EngravingRules" ; import { GraphicalMeasure } from "../Graphical/GraphicalMeasure" ; import { RhythmInstruction } from "./Instructions" ; /**
 * The Source Measure represents the source data of a unique measure, including all instruments with their staves.
 * There exists one source measure per XML measure or per paper sheet measure (e.g. the source measures are not doubled in repetitions)
 */ export class SourceMeasure { param completeNumberOfStaves param rules constructor ( completeNumberOfStaves , rules ) { this . completeNumberOfStaves = completeNumberOfStaves ; this . implicitMeasure = false ; this . hasEndLine = false ; this . endingBarStyleXml = "" ; this . endingBarStyleEnum = SystemLinesEnum . SingleThin ; this . firstInstructionsStaffEntries = new Array ( completeNumberOfStaves ) ; this . lastInstructionsStaffEntries = new Array ( completeNumberOfStaves ) ; this . rules = rules ; this . TempoInBPM = 0 ; for ( let i = 0 ; i < completeNumberOfStaves ; i ++ ) { this . graphicalMeasureErrors . push ( false ) ; this . staffLinkedExpressions . push ( [ ] ) ; } } /**
     * The unique measure list index starting with 0.
     */ public measureListIndex : number ; /**
     * The style of the ending bar line.
     */ public endingBarStyleXml : string ; public endingBarStyleEnum : SystemLinesEnum ; /** Whether the MusicXML says to print a new system (line break). See OSMDOptions.newSystemFromXML */ public printNewSystemXml : boolean = false ; /** Whether the MusicXML says to print a new page (page break). See OSMDOptions.newPageFromXML */ public printNewPageXml : boolean = false ; public IsSystemStartMeasure : boolean = false ; private measureNumber : number ; public MeasureNumberXML : number ; public MeasureNumberPrinted : number ; public RhythmPrinted : RhythmInstruction ; public multipleRestMeasures : number ; private absoluteTimestamp : Fraction ; private completeNumberOfStaves : number ; private duration : Fraction ; private activeTimeSignature : Fraction ; public hasLyrics : boolean = false ; public hasMoodExpressions : boolean = false ; /** Whether the SourceMeasure only has rests, no other entries.
     *  Not the same as GraphicalMeasure.hasOnlyRests, because one SourceMeasure can have many GraphicalMeasures (staffs).
     */ public allRests : boolean = false ; public isReducedToMultiRest : boolean = false ; /** If this measure is a MultipleRestMeasure, this is the number of the measure in that sequence of measures. */ public multipleRestMeasureNumber : number = 0 ; private staffLinkedExpressions : MultiExpression [ ] [ ] = [ ] ; private tempoExpressions : MultiTempoExpression [ ] = [ ] ; public rehearsalExpression : RehearsalExpression ; private verticalSourceStaffEntryContainers : VerticalSourceStaffEntryContainer [ ] = [ ] ; private implicitMeasure : boolean ; private hasEndLine : boolean ; public hasEndClef : boolean ; private graphicalMeasureErrors : boolean [ ] = [ ] ; private firstInstructionsStaffEntries : SourceStaffEntry [ ] ; private lastInstructionsStaffEntries : SourceStaffEntry [ ] ; private firstRepetitionInstructions : RepetitionInstruction [ ] = [ ] ; private lastRepetitionInstructions : RepetitionInstruction [ ] = [ ] ; private rules : EngravingRules ; private tempoInBPM : number ; private verticalMeasureList : GraphicalMeasure [ ] ; public get MeasureNumber ( ) : number { return this . measureNumber ; } public set MeasureNumber ( value ) { this . measureNumber = value ; } public getPrintedMeasureNumber ( ) { if ( this . rules . UseXMLMeasureNumbers ) { if ( Number . isInteger ( this . MeasureNumberXML ) ) { this . MeasureNumberPrinted = this . MeasureNumberXML ; return this . MeasureNumberPrinted ; } } this . MeasureNumberPrinted = this . MeasureNumber ; return this . MeasureNumberPrinted ; } public get AbsoluteTimestamp ( ) : Fraction { return this . absoluteTimestamp ; } public set AbsoluteTimestamp ( value ) { this . absoluteTimestamp = value ; } public get CompleteNumberOfStaves ( ) : number { return this . completeNumberOfStaves ; } public get Duration ( ) : Fraction { return this . duration ; } public set Duration ( value ) { this . duration = value ; } public get ActiveTimeSignature ( ) : Fraction { return this . activeTimeSignature ; } public set ActiveTimeSignature ( value ) { this . activeTimeSignature = value ; } public get ImplicitMeasure ( ) : boolean { return this . implicitMeasure ; } public set ImplicitMeasure ( value ) { this . implicitMeasure = value ; } public get HasEndLine ( ) : boolean { return this . hasEndLine ; } public set HasEndLine ( value ) { this . hasEndLine = value ; } public get StaffLinkedExpressions ( ) : MultiExpression [ ] [ ] { return this . staffLinkedExpressions ; } public get TempoExpressions ( ) : MultiTempoExpression [ ] { return this . tempoExpressions ; } public get VerticalSourceStaffEntryContainers ( ) : VerticalSourceStaffEntryContainer [ ] { return this . verticalSourceStaffEntryContainers ; } public get FirstInstructionsStaffEntries ( ) : SourceStaffEntry [ ] { return this . firstInstructionsStaffEntries ; } public get LastInstructionsStaffEntries ( ) : SourceStaffEntry [ ] { return this . lastInstructionsStaffEntries ; } public get FirstRepetitionInstructions ( ) : RepetitionInstruction [ ] { return this . firstRepetitionInstructions ; } public get LastRepetitionInstructions ( ) : RepetitionInstruction [ ] { return this . lastRepetitionInstructions ; } public getErrorInMeasure ( staffIndex ) { return this . graphicalMeasureErrors [ staffIndex ] ; } public setErrorInGraphicalMeasure ( staffIndex , hasError ) { this . graphicalMeasureErrors [ staffIndex ] = hasError ; } public getNextMeasure ( measures ) { return measures [ this . measureListIndex + 1 ] ; } public getPreviousMeasure ( measures ) { if ( this . measureListIndex > 1 ) { return measures [ this . measureListIndex - 1 ] ; } return undefined ; } public get Rules ( ) : EngravingRules { return this . rules ; } public get VerticalMeasureList ( ) : GraphicalMeasure [ ] { return this . verticalMeasureList ; } public set VerticalMeasureList ( value ) { this . verticalMeasureList = value ; } public get TempoInBPM ( ) : number { return this . tempoInBPM ; } public set TempoInBPM ( value ) { this . tempoInBPM = value ; } param inMeasureTimestamp param inSourceMeasureStaffIndex param staff returns { { createdNewContainer : boolean , staffEntry : SourceStaffEntry } } public findOrCreateStaffEntry ( inMeasureTimestamp , inSourceMeasureStaffIndex , staff ) { let staffEntry = undefined ; let existingVerticalSourceStaffEntryContainer ; for ( const container of this . verticalSourceStaffEntryContainers ) { if ( container . Timestamp . Equals ( inMeasureTimestamp ) ) { existingVerticalSourceStaffEntryContainer = container ; break ; } } if ( existingVerticalSourceStaffEntryContainer ) { if ( existingVerticalSourceStaffEntryContainer . StaffEntries [ inSourceMeasureStaffIndex ] ) { staffEntry = existingVerticalSourceStaffEntryContainer . StaffEntries [ inSourceMeasureStaffIndex ] ; } else { staffEntry = new SourceStaffEntry ( existingVerticalSourceStaffEntryContainer , staff ) ; existingVerticalSourceStaffEntryContainer . StaffEntries [ inSourceMeasureStaffIndex ] = staffEntry ; } return { createdNewContainer : false , staffEntry : staffEntry } ; } const last = this . verticalSourceStaffEntryContainers [ this . verticalSourceStaffEntryContainers . length - 1 ] ; if ( this . verticalSourceStaffEntryContainers . length === 0 || last . Timestamp . lt ( inMeasureTimestamp ) ) { const container = new VerticalSourceStaffEntryContainer ( this , inMeasureTimestamp . clone ( ) , this . completeNumberOfStaves ) ; this . verticalSourceStaffEntryContainers . push ( container ) ; staffEntry = new SourceStaffEntry ( container , staff ) ; container . StaffEntries [ inSourceMeasureStaffIndex ] = staffEntry ; } else { for ( let i = this . verticalSourceStaffEntryContainers . length - 1 ; i >= 0 ; i -- ) { if ( this . verticalSourceStaffEntryContainers [ i ] . Timestamp . lt ( inMeasureTimestamp ) ) { const container = new VerticalSourceStaffEntryContainer ( this , inMeasureTimestamp . clone ( ) , this . completeNumberOfStaves ) ; this . verticalSourceStaffEntryContainers . splice ( i + 1 , 0 , container ) ; staffEntry = new SourceStaffEntry ( container , staff ) ; container . StaffEntries [ inSourceMeasureStaffIndex ] = staffEntry ; break ; } if ( i === 0 ) { const container = new VerticalSourceStaffEntryContainer ( this , inMeasureTimestamp . clone ( ) , this . completeNumberOfStaves ) ; this . verticalSourceStaffEntryContainers . splice ( i , 0 , container ) ; staffEntry = new SourceStaffEntry ( container , staff ) ; container . StaffEntries [ inSourceMeasureStaffIndex ] = staffEntry ; break ; } } } return { createdNewContainer : true , staffEntry : staffEntry } ; } param sse param voice returns { { createdVoiceEntry : boolean , voiceEntry : VoiceEntry } } public findOrCreateVoiceEntry ( sse , voice ) { let ve = undefined ; let createdNewVoiceEntry = false ; for ( const voiceEntry of sse . VoiceEntries ) { if ( voiceEntry . ParentVoice === voice ) { ve = voiceEntry ; break ; } } if ( ! ve ) { ve = new VoiceEntry ( sse . Timestamp , voice , sse ) ; createdNewVoiceEntry = true ; } return { createdVoiceEntry : createdNewVoiceEntry , voiceEntry : ve } ; } param verticalIndex param horizontalIndex returns { any } public getPreviousSourceStaffEntryFromIndex ( verticalIndex , horizontalIndex ) { for ( let i = horizontalIndex - 1 ; i >= 0 ; i -- ) { if ( this . verticalSourceStaffEntryContainers [ i ] [ verticalIndex ] ) { return this . verticalSourceStaffEntryContainers [ i ] [ verticalIndex ] ; } } return undefined ; } param musicTimestamp returns { number } public getVerticalContainerIndexByTimestamp ( musicTimestamp ) { for ( let idx = 0 , len = this . VerticalSourceStaffEntryContainers . length ; idx < len ; ++ idx ) { if ( this . VerticalSourceStaffEntryContainers [ idx ] . Timestamp . Equals ( musicTimestamp ) ) { return idx ; } } return - 1 ; } param musicTimestamp returns { any } public getVerticalContainerByTimestamp ( musicTimestamp ) { for ( let idx = 0 , len = this . VerticalSourceStaffEntryContainers . length ; idx < len ; ++ idx ) { const verticalSourceStaffEntryContainer = this . VerticalSourceStaffEntryContainers [ idx ] ; if ( verticalSourceStaffEntryContainer . Timestamp . Equals ( musicTimestamp ) ) { return verticalSourceStaffEntryContainer ; } } return undefined ; } param index public checkForEmptyVerticalContainer ( index ) { let undefinedCounter = 0 ; for ( let i = 0 ; i < this . completeNumberOfStaves ; i ++ ) { if ( ! this . verticalSourceStaffEntryContainers [ index ] [ i ] ) { undefinedCounter ++ ; } } if ( undefinedCounter === this . completeNumberOfStaves ) { this . verticalSourceStaffEntryContainers . splice ( index , 1 ) ; } } param musicSheet param maxInstDuration returns { Fraction } public reverseCheck ( musicSheet , maxInstDuration ) { let maxDuration = new Fraction ( 0 , 1 ) ; const instrumentsDurations = [ ] ; for ( let i = 0 ; i < musicSheet . Instruments . length ; i ++ ) { let instrumentDuration = new Fraction ( 0 , 1 ) ; const inSourceMeasureInstrumentIndex = musicSheet . getGlobalStaffIndexOfFirstStaff ( musicSheet . Instruments [ i ] ) ; for ( let j = 0 ; j < musicSheet . Instruments [ i ] . Staves . length ; j ++ ) { const lastStaffEntry = this . getLastSourceStaffEntryForInstrument ( inSourceMeasureInstrumentIndex + j ) ; if ( lastStaffEntry !== undefined && ! lastStaffEntry . hasTie ( ) ) { const verticalContainerIndex = this . verticalSourceStaffEntryContainers . indexOf ( lastStaffEntry . VerticalContainerParent ) ; for ( let m = verticalContainerIndex - 1 ; m >= 0 ; m -- ) { const previousStaffEntry = this . verticalSourceStaffEntryContainers [ m ] [ inSourceMeasureInstrumentIndex + j ] ; if ( previousStaffEntry !== undefined && previousStaffEntry . hasTie ( ) ) { if ( instrumentDuration . lt ( Fraction . plus ( previousStaffEntry . Timestamp , previousStaffEntry . calculateMaxNoteLength ( ) ) ) ) { instrumentDuration = Fraction . plus ( previousStaffEntry . Timestamp , previousStaffEntry . calculateMaxNoteLength ( ) ) ; break ; } } } } } instrumentsDurations . push ( instrumentDuration ) ; } for ( let idx = 0 , len = instrumentsDurations . length ; idx < len ; ++ idx ) { const instrumentsDuration = instrumentsDurations [ idx ] ; if ( maxDuration . lt ( instrumentsDuration ) ) { maxDuration = instrumentsDuration ; } } return Fraction . max ( maxDuration , maxInstDuration ) ; } param musicSheet param instrumentMaxTieNoteFractions returns { Fraction [ ] } public calculateInstrumentsDuration ( musicSheet , instrumentMaxTieNoteFractions ) { const instrumentsDurations = [ ] ; for ( let i = 0 ; i < musicSheet . Instruments . length ; i ++ ) { let instrumentDuration = new Fraction ( 0 , 1 ) ; const inSourceMeasureInstrumentIndex = musicSheet . getGlobalStaffIndexOfFirstStaff ( musicSheet . Instruments [ i ] ) ; for ( let j = 0 ; j < musicSheet . Instruments [ i ] . Staves . length ; j ++ ) { const lastStaffEntry = this . getLastSourceStaffEntryForInstrument ( inSourceMeasureInstrumentIndex + j ) ; if ( lastStaffEntry !== undefined && lastStaffEntry . Timestamp ) { if ( instrumentDuration . lt ( Fraction . plus ( lastStaffEntry . Timestamp , lastStaffEntry . calculateMaxNoteLength ( ) ) ) ) { instrumentDuration = Fraction . plus ( lastStaffEntry . Timestamp , lastStaffEntry . calculateMaxNoteLength ( ) ) ; } } } if ( instrumentDuration . lt ( instrumentMaxTieNoteFractions [ i ] ) ) { instrumentDuration = instrumentMaxTieNoteFractions [ i ] ; } instrumentsDurations . push ( instrumentDuration ) ; } return instrumentsDurations ; } public getEntriesPerStaff ( staffIndex ) { const sourceStaffEntries = [ ] ; for ( const container of this . VerticalSourceStaffEntryContainers ) { const sse = container . StaffEntries [ staffIndex ] ; if ( sse ) { sourceStaffEntries . push ( sse ) ; } } return sourceStaffEntries ; } returns { boolean } public hasBeginInstructions ( ) { for ( let staffIndex = 0 , len = this . FirstInstructionsStaffEntries . length ; staffIndex < len ; staffIndex ++ ) { const beginInstructionsStaffEntry = this . FirstInstructionsStaffEntries [ staffIndex ] ; if ( beginInstructionsStaffEntry !== undefined && beginInstructionsStaffEntry . Instructions . length > 0 ) { return true ; } } return false ; } public beginsWithLineRepetition ( ) { for ( let idx = 0 , len = this . FirstRepetitionInstructions . length ; idx < len ; ++ idx ) { const instr = this . FirstRepetitionInstructions [ idx ] ; if ( instr . type === RepetitionInstructionEnum . StartLine ) { return true ; } if ( instr . parentRepetition !== undefined && instr === instr . parentRepetition . startMarker && ! instr . parentRepetition . FromWords ) { return true ; } } return false ; } returns { boolean } public endsWithLineRepetition ( ) { for ( let idx = 0 , len = this . LastRepetitionInstructions . length ; idx < len ; ++ idx ) { const instruction = this . LastRepetitionInstructions [ idx ] ; if ( instruction . type === RepetitionInstructionEnum . BackJumpLine ) { return true ; } const rep = instruction . parentRepetition ; if ( ! rep ) { continue ; } if ( rep . FromWords ) { continue ; } for ( let idx2 = 0 , len2 = rep . BackwardJumpInstructions . length ; idx2 < len2 ; ++ idx2 ) { const backJumpInstruction = rep . BackwardJumpInstructions [ idx2 ] ; if ( instruction === backJumpInstruction ) { return true ; } } } return false ; } returns { boolean } public beginsWithWordRepetition ( ) { for ( let idx = 0 , len = this . FirstRepetitionInstructions . length ; idx < len ; ++ idx ) { const instruction = this . FirstRepetitionInstructions [ idx ] ; if ( instruction . parentRepetition !== undefined && instruction === instruction . parentRepetition . startMarker && instruction . parentRepetition . FromWords ) { return true ; } } return false ; } returns { boolean } public endsWithWordRepetition ( ) { for ( let idx = 0 , len = this . LastRepetitionInstructions . length ; idx < len ; ++ idx ) { const instruction = this . LastRepetitionInstructions [ idx ] ; const rep = instruction . parentRepetition ; if ( ! rep ) { continue ; } if ( ! rep . FromWords ) { continue ; } for ( let idx2 = 0 , len2 = rep . BackwardJumpInstructions . length ; idx2 < len2 ; ++ idx2 ) { const backJumpInstruction = rep . BackwardJumpInstructions [ idx2 ] ; if ( instruction === backJumpInstruction ) { return true ; } } if ( instruction === rep . forwardJumpInstruction ) { return true ; } } return false ; } public beginsRepetitionEnding ( ) { for ( const instruction of this . FirstRepetitionInstructions ) { if ( instruction . type === RepetitionInstructionEnum . Ending && instruction . alignment === AlignmentType . Begin ) { return true ; } } return false ; } public endsRepetitionEnding ( ) { for ( const instruction of this . LastRepetitionInstructions ) { if ( instruction . type === RepetitionInstructionEnum . Ending && instruction . alignment === AlignmentType . End ) { return true ; } } return false ; } public getKeyInstruction ( staffIndex ) { if ( this . FirstInstructionsStaffEntries [ staffIndex ] ) { const sourceStaffEntry = this . FirstInstructionsStaffEntries [ staffIndex ] ; for ( let idx = 0 , len = sourceStaffEntry . Instructions . length ; idx < len ; ++ idx ) { const abstractNotationInstruction = sourceStaffEntry . Instructions [ idx ] ; if ( abstractNotationInstruction instanceof KeyInstruction ) { return < KeyInstruction > abstractNotationInstruction ; } } } return undefined ; } param instrumentIndex returns { SourceStaffEntry } private getLastSourceStaffEntryForInstrument ( instrumentIndex ) { let entry ; for ( let i = this . verticalSourceStaffEntryContainers . length - 1 ; i >= 0 ; i -- ) { entry = this . verticalSourceStaffEntryContainers [ i ] . StaffEntries [ instrumentIndex ] ; if ( entry ) { break ; } } return entry ; } public canBeReducedToMultiRest ( ) { let allRestsOrInvisible = true ; let visibleLyrics = false ; for ( const container of this . verticalSourceStaffEntryContainers ) { if ( ! container ) { continue ; } for ( const staffEntry of container . StaffEntries ) { if ( ! staffEntry || ! staffEntry . ParentStaff . ParentInstrument . Visible ) { continue ; } if ( staffEntry . ChordContainers . length > 0 ) { return false ; } if ( staffEntry . ParentStaff . hasLyrics ) { visibleLyrics = true ; } if ( this . firstRepetitionInstructions . length > 0 || this . lastRepetitionInstructions . length > 0 ) { return false ; } for ( const voiceEntry of staffEntry . VoiceEntries ) { for ( const note of voiceEntry . Notes ) { if ( ! note . isRest ( ) ) { allRestsOrInvisible = false ; break ; } } if ( ! allRestsOrInvisible ) { break ; } } } } if ( ! allRestsOrInvisible || visibleLyrics || this . hasMoodExpressions || this . tempoExpressions . length > 0 ) { return false ; } for ( const multiExpressions of this . staffLinkedExpressions ) { if ( multiExpressions . length > 0 ) { return false ; } } for ( const lastStaffEntry of this . lastInstructionsStaffEntries ) { for ( let idx = 0 , len = lastStaffEntry ?. Instructions . length ; idx < len ; ++ idx ) { const abstractNotationInstruction = lastStaffEntry . Instructions [ idx ] ; if ( abstractNotationInstruction instanceof ClefInstruction ) { return false ; } } } return this . Duration ?. RealValue === this . ActiveTimeSignature ?. RealValue ; } }