import {GraphicalStaffEntry} from "./GraphicalStaffEntry"; import {StaffLine} from "./StaffLine"; import {GraphicalMusicSheet} from "./GraphicalMusicSheet"; import {EngravingRules} from "./EngravingRules"; import {Tie} from "../VoiceData/Tie"; import {Fraction} from "../../Common/DataObjects/Fraction"; import {Note} from "../VoiceData/Note"; import {MusicSheet} from "../MusicSheet"; import {StaffMeasure} from "./StaffMeasure"; import {ClefInstruction} from "../VoiceData/Instructions/ClefInstruction"; import {LyricWord} from "../VoiceData/Lyrics/LyricsWord"; import {SourceMeasure} from "../VoiceData/SourceMeasure"; import {GraphicalMusicPage} from "./GraphicalMusicPage"; import {GraphicalNote} from "./GraphicalNote"; import {Beam} from "../VoiceData/Beam"; import {OctaveEnum} from "../VoiceData/Expressions/ContinuousExpressions/OctaveShift"; import {LyricsEntry} from "../VoiceData/Lyrics/LyricsEntry"; import {VoiceEntry} from "../VoiceData/VoiceEntry"; import {OrnamentContainer} from "../VoiceData/OrnamentContainer"; import {ArticulationEnum} from "../VoiceData/VoiceEntry"; import {Tuplet} from "../VoiceData/Tuplet"; import {MusicSystem} from "./MusicSystem"; import {GraphicalTie} from "./GraphicalTie"; import {RepetitionInstruction} from "../VoiceData/Instructions/RepetitionInstruction"; import {MultiExpression} from "../VoiceData/Expressions/MultiExpression"; import {StaffEntryLink} from "../VoiceData/StaffEntryLink"; import {MusicSystemBuilder} from "./MusicSystemBuilder"; import {MultiTempoExpression} from "../VoiceData/Expressions/MultiTempoExpression"; import {Repetition} from "../MusicSource/Repetition"; import {PointF2D} from "../../Common/DataObjects/PointF2D"; import {SourceStaffEntry} from "../VoiceData/SourceStaffEntry"; import {BoundingBox} from "./BoundingBox"; import {Instrument} from "../Instrument"; import {GraphicalLabel} from "./GraphicalLabel"; import {TextAlignment} from "../../Common/Enums/TextAlignment"; import {VerticalGraphicalStaffEntryContainer} from "./VerticalGraphicalStaffEntryContainer"; import {KeyInstruction} from "../VoiceData/Instructions/KeyInstruction"; import {AbstractNotationInstruction} from "../VoiceData/Instructions/AbstractNotationInstruction"; import {ClefEnum} from "../VoiceData/Instructions/ClefInstruction"; import {TechnicalInstruction} from "../VoiceData/Instructions/TechnicalInstruction"; import {Pitch} from "../../Common/DataObjects/Pitch"; import {LinkedVoice} from "../VoiceData/LinkedVoice"; import {ColDirEnum} from "./BoundingBox"; import {IGraphicalSymbolFactory} from "../Interfaces/IGraphicalSymbolFactory"; import {ITextMeasurer} from "../Interfaces/ITextMeasurer"; import {ITransposeCalculator} from "../Interfaces/ITransposeCalculator"; import {OctaveShiftParams} from "./OctaveShiftParams"; import {AccidentalCalculator} from "./AccidentalCalculator"; import {MidiInstrument} from "../VoiceData/Instructions/ClefInstruction"; import {Staff} from "../VoiceData/Staff"; import {OctaveShift} from "../VoiceData/Expressions/ContinuousExpressions/OctaveShift"; import {Logging} from "../../Common/Logging"; import Dictionary from "typescript-collections/dist/lib/Dictionary"; import {CollectionUtil} from "../../Util/CollectionUtil"; /** * Class used to do all the calculations in a MusicSheet, which in the end populates a GraphicalMusicSheet. */ export abstract class MusicSheetCalculator { public static transposeCalculator: ITransposeCalculator; protected static textMeasurer: ITextMeasurer; protected staffEntriesWithGraphicalTies: GraphicalStaffEntry[] = []; protected staffEntriesWithOrnaments: GraphicalStaffEntry[] = []; protected staffEntriesWithChordSymbols: GraphicalStaffEntry[] = []; protected staffLinesWithLyricWords: StaffLine[] = []; protected staffLinesWithGraphicalExpressions: StaffLine[] = []; protected graphicalMusicSheet: GraphicalMusicSheet; protected rules: EngravingRules; protected symbolFactory: IGraphicalSymbolFactory; constructor(symbolFactory: IGraphicalSymbolFactory) { this.symbolFactory = symbolFactory; } public static get TextMeasurer(): ITextMeasurer { return MusicSheetCalculator.textMeasurer; } public static set TextMeasurer(value: ITextMeasurer) { MusicSheetCalculator.textMeasurer = value; } protected get leadSheet(): boolean { return this.graphicalMusicSheet.LeadSheet; } private static addTieToTieTimestampsDict(tieTimestampListDict: Dictionary, note: Note): void { note.NoteTie.initializeBoolList(); let tieTimestampList: Fraction[] = []; for (let m: number = 0; m < note.NoteTie.Fractions.length; m++) { let musicTimestamp: Fraction; if (m === 0) { musicTimestamp = Fraction.plus(note.calculateNoteLengthWithoutTie(), note.getAbsoluteTimestamp()); } else { musicTimestamp = Fraction.plus(tieTimestampList[m - 1], note.NoteTie.Fractions[m - 1]); } tieTimestampList.push(musicTimestamp); } tieTimestampListDict.setValue(note.NoteTie, tieTimestampList); } private static setMeasuresMinStaffEntriesWidth(measures: StaffMeasure[], minimumStaffEntriesWidth: number): void { for (let idx: number = 0, len: number = measures.length; idx < len; ++idx) { let measure: StaffMeasure = measures[idx]; measure.minimumStaffEntriesWidth = minimumStaffEntriesWidth; } } public initialize(graphicalMusicSheet: GraphicalMusicSheet): void { this.graphicalMusicSheet = graphicalMusicSheet; this.rules = graphicalMusicSheet.ParentMusicSheet.rules; this.prepareGraphicalMusicSheet(); //this.calculate(); } public prepareGraphicalMusicSheet(): void { //this.graphicalMusicSheet.SystemImages.length = 0; let musicSheet: MusicSheet = this.graphicalMusicSheet.ParentMusicSheet; this.staffEntriesWithGraphicalTies = []; this.staffEntriesWithOrnaments = []; this.staffEntriesWithChordSymbols = []; this.staffLinesWithLyricWords = []; this.staffLinesWithGraphicalExpressions = []; this.graphicalMusicSheet.Initialize(); let measureList: StaffMeasure[][] = this.graphicalMusicSheet.MeasureList; let accidentalCalculators: AccidentalCalculator[] = this.createAccidentalCalculators(); let activeClefs: ClefInstruction[] = this.graphicalMusicSheet.initializeActiveClefs(); let lyricWords: LyricWord[] = []; let completeNumberOfStaves: number = musicSheet.getCompleteNumberOfStaves(); let openOctaveShifts: OctaveShiftParams[] = []; let tieTimestampListDictList: Dictionary[] = []; for (let i: number = 0; i < completeNumberOfStaves; i++) { let tieTimestampListDict: Dictionary = new Dictionary(); tieTimestampListDictList.push(tieTimestampListDict); openOctaveShifts.push(undefined); } for (let idx: number = 0, len: number = musicSheet.SourceMeasures.length; idx < len; ++idx) { let sourceMeasure: SourceMeasure = musicSheet.SourceMeasures[idx]; let graphicalMeasures: StaffMeasure[] = this.createGraphicalMeasuresForSourceMeasure( sourceMeasure, accidentalCalculators, lyricWords, tieTimestampListDictList, openOctaveShifts, activeClefs ); measureList.push(graphicalMeasures); } this.handleStaffEntries(); this.calculateVerticalContainersList(); this.setIndecesToVerticalGraphicalContainers(); } public calculate(): void { this.clearSystemsAndMeasures(); this.clearRecreatedObjects(); this.createGraphicalTies(); this.calculateSheetLabelBoundingBoxes(); this.calculateXLayout(this.graphicalMusicSheet, this.maxInstrNameLabelLength()); this.graphicalMusicSheet.MusicPages.length = 0; this.calculateMusicSystems(); this.graphicalMusicSheet.MusicPages[0].PositionAndShape.BorderMarginBottom += 9; GraphicalMusicSheet.transformRelativeToAbsolutePosition(this.graphicalMusicSheet); } public calculateXLayout(graphicalMusicSheet: GraphicalMusicSheet, maxInstrNameLabelLength: number): void { let minLength: number = 0; let maxInstructionsLength: number = this.rules.MaxInstructionsConstValue; if (this.graphicalMusicSheet.MeasureList.length > 0) { let measures: StaffMeasure[] = this.graphicalMusicSheet.MeasureList[0]; let minimumStaffEntriesWidth: number = this.calculateMeasureXLayout(measures); MusicSheetCalculator.setMeasuresMinStaffEntriesWidth(measures, minimumStaffEntriesWidth); minLength = minimumStaffEntriesWidth * 1.2 + maxInstrNameLabelLength + maxInstructionsLength; for (let i: number = 1; i < this.graphicalMusicSheet.MeasureList.length; i++) { measures = this.graphicalMusicSheet.MeasureList[i]; minimumStaffEntriesWidth = this.calculateMeasureXLayout(measures); MusicSheetCalculator.setMeasuresMinStaffEntriesWidth(measures, minimumStaffEntriesWidth); minLength = Math.max(minLength, minimumStaffEntriesWidth * 1.2 + maxInstructionsLength); } } this.graphicalMusicSheet.MinAllowedSystemWidth = minLength; } protected calculateMeasureXLayout(measures: StaffMeasure[]): number { throw new Error("abstract, not implemented"); } protected calculateSystemYLayout(): void { throw new Error("abstract, not implemented"); } protected initStaffMeasuresCreation(): void { throw new Error("abstract, not implemented"); } protected handleBeam(graphicalNote: GraphicalNote, beam: Beam, openBeams: Beam[]): void { throw new Error("abstract, not implemented"); } protected createGraphicalTieNote(beams: Beam[], activeClef: ClefInstruction, octaveShiftValue: OctaveEnum, graphicalStaffEntry: GraphicalStaffEntry, duration: Fraction, numberOfDots: number, openTie: Tie, isLastTieNote: boolean): void { throw new Error("abstract, not implemented"); } protected handleVoiceEntryLyrics(lyricsEntries: Dictionary, voiceEntry: VoiceEntry, graphicalStaffEntry: GraphicalStaffEntry, openLyricWords: LyricWord[]): void { throw new Error("abstract, not implemented"); } protected handleVoiceEntryOrnaments(ornamentContainer: OrnamentContainer, voiceEntry: VoiceEntry, graphicalStaffEntry: GraphicalStaffEntry): void { throw new Error("abstract, not implemented"); } protected handleVoiceEntryArticulations(articulations: ArticulationEnum[], voiceEntry: VoiceEntry, graphicalStaffEntry: GraphicalStaffEntry): void { throw new Error("abstract, not implemented"); } protected handleTuplet(graphicalNote: GraphicalNote, tuplet: Tuplet, openTuplets: Tuplet[]): void { throw new Error("abstract, not implemented"); } protected layoutVoiceEntry(voiceEntry: VoiceEntry, graphicalNotes: GraphicalNote[], graphicalStaffEntry: GraphicalStaffEntry, hasPitchedNote: boolean, isGraceStaffEntry: boolean): void { throw new Error("abstract, not implemented"); } protected layoutStaffEntry(graphicalStaffEntry: GraphicalStaffEntry): void { throw new Error("abstract, not implemented"); } protected handleTie(tie: Tie, startGraphicalStaffEntry: GraphicalStaffEntry, staffIndex: number, measureIndex: number): void { throw new Error("abstract, not implemented"); } protected updateStaffLineBorders(staffLine: StaffLine): void { throw new Error("abstract, not implemented"); } protected calculateMeasureNumberPlacement(musicSystem: MusicSystem): void { throw new Error("abstract, not implemented"); } protected layoutGraphicalTie(tie: GraphicalTie, tieIsAtSystemBreak: boolean): void { throw new Error("abstract, not implemented"); } protected calculateSingleStaffLineLyricsPosition(staffLine: StaffLine, lyricVersesNumber: number[]): void { throw new Error("abstract, not implemented"); } protected calculateSingleOctaveShift(sourceMeasure: SourceMeasure, multiExpression: MultiExpression, measureIndex: number, staffIndex: number): void { throw new Error("abstract, not implemented"); } protected calculateWordRepetitionInstruction(repetitionInstruction: RepetitionInstruction, measureIndex: number): void { throw new Error("abstract, not implemented"); } protected calculateMoodAndUnknownExpression(multiExpression: MultiExpression, measureIndex: number, staffIndex: number): void { throw new Error("abstract, not implemented"); } protected clearRecreatedObjects(): void { Logging.debug("clearRecreatedObjects not implemented"); } protected handleStaffEntryLink(graphicalStaffEntry: GraphicalStaffEntry, staffEntryLinks: StaffEntryLink[]): void { Logging.debug("handleStaffEntryLink not implemented"); } protected calculateMusicSystems(): void { if (this.graphicalMusicSheet.MeasureList === undefined) { return; } let allMeasures: StaffMeasure[][] = this.graphicalMusicSheet.MeasureList; if (allMeasures === undefined) { return; } let visibleMeasureList: StaffMeasure[][] = []; for (let idx: number = 0, len: number = allMeasures.length; idx < len; ++idx) { let staffMeasures: StaffMeasure[] = allMeasures[idx]; let visibleStaffMeasures: StaffMeasure[] = []; for (let idx2: number = 0, len2: number = staffMeasures.length; idx2 < len2; ++idx2) { let staffMeasure: StaffMeasure = allMeasures[idx][idx2]; if (staffMeasure.isVisible()) { visibleStaffMeasures.push(staffMeasure); } } visibleMeasureList.push(visibleStaffMeasures); } let numberOfStaffLines: number = 0; for (let idx: number = 0, len: number = visibleMeasureList.length; idx < len; ++idx) { let gmlist: StaffMeasure[] = visibleMeasureList[idx]; numberOfStaffLines = Math.max(gmlist.length, numberOfStaffLines); break; } if (numberOfStaffLines === 0) { return; } let musicSystemBuilder: MusicSystemBuilder = new MusicSystemBuilder(); musicSystemBuilder.initialize(this.graphicalMusicSheet, visibleMeasureList, numberOfStaffLines, this.symbolFactory); musicSystemBuilder.buildMusicSystems(); this.checkMeasuresForWholeRestNotes(); if (!this.leadSheet) { this.calculateBeams(); this.optimizeRestPlacement(); this.calculateStaffEntryArticulationMarks(); this.calculateTieCurves(); } this.calculateSkyBottomLines(); this.calculateTupletNumbers(); for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) { let graphicalMusicPage: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx]; for (let idx2: number = 0, len2: number = graphicalMusicPage.MusicSystems.length; idx2 < len2; ++idx2) { let musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2]; this.calculateMeasureNumberPlacement(musicSystem); } } if (!this.leadSheet) { this.calculateSlurs(); } if (!this.leadSheet) { this.calculateOrnaments(); } this.updateSkyBottomLines(); this.calculateChordSymbols(); if (!this.leadSheet) { this.calculateDynamicExpressions(); this.optimizeStaffLineDynamicExpressionsPositions(); this.calculateMoodAndUnknownExpressions(); this.calculateOctaveShifts(); this.calculateWordRepetitionInstructions(); } this.calculateRepetitionEndings(); if (!this.leadSheet) { this.calculateTempoExpressions(); } this.calculateLyricsPosition(); for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) { let graphicalMusicPage: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx]; for (let idx2: number = 0, len2: number = graphicalMusicPage.MusicSystems.length; idx2 < len2; ++idx2) { let musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2]; for (let idx3: number = 0, len3: number = musicSystem.StaffLines.length; idx3 < len3; ++idx3) { let staffLine: StaffLine = musicSystem.StaffLines[idx3]; this.updateStaffLineBorders(staffLine); } } } this.calculateComments(); this.calculateSystemYLayout(); this.calculateMarkedAreas(); for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) { let graphicalMusicPage: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx]; for (let idx2: number = 0, len2: number = graphicalMusicPage.MusicSystems.length; idx2 < len2; ++idx2) { let musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2]; musicSystem.setMusicSystemLabelsYPosition(); if (!this.leadSheet) { musicSystem.setYPositionsToVerticalLineObjectsAndCreateLines(this.rules); musicSystem.createSystemLeftLine(this.rules.SystemThinLineWidth, this.rules.SystemLabelsRightMargin); musicSystem.createInstrumentBrackets(this.graphicalMusicSheet.ParentMusicSheet.Instruments, this.rules.StaffHeight); musicSystem.createGroupBrackets(this.graphicalMusicSheet.ParentMusicSheet.InstrumentalGroups, this.rules.StaffHeight, 0); musicSystem.alignBeginInstructions(); } else if (musicSystem === musicSystem.Parent.MusicSystems[0]) { musicSystem.createSystemLeftLine(this.rules.SystemThinLineWidth, this.rules.SystemLabelsRightMargin); } musicSystem.calculateBorders(this.rules); } let distance: number = graphicalMusicPage.MusicSystems[0].PositionAndShape.BorderTop; for (let idx2: number = 0, len2: number = graphicalMusicPage.MusicSystems.length; idx2 < len2; ++idx2) { let musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2]; // let newPosition: PointF2D = new PointF2D(musicSystem.PositionAndShape.RelativePosition.x, // musicSystem.PositionAndShape.RelativePosition.y - distance); musicSystem.PositionAndShape.RelativePosition = new PointF2D(musicSystem.PositionAndShape.RelativePosition.x, musicSystem.PositionAndShape.RelativePosition.y - distance); } for (let idx2: number = 0, len2: number = graphicalMusicPage.MusicSystems.length; idx2 < len2; ++idx2) { let musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2]; for (let idx3: number = 0, len3: number = musicSystem.StaffLines.length; idx3 < len3; ++idx3) { let staffLine: StaffLine = musicSystem.StaffLines[idx3]; staffLine.addActivitySymbolClickArea(); } } if (graphicalMusicPage === this.graphicalMusicSheet.MusicPages[0]) { this.calculatePageLabels(graphicalMusicPage); } graphicalMusicPage.PositionAndShape.calculateTopBottomBorders(); } } protected updateSkyBottomLine(staffLine: StaffLine): void { Logging.debug("updateSkyBottomLine not implemented"); } protected calculateSkyBottomLine(staffLine: StaffLine): void { Logging.debug("calculateSkyBottomLine not implemented"); } protected calculateMarkedAreas(): void { Logging.debug("calculateMarkedAreas not implemented"); } protected calculateComments(): void { Logging.debug("calculateComments not implemented"); } protected optimizeStaffLineDynamicExpressionsPositions(): void { return; } protected calculateChordSymbols(): void { return; } protected layoutMeasureWithWholeRest(rest: GraphicalNote, gse: GraphicalStaffEntry, measure: StaffMeasure): void { return; } protected layoutBeams(staffEntry: GraphicalStaffEntry): void { return; } protected layoutArticulationMarks(articulations: ArticulationEnum[], voiceEntry: VoiceEntry, graphicalStaffEntry: GraphicalStaffEntry): void { return; } protected layoutOrnament(ornaments: OrnamentContainer, voiceEntry: VoiceEntry, graphicalStaffEntry: GraphicalStaffEntry): void { return; } protected calculateRestNotePlacementWithinGraphicalBeam(graphicalStaffEntry: GraphicalStaffEntry, restNote: GraphicalNote, previousNote: GraphicalNote, nextStaffEntry: GraphicalStaffEntry, nextNote: GraphicalNote): void { return; } protected calculateTupletNumbers(): void { return; } protected calculateSlurs(): void { return; } protected calculateDynamicExpressionsForSingleMultiExpression(multiExpression: MultiExpression, measureIndex: number, staffIndex: number): void { return; } protected calcGraphicalRepetitionEndingsRecursively(repetition: Repetition): void { return; } protected layoutSingleRepetitionEnding(start: StaffMeasure, end: StaffMeasure, numberText: string, offset: number, leftOpen: boolean, rightOpen: boolean): void { return; } protected calculateTempoExpressionsForSingleMultiTempoExpression(sourceMeasure: SourceMeasure, multiTempoExpression: MultiTempoExpression, measureIndex: number): void { return; } protected clearSystemsAndMeasures(): void { for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) { let graphicalMusicPage: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx]; for (let idx2: number = 0, len2: number = graphicalMusicPage.MusicSystems.length; idx2 < len2; ++idx2) { let musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2]; for (let idx3: number = 0, len3: number = musicSystem.StaffLines.length; idx3 < len3; ++idx3) { let staffLine: StaffLine = musicSystem.StaffLines[idx3]; for (let idx4: number = 0, len4: number = staffLine.Measures.length; idx4 < len4; ++idx4) { let graphicalMeasure: StaffMeasure = staffLine.Measures[idx4]; if (graphicalMeasure.FirstInstructionStaffEntry !== undefined) { let index: number = graphicalMeasure.PositionAndShape.ChildElements.indexOf( graphicalMeasure.FirstInstructionStaffEntry.PositionAndShape ); if (index > -1) { graphicalMeasure.PositionAndShape.ChildElements.splice(index, 1); } graphicalMeasure.FirstInstructionStaffEntry = undefined; graphicalMeasure.beginInstructionsWidth = 0.0; } if (graphicalMeasure.LastInstructionStaffEntry !== undefined) { let index: number = graphicalMeasure.PositionAndShape.ChildElements.indexOf( graphicalMeasure.LastInstructionStaffEntry.PositionAndShape ); if (index > -1) { graphicalMeasure.PositionAndShape.ChildElements.splice(index, 1); } graphicalMeasure.LastInstructionStaffEntry = undefined; graphicalMeasure.endInstructionsWidth = 0.0; } } staffLine.Measures = []; staffLine.PositionAndShape.ChildElements = []; } musicSystem.StaffLines.length = 0; musicSystem.PositionAndShape.ChildElements = []; } graphicalMusicPage.MusicSystems = []; graphicalMusicPage.PositionAndShape.ChildElements = []; } this.graphicalMusicSheet.MusicPages = []; } protected handleVoiceEntry(voiceEntry: VoiceEntry, graphicalStaffEntry: GraphicalStaffEntry, accidentalCalculator: AccidentalCalculator, openLyricWords: LyricWord[], tieTimestampListDict: Dictionary, activeClef: ClefInstruction, openTuplets: Tuplet[], openBeams: Beam[], octaveShiftValue: OctaveEnum, grace: boolean = false, linkedNotes: Note[] = undefined, sourceStaffEntry: SourceStaffEntry = undefined): OctaveEnum { let graphicalNotes: GraphicalNote[] = graphicalStaffEntry.findOrCreateGraphicalNotesListFromVoiceEntry(voiceEntry); for (let idx: number = 0, len: number = voiceEntry.Notes.length; idx < len; ++idx) { let note: Note = voiceEntry.Notes[idx]; if (sourceStaffEntry !== undefined && sourceStaffEntry.Link !== undefined && linkedNotes !== undefined && linkedNotes.indexOf(note) > -1) { continue; } let graphicalNote: GraphicalNote; let numberOfDots: number = note.calculateNumberOfNeededDots(); if (grace) { graphicalNote = this.symbolFactory.createGraceNote(note, numberOfDots, graphicalStaffEntry, activeClef, octaveShiftValue); } else { graphicalNote = this.symbolFactory.createNote(note, numberOfDots, graphicalStaffEntry, activeClef, octaveShiftValue); } if (note.NoteTie !== undefined) { MusicSheetCalculator.addTieToTieTimestampsDict(tieTimestampListDict, note); } if (note.Pitch !== undefined) { this.checkNoteForAccidental(graphicalNote, accidentalCalculator, activeClef, octaveShiftValue, grace); } this.resetYPositionForLeadSheet(graphicalNote.PositionAndShape); graphicalStaffEntry.addGraphicalNoteToListAtCorrectYPosition(graphicalNotes, graphicalNote); graphicalStaffEntry.PositionAndShape.ChildElements.push(graphicalNote.PositionAndShape); graphicalNote.PositionAndShape.calculateBoundingBox(); if (!this.leadSheet) { if (note.NoteBeam !== undefined) { this.handleBeam(graphicalNote, note.NoteBeam, openBeams); } if (note.NoteTuplet !== undefined) { this.handleTuplet(graphicalNote, note.NoteTuplet, openTuplets); } } } if (voiceEntry.Articulations.length > 0) { this.handleVoiceEntryArticulations(voiceEntry.Articulations, voiceEntry, graphicalStaffEntry); } if (voiceEntry.TechnicalInstructions.length > 0) { this.checkVoiceEntriesForTechnicalInstructions(voiceEntry, graphicalStaffEntry); } if (voiceEntry.LyricsEntries.size() > 0) { this.handleVoiceEntryLyrics(voiceEntry.LyricsEntries, voiceEntry, graphicalStaffEntry, openLyricWords); } if (voiceEntry.OrnamentContainer !== undefined) { this.handleVoiceEntryOrnaments(voiceEntry.OrnamentContainer, voiceEntry, graphicalStaffEntry); } return octaveShiftValue; } protected handleVoiceEntryGraceNotes(graceEntries: VoiceEntry[], graphicalGraceEntries: GraphicalStaffEntry[], graphicalStaffEntry: GraphicalStaffEntry, accidentalCalculator: AccidentalCalculator, activeClef: ClefInstruction, octaveShiftValue: OctaveEnum, lyricWords: LyricWord[], tieTimestampListDict: Dictionary, tuplets: Tuplet[], beams: Beam[]): void { if (graceEntries !== undefined) { for (let idx: number = 0, len: number = graceEntries.length; idx < len; ++idx) { let graceVoiceEntry: VoiceEntry = graceEntries[idx]; let graceStaffEntry: GraphicalStaffEntry = this.symbolFactory.createGraceStaffEntry( graphicalStaffEntry, graphicalStaffEntry.parentMeasure ); graphicalGraceEntries.push(graceStaffEntry); graphicalStaffEntry.PositionAndShape.ChildElements.push(graceStaffEntry.PositionAndShape); this.handleVoiceEntry( graceVoiceEntry, graceStaffEntry, accidentalCalculator, lyricWords, tieTimestampListDict, activeClef, tuplets, beams, octaveShiftValue, true ); } } } protected handleOpenTies(measure: StaffMeasure, beams: Beam[], tieTimestampListDict: Dictionary, activeClef: ClefInstruction, octaveShiftParams: OctaveShiftParams): void { CollectionUtil.removeDictElementIfTrue(tieTimestampListDict, function (openTie: Tie, tieTimestamps: Fraction[]): boolean { // for (let m: number = tieTimestampListDict.size() - 1; m >= 0; m--) { // let keyValuePair: KeyValuePair = tieTimestampListDict.ElementAt(m); // let openTie: Tie = keyValuePair.Key; // let tieTimestamps: Fraction[] = keyValuePair.Value; let absoluteTimestamp: Fraction = undefined; let k: number; let removeTie: boolean = false; for (; k < tieTimestamps.length; k++) { if (!openTie.NoteHasBeenCreated[k]) { absoluteTimestamp = tieTimestamps[k]; if (absoluteTimestamp >= Fraction.plus(measure.parentSourceMeasure.AbsoluteTimestamp, measure.parentSourceMeasure.Duration)) { continue; } let graphicalStaffEntry: GraphicalStaffEntry = undefined; if (absoluteTimestamp !== undefined) { for (let idx: number = 0, len: number = measure.staffEntries.length; idx < len; ++idx) { let gse: GraphicalStaffEntry = measure.staffEntries[idx]; if (gse.getAbsoluteTimestamp() === absoluteTimestamp) { graphicalStaffEntry = gse; break; } } if (graphicalStaffEntry === undefined) { graphicalStaffEntry = this.createStaffEntryForTieNote(measure, absoluteTimestamp, openTie); } } if (graphicalStaffEntry !== undefined) { let octaveShiftValue: OctaveEnum = OctaveEnum.NONE; if (octaveShiftParams !== undefined) { if (graphicalStaffEntry.getAbsoluteTimestamp() >= octaveShiftParams.getAbsoluteStartTimestamp && graphicalStaffEntry.getAbsoluteTimestamp() <= octaveShiftParams.getAbsoluteEndTimestamp) { octaveShiftValue = octaveShiftParams.getOpenOctaveShift.Type; } } let isLastTieNote: boolean = k === tieTimestamps.length - 1; let tieFraction: Fraction = openTie.Fractions[k]; let numberOfDots: number = openTie.Start.calculateNumberOfNeededDots(); this.createGraphicalTieNote( beams, activeClef, octaveShiftValue, graphicalStaffEntry, tieFraction, numberOfDots, openTie, isLastTieNote ); let tieStartNote: Note = openTie.Start; if (isLastTieNote && tieStartNote.ParentVoiceEntry.Articulations.length === 1 && tieStartNote.ParentVoiceEntry.Articulations[0] === ArticulationEnum.fermata) { this.symbolFactory.addFermataAtTiedEndNote(tieStartNote, graphicalStaffEntry); } openTie.NoteHasBeenCreated[k] = true; if (openTie.allGraphicalNotesHaveBeenCreated()) { removeTie = true; //tieTimestampListDict.remove(openTie); } } } } return removeTie; }); } protected resetYPositionForLeadSheet(psi: BoundingBox): void { if (this.leadSheet) { psi.RelativePosition = new PointF2D(psi.RelativePosition.x, 0.0); } } protected layoutVoiceEntries(graphicalStaffEntry: GraphicalStaffEntry): void { graphicalStaffEntry.PositionAndShape.RelativePosition = new PointF2D(0.0, 0.0); let isGraceStaffEntry: boolean = graphicalStaffEntry.staffEntryParent !== undefined; if (!this.leadSheet) { let graphicalStaffEntryNotes: GraphicalNote[][] = graphicalStaffEntry.notes; for (let idx4: number = 0, len4: number = graphicalStaffEntryNotes.length; idx4 < len4; ++idx4) { let graphicalNotes: GraphicalNote[] = graphicalStaffEntryNotes[idx4]; if (graphicalNotes.length === 0) { continue; } let voiceEntry: VoiceEntry = graphicalNotes[0].sourceNote.ParentVoiceEntry; let hasPitchedNote: boolean = graphicalNotes[0].sourceNote.Pitch !== undefined; this.layoutVoiceEntry(voiceEntry, graphicalNotes, graphicalStaffEntry, hasPitchedNote, isGraceStaffEntry); } } } protected maxInstrNameLabelLength(): number { let maxLabelLength: number = 0.0; for (let instrument of this.graphicalMusicSheet.ParentMusicSheet.Instruments) { if (instrument.Voices.length > 0 && instrument.Voices[0].Visible) { let graphicalLabel: GraphicalLabel = new GraphicalLabel(instrument.NameLabel, this.rules.InstrumentLabelTextHeight, TextAlignment.LeftCenter); graphicalLabel.setLabelPositionAndShapeBorders(); maxLabelLength = Math.max(maxLabelLength, graphicalLabel.PositionAndShape.MarginSize.width); } } return maxLabelLength; } protected calculateSheetLabelBoundingBoxes(): void { let musicSheet: MusicSheet = this.graphicalMusicSheet.ParentMusicSheet; if (musicSheet.Title !== undefined) { let title: GraphicalLabel = new GraphicalLabel(musicSheet.Title, this.rules.SheetTitleHeight, TextAlignment.CenterBottom); this.graphicalMusicSheet.Title = title; title.setLabelPositionAndShapeBorders(); } if (musicSheet.Subtitle !== undefined) { let subtitle: GraphicalLabel = new GraphicalLabel(musicSheet.Subtitle, this.rules.SheetSubtitleHeight, TextAlignment.CenterCenter); this.graphicalMusicSheet.Subtitle = subtitle; subtitle.setLabelPositionAndShapeBorders(); } if (musicSheet.Composer !== undefined) { let composer: GraphicalLabel = new GraphicalLabel(musicSheet.Composer, this.rules.SheetComposerHeight, TextAlignment.RightCenter); this.graphicalMusicSheet.Composer = composer; composer.setLabelPositionAndShapeBorders(); } if (musicSheet.Lyricist !== undefined) { let lyricist: GraphicalLabel = new GraphicalLabel(musicSheet.Lyricist, this.rules.SheetAuthorHeight, TextAlignment.LeftCenter); this.graphicalMusicSheet.Lyricist = lyricist; lyricist.setLabelPositionAndShapeBorders(); } } protected checkMeasuresForWholeRestNotes(): void { for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) { let musicPage: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx]; for (let idx2: number = 0, len2: number = musicPage.MusicSystems.length; idx2 < len2; ++idx2) { let musicSystem: MusicSystem = musicPage.MusicSystems[idx2]; for (let idx3: number = 0, len3: number = musicSystem.StaffLines.length; idx3 < len3; ++idx3) { let staffLine: StaffLine = musicSystem.StaffLines[idx3]; for (let idx4: number = 0, len4: number = staffLine.Measures.length; idx4 < len4; ++idx4) { let measure: StaffMeasure = staffLine.Measures[idx4]; if (measure.staffEntries.length === 1) { let gse: GraphicalStaffEntry = measure.staffEntries[0]; if (gse.notes.length > 0 && gse.notes[0].length > 0) { let graphicalNote: GraphicalNote = gse.notes[0][0]; if (graphicalNote.sourceNote.Pitch === undefined && (new Fraction(1, 2)).lt(graphicalNote.sourceNote.Length)) { this.layoutMeasureWithWholeRest(graphicalNote, gse, measure); } } } } } } } } protected optimizeRestNotePlacement(graphicalStaffEntry: GraphicalStaffEntry, measure: StaffMeasure): void { if (graphicalStaffEntry.notes.length === 0) { return; } let voice1Notes: GraphicalNote[] = graphicalStaffEntry.notes[0]; if (voice1Notes.length === 0) { return; } let voice1Note1: GraphicalNote = voice1Notes[0]; let voice1Note1IsRest: boolean = voice1Note1.sourceNote.Pitch === undefined; if (graphicalStaffEntry.notes.length === 2) { let voice2Note1IsRest: boolean = false; let voice2Notes: GraphicalNote[] = graphicalStaffEntry.notes[1]; if (voice2Notes.length > 0) { let voice2Note1: GraphicalNote = voice2Notes[0]; voice2Note1IsRest = voice2Note1.sourceNote.Pitch === undefined; } if (voice1Note1IsRest && voice2Note1IsRest) { this.calculateTwoRestNotesPlacementWithCollisionDetection(graphicalStaffEntry); } else if (voice1Note1IsRest || voice2Note1IsRest) { this.calculateRestNotePlacementWithCollisionDetectionFromGraphicalNote(graphicalStaffEntry); } } else if (voice1Note1IsRest && graphicalStaffEntry !== measure.staffEntries[0] && graphicalStaffEntry !== measure.staffEntries[measure.staffEntries.length - 1]) { let staffEntryIndex: number = measure.staffEntries.indexOf(graphicalStaffEntry); let previousStaffEntry: GraphicalStaffEntry = measure.staffEntries[staffEntryIndex - 1]; let nextStaffEntry: GraphicalStaffEntry = measure.staffEntries[staffEntryIndex + 1]; if (previousStaffEntry.notes.length === 1) { let previousNote: GraphicalNote = previousStaffEntry.notes[0][0]; if (previousNote.sourceNote.NoteBeam !== undefined && nextStaffEntry.notes.length === 1) { let nextNote: GraphicalNote = nextStaffEntry.notes[0][0]; if (nextNote.sourceNote.NoteBeam !== undefined && previousNote.sourceNote.NoteBeam === nextNote.sourceNote.NoteBeam) { this.calculateRestNotePlacementWithinGraphicalBeam( graphicalStaffEntry, voice1Note1, previousNote, nextStaffEntry, nextNote ); graphicalStaffEntry.PositionAndShape.calculateBoundingBox(); } } } } } protected getRelativePositionInStaffLineFromTimestamp(timestamp: Fraction, verticalIndex: number, staffLine: StaffLine, multiStaffInstrument: boolean, firstVisibleMeasureRelativeX: number = 0.0): PointF2D { let relative: PointF2D = new PointF2D(); let leftStaffEntry: GraphicalStaffEntry = undefined; let rightStaffEntry: GraphicalStaffEntry = undefined; let numEntries: number = this.graphicalMusicSheet.VerticalGraphicalStaffEntryContainers.length; let index: number = this.graphicalMusicSheet.GetInterpolatedIndexInVerticalContainers(timestamp); let leftIndex: number = Math.min(Math.floor(index), numEntries - 1); let rightIndex: number = Math.min(Math.ceil(index), numEntries - 1); if (leftIndex < 0 || verticalIndex < 0) { return relative; } leftStaffEntry = this.getFirstLeftNotNullStaffEntryFromContainer(leftIndex, verticalIndex, multiStaffInstrument); rightStaffEntry = this.getFirstRightNotNullStaffEntryFromContainer(rightIndex, verticalIndex, multiStaffInstrument); if (leftStaffEntry !== undefined && rightStaffEntry !== undefined) { let measureRelativeX: number = leftStaffEntry.parentMeasure.PositionAndShape.RelativePosition.x; if (firstVisibleMeasureRelativeX > 0) { measureRelativeX = firstVisibleMeasureRelativeX; } let leftX: number = leftStaffEntry.PositionAndShape.RelativePosition.x + measureRelativeX; let rightX: number = rightStaffEntry.PositionAndShape.RelativePosition.x + rightStaffEntry.parentMeasure.PositionAndShape.RelativePosition.x; if (firstVisibleMeasureRelativeX > 0) { rightX = rightStaffEntry.PositionAndShape.RelativePosition.x + measureRelativeX; } let timestampQuotient: number = 0.0; if (leftStaffEntry !== rightStaffEntry) { let leftTimestamp: Fraction = leftStaffEntry.getAbsoluteTimestamp(); let rightTimestamp: Fraction = rightStaffEntry.getAbsoluteTimestamp(); let leftDifference: Fraction = Fraction.minus(timestamp, leftTimestamp); timestampQuotient = leftDifference.RealValue / Fraction.minus(rightTimestamp, leftTimestamp).RealValue; } if (leftStaffEntry.parentMeasure.ParentStaffLine !== rightStaffEntry.parentMeasure.ParentStaffLine) { if (leftStaffEntry.parentMeasure.ParentStaffLine === staffLine) { rightX = staffLine.PositionAndShape.Size.width; } else { leftX = staffLine.PositionAndShape.RelativePosition.x; } } relative = new PointF2D(leftX + (rightX - leftX) * timestampQuotient, 0.0); } return relative; } protected getRelativeXPositionFromTimestamp(timestamp: Fraction): number { let numEntries: number = this.graphicalMusicSheet.VerticalGraphicalStaffEntryContainers.length; let index: number = this.graphicalMusicSheet.GetInterpolatedIndexInVerticalContainers(timestamp); let discreteIndex: number = Math.max(0, Math.min(Math.round(index), numEntries - 1)); let gse: GraphicalStaffEntry = this.graphicalMusicSheet.VerticalGraphicalStaffEntryContainers[discreteIndex].getFirstNonNullStaffEntry(); let posX: number = gse.PositionAndShape.RelativePosition.x + gse.parentMeasure.PositionAndShape.RelativePosition.x; return posX; } protected calculatePageLabels(page: GraphicalMusicPage): void { let firstSystemAbsoluteTopMargin: number = 10; if (page.MusicSystems.length > 0) { let firstMusicSystem: MusicSystem = page.MusicSystems[0]; firstSystemAbsoluteTopMargin = firstMusicSystem.PositionAndShape.RelativePosition.y + firstMusicSystem.PositionAndShape.BorderTop; } if (this.graphicalMusicSheet.Title !== undefined) { let title: GraphicalLabel = this.graphicalMusicSheet.Title; title.PositionAndShape.Parent = page.PositionAndShape; page.PositionAndShape.ChildElements.push(title.PositionAndShape); let relative: PointF2D = new PointF2D(); relative.x = this.graphicalMusicSheet.ParentMusicSheet.pageWidth / 2; relative.y = this.rules.TitleTopDistance + this.rules.SheetTitleHeight; title.PositionAndShape.RelativePosition = relative; page.Labels.push(title); } if (this.graphicalMusicSheet.Subtitle !== undefined) { let subtitle: GraphicalLabel = this.graphicalMusicSheet.Subtitle; subtitle.PositionAndShape.Parent = page.PositionAndShape; page.PositionAndShape.ChildElements.push(subtitle.PositionAndShape); let relative: PointF2D = new PointF2D(); relative.x = this.graphicalMusicSheet.ParentMusicSheet.pageWidth / 2; relative.y = this.rules.TitleTopDistance + this.rules.SheetTitleHeight + this.rules.SheetMinimumDistanceBetweenTitleAndSubtitle; subtitle.PositionAndShape.RelativePosition = relative; page.Labels.push(subtitle); } if (this.graphicalMusicSheet.Composer !== undefined) { let composer: GraphicalLabel = this.graphicalMusicSheet.Composer; composer.PositionAndShape.Parent = page.PositionAndShape; page.PositionAndShape.ChildElements.push(composer.PositionAndShape); composer.setLabelPositionAndShapeBorders(); let relative: PointF2D = new PointF2D(); relative.x = this.graphicalMusicSheet.ParentMusicSheet.pageWidth - this.rules.PageRightMargin; relative.y = firstSystemAbsoluteTopMargin - this.rules.SystemComposerDistance; composer.PositionAndShape.RelativePosition = relative; page.Labels.push(composer); } if (this.graphicalMusicSheet.Lyricist !== undefined) { let lyricist: GraphicalLabel = this.graphicalMusicSheet.Lyricist; lyricist.PositionAndShape.Parent = page.PositionAndShape; page.PositionAndShape.ChildElements.push(lyricist.PositionAndShape); lyricist.setLabelPositionAndShapeBorders(); let relative: PointF2D = new PointF2D(); relative.x = this.rules.PageLeftMargin; relative.y = firstSystemAbsoluteTopMargin - this.rules.SystemComposerDistance; lyricist.PositionAndShape.RelativePosition = relative; page.Labels.push(lyricist); } } protected createGraphicalTies(): void { for (let measureIndex: number = 0; measureIndex < this.graphicalMusicSheet.ParentMusicSheet.SourceMeasures.length; measureIndex++) { let sourceMeasure: SourceMeasure = this.graphicalMusicSheet.ParentMusicSheet.SourceMeasures[measureIndex]; for (let staffIndex: number = 0; staffIndex < sourceMeasure.CompleteNumberOfStaves; staffIndex++) { for (let j: number = 0; j < sourceMeasure.VerticalSourceStaffEntryContainers.length; j++) { let sourceStaffEntry: SourceStaffEntry = sourceMeasure.VerticalSourceStaffEntryContainers[j].StaffEntries[staffIndex]; if (sourceStaffEntry !== undefined) { let startStaffEntry: GraphicalStaffEntry = this.graphicalMusicSheet.findGraphicalStaffEntryFromMeasureList( staffIndex, measureIndex, sourceStaffEntry ); for (let idx: number = 0, len: number = sourceStaffEntry.VoiceEntries.length; idx < len; ++idx) { let voiceEntry: VoiceEntry = sourceStaffEntry.VoiceEntries[idx]; for (let idx2: number = 0, len2: number = voiceEntry.Notes.length; idx2 < len2; ++idx2) { let note: Note = voiceEntry.Notes[idx2]; if (note.NoteTie !== undefined) { let tie: Tie = note.NoteTie; this.handleTie(tie, startStaffEntry, staffIndex, measureIndex); } } } } } } } } private createAccidentalCalculators(): AccidentalCalculator[] { let accidentalCalculators: AccidentalCalculator[] = []; let firstSourceMeasure: SourceMeasure = this.graphicalMusicSheet.ParentMusicSheet.getFirstSourceMeasure(); if (firstSourceMeasure !== undefined) { for (let i: number = 0; i < firstSourceMeasure.CompleteNumberOfStaves; i++) { let accidentalCalculator: AccidentalCalculator = new AccidentalCalculator(this.symbolFactory); accidentalCalculators.push(accidentalCalculator); if (firstSourceMeasure.FirstInstructionsStaffEntries[i] !== undefined) { for (let idx: number = 0, len: number = firstSourceMeasure.FirstInstructionsStaffEntries[i].Instructions.length; idx < len; ++idx) { let abstractNotationInstruction: AbstractNotationInstruction = firstSourceMeasure.FirstInstructionsStaffEntries[i].Instructions[idx]; if (abstractNotationInstruction instanceof KeyInstruction) { let keyInstruction: KeyInstruction = abstractNotationInstruction; accidentalCalculator.ActiveKeyInstruction = keyInstruction; } } } } } return accidentalCalculators; } private calculateVerticalContainersList(): void { let numberOfEntries: number = this.graphicalMusicSheet.MeasureList[0].length; for (let i: number = 0; i < this.graphicalMusicSheet.MeasureList.length; i++) { for (let j: number = 0; j < numberOfEntries; j++) { let measure: StaffMeasure = this.graphicalMusicSheet.MeasureList[i][j]; for (let idx: number = 0, len: number = measure.staffEntries.length; idx < len; ++idx) { let graphicalStaffEntry: GraphicalStaffEntry = measure.staffEntries[idx]; let verticalContainer: VerticalGraphicalStaffEntryContainer = this.graphicalMusicSheet.getOrCreateVerticalContainer(graphicalStaffEntry.getAbsoluteTimestamp()); if (verticalContainer !== undefined) { verticalContainer.StaffEntries[j] = graphicalStaffEntry; graphicalStaffEntry.parentVerticalContainer = verticalContainer; } else { ; } } } } } private setIndecesToVerticalGraphicalContainers(): void { for (let i: number = 0; i < this.graphicalMusicSheet.VerticalGraphicalStaffEntryContainers.length; i++) { this.graphicalMusicSheet.VerticalGraphicalStaffEntryContainers[i].Index = i; } } private createGraphicalMeasuresForSourceMeasure(sourceMeasure: SourceMeasure, accidentalCalculators: AccidentalCalculator[], openLyricWords: LyricWord[], tieTimestampListDictList: Dictionary[], openOctaveShifts: OctaveShiftParams[], activeClefs: ClefInstruction[]): StaffMeasure[] { this.initStaffMeasuresCreation(); let verticalMeasureList: StaffMeasure[] = []; let openBeams: Beam[] = []; let openTuplets: Tuplet[] = []; let staffEntryLinks: StaffEntryLink[] = []; for (let staffIndex: number = 0; staffIndex < sourceMeasure.CompleteNumberOfStaves; staffIndex++) { let measure: StaffMeasure = this.createGraphicalMeasure( sourceMeasure, tieTimestampListDictList[staffIndex], openTuplets, openBeams, accidentalCalculators[staffIndex], activeClefs, openOctaveShifts, openLyricWords, staffIndex, staffEntryLinks ); verticalMeasureList.push(measure); } this.graphicalMusicSheet.sourceToGraphicalMeasureLinks.setValue(sourceMeasure, verticalMeasureList); return verticalMeasureList; } private createGraphicalMeasure(sourceMeasure: SourceMeasure, tieTimestampListDict: Dictionary, openTuplets: Tuplet[], openBeams: Beam[], accidentalCalculator: AccidentalCalculator, activeClefs: ClefInstruction[], openOctaveShifts: OctaveShiftParams[], openLyricWords: LyricWord[], staffIndex: number, staffEntryLinks: StaffEntryLink[]): StaffMeasure { let staff: Staff = this.graphicalMusicSheet.ParentMusicSheet.getStaffFromIndex(staffIndex); let measure: StaffMeasure = this.symbolFactory.createStaffMeasure(sourceMeasure, staff); measure.hasError = sourceMeasure.getErrorInMeasure(staffIndex); if (sourceMeasure.FirstInstructionsStaffEntries[staffIndex] !== undefined) { for (let idx: number = 0, len: number = sourceMeasure.FirstInstructionsStaffEntries[staffIndex].Instructions.length; idx < len; ++idx) { let instruction: AbstractNotationInstruction = sourceMeasure.FirstInstructionsStaffEntries[staffIndex].Instructions[idx]; if (instruction instanceof KeyInstruction) { let key: KeyInstruction = KeyInstruction.copy(instruction); if (this.graphicalMusicSheet.ParentMusicSheet.Transpose !== 0 && measure.ParentStaff.ParentInstrument.MidiInstrumentId !== MidiInstrument.Percussion && MusicSheetCalculator.transposeCalculator !== undefined) { MusicSheetCalculator.transposeCalculator.transposeKey( key, this.graphicalMusicSheet.ParentMusicSheet.Transpose ); } accidentalCalculator.ActiveKeyInstruction = key; } } } for (let idx: number = 0, len: number = sourceMeasure.StaffLinkedExpressions[staffIndex].length; idx < len; ++idx) { let multiExpression: MultiExpression = sourceMeasure.StaffLinkedExpressions[staffIndex][idx]; if (multiExpression.OctaveShiftStart !== undefined) { let openOctaveShift: OctaveShift = multiExpression.OctaveShiftStart; openOctaveShifts[staffIndex] = new OctaveShiftParams( openOctaveShift, multiExpression.AbsoluteTimestamp, openOctaveShift.ParentEndMultiExpression.AbsoluteTimestamp ); } } for (let entryIndex: number = 0; entryIndex < sourceMeasure.VerticalSourceStaffEntryContainers.length; entryIndex++) { let sourceStaffEntry: SourceStaffEntry = sourceMeasure.VerticalSourceStaffEntryContainers[entryIndex].StaffEntries[staffIndex]; if (sourceStaffEntry !== undefined) { for (let idx: number = 0, len: number = sourceStaffEntry.Instructions.length; idx < len; ++idx) { let abstractNotationInstruction: AbstractNotationInstruction = sourceStaffEntry.Instructions[idx]; if (abstractNotationInstruction instanceof ClefInstruction) { activeClefs[staffIndex] = abstractNotationInstruction; } } let graphicalStaffEntry: GraphicalStaffEntry = this.symbolFactory.createStaffEntry(sourceStaffEntry, measure); if (measure.staffEntries.length > entryIndex) { measure.addGraphicalStaffEntryAtTimestamp(graphicalStaffEntry); } else { measure.addGraphicalStaffEntry(graphicalStaffEntry); } let linkedNotes: Note[] = []; if (sourceStaffEntry.Link !== undefined) { sourceStaffEntry.findLinkedNotes(linkedNotes); this.handleStaffEntryLink(graphicalStaffEntry, staffEntryLinks); } let octaveShiftValue: OctaveEnum = OctaveEnum.NONE; if (openOctaveShifts[staffIndex] !== undefined) { let octaveShiftParams: OctaveShiftParams = openOctaveShifts[staffIndex]; if (sourceStaffEntry.AbsoluteTimestamp >= octaveShiftParams.getAbsoluteStartTimestamp && sourceStaffEntry.AbsoluteTimestamp <= octaveShiftParams.getAbsoluteEndTimestamp) { octaveShiftValue = octaveShiftParams.getOpenOctaveShift.Type; } } for (let idx: number = 0, len: number = sourceStaffEntry.VoiceEntries.length; idx < len; ++idx) { let voiceEntry: VoiceEntry = sourceStaffEntry.VoiceEntries[idx]; this.handleVoiceEntryGraceNotes( voiceEntry.graceVoiceEntriesBefore, graphicalStaffEntry.graceStaffEntriesBefore, graphicalStaffEntry, accidentalCalculator, activeClefs[staffIndex], octaveShiftValue, openLyricWords, tieTimestampListDict, openTuplets, openBeams ); octaveShiftValue = this.handleVoiceEntry( voiceEntry, graphicalStaffEntry, accidentalCalculator, openLyricWords, tieTimestampListDict, activeClefs[staffIndex], openTuplets, openBeams, octaveShiftValue, false, linkedNotes, sourceStaffEntry ); this.handleVoiceEntryGraceNotes( voiceEntry.graceVoiceEntriesAfter, graphicalStaffEntry.graceStaffEntriesAfter, graphicalStaffEntry, accidentalCalculator, activeClefs[staffIndex], octaveShiftValue, openLyricWords, tieTimestampListDict, openTuplets, openBeams ); } if (sourceStaffEntry.Instructions.length > 0) { let clefInstruction: ClefInstruction = sourceStaffEntry.Instructions[0]; this.symbolFactory.createInStaffClef(graphicalStaffEntry, clefInstruction); } if (sourceStaffEntry.ChordContainer !== undefined) { sourceStaffEntry.ParentStaff.ParentInstrument.HasChordSymbols = true; this.symbolFactory.createChordSymbol(sourceStaffEntry, graphicalStaffEntry, this.graphicalMusicSheet.ParentMusicSheet.Transpose); } } } if (tieTimestampListDict.size() > 0) { this.handleOpenTies( measure, openBeams, tieTimestampListDict, activeClefs[staffIndex], openOctaveShifts[staffIndex] ); } accidentalCalculator.doCalculationsAtEndOfMeasure(); if (sourceMeasure.LastInstructionsStaffEntries[staffIndex] !== undefined) { let lastStaffEntry: SourceStaffEntry = sourceMeasure.LastInstructionsStaffEntries[staffIndex]; for (let idx: number = 0, len: number = lastStaffEntry.Instructions.length; idx < len; ++idx) { let abstractNotationInstruction: AbstractNotationInstruction = lastStaffEntry.Instructions[idx]; if (abstractNotationInstruction instanceof ClefInstruction) { activeClefs[staffIndex] = abstractNotationInstruction; } } } for (let idx: number = 0, len: number = sourceMeasure.StaffLinkedExpressions[staffIndex].length; idx < len; ++idx) { let multiExpression: MultiExpression = sourceMeasure.StaffLinkedExpressions[staffIndex][idx]; if (multiExpression.OctaveShiftEnd !== undefined && openOctaveShifts[staffIndex] !== undefined && multiExpression.OctaveShiftEnd === openOctaveShifts[staffIndex].getOpenOctaveShift) { openOctaveShifts[staffIndex] = undefined; } } if (measure.staffEntries.length === 0) { let sourceStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, staff); let note: Note = new Note(undefined, sourceStaffEntry, Fraction.createFromFraction(sourceMeasure.Duration), undefined); let graphicalStaffEntry: GraphicalStaffEntry = this.symbolFactory.createStaffEntry(sourceStaffEntry, measure); measure.addGraphicalStaffEntry(graphicalStaffEntry); graphicalStaffEntry.relInMeasureTimestamp = new Fraction(0, 1); let graphicalNotes: GraphicalNote[] = []; graphicalStaffEntry.notes.push(graphicalNotes); let numberOfDots: number = note.calculateNumberOfNeededDots(); let graphicalNote: GraphicalNote = this.symbolFactory.createNote( note, numberOfDots, graphicalStaffEntry, new ClefInstruction(ClefEnum.G, 0, 2), OctaveEnum.NONE); graphicalNotes.push(graphicalNote); graphicalStaffEntry.PositionAndShape.ChildElements.push(graphicalNote.PositionAndShape); } return measure; } private checkVoiceEntriesForTechnicalInstructions(voiceEntry: VoiceEntry, graphicalStaffEntry: GraphicalStaffEntry): void { for (let idx: number = 0, len: number = voiceEntry.TechnicalInstructions.length; idx < len; ++idx) { let technicalInstruction: TechnicalInstruction = voiceEntry.TechnicalInstructions[idx]; this.symbolFactory.createGraphicalTechnicalInstruction(technicalInstruction, graphicalStaffEntry); } } private checkNoteForAccidental(graphicalNote: GraphicalNote, accidentalCalculator: AccidentalCalculator, activeClef: ClefInstruction, octaveEnum: OctaveEnum, grace: boolean = false): void { let pitch: Pitch = graphicalNote.sourceNote.Pitch; let transpose: number = this.graphicalMusicSheet.ParentMusicSheet.Transpose; if (transpose !== 0 && graphicalNote.sourceNote.ParentStaffEntry.ParentStaff.ParentInstrument.MidiInstrumentId !== MidiInstrument.Percussion) { pitch = graphicalNote.Transpose( accidentalCalculator.ActiveKeyInstruction, activeClef, transpose, octaveEnum ); if (graphicalNote.sourceNote.NoteTie !== undefined) { graphicalNote.sourceNote.NoteTie.BaseNoteYPosition = graphicalNote.PositionAndShape.RelativePosition.y; } } graphicalNote.sourceNote.halfTone = pitch.getHalfTone(); let scalingFactor: number = 1.0; if (grace) { scalingFactor = this.rules.GraceNoteScalingFactor; } accidentalCalculator.checkAccidental(graphicalNote, pitch, grace, scalingFactor); } // needed to disable linter, as it doesn't recognize the existing usage of this method. // ToDo: check if a newer version doesn't have the problem. /* tslint:disable:no-unused-variable */ private createStaffEntryForTieNote(measure: StaffMeasure, absoluteTimestamp: Fraction, openTie: Tie): GraphicalStaffEntry { /* tslint:enable:no-unused-variable */ let graphicalStaffEntry: GraphicalStaffEntry; graphicalStaffEntry = this.symbolFactory.createStaffEntry(openTie.Start.ParentStaffEntry, measure); graphicalStaffEntry.relInMeasureTimestamp = Fraction.minus(absoluteTimestamp, measure.parentSourceMeasure.AbsoluteTimestamp); this.resetYPositionForLeadSheet(graphicalStaffEntry.PositionAndShape); measure.addGraphicalStaffEntry(graphicalStaffEntry); return graphicalStaffEntry; } private updateSkyBottomLines(): void { for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) { let graphicalMusicPage: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx]; for (let idx2: number = 0, len2: number = graphicalMusicPage.MusicSystems.length; idx2 < len2; ++idx2) { let musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2]; for (let idx3: number = 0, len3: number = musicSystem.StaffLines.length; idx3 < len3; ++idx3) { let staffLine: StaffLine = musicSystem.StaffLines[idx3]; this.updateSkyBottomLine(staffLine); } } } } private handleStaffEntries(): void { for (let idx: number = 0, len: number = this.graphicalMusicSheet.MeasureList.length; idx < len; ++idx) { let measures: StaffMeasure[] = this.graphicalMusicSheet.MeasureList[idx]; for (let idx2: number = 0, len2: number = measures.length; idx2 < len2; ++idx2) { let measure: StaffMeasure = measures[idx2]; for (let idx3: number = 0, len3: number = measure.staffEntries.length; idx3 < len3; ++idx3) { let graphicalStaffEntry: GraphicalStaffEntry = measure.staffEntries[idx3]; if (graphicalStaffEntry.parentMeasure !== undefined && graphicalStaffEntry.notes.length > 0 && graphicalStaffEntry.notes[0].length > 0) { this.layoutVoiceEntries(graphicalStaffEntry); this.layoutStaffEntry(graphicalStaffEntry); } } } } } private calculateSkyBottomLines(): void { for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) { let graphicalMusicPage: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx]; for (let idx2: number = 0, len2: number = graphicalMusicPage.MusicSystems.length; idx2 < len2; ++idx2) { let musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2]; for (let idx3: number = 0, len3: number = musicSystem.StaffLines.length; idx3 < len3; ++idx3) { let staffLine: StaffLine = musicSystem.StaffLines[idx3]; this.calculateSkyBottomLine(staffLine); } } } } private calculateBeams(): void { for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) { let musicPage: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx]; for (let idx2: number = 0, len2: number = musicPage.MusicSystems.length; idx2 < len2; ++idx2) { let musicSystem: MusicSystem = musicPage.MusicSystems[idx2]; for (let idx3: number = 0, len3: number = musicSystem.StaffLines.length; idx3 < len3; ++idx3) { let staffLine: StaffLine = musicSystem.StaffLines[idx3]; for (let idx4: number = 0, len4: number = staffLine.Measures.length; idx4 < len4; ++idx4) { let measure: StaffMeasure = staffLine.Measures[idx4]; for (let idx5: number = 0, len5: number = measure.staffEntries.length; idx5 < len5; ++idx5) { let staffEntry: GraphicalStaffEntry = measure.staffEntries[idx5]; this.layoutBeams(staffEntry); } } } } } } private calculateStaffEntryArticulationMarks(): void { for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) { let page: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx]; for (let idx2: number = 0, len2: number = page.MusicSystems.length; idx2 < len2; ++idx2) { let system: MusicSystem = page.MusicSystems[idx2]; for (let idx3: number = 0, len3: number = system.StaffLines.length; idx3 < len3; ++idx3) { let line: StaffLine = system.StaffLines[idx3]; for (let idx4: number = 0, len4: number = line.Measures.length; idx4 < len4; ++idx4) { let measure: StaffMeasure = line.Measures[idx4]; for (let idx5: number = 0, len5: number = measure.staffEntries.length; idx5 < len5; ++idx5) { let graphicalStaffEntry: GraphicalStaffEntry = measure.staffEntries[idx5]; for (let idx6: number = 0, len6: number = graphicalStaffEntry.sourceStaffEntry.VoiceEntries.length; idx6 < len6; ++idx6) { let voiceEntry: VoiceEntry = graphicalStaffEntry.sourceStaffEntry.VoiceEntries[idx6]; if (voiceEntry.Articulations.length > 0) { this.layoutArticulationMarks(voiceEntry.Articulations, voiceEntry, graphicalStaffEntry); } } } } } } } } private calculateOrnaments(): void { for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) { let page: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx]; for (let idx2: number = 0, len2: number = page.MusicSystems.length; idx2 < len2; ++idx2) { let system: MusicSystem = page.MusicSystems[idx2]; for (let idx3: number = 0, len3: number = system.StaffLines.length; idx3 < len3; ++idx3) { let line: StaffLine = system.StaffLines[idx3]; for (let idx4: number = 0, len4: number = line.Measures.length; idx4 < len4; ++idx4) { let measure: StaffMeasure = line.Measures[idx4]; for (let idx5: number = 0, len5: number = measure.staffEntries.length; idx5 < len5; ++idx5) { let graphicalStaffEntry: GraphicalStaffEntry = measure.staffEntries[idx5]; for (let idx6: number = 0, len6: number = graphicalStaffEntry.sourceStaffEntry.VoiceEntries.length; idx6 < len6; ++idx6) { let voiceEntry: VoiceEntry = graphicalStaffEntry.sourceStaffEntry.VoiceEntries[idx6]; if (voiceEntry.OrnamentContainer !== undefined) { if (voiceEntry.hasTie() && graphicalStaffEntry.relInMeasureTimestamp !== voiceEntry.Timestamp) { continue; } this.layoutOrnament(voiceEntry.OrnamentContainer, voiceEntry, graphicalStaffEntry); if (!(this.staffEntriesWithOrnaments.indexOf(graphicalStaffEntry) !== -1)) { this.staffEntriesWithOrnaments.push(graphicalStaffEntry); } } } } } } } } } private optimizeRestPlacement(): void { for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) { let page: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx]; for (let idx2: number = 0, len2: number = page.MusicSystems.length; idx2 < len2; ++idx2) { let system: MusicSystem = page.MusicSystems[idx2]; for (let idx3: number = 0, len3: number = system.StaffLines.length; idx3 < len3; ++idx3) { let line: StaffLine = system.StaffLines[idx3]; for (let idx4: number = 0, len4: number = line.Measures.length; idx4 < len4; ++idx4) { let measure: StaffMeasure = line.Measures[idx4]; for (let idx5: number = 0, len5: number = measure.staffEntries.length; idx5 < len5; ++idx5) { let graphicalStaffEntry: GraphicalStaffEntry = measure.staffEntries[idx5]; this.optimizeRestNotePlacement(graphicalStaffEntry, measure); } } } } } } private calculateTwoRestNotesPlacementWithCollisionDetection(graphicalStaffEntry: GraphicalStaffEntry): void { let firstRestNote: GraphicalNote = graphicalStaffEntry.notes[0][0]; let secondRestNote: GraphicalNote = graphicalStaffEntry.notes[1][0]; secondRestNote.PositionAndShape.RelativePosition = new PointF2D(0.0, 2.5); graphicalStaffEntry.PositionAndShape.calculateAbsolutePositionsRecursiveWithoutTopelement(); firstRestNote.PositionAndShape.computeNonOverlappingPositionWithMargin( graphicalStaffEntry.PositionAndShape, ColDirEnum.Up, new PointF2D(0.0, secondRestNote.PositionAndShape.RelativePosition.y) ); let relative: PointF2D = firstRestNote.PositionAndShape.RelativePosition; relative.y -= 1.0; firstRestNote.PositionAndShape.RelativePosition = relative; graphicalStaffEntry.PositionAndShape.calculateBoundingBox(); } private calculateRestNotePlacementWithCollisionDetectionFromGraphicalNote(graphicalStaffEntry: GraphicalStaffEntry): void { let restNote: GraphicalNote; let graphicalNotes: GraphicalNote[]; if (graphicalStaffEntry.notes[0][0].sourceNote.Pitch === undefined) { restNote = graphicalStaffEntry.notes[0][0]; graphicalNotes = graphicalStaffEntry.notes[1]; } else { graphicalNotes = graphicalStaffEntry.notes[0]; restNote = graphicalStaffEntry.notes[1][0]; } let collision: boolean = false; graphicalStaffEntry.PositionAndShape.calculateAbsolutePositionsRecursiveWithoutTopelement(); for (let idx: number = 0, len: number = graphicalNotes.length; idx < len; ++idx) { let graphicalNote: GraphicalNote = graphicalNotes[idx]; if (restNote.PositionAndShape.marginCollisionDetection(graphicalNote.PositionAndShape)) { collision = true; break; } } if (collision) { if (restNote.sourceNote.ParentVoiceEntry.ParentVoice instanceof LinkedVoice) { let bottomBorder: number = graphicalNotes[0].PositionAndShape.BorderMarginBottom + graphicalNotes[0].PositionAndShape.RelativePosition.y; restNote.PositionAndShape.RelativePosition = new PointF2D(0.0, bottomBorder - restNote.PositionAndShape.BorderMarginTop + 0.5); } else { let last: GraphicalNote = graphicalNotes[graphicalNotes.length - 1]; let topBorder: number = last.PositionAndShape.BorderMarginTop + last.PositionAndShape.RelativePosition.y; if (graphicalNotes[0].sourceNote.ParentVoiceEntry.ParentVoice instanceof LinkedVoice) { restNote.PositionAndShape.RelativePosition = new PointF2D(0.0, topBorder - restNote.PositionAndShape.BorderMarginBottom - 0.5); } else { let bottomBorder: number = graphicalNotes[0].PositionAndShape.BorderMarginBottom + graphicalNotes[0].PositionAndShape.RelativePosition.y; if (bottomBorder < 2.0) { restNote.PositionAndShape.RelativePosition = new PointF2D(0.0, bottomBorder - restNote.PositionAndShape.BorderMarginTop + 0.5); } else { restNote.PositionAndShape.RelativePosition = new PointF2D(0.0, topBorder - restNote.PositionAndShape.BorderMarginBottom - 0.0); } } } } graphicalStaffEntry.PositionAndShape.calculateBoundingBox(); } private calculateTieCurves(): void { for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) { let graphicalMusicPage: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx]; for (let idx2: number = 0, len2: number = graphicalMusicPage.MusicSystems.length; idx2 < len2; ++idx2) { let musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2]; for (let idx3: number = 0, len3: number = musicSystem.StaffLines.length; idx3 < len3; ++idx3) { let staffLine: StaffLine = musicSystem.StaffLines[idx3]; for (let idx4: number = 0, len5: number = staffLine.Measures.length; idx4 < len5; ++idx4) { let measure: StaffMeasure = staffLine.Measures[idx4]; for (let idx6: number = 0, len6: number = measure.staffEntries.length; idx6 < len6; ++idx6) { let staffEntry: GraphicalStaffEntry = measure.staffEntries[idx6]; let graphicalTies: GraphicalTie[] = staffEntry.GraphicalTies; for (let idx7: number = 0, len7: number = graphicalTies.length; idx7 < len7; ++idx7) { let graphicalTie: GraphicalTie = graphicalTies[idx7]; if (graphicalTie.StartNote !== undefined && graphicalTie.StartNote.parentStaffEntry === staffEntry) { let tieIsAtSystemBreak: boolean = ( graphicalTie.StartNote.parentStaffEntry.parentMeasure.ParentStaffLine !== graphicalTie.EndNote.parentStaffEntry.parentMeasure.ParentStaffLine ); this.layoutGraphicalTie(graphicalTie, tieIsAtSystemBreak); } } } } } } } } // Commented because unused: //private calculateFingering(): void { // for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) { // let graphicalMusicPage: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx]; // for (let idx2: number = 0, len2: number = graphicalMusicPage.MusicSystems.length; idx2 < len2; ++idx2) { // let musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2]; // for (let idx3: number = 0, len3: number = musicSystem.StaffLines.length; idx3 < len3; ++idx3) { // let staffLine: StaffLine = musicSystem.StaffLines[idx3]; // let skyBottomLineCalculator: SkyBottomLineCalculator = new SkyBottomLineCalculator(this.rules); // for (let idx4: number = 0, len4: number = staffLine.Measures.length; idx4 < len4; ++idx4) { // let measure: StaffMeasure = staffLine.Measures[idx4]; // let measureRelativePosition: PointF2D = measure.PositionAndShape.RelativePosition; // for (let idx5: number = 0, len5: number = measure.staffEntries.length; idx5 < len5; ++idx5) { // let staffEntry: GraphicalStaffEntry = measure.staffEntries[idx5]; // let hasTechnicalInstruction: boolean = false; // for (let idx6: number = 0, len6: number = staffEntry.sourceStaffEntry.VoiceEntries.length; idx6 < len6; ++idx6) { // let ve: VoiceEntry = staffEntry.sourceStaffEntry.VoiceEntries[idx6]; // if (ve.TechnicalInstructions.length > 0) { // hasTechnicalInstruction = true; // break; // } // } // if (hasTechnicalInstruction) { // this.layoutFingering(staffLine, skyBottomLineCalculator, staffEntry, measureRelativePosition); // } // } // } // } // } // } //} private calculateLyricsPosition(): void { for (let idx: number = 0, len: number = this.graphicalMusicSheet.ParentMusicSheet.Instruments.length; idx < len; ++idx) { let instrument: Instrument = this.graphicalMusicSheet.ParentMusicSheet.Instruments[idx]; if (instrument.HasLyrics && instrument.LyricVersesNumbers.length > 0) { instrument.LyricVersesNumbers.sort(); } } for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) { let graphicalMusicPage: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx]; for (let idx2: number = 0, len2: number = graphicalMusicPage.MusicSystems.length; idx2 < len2; ++idx2) { let musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2]; for (let idx3: number = 0, len3: number = musicSystem.StaffLines.length; idx3 < len3; ++idx3) { let staffLine: StaffLine = musicSystem.StaffLines[idx3]; this.calculateSingleStaffLineLyricsPosition(staffLine, staffLine.ParentStaff.ParentInstrument.LyricVersesNumbers); } } } } private calculateDynamicExpressions(): void { for (let i: number = 0; i < this.graphicalMusicSheet.ParentMusicSheet.SourceMeasures.length; i++) { let sourceMeasure: SourceMeasure = this.graphicalMusicSheet.ParentMusicSheet.SourceMeasures[i]; for (let j: number = 0; j < sourceMeasure.StaffLinkedExpressions.length; j++) { if (this.graphicalMusicSheet.MeasureList[i][j].ParentStaff.ParentInstrument.Visible) { for (let k: number = 0; k < sourceMeasure.StaffLinkedExpressions[j].length; k++) { if (sourceMeasure.StaffLinkedExpressions[j][k].InstantaniousDynamic !== undefined || (sourceMeasure.StaffLinkedExpressions[j][k].StartingContinuousDynamic !== undefined && sourceMeasure.StaffLinkedExpressions[j][k].StartingContinuousDynamic.StartMultiExpression === sourceMeasure.StaffLinkedExpressions[j][k] && sourceMeasure.StaffLinkedExpressions[j][k].UnknownList.length === 0) ) { this.calculateDynamicExpressionsForSingleMultiExpression(sourceMeasure.StaffLinkedExpressions[j][k], i, j); } } } } } } private calculateOctaveShifts(): void { for (let i: number = 0; i < this.graphicalMusicSheet.ParentMusicSheet.SourceMeasures.length; i++) { let sourceMeasure: SourceMeasure = this.graphicalMusicSheet.ParentMusicSheet.SourceMeasures[i]; for (let j: number = 0; j < sourceMeasure.StaffLinkedExpressions.length; j++) { if (this.graphicalMusicSheet.MeasureList[i][j].ParentStaff.ParentInstrument.Visible) { for (let k: number = 0; k < sourceMeasure.StaffLinkedExpressions[j].length; k++) { if ((sourceMeasure.StaffLinkedExpressions[j][k].OctaveShiftStart !== undefined)) { this.calculateSingleOctaveShift(sourceMeasure, sourceMeasure.StaffLinkedExpressions[j][k], i, j); } } } } } } private getFirstLeftNotNullStaffEntryFromContainer(horizontalIndex: number, verticalIndex: number, multiStaffInstrument: boolean): GraphicalStaffEntry { if (this.graphicalMusicSheet.VerticalGraphicalStaffEntryContainers[horizontalIndex].StaffEntries[verticalIndex] !== undefined) { return this.graphicalMusicSheet.VerticalGraphicalStaffEntryContainers[horizontalIndex].StaffEntries[verticalIndex]; } for (let i: number = horizontalIndex - 1; i >= 0; i--) { if (this.graphicalMusicSheet.VerticalGraphicalStaffEntryContainers[i].StaffEntries[verticalIndex] !== undefined) { return this.graphicalMusicSheet.VerticalGraphicalStaffEntryContainers[i].StaffEntries[verticalIndex]; } } return undefined; } private getFirstRightNotNullStaffEntryFromContainer(horizontalIndex: number, verticalIndex: number, multiStaffInstrument: boolean): GraphicalStaffEntry { if (this.graphicalMusicSheet.VerticalGraphicalStaffEntryContainers[horizontalIndex].StaffEntries[verticalIndex] !== undefined) { return this.graphicalMusicSheet.VerticalGraphicalStaffEntryContainers[horizontalIndex].StaffEntries[verticalIndex]; } for (let i: number = horizontalIndex + 1; i < this.graphicalMusicSheet.VerticalGraphicalStaffEntryContainers.length; i++) { if (this.graphicalMusicSheet.VerticalGraphicalStaffEntryContainers[i].StaffEntries[verticalIndex] !== undefined) { return this.graphicalMusicSheet.VerticalGraphicalStaffEntryContainers[i].StaffEntries[verticalIndex]; } } return undefined; } private calculateWordRepetitionInstructions(): void { for (let i: number = 0; i < this.graphicalMusicSheet.ParentMusicSheet.SourceMeasures.length; i++) { let sourceMeasure: SourceMeasure = this.graphicalMusicSheet.ParentMusicSheet.SourceMeasures[i]; for (let idx: number = 0, len: number = sourceMeasure.FirstRepetitionInstructions.length; idx < len; ++idx) { let instruction: RepetitionInstruction = sourceMeasure.FirstRepetitionInstructions[idx]; this.calculateWordRepetitionInstruction(instruction, i); } for (let idx: number = 0, len: number = sourceMeasure.LastRepetitionInstructions.length; idx < len; ++idx) { let instruction: RepetitionInstruction = sourceMeasure.LastRepetitionInstructions[idx]; this.calculateWordRepetitionInstruction(instruction, i); } } } private calculateRepetitionEndings(): void { let musicsheet: MusicSheet = this.graphicalMusicSheet.ParentMusicSheet; for (let idx: number = 0, len: number = musicsheet.Repetitions.length; idx < len; ++idx) { let partListEntry: Repetition = musicsheet.Repetitions[idx]; this.calcGraphicalRepetitionEndingsRecursively(partListEntry); } } private calculateTempoExpressions(): void { for (let i: number = 0; i < this.graphicalMusicSheet.ParentMusicSheet.SourceMeasures.length; i++) { let sourceMeasure: SourceMeasure = this.graphicalMusicSheet.ParentMusicSheet.SourceMeasures[i]; for (let j: number = 0; j < sourceMeasure.TempoExpressions.length; j++) { this.calculateTempoExpressionsForSingleMultiTempoExpression(sourceMeasure, sourceMeasure.TempoExpressions[j], i); } } } private calculateMoodAndUnknownExpressions(): void { for (let i: number = 0; i < this.graphicalMusicSheet.ParentMusicSheet.SourceMeasures.length; i++) { let sourceMeasure: SourceMeasure = this.graphicalMusicSheet.ParentMusicSheet.SourceMeasures[i]; for (let j: number = 0; j < sourceMeasure.StaffLinkedExpressions.length; j++) { if (this.graphicalMusicSheet.MeasureList[i][j].ParentStaff.ParentInstrument.Visible) { for (let k: number = 0; k < sourceMeasure.StaffLinkedExpressions[j].length; k++) { if ((sourceMeasure.StaffLinkedExpressions[j][k].MoodList.length > 0) || (sourceMeasure.StaffLinkedExpressions[j][k].UnknownList.length > 0)) { this.calculateMoodAndUnknownExpression(sourceMeasure.StaffLinkedExpressions[j][k], i, j); } } } } } } }