Ver código fonte

feat(Articulations): Added ArticulationReader - articulations are read from xml

Matthias Uiberacker 7 anos atrás
pai
commit
f529f4580f

+ 2 - 1
src/Common/DataObjects/Pitch.ts

@@ -14,7 +14,8 @@ export enum AccidentalEnum {
     FLAT = -1,
     NONE = 0,
     SHARP = 1,
-    DOUBLESHARP = 2
+    DOUBLESHARP = 2,
+    NATURAL = 3
 }
 
 // This class represents a musical note. The middle A (440 Hz) lies in the octave with the value 1.

+ 15 - 42
src/MusicalScore/Graphical/MusicSheetCalculator.ts

@@ -275,11 +275,23 @@ export abstract class MusicSheetCalculator {
 
     protected handleVoiceEntryArticulations(articulations: ArticulationEnum[],
                                             voiceEntry: VoiceEntry,
-                                            graphicalStaffEntry: GraphicalStaffEntry): void {
+                                            staffEntry: GraphicalStaffEntry): void {
         throw new Error("abstract, not implemented");
     }
 
-    protected handleTuplet(graphicalNote: GraphicalNote, tuplet: Tuplet, openTuplets: Tuplet[]): void {
+  /**
+   * Adds a technical instruction at the given staff entry.
+   * @param technicalInstructions
+   * @param voiceEntry
+   * @param staffEntry
+   */
+  protected handleVoiceEntryTechnicalInstructions(technicalInstructions: TechnicalInstruction[],
+                                                  voiceEntry: VoiceEntry, staffEntry: GraphicalStaffEntry): void {
+    throw new Error("abstract, not implemented");
+  }
+
+
+  protected handleTuplet(graphicalNote: GraphicalNote, tuplet: Tuplet, openTuplets: Tuplet[]): void {
         throw new Error("abstract, not implemented");
     }
 
@@ -734,7 +746,7 @@ export abstract class MusicSheetCalculator {
             this.handleVoiceEntryArticulations(voiceEntry.Articulations, voiceEntry, graphicalStaffEntry);
         }
         if (voiceEntry.TechnicalInstructions.length > 0) {
-            this.checkVoiceEntriesForTechnicalInstructions(voiceEntry, graphicalStaffEntry);
+            this.handleVoiceEntryTechnicalInstructions(voiceEntry.TechnicalInstructions, voiceEntry, graphicalStaffEntry);
         }
         if (voiceEntry.LyricsEntries.size() > 0) {
             this.handleVoiceEntryLyrics(voiceEntry.LyricsEntries, voiceEntry, graphicalStaffEntry, openLyricWords);
@@ -1332,13 +1344,6 @@ export abstract class MusicSheetCalculator {
         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;
@@ -1591,38 +1596,6 @@ export abstract class MusicSheetCalculator {
         }
     }
 
-    // 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];

+ 1 - 9
src/MusicalScore/Graphical/VexFlow/VexFlowGraphicalSymbolFactory.ts

@@ -16,7 +16,6 @@ import {ClefInstruction} from "../../VoiceData/Instructions/ClefInstruction";
 import {OctaveEnum} from "../../VoiceData/Expressions/ContinuousExpressions/OctaveShift";
 import {GraphicalNote} from "../GraphicalNote";
 import {Pitch} from "../../../Common/DataObjects/Pitch";
-import {TechnicalInstruction} from "../../VoiceData/Instructions/TechnicalInstruction";
 import {VexFlowGraphicalNote} from "./VexFlowGraphicalNote";
 import {Fraction} from "../../../Common/DataObjects/Fraction";
 import {GraphicalChordSymbolContainer} from "../GraphicalChordSymbolContainer";
@@ -150,14 +149,7 @@ export class VexFlowGraphicalSymbolFactory implements IGraphicalSymbolFactory {
         return;
     }
 
-    /**
-     * Adds a technical instruction at the given staff entry.
-     * @param technicalInstruction
-     * @param graphicalStaffEntry
-     */
-    public createGraphicalTechnicalInstruction(technicalInstruction: TechnicalInstruction, graphicalStaffEntry: GraphicalStaffEntry): void {
-        return;
-    }
+
 
     /**
      * Adds a clef change within a measure before the given staff entry.

+ 268 - 231
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetCalculator.ts

@@ -29,252 +29,289 @@ import Vex = require("vexflow");
 import {Logging} from "../../../Common/Logging";
 import {unitInPixels} from "./VexFlowMusicSheetDrawer";
 import {VexFlowGraphicalNote} from "./VexFlowGraphicalNote";
+import {TechnicalInstruction} from "../../VoiceData/Instructions/TechnicalInstruction";
 
 export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
-    constructor() {
-        super(new VexFlowGraphicalSymbolFactory());
-        let a: LyricsEntry = new LyricsEntry(undefined, undefined, undefined);
-        a = a;
-        MusicSheetCalculator.TextMeasurer = new VexFlowTextMeasurer();
+  constructor() {
+    super(new VexFlowGraphicalSymbolFactory());
+    let a: LyricsEntry = new LyricsEntry(undefined, undefined, undefined);
+    a = a;
+    MusicSheetCalculator.TextMeasurer = new VexFlowTextMeasurer();
+  }
+
+  protected clearRecreatedObjects(): void {
+    super.clearRecreatedObjects();
+    for (let staffMeasures of this.graphicalMusicSheet.MeasureList) {
+      for (let staffMeasure of staffMeasures) {
+        (<VexFlowMeasure>staffMeasure).clean();
+      }
     }
+  }
+
+  //protected clearSystemsAndMeasures(): void {
+  //    for (let measure of measures) {
+  //
+  //    }
+  //}
+
+  /**
+   * Calculates the x layout of the staff entries within the staff measures belonging to one source measure.
+   * All staff entries are x-aligned throughout all vertically aligned staff measures.
+   * This method is called within calculateXLayout.
+   * The staff entries are aligned with minimum needed x distances.
+   * The MinimumStaffEntriesWidth of every measure will be set - needed for system building.
+   * @param measures
+   * @returns the minimum required x width of the source measure (=list of staff measures)
+   */
+  protected calculateMeasureXLayout(measures: StaffMeasure[]): number {
+    // Finalize beams
+    /*for (let measure of measures) {
+     (measure as VexFlowMeasure).finalizeBeams();
+     (measure as VexFlowMeasure).finalizeTuplets();
+     }*/
+    // Format the voices
+    let allVoices: Vex.Flow.Voice[] = [];
+    let formatter: Vex.Flow.Formatter = new Vex.Flow.Formatter({
+      align_rests: true,
+    });
+
+    for (let measure of measures) {
+      let mvoices: { [voiceID: number]: Vex.Flow.Voice; } = (measure as VexFlowMeasure).vfVoices;
+      let voices: Vex.Flow.Voice[] = [];
+      for (let voiceID in mvoices) {
+        if (mvoices.hasOwnProperty(voiceID)) {
+          voices.push(mvoices[voiceID]);
+          allVoices.push(mvoices[voiceID]);
 
-    protected clearRecreatedObjects(): void {
-        super.clearRecreatedObjects();
-        for (let staffMeasures of this.graphicalMusicSheet.MeasureList) {
-            for (let staffMeasure of staffMeasures) {
-                (<VexFlowMeasure>staffMeasure).clean();
-            }
         }
+      }
+      if (voices.length === 0) {
+        Logging.warn("Found a measure with no voices... Continuing anyway.", mvoices);
+        continue;
+      }
+      formatter.joinVoices(voices);
     }
 
-    //protected clearSystemsAndMeasures(): void {
-    //    for (let measure of measures) {
-    //
-    //    }
-    //}
-
-    /**
-     * Calculates the x layout of the staff entries within the staff measures belonging to one source measure.
-     * All staff entries are x-aligned throughout all vertically aligned staff measures.
-     * This method is called within calculateXLayout.
-     * The staff entries are aligned with minimum needed x distances.
-     * The MinimumStaffEntriesWidth of every measure will be set - needed for system building.
-     * @param measures
-     * @returns the minimum required x width of the source measure (=list of staff measures)
-     */
-    protected calculateMeasureXLayout(measures: StaffMeasure[]): number {
-        // Finalize beams
-        /*for (let measure of measures) {
-            (measure as VexFlowMeasure).finalizeBeams();
-            (measure as VexFlowMeasure).finalizeTuplets();
-        }*/
-        // Format the voices
-        let allVoices: Vex.Flow.Voice[] = [];
-        let formatter: Vex.Flow.Formatter = new Vex.Flow.Formatter({
-            align_rests: true,
-        });
-
-        for (let measure of measures) {
-            let mvoices:  { [voiceID: number]: Vex.Flow.Voice; } = (measure as VexFlowMeasure).vfVoices;
-            let voices: Vex.Flow.Voice[] = [];
-            for (let voiceID in mvoices) {
-                if (mvoices.hasOwnProperty(voiceID)) {
-                    voices.push(mvoices[voiceID]);
-                    allVoices.push(mvoices[voiceID]);
-
-                }
-            }
-            if (voices.length === 0) {
-                Logging.warn("Found a measure with no voices... Continuing anyway.", mvoices);
-                continue;
-            }
-            formatter.joinVoices(voices);
-        }
-
-        let width: number = 200;
-        if (allVoices.length > 0) {
-            let firstMeasure: VexFlowMeasure = measures[0] as VexFlowMeasure;
-            // FIXME: The following ``+ 5.0'' is temporary: it was added as a workaround for
-            // FIXME: a more relaxed formatting of voices
-            width = formatter.preCalculateMinTotalWidth(allVoices) / unitInPixels + 5.0;
-            for (let measure of measures) {
-                measure.minimumStaffEntriesWidth = width;
-                (measure as VexFlowMeasure).formatVoices = undefined;
-            }
-            firstMeasure.formatVoices = (w: number) => {
-                formatter.format(allVoices, w);
-            };
-        }
-
-        return width;
-    }
-
-    protected createGraphicalTie(tie: Tie, startGse: GraphicalStaffEntry, endGse: GraphicalStaffEntry,
-                                 startNote: GraphicalNote, endNote: GraphicalNote): GraphicalTie {
-        return new GraphicalTie(tie, startNote, endNote);
-    }
-
-
-    protected updateStaffLineBorders(staffLine: StaffLine): void {
-        return;
-    }
-
-    protected calculateMeasureNumberPlacement(musicSystem: MusicSystem): void {
-        return;
+    let width: number = 200;
+    if (allVoices.length > 0) {
+      let firstMeasure: VexFlowMeasure = measures[0] as VexFlowMeasure;
+      // FIXME: The following ``+ 5.0'' is temporary: it was added as a workaround for
+      // FIXME: a more relaxed formatting of voices
+      width = formatter.preCalculateMinTotalWidth(allVoices) / unitInPixels + 5.0;
+      for (let measure of measures) {
+        measure.minimumStaffEntriesWidth = width;
+        (measure as VexFlowMeasure).formatVoices = undefined;
+      }
+      firstMeasure.formatVoices = (w: number) => {
+        formatter.format(allVoices, w);
+      };
     }
 
-    protected staffMeasureCreatedCalculations(measure: StaffMeasure): void {
-        (measure as VexFlowMeasure).staffMeasureCreatedCalculations();
-    }
-
-    /**
-     * Can be used to calculate articulations, stem directions, helper(ledger) lines, and overlapping note x-displacement.
-     * Is Excecuted per voice entry of a staff entry.
-     * After that layoutStaffEntry is called.
-     * @param voiceEntry
-     * @param graphicalNotes
-     * @param graphicalStaffEntry
-     * @param hasPitchedNote
-     * @param isGraceStaffEntry
-     */
-    protected layoutVoiceEntry(voiceEntry: VoiceEntry, graphicalNotes: GraphicalNote[], graphicalStaffEntry: GraphicalStaffEntry,
-                               hasPitchedNote: boolean, isGraceStaffEntry: boolean): void {
-        return;
-    }
-
-    /**
-     * Do all layout calculations that have to be done per staff entry, like dots, ornaments, arpeggios....
-     * This method is called after the voice entries are handled by layoutVoiceEntry().
-     * @param graphicalStaffEntry
-     */
-    protected layoutStaffEntry(graphicalStaffEntry: GraphicalStaffEntry): void {
-        (graphicalStaffEntry.parentMeasure as VexFlowMeasure).layoutStaffEntry(graphicalStaffEntry);
-    }
-
-    /**
-     * calculates the y positions of the staff lines within a system and
-     * furthermore the y positions of the systems themselves.
-     */
-    protected calculateSystemYLayout(): void {
-        for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) {
-            let graphicalMusicPage: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx];
-            if (!this.leadSheet) {
-                let globalY: number = this.rules.PageTopMargin + this.rules.TitleTopDistance + this.rules.SheetTitleHeight +
-                    this.rules.TitleBottomDistance;
-                for (let idx2: number = 0, len2: number = graphicalMusicPage.MusicSystems.length; idx2 < len2; ++idx2) {
-                    let musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2];
-                    // calculate y positions of stafflines within system
-                    let y: number = 0;
-                    for (let line of musicSystem.StaffLines) {
-                        line.PositionAndShape.RelativePosition.y = y;
-                        y += 10;
-                    }
-                    // set y positions of systems using the previous system and a fixed distance.
-                    musicSystem.PositionAndShape.BorderBottom = y + 0;
-                    musicSystem.PositionAndShape.RelativePosition.x = this.rules.PageLeftMargin + this.rules.SystemLeftMargin;
-                    musicSystem.PositionAndShape.RelativePosition.y = globalY;
-                    globalY += y + 5;
-                }
-            }
+    return width;
+  }
+
+  protected createGraphicalTie(tie: Tie, startGse: GraphicalStaffEntry, endGse: GraphicalStaffEntry,
+                               startNote: GraphicalNote, endNote: GraphicalNote): GraphicalTie {
+    return new GraphicalTie(tie, startNote, endNote);
+  }
+
+
+  protected updateStaffLineBorders(staffLine: StaffLine): void {
+    return;
+  }
+
+  protected calculateMeasureNumberPlacement(musicSystem: MusicSystem): void {
+    return;
+  }
+
+  protected staffMeasureCreatedCalculations(measure: StaffMeasure): void {
+    (measure as VexFlowMeasure).staffMeasureCreatedCalculations();
+  }
+
+  /**
+   * Can be used to calculate articulations, stem directions, helper(ledger) lines, and overlapping note x-displacement.
+   * Is Excecuted per voice entry of a staff entry.
+   * After that layoutStaffEntry is called.
+   * @param voiceEntry
+   * @param graphicalNotes
+   * @param graphicalStaffEntry
+   * @param hasPitchedNote
+   * @param isGraceStaffEntry
+   */
+  protected layoutVoiceEntry(voiceEntry: VoiceEntry, graphicalNotes: GraphicalNote[], graphicalStaffEntry: GraphicalStaffEntry,
+                             hasPitchedNote: boolean, isGraceStaffEntry: boolean): void {
+    return;
+  }
+
+  /**
+   * Do all layout calculations that have to be done per staff entry, like dots, ornaments, arpeggios....
+   * This method is called after the voice entries are handled by layoutVoiceEntry().
+   * @param graphicalStaffEntry
+   */
+  protected layoutStaffEntry(graphicalStaffEntry: GraphicalStaffEntry): void {
+    (graphicalStaffEntry.parentMeasure as VexFlowMeasure).layoutStaffEntry(graphicalStaffEntry);
+  }
+
+  /**
+   * calculates the y positions of the staff lines within a system and
+   * furthermore the y positions of the systems themselves.
+   */
+  protected calculateSystemYLayout(): void {
+    for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) {
+      let graphicalMusicPage: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx];
+      if (!this.leadSheet) {
+        let globalY: number = this.rules.PageTopMargin + this.rules.TitleTopDistance + this.rules.SheetTitleHeight +
+          this.rules.TitleBottomDistance;
+        for (let idx2: number = 0, len2: number = graphicalMusicPage.MusicSystems.length; idx2 < len2; ++idx2) {
+          let musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2];
+          // calculate y positions of stafflines within system
+          let y: number = 0;
+          for (let line of musicSystem.StaffLines) {
+            line.PositionAndShape.RelativePosition.y = y;
+            y += 10;
+          }
+          // set y positions of systems using the previous system and a fixed distance.
+          musicSystem.PositionAndShape.BorderBottom = y + 0;
+          musicSystem.PositionAndShape.RelativePosition.x = this.rules.PageLeftMargin + this.rules.SystemLeftMargin;
+          musicSystem.PositionAndShape.RelativePosition.y = globalY;
+          globalY += y + 5;
         }
+      }
     }
-
-    /**
-     * Is called at the begin of the method for creating the vertically aligned staff measures belonging to one source measure.
-     */
-    protected initStaffMeasuresCreation(): void {
-        return;
+  }
+
+  /**
+   * Is called at the begin of the method for creating the vertically aligned staff measures belonging to one source measure.
+   */
+  protected initStaffMeasuresCreation(): void {
+    return;
+  }
+
+  /**
+   * add here all given articulations to the VexFlowGraphicalStaffEntry and prepare them for rendering.
+   * @param articulations
+   * @param voiceEntry
+   * @param graphicalStaffEntry
+   */
+  protected layoutArticulationMarks(articulations: ArticulationEnum[], voiceEntry: VoiceEntry, graphicalStaffEntry: GraphicalStaffEntry): void {
+    // uncomment this when implementing:
+    // let vfse: VexFlowStaffEntry = (graphicalStaffEntry as VexFlowStaffEntry);
+
+    return;
+  }
+
+  protected layoutGraphicalTie(tie: GraphicalTie, tieIsAtSystemBreak: boolean): void {
+    let startNote: VexFlowGraphicalNote = (tie.StartNote as VexFlowGraphicalNote);
+    let vfStartNote: Vex.Flow.StaveNote = undefined;
+    if (startNote !== undefined) {
+      vfStartNote = startNote.vfnote[0];
     }
 
-    protected layoutGraphicalTie(tie: GraphicalTie, tieIsAtSystemBreak: boolean): void {
-        let startNote: VexFlowGraphicalNote = (tie.StartNote as VexFlowGraphicalNote);
-        let vfStartNote: Vex.Flow.StaveNote = undefined;
-        if (startNote !== undefined) {
-            vfStartNote = startNote.vfnote[0];
-        }
-
-        let endNote: VexFlowGraphicalNote = (tie.EndNote as VexFlowGraphicalNote);
-        let vfEndNote: Vex.Flow.StaveNote = undefined;
-        if (endNote !== undefined) {
-            vfEndNote = endNote.vfnote[0];
-        }
-
-
-        if (tieIsAtSystemBreak) {
-            // split tie into two ties:
-            let vfTie1: Vex.Flow.StaveTie = new Vex.Flow.StaveTie({
-                first_note: vfStartNote,
-            });
-            let measure1: VexFlowMeasure = (startNote.parentStaffEntry.parentMeasure as VexFlowMeasure);
-            measure1.vfTies.push(vfTie1);
-
-            let vfTie2: Vex.Flow.StaveTie = new Vex.Flow.StaveTie({
-                last_note : vfEndNote,
-            });
-            let measure2: VexFlowMeasure = (endNote.parentStaffEntry.parentMeasure as VexFlowMeasure);
-            measure2.vfTies.push(vfTie2);
-        } else {
-            let vfTie: Vex.Flow.StaveTie = new Vex.Flow.StaveTie({
-                first_note: vfStartNote,
-                last_note : vfEndNote,
-            });
-            let measure: VexFlowMeasure = (endNote.parentStaffEntry.parentMeasure as VexFlowMeasure);
-            measure.vfTies.push(vfTie);
-        }
-    }
-
-    protected calculateSingleStaffLineLyricsPosition(staffLine: StaffLine, lyricVersesNumber: number[]): void {
-        return;
-    }
-
-    protected calculateSingleOctaveShift(sourceMeasure: SourceMeasure, multiExpression: MultiExpression, measureIndex: number, staffIndex: number): void {
-        return;
-    }
-
-    protected calculateWordRepetitionInstruction(repetitionInstruction: RepetitionInstruction, measureIndex: number): void {
-        return;
-    }
-
-    protected calculateMoodAndUnknownExpression(multiExpression: MultiExpression, measureIndex: number, staffIndex: number): void {
-        return;
-    }
-
-    protected handleTiedGraphicalNote(  tiedGraphicalNote: GraphicalNote, beams: Beam[], activeClef: ClefInstruction,
-                                        octaveShiftValue: OctaveEnum, graphicalStaffEntry: GraphicalStaffEntry, duration: Fraction,
-                                        openTie: Tie, isLastTieNote: boolean): void {
-        return;
-    }
-
-    /**
-     * Is called if a note is part of a beam.
-     * @param graphicalNote
-     * @param beam
-     * @param openBeams a list of all currently open beams
-     */
-    protected handleBeam(graphicalNote: GraphicalNote, beam: Beam, openBeams: Beam[]): void {
-        (graphicalNote.parentStaffEntry.parentMeasure as VexFlowMeasure).handleBeam(graphicalNote, beam);
+    let endNote: VexFlowGraphicalNote = (tie.EndNote as VexFlowGraphicalNote);
+    let vfEndNote: Vex.Flow.StaveNote = undefined;
+    if (endNote !== undefined) {
+      vfEndNote = endNote.vfnote[0];
     }
 
-    protected handleVoiceEntryLyrics(lyricsEntries: Dictionary<number, LyricsEntry>, voiceEntry: VoiceEntry,
-                                     graphicalStaffEntry: GraphicalStaffEntry, openLyricWords: LyricWord[]): void {
-        return;
-    }
-
-    protected handleVoiceEntryOrnaments(ornamentContainer: OrnamentContainer, voiceEntry: VoiceEntry, graphicalStaffEntry: GraphicalStaffEntry): void {
-        return;
-    }
-
-    protected handleVoiceEntryArticulations(articulations: ArticulationEnum[], voiceEntry: VoiceEntry, graphicalStaffEntry: GraphicalStaffEntry): void {
-        return;
-    }
 
-    /**
-     * Is called if a note is part of a tuplet.
-     * @param graphicalNote
-     * @param tuplet
-     * @param openTuplets a list of all currently open tuplets
-     */
-    protected handleTuplet(graphicalNote: GraphicalNote, tuplet: Tuplet, openTuplets: Tuplet[]): void {
-        (graphicalNote.parentStaffEntry.parentMeasure as VexFlowMeasure).handleTuplet(graphicalNote, tuplet);
+    if (tieIsAtSystemBreak) {
+      // split tie into two ties:
+      let vfTie1: Vex.Flow.StaveTie = new Vex.Flow.StaveTie({
+        first_note: vfStartNote,
+      });
+      let measure1: VexFlowMeasure = (startNote.parentStaffEntry.parentMeasure as VexFlowMeasure);
+      measure1.vfTies.push(vfTie1);
+
+      let vfTie2: Vex.Flow.StaveTie = new Vex.Flow.StaveTie({
+        last_note: vfEndNote,
+      });
+      let measure2: VexFlowMeasure = (endNote.parentStaffEntry.parentMeasure as VexFlowMeasure);
+      measure2.vfTies.push(vfTie2);
+    } else {
+      let vfTie: Vex.Flow.StaveTie = new Vex.Flow.StaveTie({
+        first_note: vfStartNote,
+        last_note: vfEndNote,
+      });
+      let measure: VexFlowMeasure = (endNote.parentStaffEntry.parentMeasure as VexFlowMeasure);
+      measure.vfTies.push(vfTie);
     }
+  }
+
+  protected calculateSingleStaffLineLyricsPosition(staffLine: StaffLine, lyricVersesNumber: number[]): void {
+    return;
+  }
+
+  protected calculateSingleOctaveShift(sourceMeasure: SourceMeasure, multiExpression: MultiExpression, measureIndex: number, staffIndex: number): void {
+    return;
+  }
+
+  protected calculateWordRepetitionInstruction(repetitionInstruction: RepetitionInstruction, measureIndex: number): void {
+    return;
+  }
+
+  protected calculateMoodAndUnknownExpression(multiExpression: MultiExpression, measureIndex: number, staffIndex: number): void {
+    return;
+  }
+
+  protected handleTiedGraphicalNote(tiedGraphicalNote: GraphicalNote, beams: Beam[], activeClef: ClefInstruction,
+                                    octaveShiftValue: OctaveEnum, graphicalStaffEntry: GraphicalStaffEntry, duration: Fraction,
+                                    openTie: Tie, isLastTieNote: boolean): void {
+    return;
+  }
+
+  /**
+   * Is called if a note is part of a beam.
+   * @param graphicalNote
+   * @param beam
+   * @param openBeams a list of all currently open beams
+   */
+  protected handleBeam(graphicalNote: GraphicalNote, beam: Beam, openBeams: Beam[]): void {
+    (graphicalNote.parentStaffEntry.parentMeasure as VexFlowMeasure).handleBeam(graphicalNote, beam);
+  }
+
+  protected handleVoiceEntryLyrics(lyricsEntries: Dictionary<number, LyricsEntry>, voiceEntry: VoiceEntry,
+                                   graphicalStaffEntry: GraphicalStaffEntry, openLyricWords: LyricWord[]): void {
+    return;
+  }
+
+  protected handleVoiceEntryOrnaments(ornamentContainer: OrnamentContainer, voiceEntry: VoiceEntry, graphicalStaffEntry: GraphicalStaffEntry): void {
+    return;
+  }
+
+  /**
+   * Add articulations to the given vexflow staff entry.
+   * @param articulations
+   * @param voiceEntry
+   * @param graphicalStaffEntry
+   */
+  protected handleVoiceEntryArticulations(articulations: ArticulationEnum[],
+                                          voiceEntry: VoiceEntry, staffEntry: GraphicalStaffEntry): void {
+    // uncomment this when implementing:
+    // let vfse: VexFlowStaffEntry = (graphicalStaffEntry as VexFlowStaffEntry);
+
+    return;
+  }
+
+  /**
+   * Add technical instructions to the given vexflow staff entry.
+   * @param technicalInstructions
+   * @param voiceEntry
+   * @param staffEntry
+   */
+  protected handleVoiceEntryTechnicalInstructions(technicalInstructions: TechnicalInstruction[],
+                                                  voiceEntry: VoiceEntry, staffEntry: GraphicalStaffEntry): void {
+    // uncomment this when implementing:
+    // let vfse: VexFlowStaffEntry = (graphicalStaffEntry as VexFlowStaffEntry);
+    return;
+  }
+
+  /**
+   * Is called if a note is part of a tuplet.
+   * @param graphicalNote
+   * @param tuplet
+   * @param openTuplets a list of all currently open tuplets
+   */
+  protected handleTuplet(graphicalNote: GraphicalNote, tuplet: Tuplet, openTuplets: Tuplet[]): void {
+    (graphicalNote.parentStaffEntry.parentMeasure as VexFlowMeasure).handleTuplet(graphicalNote, tuplet);
+  }
 }

+ 0 - 5
src/MusicalScore/Interfaces/IGraphicalSymbolFactory.ts

@@ -12,7 +12,6 @@ import {SourceStaffEntry} from "../VoiceData/SourceStaffEntry";
 import {Staff} from "../VoiceData/Staff";
 import {StaffLine} from "../Graphical/StaffLine";
 import {StaffMeasure} from "../Graphical/StaffMeasure";
-import {TechnicalInstruction} from "../VoiceData/Instructions/TechnicalInstruction";
 
 export interface IGraphicalSymbolFactory {
 
@@ -44,10 +43,6 @@ export interface IGraphicalSymbolFactory {
 
     addFermataAtTiedEndNote(tiedNote: Note, graphicalStaffEntry: GraphicalStaffEntry): void;
 
-    createGraphicalTechnicalInstruction(
-        technicalInstruction: TechnicalInstruction,
-        graphicalStaffEntry: GraphicalStaffEntry): void;
-
     createInStaffClef(graphicalStaffEntry: GraphicalStaffEntry, clefInstruction: ClefInstruction): void;
 
     createChordSymbol(

+ 195 - 0
src/MusicalScore/ScoreIO/MusicSymbolModules/ArticulationReader.ts

@@ -0,0 +1,195 @@
+import {ArticulationEnum, VoiceEntry} from "../../VoiceData/VoiceEntry";
+import {IXmlAttribute, IXmlElement} from "../../../Common/FileIO/Xml";
+import {Logging} from "../../../Common/Logging";
+import {TechnicalInstruction, TechnicalInstructionType} from "../../VoiceData/Instructions/TechnicalInstruction";
+import {OrnamentContainer, OrnamentEnum} from "../../VoiceData/OrnamentContainer";
+import {PlacementEnum} from "../../VoiceData/Expressions/AbstractExpression";
+import {AccidentalEnum} from "../../../Common/DataObjects/Pitch";
+export class ArticulationReader {
+
+  private getAccEnumFromString(input: string): AccidentalEnum {
+    switch (input) {
+      case "natural":
+        return AccidentalEnum.NATURAL;
+      case "sharp":
+        return AccidentalEnum.SHARP;
+      case "sharp-sharp":
+      case "double-sharp":
+        return AccidentalEnum.DOUBLESHARP;
+      case "flat":
+        return AccidentalEnum.FLAT;
+      case "flat-flat":
+        return AccidentalEnum.DOUBLEFLAT;
+      default:
+        return AccidentalEnum.NONE;
+    }
+  }
+
+  /**
+   * This method adds an Articulation Expression to the currentVoiceEntry.
+   * @param node
+   * @param currentVoiceEntry
+   */
+  public addArticulationExpression(node: IXmlElement, currentVoiceEntry: VoiceEntry): void {
+    if (node !== undefined && node.elements().length > 0) {
+      let childNotes: IXmlElement[] = node.elements();
+      for (let idx: number = 0, len: number = childNotes.length; idx < len; ++idx) {
+        let childNote: IXmlElement = childNotes[idx];
+        let name: string = childNote.name;
+        try {
+          // some Articulations appear in Xml separated with a "-" (eg strong-accent), we remove it for enum parsing
+          name.replace("-", "");
+          let articulationEnum: ArticulationEnum = ArticulationEnum[name];
+          if (VoiceEntry.isSupportedArticulation(articulationEnum)) {
+            // staccato should be first
+            if (name === "staccato") {
+              if (currentVoiceEntry.Articulations.length > 0 &&
+                currentVoiceEntry.Articulations[0] !== ArticulationEnum.staccato) {
+                currentVoiceEntry.Articulations.splice(0, 0, articulationEnum);
+              }
+            }
+
+            // don't add the same articulation twice
+            if (currentVoiceEntry.Articulations.indexOf(articulationEnum) === -1) {
+              currentVoiceEntry.Articulations.push(articulationEnum);
+            }
+          }
+        } catch (err) {
+          let errorMsg: string = "Invalid note articulation.";
+          Logging.log("addArticulationExpression", errorMsg);
+          return;
+        }
+      }
+    }
+  }
+
+  /**
+   * This method add a Fermata to the currentVoiceEntry.
+   * @param xmlNode
+   * @param currentVoiceEntry
+   */
+  public addFermata(xmlNode: IXmlElement, currentVoiceEntry: VoiceEntry): void {
+    // fermata appears as separate tag in XML
+    let articulationEnum: ArticulationEnum = ArticulationEnum.fermata;
+    if (xmlNode.attributes().length > 0 && xmlNode.attribute("type") !== undefined) {
+      if (xmlNode.attribute("type").value === "inverted") {
+        articulationEnum = ArticulationEnum.invertedfermata;
+      }
+    }
+    // add to VoiceEntry
+    currentVoiceEntry.Articulations.push(articulationEnum);
+  }
+
+  /**
+   * This method add a technical Articulation to the currentVoiceEntry.
+   * @param xmlNode
+   * @param currentVoiceEntry
+   */
+  public addTechnicalArticulations(xmlNode: IXmlElement, currentVoiceEntry: VoiceEntry): void {
+    let node: IXmlElement = xmlNode.element("up-bow");
+    if (node !== undefined) {
+      if (currentVoiceEntry.Articulations.indexOf(ArticulationEnum.upbow) === -1) {
+        currentVoiceEntry.Articulations.push(ArticulationEnum.upbow);
+      }
+    }
+    node = xmlNode.element("down-bow");
+    if (node !== undefined) {
+      if (currentVoiceEntry.Articulations.indexOf(ArticulationEnum.downbow) === -1) {
+        currentVoiceEntry.Articulations.push(ArticulationEnum.downbow);
+      }
+    }
+    node = xmlNode.element("open-string");
+    if (node !== undefined) {
+      if (currentVoiceEntry.Articulations.indexOf(ArticulationEnum.naturalharmonic) === -1) {
+        currentVoiceEntry.Articulations.push(ArticulationEnum.naturalharmonic);
+      }
+    }
+    node = xmlNode.element("stopped");
+    if (node !== undefined) {
+      if (currentVoiceEntry.Articulations.indexOf(ArticulationEnum.lefthandpizzicato) === -1) {
+        currentVoiceEntry.Articulations.push(ArticulationEnum.lefthandpizzicato);
+      }
+    }
+    node = xmlNode.element("snap-pizzicato");
+    if (node !== undefined) {
+      if (currentVoiceEntry.Articulations.indexOf(ArticulationEnum.snappizzicato) === -1) {
+        currentVoiceEntry.Articulations.push(ArticulationEnum.snappizzicato);
+      }
+    }
+    node = xmlNode.element("fingering");
+    if (node !== undefined) {
+      let currentTechnicalInstruction: TechnicalInstruction = new TechnicalInstruction();
+      currentTechnicalInstruction.type = TechnicalInstructionType.Fingering;
+      currentTechnicalInstruction.value = node.value;
+      currentVoiceEntry.TechnicalInstructions.push(currentTechnicalInstruction);
+    }
+  }
+
+  /**
+   * This method adds an Ornament to the currentVoiceEntry.
+   * @param ornamentsNode
+   * @param currentVoiceEntry
+   */
+  public addOrnament(ornamentsNode: IXmlElement, currentVoiceEntry: VoiceEntry): void {
+    if (ornamentsNode !== undefined) {
+      let ornament: OrnamentContainer = undefined;
+      let node: IXmlElement = ornamentsNode.element("trill-mark");
+      if (node !== undefined) {
+        ornament = new OrnamentContainer(OrnamentEnum.Trill);
+      }
+      node = ornamentsNode.element("turn");
+      if (node !== undefined) {
+        ornament = new OrnamentContainer(OrnamentEnum.Turn);
+      }
+      node = ornamentsNode.element("inverted-turn");
+      if (node !== undefined) {
+        ornament = new OrnamentContainer(OrnamentEnum.InvertedTurn);
+      }
+      node = ornamentsNode.element("delayed-turn");
+      if (node !== undefined) {
+        ornament = new OrnamentContainer(OrnamentEnum.DelayedTurn);
+      }
+      node = ornamentsNode.element("delayed-inverted-turn");
+      if (node !== undefined) {
+        ornament = new OrnamentContainer(OrnamentEnum.DelayedInvertedTurn);
+      }
+      node = ornamentsNode.element("mordent");
+      if (node !== undefined) {
+        ornament = new OrnamentContainer(OrnamentEnum.Mordent);
+      }
+      node = ornamentsNode.element("inverted-mordent");
+      if (node !== undefined) {
+        ornament = new OrnamentContainer(OrnamentEnum.InvertedMordent);
+      }
+      if (ornament !== undefined) {
+        let accidentalsList: IXmlElement[] = ornamentsNode.elements("accidental-mark");
+        if (accidentalsList !== undefined) {
+          let placement: PlacementEnum = PlacementEnum.Below;
+          let accidental: AccidentalEnum = AccidentalEnum.NONE;
+          let accidentalsListArr: IXmlElement[] = accidentalsList;
+          for (let idx: number = 0, len: number = accidentalsListArr.length; idx < len; ++idx) {
+            let accidentalNode: IXmlElement = accidentalsListArr[idx];
+            let text: string = accidentalNode.value;
+            accidental = this.getAccEnumFromString(text);
+            let placementAttr: IXmlAttribute = accidentalNode.attribute("placement");
+            if (accidentalNode.hasAttributes && placementAttr !== undefined) {
+              text = placementAttr.value;
+              if (text === "above") {
+                placement = PlacementEnum.Above;
+              } else if (text === "below") {
+                placement = PlacementEnum.Below;
+              }
+            }
+            if (placement === PlacementEnum.Above) {
+              ornament.AccidentalAbove = accidental;
+            } else if (placement === PlacementEnum.Below) {
+              ornament.AccidentalBelow = accidental;
+            }
+          }
+        }
+        // add this to currentVoiceEntry
+        currentVoiceEntry.OrnamentContainer = ornament;
+      }
+    }
+  }
+}

+ 897 - 881
src/MusicalScore/ScoreIO/VoiceGenerator.ts

@@ -27,6 +27,7 @@ import {Pitch} from "../../Common/DataObjects/Pitch";
 import {IXmlAttribute} from "../../Common/FileIO/Xml";
 import {CollectionUtil} from "../../Util/CollectionUtil";
 import Dictionary from "typescript-collections/dist/lib/Dictionary";
+import {ArticulationReader} from "./MusicSymbolModules/ArticulationReader";
 
 /**
  * To be implemented
@@ -34,945 +35,960 @@ import Dictionary from "typescript-collections/dist/lib/Dictionary";
 export type SlurReader = any;
 
 export class VoiceGenerator {
-    constructor(instrument: Instrument, voiceId: number, slurReader: SlurReader, mainVoice: Voice = undefined) {
-        this.musicSheet = instrument.GetMusicSheet;
-        // this.slurReader = slurReader;
-        if (mainVoice !== undefined) {
-            this.voice = new LinkedVoice(instrument, voiceId, mainVoice);
-        } else {
-            this.voice = new Voice(instrument, voiceId);
+  constructor(instrument: Instrument, voiceId: number, slurReader: SlurReader, mainVoice: Voice = undefined) {
+    this.musicSheet = instrument.GetMusicSheet;
+    // this.slurReader = slurReader;
+    if (mainVoice !== undefined) {
+      this.voice = new LinkedVoice(instrument, voiceId, mainVoice);
+    } else {
+      this.voice = new Voice(instrument, voiceId);
+    }
+    instrument.Voices.push(this.voice);
+    //this.lyricsReader = MusicSymbolModuleFactory.createLyricsReader(this.musicSheet);
+    this.articulationReader = new ArticulationReader();
+  }
+
+  // private slurReader: SlurReader;
+  //private lyricsReader: LyricsReader;
+  private articulationReader: ArticulationReader;
+  private musicSheet: MusicSheet;
+  private voice: Voice;
+  private currentVoiceEntry: VoiceEntry;
+  private currentNote: Note;
+  private currentMeasure: SourceMeasure;
+  private currentStaffEntry: SourceStaffEntry;
+  private lastBeamTag: string = "";
+  private openBeam: Beam;
+  private openGraceBeam: Beam;
+  private openTieDict: { [_: number]: Tie; } = {};
+  private currentOctaveShift: number = 0;
+  private tupletDict: { [_: number]: Tuplet; } = {};
+  private openTupletNumber: number = 0;
+
+  public get GetVoice(): Voice {
+    return this.voice;
+  }
+
+  public get OctaveShift(): number {
+    return this.currentOctaveShift;
+  }
+
+  public set OctaveShift(value: number) {
+    this.currentOctaveShift = value;
+  }
+
+  /**
+   * Create new [[VoiceEntry]], add it to given [[SourceStaffEntry]] and if given so, to [[Voice]].
+   * @param musicTimestamp
+   * @param parentStaffEntry
+   * @param addToVoice
+   */
+  public createVoiceEntry(musicTimestamp: Fraction, parentStaffEntry: SourceStaffEntry, addToVoice: boolean): void {
+    this.currentVoiceEntry = new VoiceEntry(musicTimestamp.clone(), this.voice, parentStaffEntry);
+    if (addToVoice) {
+      this.voice.VoiceEntries.push(this.currentVoiceEntry);
+    }
+    if (parentStaffEntry.VoiceEntries.indexOf(this.currentVoiceEntry) === -1) {
+      parentStaffEntry.VoiceEntries.push(this.currentVoiceEntry);
+    }
+  }
+
+  /**
+   * Create [[Note]]s and handle Lyrics, Articulations, Beams, Ties, Slurs, Tuplets.
+   * @param noteNode
+   * @param noteDuration
+   * @param divisions
+   * @param restNote
+   * @param graceNote
+   * @param parentStaffEntry
+   * @param parentMeasure
+   * @param measureStartAbsoluteTimestamp
+   * @param maxTieNoteFraction
+   * @param chord
+   * @param guitarPro
+   * @returns {Note}
+   */
+  public read(noteNode: IXmlElement, noteDuration: Fraction, restNote: boolean, graceNote: boolean,
+              parentStaffEntry: SourceStaffEntry, parentMeasure: SourceMeasure,
+              measureStartAbsoluteTimestamp: Fraction, maxTieNoteFraction: Fraction, chord: boolean, guitarPro: boolean): Note {
+    this.currentStaffEntry = parentStaffEntry;
+    this.currentMeasure = parentMeasure;
+    //Logging.debug("read called:", restNote);
+    try {
+      this.currentNote = restNote
+        ? this.addRestNote(noteDuration)
+        : this.addSingleNote(noteNode, noteDuration, graceNote, chord, guitarPro);
+      // (*)
+      //if (this.lyricsReader !== undefined && noteNode.element("lyric") !== undefined) {
+      //    this.lyricsReader.addLyricEntry(noteNode, this.currentVoiceEntry);
+      //    this.voice.Parent.HasLyrics = true;
+      //}
+      let hasTupletCommand: boolean = false;
+      let notationNode: IXmlElement = noteNode.element("notations");
+      if (notationNode !== undefined) {
+        // let articNode: IXmlElement = undefined;
+        // (*)
+        if (this.articulationReader !== undefined) {
+          this.readArticulations(notationNode, this.currentVoiceEntry);
         }
-        instrument.Voices.push(this.voice);
-        //this.lyricsReader = MusicSymbolModuleFactory.createLyricsReader(this.musicSheet);
-        //this.articulationReader = MusicSymbolModuleFactory.createArticulationReader();
-    }
-
-    // private slurReader: SlurReader;
-    //private lyricsReader: LyricsReader;
-    //private articulationReader: ArticulationReader;
-    private musicSheet: MusicSheet;
-    private voice: Voice;
-    private currentVoiceEntry: VoiceEntry;
-    private currentNote: Note;
-    private currentMeasure: SourceMeasure;
-    private currentStaffEntry: SourceStaffEntry;
-    private lastBeamTag: string = "";
-    private openBeam: Beam;
-    private openGraceBeam: Beam;
-    private openTieDict: { [_: number]: Tie; } = {};
-    private currentOctaveShift: number = 0;
-    private tupletDict: { [_: number]: Tuplet; } = {};
-    private openTupletNumber: number = 0;
-
-    public get GetVoice(): Voice {
-        return this.voice;
-    }
-    public get OctaveShift(): number {
-        return this.currentOctaveShift;
-    }
-    public set OctaveShift(value: number) {
-        this.currentOctaveShift = value;
-    }
-
-    /**
-     * Create new [[VoiceEntry]], add it to given [[SourceStaffEntry]] and if given so, to [[Voice]].
-     * @param musicTimestamp
-     * @param parentStaffEntry
-     * @param addToVoice
-     */
-    public createVoiceEntry(musicTimestamp: Fraction, parentStaffEntry: SourceStaffEntry, addToVoice: boolean): void {
-        this.currentVoiceEntry = new VoiceEntry(musicTimestamp.clone(), this.voice, parentStaffEntry);
-        if (addToVoice) {
-            this.voice.VoiceEntries.push(this.currentVoiceEntry);
+        //let slurNodes: IXmlElement[] = undefined;
+        // (*)
+        //if (this.slurReader !== undefined && (slurNodes = notationNode.elements("slur")))
+        //    this.slurReader.addSlur(slurNodes, this.currentNote);
+        // check for Tuplets
+        let tupletNodeList: IXmlElement[] = notationNode.elements("tuplet");
+        if (tupletNodeList.length > 0) {
+          this.openTupletNumber = this.addTuplet(noteNode, tupletNodeList);
+          hasTupletCommand = true;
         }
-        if (parentStaffEntry.VoiceEntries.indexOf(this.currentVoiceEntry) === -1) {
-            parentStaffEntry.VoiceEntries.push(this.currentVoiceEntry);
+        // check for Arpeggios
+        if (notationNode.element("arpeggiate") !== undefined && !graceNote) {
+          this.currentVoiceEntry.ArpeggiosNotesIndices.push(this.currentVoiceEntry.Notes.indexOf(this.currentNote));
         }
-    }
-
-    /**
-     * Create [[Note]]s and handle Lyrics, Articulations, Beams, Ties, Slurs, Tuplets.
-     * @param noteNode
-     * @param noteDuration
-     * @param divisions
-     * @param restNote
-     * @param graceNote
-     * @param parentStaffEntry
-     * @param parentMeasure
-     * @param measureStartAbsoluteTimestamp
-     * @param maxTieNoteFraction
-     * @param chord
-     * @param guitarPro
-     * @returns {Note}
-     */
-    public read(
-        noteNode: IXmlElement, noteDuration: Fraction, restNote: boolean, graceNote: boolean,
-        parentStaffEntry: SourceStaffEntry, parentMeasure: SourceMeasure,
-        measureStartAbsoluteTimestamp: Fraction, maxTieNoteFraction: Fraction, chord: boolean, guitarPro: boolean
-    ): Note {
-        this.currentStaffEntry = parentStaffEntry;
-        this.currentMeasure = parentMeasure;
-        //Logging.debug("read called:", restNote);
-        try {
-            this.currentNote = restNote
-                ? this.addRestNote(noteDuration)
-                : this.addSingleNote(noteNode, noteDuration, graceNote, chord, guitarPro);
-            // (*)
-            //if (this.lyricsReader !== undefined && noteNode.element("lyric") !== undefined) {
-            //    this.lyricsReader.addLyricEntry(noteNode, this.currentVoiceEntry);
-            //    this.voice.Parent.HasLyrics = true;
-            //}
-            let hasTupletCommand: boolean = false;
-            let notationNode: IXmlElement = noteNode.element("notations");
-            if (notationNode !== undefined) {
-                // let articNode: IXmlElement = undefined;
-                // (*)
-                //if (this.articulationReader !== undefined) {
-                //    this.readArticulations(notationNode, this.currentVoiceEntry);
-                //}
-                //let slurNodes: IXmlElement[] = undefined;
-                // (*)
-                //if (this.slurReader !== undefined && (slurNodes = notationNode.elements("slur")))
-                //    this.slurReader.addSlur(slurNodes, this.currentNote);
-                // check for Tuplets
-                let tupletNodeList: IXmlElement[] = notationNode.elements("tuplet");
-                if (tupletNodeList.length > 0) {
-                  this.openTupletNumber = this.addTuplet(noteNode, tupletNodeList);
-                  hasTupletCommand = true;
-                }
-                // check for Arpeggios
-                if (notationNode.element("arpeggiate") !== undefined && !graceNote) {
-                    this.currentVoiceEntry.ArpeggiosNotesIndices.push(this.currentVoiceEntry.Notes.indexOf(this.currentNote));
-                }
-                // check for Ties - must be the last check
-                let tiedNodeList: IXmlElement[] = notationNode.elements("tied");
-                if (tiedNodeList.length > 0) {
-                    this.addTie(tiedNodeList, measureStartAbsoluteTimestamp, maxTieNoteFraction);
-                }
-
-                // remove open ties, if there is already a gap between the last tie note and now.
-                let openTieDict: { [_: number]: Tie; } = this.openTieDict;
-                for (let key in openTieDict) {
-                    if (openTieDict.hasOwnProperty(key)) {
-                        let tie: Tie = openTieDict[key];
-                        if (Fraction.plus(tie.Start.ParentStaffEntry.Timestamp, tie.Start.Length).lt(this.currentStaffEntry.Timestamp)) {
-                            delete openTieDict[key];
-                        }
-                    }
-                }
-            }
-            // time-modification yields tuplet in currentNote
-            // mustn't execute method, if this is the Note where the Tuplet has been created
-            if (noteNode.element("time-modification") !== undefined && !hasTupletCommand) {
-                this.handleTimeModificationNode(noteNode);
-            }
-        } catch (err) {
-            let errorMsg: string = ITextTranslation.translateText(
-                "ReaderErrorMessages/NoteError", "Ignored erroneous Note."
-            );
-            this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+        // check for Ties - must be the last check
+        let tiedNodeList: IXmlElement[] = notationNode.elements("tied");
+        if (tiedNodeList.length > 0) {
+          this.addTie(tiedNodeList, measureStartAbsoluteTimestamp, maxTieNoteFraction);
         }
 
-        return this.currentNote;
-    }
-
-    /**
-     * Handle the GraceNotes that appear before the Measure's End
-     * and aren't assigned to any normal (with [[VoiceEntries]]) [[SourceStaffEntry]]s yet.
-     */
-    public checkForOpenGraceNotes(): void {
-        if (
-            this.currentStaffEntry !== undefined
-            && this.currentStaffEntry.VoiceEntries.length === 0
-            && this.currentVoiceEntry.graceVoiceEntriesBefore !== undefined
-            && this.currentVoiceEntry.graceVoiceEntriesBefore.length > 0
-        ) {
-            let voice: Voice = this.currentVoiceEntry.ParentVoice;
-            let horizontalIndex: number = this.currentMeasure.VerticalSourceStaffEntryContainers.indexOf(this.currentStaffEntry.VerticalContainerParent);
-            let verticalIndex: number = this.currentStaffEntry.VerticalContainerParent.StaffEntries.indexOf(this.currentStaffEntry);
-            let previousStaffEntry: SourceStaffEntry = this.currentMeasure.getPreviousSourceStaffEntryFromIndex(verticalIndex, horizontalIndex);
-            if (previousStaffEntry !== undefined) {
-                let previousVoiceEntry: VoiceEntry = undefined;
-                for (let idx: number = 0, len: number = previousStaffEntry.VoiceEntries.length; idx < len; ++idx) {
-                    let voiceEntry: VoiceEntry = previousStaffEntry.VoiceEntries[idx];
-                    if (voiceEntry.ParentVoice === voice) {
-                        previousVoiceEntry = voiceEntry;
-                        previousVoiceEntry.graceVoiceEntriesAfter = [];
-                        for (let idx2: number = 0, len2: number = this.currentVoiceEntry.graceVoiceEntriesBefore.length; idx2 < len2; ++idx2) {
-                            let graceVoiceEntry: VoiceEntry = this.currentVoiceEntry.graceVoiceEntriesBefore[idx2];
-                            previousVoiceEntry.graceVoiceEntriesAfter.push(graceVoiceEntry);
-                        }
-                        this.currentVoiceEntry.graceVoiceEntriesBefore = [];
-                        this.currentStaffEntry = undefined;
-                        break;
-                    }
-                }
+        // remove open ties, if there is already a gap between the last tie note and now.
+        let openTieDict: { [_: number]: Tie; } = this.openTieDict;
+        for (let key in openTieDict) {
+          if (openTieDict.hasOwnProperty(key)) {
+            let tie: Tie = openTieDict[key];
+            if (Fraction.plus(tie.Start.ParentStaffEntry.Timestamp, tie.Start.Length).lt(this.currentStaffEntry.Timestamp)) {
+              delete openTieDict[key];
             }
+          }
         }
+      }
+      // time-modification yields tuplet in currentNote
+      // mustn't execute method, if this is the Note where the Tuplet has been created
+      if (noteNode.element("time-modification") !== undefined && !hasTupletCommand) {
+        this.handleTimeModificationNode(noteNode);
+      }
+    } catch (err) {
+      let errorMsg: string = ITextTranslation.translateText(
+        "ReaderErrorMessages/NoteError", "Ignored erroneous Note."
+      );
+      this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
     }
 
-    /**
-     * Create a new [[StaffEntryLink]] and sets the currenstStaffEntry accordingly.
-     * @param index
-     * @param currentStaff
-     * @param currentStaffEntry
-     * @param currentMeasure
-     * @returns {SourceStaffEntry}
-     */
-    public checkForStaffEntryLink(
-        index: number, currentStaff: Staff, currentStaffEntry: SourceStaffEntry, currentMeasure: SourceMeasure
-    ): SourceStaffEntry {
-        let staffEntryLink: StaffEntryLink = new StaffEntryLink(this.currentVoiceEntry);
-        staffEntryLink.LinkStaffEntries.push(currentStaffEntry);
-        currentStaffEntry.Link = staffEntryLink;
-        let linkMusicTimestamp: Fraction = this.currentVoiceEntry.Timestamp.clone();
-        let verticalSourceStaffEntryContainer: VerticalSourceStaffEntryContainer = currentMeasure.getVerticalContainerByTimestamp(linkMusicTimestamp);
-        currentStaffEntry = verticalSourceStaffEntryContainer.StaffEntries[index];
-        if (currentStaffEntry === undefined) {
-            currentStaffEntry = new SourceStaffEntry(verticalSourceStaffEntryContainer, currentStaff);
-            verticalSourceStaffEntryContainer.StaffEntries[index] = currentStaffEntry;
-        }
-        currentStaffEntry.VoiceEntries.push(this.currentVoiceEntry);
-        staffEntryLink.LinkStaffEntries.push(currentStaffEntry);
-        currentStaffEntry.Link = staffEntryLink;
-        return currentStaffEntry;
-    }
-    public checkForOpenBeam(): void {
-        if (this.openBeam !== undefined && this.currentNote !== undefined) {
-            this.handleOpenBeam();
-        }
-    }
-    public checkOpenTies(): void {
-        let openTieDict: {[key: number]: Tie} = this.openTieDict;
-        for (let key in openTieDict) {
-            if (openTieDict.hasOwnProperty(key)) {
-                let tie: Tie = openTieDict[key];
-                if (Fraction.plus(tie.Start.ParentStaffEntry.Timestamp, tie.Start.Length)
-                        .lt(tie.Start.ParentStaffEntry.VerticalContainerParent.ParentMeasure.Duration)) {
-                    delete openTieDict[key];
-                }
+    return this.currentNote;
+  }
+
+  /**
+   * Handle the GraceNotes that appear before the Measure's End
+   * and aren't assigned to any normal (with [[VoiceEntries]]) [[SourceStaffEntry]]s yet.
+   */
+  public checkForOpenGraceNotes(): void {
+    if (
+      this.currentStaffEntry !== undefined
+      && this.currentStaffEntry.VoiceEntries.length === 0
+      && this.currentVoiceEntry.graceVoiceEntriesBefore !== undefined
+      && this.currentVoiceEntry.graceVoiceEntriesBefore.length > 0
+    ) {
+      let voice: Voice = this.currentVoiceEntry.ParentVoice;
+      let horizontalIndex: number = this.currentMeasure.VerticalSourceStaffEntryContainers.indexOf(this.currentStaffEntry.VerticalContainerParent);
+      let verticalIndex: number = this.currentStaffEntry.VerticalContainerParent.StaffEntries.indexOf(this.currentStaffEntry);
+      let previousStaffEntry: SourceStaffEntry = this.currentMeasure.getPreviousSourceStaffEntryFromIndex(verticalIndex, horizontalIndex);
+      if (previousStaffEntry !== undefined) {
+        let previousVoiceEntry: VoiceEntry = undefined;
+        for (let idx: number = 0, len: number = previousStaffEntry.VoiceEntries.length; idx < len; ++idx) {
+          let voiceEntry: VoiceEntry = previousStaffEntry.VoiceEntries[idx];
+          if (voiceEntry.ParentVoice === voice) {
+            previousVoiceEntry = voiceEntry;
+            previousVoiceEntry.graceVoiceEntriesAfter = [];
+            for (let idx2: number = 0, len2: number = this.currentVoiceEntry.graceVoiceEntriesBefore.length; idx2 < len2; ++idx2) {
+              let graceVoiceEntry: VoiceEntry = this.currentVoiceEntry.graceVoiceEntriesBefore[idx2];
+              previousVoiceEntry.graceVoiceEntriesAfter.push(graceVoiceEntry);
             }
+            this.currentVoiceEntry.graceVoiceEntriesBefore = [];
+            this.currentStaffEntry = undefined;
+            break;
+          }
         }
+      }
     }
-    public hasVoiceEntry(): boolean {
-        return this.currentVoiceEntry !== undefined;
-    }
-
-    /**
-     *
-     * @param type
-     * @returns {Fraction} - a Note's Duration from a given type (type must be valid).
-     */
-    public getNoteDurationFromType(type: string): Fraction {
-        switch (type) {
-            case "1024th":
-                return new Fraction(1, 1024);
-            case "512th":
-                return new Fraction(1, 512);
-            case "256th":
-                return new Fraction(1, 256);
-            case "128th":
-                return new Fraction(1, 128);
-            case "64th":
-                return new Fraction(1, 64);
-            case "32th":
-            case "32nd":
-                return new Fraction(1, 32);
-            case "16th":
-                return new Fraction(1, 16);
-            case "eighth":
-                return new Fraction(1, 8);
-            case "quarter":
-                return new Fraction(1, 4);
-            case "half":
-                return new Fraction(1, 2);
-            case "whole":
-                return new Fraction(1, 1);
-            case "breve":
-                return new Fraction(2, 1);
-            case "long":
-                return new Fraction(4, 1);
-            case "maxima":
-                return new Fraction(8, 1);
-            default: {
-                let errorMsg: string = ITextTranslation.translateText(
-                    "ReaderErrorMessages/NoteDurationError", "Invalid note duration."
-                );
-                throw new MusicSheetReadingException(errorMsg);
-            }
+  }
+
+  /**
+   * Create a new [[StaffEntryLink]] and sets the currenstStaffEntry accordingly.
+   * @param index
+   * @param currentStaff
+   * @param currentStaffEntry
+   * @param currentMeasure
+   * @returns {SourceStaffEntry}
+   */
+  public checkForStaffEntryLink(index: number, currentStaff: Staff, currentStaffEntry: SourceStaffEntry, currentMeasure: SourceMeasure): SourceStaffEntry {
+    let staffEntryLink: StaffEntryLink = new StaffEntryLink(this.currentVoiceEntry);
+    staffEntryLink.LinkStaffEntries.push(currentStaffEntry);
+    currentStaffEntry.Link = staffEntryLink;
+    let linkMusicTimestamp: Fraction = this.currentVoiceEntry.Timestamp.clone();
+    let verticalSourceStaffEntryContainer: VerticalSourceStaffEntryContainer = currentMeasure.getVerticalContainerByTimestamp(linkMusicTimestamp);
+    currentStaffEntry = verticalSourceStaffEntryContainer.StaffEntries[index];
+    if (currentStaffEntry === undefined) {
+      currentStaffEntry = new SourceStaffEntry(verticalSourceStaffEntryContainer, currentStaff);
+      verticalSourceStaffEntryContainer.StaffEntries[index] = currentStaffEntry;
+    }
+    currentStaffEntry.VoiceEntries.push(this.currentVoiceEntry);
+    staffEntryLink.LinkStaffEntries.push(currentStaffEntry);
+    currentStaffEntry.Link = staffEntryLink;
+    return currentStaffEntry;
+  }
+
+  public checkForOpenBeam(): void {
+    if (this.openBeam !== undefined && this.currentNote !== undefined) {
+      this.handleOpenBeam();
+    }
+  }
+
+  public checkOpenTies(): void {
+    let openTieDict: { [key: number]: Tie } = this.openTieDict;
+    for (let key in openTieDict) {
+      if (openTieDict.hasOwnProperty(key)) {
+        let tie: Tie = openTieDict[key];
+        if (Fraction.plus(tie.Start.ParentStaffEntry.Timestamp, tie.Start.Length)
+            .lt(tie.Start.ParentStaffEntry.VerticalContainerParent.ParentMeasure.Duration)) {
+          delete openTieDict[key];
         }
+      }
     }
-    // (*)
-    //private readArticulations(notationNode: IXmlElement, currentVoiceEntry: VoiceEntry): void {
-    //    let articNode: IXmlElement;
-    //    if ((articNode = notationNode.element("articulations")) !== undefined)
-    //        this.articulationReader.addArticulationExpression(articNode, currentVoiceEntry);
-    //    let fermaNode: IXmlElement = undefined;
-    //    if ((fermaNode = notationNode.element("fermata")) !== undefined)
-    //        this.articulationReader.addFermata(fermaNode, currentVoiceEntry);
-    //    let tecNode: IXmlElement = undefined;
-    //    if ((tecNode = notationNode.element("technical")) !== undefined)
-    //        this.articulationReader.addTechnicalArticulations(tecNode, currentVoiceEntry);
-    //    let ornaNode: IXmlElement = undefined;
-    //    if ((ornaNode = notationNode.element("ornaments")) !== undefined)
-    //        this.articulationReader.addOrnament(ornaNode, currentVoiceEntry);
-    //}
-
-    /**
-     * Create a new [[Note]] and adds it to the currentVoiceEntry
-     * @param node
-     * @param noteDuration
-     * @param divisions
-     * @param graceNote
-     * @param chord
-     * @param guitarPro
-     * @returns {Note}
-     */
-    private addSingleNote(
-        node: IXmlElement, noteDuration: Fraction, graceNote: boolean, chord: boolean, guitarPro: boolean
-    ): Note {
-        //Logging.debug("addSingleNote called");
-        let noteAlter: AccidentalEnum = AccidentalEnum.NONE;
-        let noteStep: NoteEnum = NoteEnum.C;
-        let noteOctave: number = 0;
-        let playbackInstrumentId: string = undefined;
-        let xmlnodeElementsArr: IXmlElement[] = node.elements();
-        for (let idx: number = 0, len: number = xmlnodeElementsArr.length; idx < len; ++idx) {
-            let noteElement: IXmlElement = xmlnodeElementsArr[idx];
+  }
+
+  public hasVoiceEntry(): boolean {
+    return this.currentVoiceEntry !== undefined;
+  }
+
+  /**
+   *
+   * @param type
+   * @returns {Fraction} - a Note's Duration from a given type (type must be valid).
+   */
+  public getNoteDurationFromType(type: string): Fraction {
+    switch (type) {
+      case "1024th":
+        return new Fraction(1, 1024);
+      case "512th":
+        return new Fraction(1, 512);
+      case "256th":
+        return new Fraction(1, 256);
+      case "128th":
+        return new Fraction(1, 128);
+      case "64th":
+        return new Fraction(1, 64);
+      case "32th":
+      case "32nd":
+        return new Fraction(1, 32);
+      case "16th":
+        return new Fraction(1, 16);
+      case "eighth":
+        return new Fraction(1, 8);
+      case "quarter":
+        return new Fraction(1, 4);
+      case "half":
+        return new Fraction(1, 2);
+      case "whole":
+        return new Fraction(1, 1);
+      case "breve":
+        return new Fraction(2, 1);
+      case "long":
+        return new Fraction(4, 1);
+      case "maxima":
+        return new Fraction(8, 1);
+      default: {
+        let errorMsg: string = ITextTranslation.translateText(
+          "ReaderErrorMessages/NoteDurationError", "Invalid note duration."
+        );
+        throw new MusicSheetReadingException(errorMsg);
+      }
+    }
+  }
+
+  private readArticulations(notationNode: IXmlElement, currentVoiceEntry: VoiceEntry): void {
+    let articNode: IXmlElement = notationNode.element("articulations");
+    if (articNode !== undefined) {
+      this.articulationReader.addArticulationExpression(articNode, currentVoiceEntry);
+    }
+    let fermaNode: IXmlElement = notationNode.element("fermata");
+    if (fermaNode !== undefined) {
+      this.articulationReader.addFermata(fermaNode, currentVoiceEntry);
+    }
+    let tecNode: IXmlElement = notationNode.element("technical");
+    if (tecNode !== undefined) {
+      this.articulationReader.addTechnicalArticulations(tecNode, currentVoiceEntry);
+    }
+    let ornaNode: IXmlElement = notationNode.element("ornaments");
+    if (ornaNode !== undefined) {
+      this.articulationReader.addOrnament(ornaNode, currentVoiceEntry);
+    }
+  }
+
+  /**
+   * Create a new [[Note]] and adds it to the currentVoiceEntry
+   * @param node
+   * @param noteDuration
+   * @param divisions
+   * @param graceNote
+   * @param chord
+   * @param guitarPro
+   * @returns {Note}
+   */
+  private addSingleNote(node: IXmlElement, noteDuration: Fraction, graceNote: boolean, chord: boolean, guitarPro: boolean): Note {
+    //Logging.debug("addSingleNote called");
+    let noteAlter: AccidentalEnum = AccidentalEnum.NONE;
+    let noteStep: NoteEnum = NoteEnum.C;
+    let noteOctave: number = 0;
+    let playbackInstrumentId: string = undefined;
+    let xmlnodeElementsArr: IXmlElement[] = node.elements();
+    for (let idx: number = 0, len: number = xmlnodeElementsArr.length; idx < len; ++idx) {
+      let noteElement: IXmlElement = xmlnodeElementsArr[idx];
+      try {
+        if (noteElement.name === "pitch") {
+          let noteElementsArr: IXmlElement[] = noteElement.elements();
+          for (let idx2: number = 0, len2: number = noteElementsArr.length; idx2 < len2; ++idx2) {
+            let pitchElement: IXmlElement = noteElementsArr[idx2];
             try {
-                if (noteElement.name === "pitch") {
-                    let noteElementsArr: IXmlElement[] = noteElement.elements();
-                    for (let idx2: number = 0, len2: number = noteElementsArr.length; idx2 < len2; ++idx2) {
-                        let pitchElement: IXmlElement = noteElementsArr[idx2];
-                        try {
-                            if (pitchElement.name === "step") {
-                                noteStep = NoteEnum[pitchElement.value];
-                                if (noteStep === undefined) {
-                                    let errorMsg: string = ITextTranslation.translateText(
-                                        "ReaderErrorMessages/NotePitchError",
-                                        "Invalid pitch while reading note."
-                                    );
-                                    this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-                                    throw new MusicSheetReadingException(errorMsg, undefined);
-                                }
-                            } else if (pitchElement.name === "alter") {
-                                noteAlter = parseInt(pitchElement.value, 10);
-                                if (isNaN(noteAlter)) {
-                                    let errorMsg: string = ITextTranslation.translateText(
-                                        "ReaderErrorMessages/NoteAlterationError", "Invalid alteration while reading note."
-                                    );
-                                    this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-                                    throw new MusicSheetReadingException(errorMsg, undefined);
-                                }
-
-                            } else if (pitchElement.name === "octave") {
-                                noteOctave = parseInt(pitchElement.value, 10);
-                                if (isNaN(noteOctave)) {
-                                    let errorMsg: string = ITextTranslation.translateText(
-                                        "ReaderErrorMessages/NoteOctaveError", "Invalid octave value while reading note."
-                                    );
-                                    this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-                                    throw new MusicSheetReadingException(errorMsg, undefined);
-                                }
-                            }
-                        } catch (ex) {
-                            Logging.log("VoiceGenerator.addSingleNote read Step: ", ex.message);
-                        }
+              if (pitchElement.name === "step") {
+                noteStep = NoteEnum[pitchElement.value];
+                if (noteStep === undefined) {
+                  let errorMsg: string = ITextTranslation.translateText(
+                    "ReaderErrorMessages/NotePitchError",
+                    "Invalid pitch while reading note."
+                  );
+                  this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                  throw new MusicSheetReadingException(errorMsg, undefined);
+                }
+              } else if (pitchElement.name === "alter") {
+                noteAlter = parseInt(pitchElement.value, 10);
+                if (isNaN(noteAlter)) {
+                  let errorMsg: string = ITextTranslation.translateText(
+                    "ReaderErrorMessages/NoteAlterationError", "Invalid alteration while reading note."
+                  );
+                  this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                  throw new MusicSheetReadingException(errorMsg, undefined);
+                }
 
-                    }
-                } else if (noteElement.name === "unpitched") {
-                    let displayStep: IXmlElement = noteElement.element("display-step");
-                    if (displayStep !== undefined) {
-                        noteStep = NoteEnum[displayStep.value.toUpperCase()];
-                    }
-                    let octave: IXmlElement = noteElement.element("display-octave");
-                    if (octave !== undefined) {
-                        noteOctave = parseInt(octave.value, 10);
-                        if (guitarPro) {
-                            noteOctave += 1;
-                        }
-                    }
-                } else if (noteElement.name === "instrument") {
-                    if (noteElement.firstAttribute !== undefined) {
-                        playbackInstrumentId = noteElement.firstAttribute.value;
-                    }
+              } else if (pitchElement.name === "octave") {
+                noteOctave = parseInt(pitchElement.value, 10);
+                if (isNaN(noteOctave)) {
+                  let errorMsg: string = ITextTranslation.translateText(
+                    "ReaderErrorMessages/NoteOctaveError", "Invalid octave value while reading note."
+                  );
+                  this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                  throw new MusicSheetReadingException(errorMsg, undefined);
                 }
+              }
             } catch (ex) {
-                Logging.log("VoiceGenerator.addSingleNote: ", ex);
+              Logging.log("VoiceGenerator.addSingleNote read Step: ", ex.message);
             }
-        }
 
-        noteOctave -= Pitch.OctaveXmlDifference;
-        let pitch: Pitch = new Pitch(noteStep, noteOctave, noteAlter);
-        let noteLength: Fraction = Fraction.createFromFraction(noteDuration);
-        let note: Note = new Note(this.currentVoiceEntry, this.currentStaffEntry, noteLength, pitch);
-        note.PlaybackInstrumentId = playbackInstrumentId;
-        if (!graceNote) {
-            this.currentVoiceEntry.Notes.push(note);
-        } else {
-            this.handleGraceNote(node, note);
-        }
-        if (node.elements("beam") && !chord) {
-            this.createBeam(node, note, graceNote);
-        }
-        return note;
-    }
-
-    /**
-     * Create a new rest note and add it to the currentVoiceEntry.
-     * @param noteDuration
-     * @param divisions
-     * @returns {Note}
-     */
-    private addRestNote(noteDuration: Fraction): Note {
-        let restFraction: Fraction = Fraction.createFromFraction(noteDuration);
-        let restNote: Note = new Note(this.currentVoiceEntry, this.currentStaffEntry, restFraction, undefined);
-        this.currentVoiceEntry.Notes.push(restNote);
-        if (this.openBeam !== undefined) {
-            this.openBeam.ExtendedNoteList.push(restNote);
+          }
+        } else if (noteElement.name === "unpitched") {
+          let displayStep: IXmlElement = noteElement.element("display-step");
+          if (displayStep !== undefined) {
+            noteStep = NoteEnum[displayStep.value.toUpperCase()];
+          }
+          let octave: IXmlElement = noteElement.element("display-octave");
+          if (octave !== undefined) {
+            noteOctave = parseInt(octave.value, 10);
+            if (guitarPro) {
+              noteOctave += 1;
+            }
+          }
+        } else if (noteElement.name === "instrument") {
+          if (noteElement.firstAttribute !== undefined) {
+            playbackInstrumentId = noteElement.firstAttribute.value;
+          }
         }
-        return restNote;
+      } catch (ex) {
+        Logging.log("VoiceGenerator.addSingleNote: ", ex);
+      }
     }
 
-    /**
-     * Handle the currentVoiceBeam.
-     * @param node
-     * @param note
-     * @param grace
-     */
-    private createBeam(node: IXmlElement, note: Note, grace: boolean): void {
-        try {
-            let beamNode: IXmlElement = node.element("beam");
-            let beamAttr: IXmlAttribute = undefined;
-            if (beamNode !== undefined && beamNode.hasAttributes) {
-                beamAttr = beamNode.attribute("number");
+    noteOctave -= Pitch.OctaveXmlDifference;
+    let pitch: Pitch = new Pitch(noteStep, noteOctave, noteAlter);
+    let noteLength: Fraction = Fraction.createFromFraction(noteDuration);
+    let note: Note = new Note(this.currentVoiceEntry, this.currentStaffEntry, noteLength, pitch);
+    note.PlaybackInstrumentId = playbackInstrumentId;
+    if (!graceNote) {
+      this.currentVoiceEntry.Notes.push(note);
+    } else {
+      this.handleGraceNote(node, note);
+    }
+    if (node.elements("beam") && !chord) {
+      this.createBeam(node, note, graceNote);
+    }
+    return note;
+  }
+
+  /**
+   * Create a new rest note and add it to the currentVoiceEntry.
+   * @param noteDuration
+   * @param divisions
+   * @returns {Note}
+   */
+  private addRestNote(noteDuration: Fraction): Note {
+    let restFraction: Fraction = Fraction.createFromFraction(noteDuration);
+    let restNote: Note = new Note(this.currentVoiceEntry, this.currentStaffEntry, restFraction, undefined);
+    this.currentVoiceEntry.Notes.push(restNote);
+    if (this.openBeam !== undefined) {
+      this.openBeam.ExtendedNoteList.push(restNote);
+    }
+    return restNote;
+  }
+
+  /**
+   * Handle the currentVoiceBeam.
+   * @param node
+   * @param note
+   * @param grace
+   */
+  private createBeam(node: IXmlElement, note: Note, grace: boolean): void {
+    try {
+      let beamNode: IXmlElement = node.element("beam");
+      let beamAttr: IXmlAttribute = undefined;
+      if (beamNode !== undefined && beamNode.hasAttributes) {
+        beamAttr = beamNode.attribute("number");
+      }
+      if (beamAttr !== undefined) {
+        let beamNumber: number = parseInt(beamAttr.value, 10);
+        let mainBeamNode: IXmlElement[] = node.elements("beam");
+        let currentBeamTag: string = mainBeamNode[0].value;
+        if (beamNumber === 1 && mainBeamNode !== undefined) {
+          if (currentBeamTag === "begin" && this.lastBeamTag !== currentBeamTag) {
+            if (grace) {
+              if (this.openGraceBeam !== undefined) {
+                this.handleOpenBeam();
+              }
+              this.openGraceBeam = new Beam();
+            } else {
+              if (this.openBeam !== undefined) {
+                this.handleOpenBeam();
+              }
+              this.openBeam = new Beam();
             }
-            if (beamAttr !== undefined) {
-                let beamNumber: number = parseInt(beamAttr.value, 10);
-                let mainBeamNode: IXmlElement[] = node.elements("beam");
-                let currentBeamTag: string = mainBeamNode[0].value;
-                if (beamNumber === 1 && mainBeamNode !== undefined) {
-                    if (currentBeamTag === "begin" && this.lastBeamTag !== currentBeamTag) {
-                        if (grace) {
-                            if (this.openGraceBeam !== undefined) {
-                                this.handleOpenBeam();
-                            }
-                            this.openGraceBeam = new Beam();
-                        } else {
-                            if (this.openBeam !== undefined) {
-                                this.handleOpenBeam();
-                            }
-                            this.openBeam = new Beam();
-                        }
-                    }
-                    this.lastBeamTag = currentBeamTag;
-                }
-                let sameVoiceEntry: boolean = false;
-                if (grace) {
-                    if (this.openGraceBeam === undefined) { return; }
-                    for (let idx: number = 0, len: number = this.openGraceBeam.Notes.length; idx < len; ++idx) {
-                        let beamNote: Note = this.openGraceBeam.Notes[idx];
-                        if (this.currentVoiceEntry === beamNote.ParentVoiceEntry) {
-                            sameVoiceEntry = true;
-                        }
-                    }
-                    if (!sameVoiceEntry) {
-                        this.openGraceBeam.addNoteToBeam(note);
-                        if (currentBeamTag === "end" && beamNumber === 1) {
-                            this.openGraceBeam = undefined;
-                        }
-                    }
-                } else {
-                    if (this.openBeam === undefined) { return; }
-                    for (let idx: number = 0, len: number = this.openBeam.Notes.length; idx < len; ++idx) {
-                        let beamNote: Note = this.openBeam.Notes[idx];
-                        if (this.currentVoiceEntry === beamNote.ParentVoiceEntry) {
-                            sameVoiceEntry = true;
-                        }
-                    }
-                    if (!sameVoiceEntry) {
-                        this.openBeam.addNoteToBeam(note);
-                        if (currentBeamTag === "end" && beamNumber === 1) {
-                            this.openBeam = undefined;
-                        }
-                    }
-                }
+          }
+          this.lastBeamTag = currentBeamTag;
+        }
+        let sameVoiceEntry: boolean = false;
+        if (grace) {
+          if (this.openGraceBeam === undefined) {
+            return;
+          }
+          for (let idx: number = 0, len: number = this.openGraceBeam.Notes.length; idx < len; ++idx) {
+            let beamNote: Note = this.openGraceBeam.Notes[idx];
+            if (this.currentVoiceEntry === beamNote.ParentVoiceEntry) {
+              sameVoiceEntry = true;
             }
-        } catch (e) {
-            let errorMsg: string = ITextTranslation.translateText(
-                "ReaderErrorMessages/BeamError", "Error while reading beam."
-            );
-            this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-            throw new MusicSheetReadingException("", e);
+          }
+          if (!sameVoiceEntry) {
+            this.openGraceBeam.addNoteToBeam(note);
+            if (currentBeamTag === "end" && beamNumber === 1) {
+              this.openGraceBeam = undefined;
+            }
+          }
+        } else {
+          if (this.openBeam === undefined) {
+            return;
+          }
+          for (let idx: number = 0, len: number = this.openBeam.Notes.length; idx < len; ++idx) {
+            let beamNote: Note = this.openBeam.Notes[idx];
+            if (this.currentVoiceEntry === beamNote.ParentVoiceEntry) {
+              sameVoiceEntry = true;
+            }
+          }
+          if (!sameVoiceEntry) {
+            this.openBeam.addNoteToBeam(note);
+            if (currentBeamTag === "end" && beamNumber === 1) {
+              this.openBeam = undefined;
+            }
+          }
         }
-
+      }
+    } catch (e) {
+      let errorMsg: string = ITextTranslation.translateText(
+        "ReaderErrorMessages/BeamError", "Error while reading beam."
+      );
+      this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+      throw new MusicSheetReadingException("", e);
     }
 
-    /**
-     * Check for open [[Beam]]s at end of [[SourceMeasure]] and closes them explicity.
-     */
-    private handleOpenBeam(): void {
-        if (this.openBeam.Notes.length === 1) {
-            let beamNote: Note = this.openBeam.Notes[0];
-            beamNote.NoteBeam = undefined;
-            this.openBeam = undefined;
-            return;
-        }
-        if (this.currentNote === CollectionUtil.last(this.openBeam.Notes)) {
-            this.openBeam = undefined;
-        } else {
-            let beamLastNote: Note = CollectionUtil.last(this.openBeam.Notes);
-            let beamLastNoteStaffEntry: SourceStaffEntry = beamLastNote.ParentStaffEntry;
-            let horizontalIndex: number = this.currentMeasure.getVerticalContainerIndexByTimestamp(beamLastNoteStaffEntry.Timestamp);
-            let verticalIndex: number = beamLastNoteStaffEntry.VerticalContainerParent.StaffEntries.indexOf(beamLastNoteStaffEntry);
-            if (horizontalIndex < this.currentMeasure.VerticalSourceStaffEntryContainers.length - 1) {
-                let nextStaffEntry: SourceStaffEntry = this.currentMeasure.VerticalSourceStaffEntryContainers[horizontalIndex + 1].StaffEntries[verticalIndex];
-                if (nextStaffEntry !== undefined) {
-                    for (let idx: number = 0, len: number = nextStaffEntry.VoiceEntries.length; idx < len; ++idx) {
-                        let voiceEntry: VoiceEntry = nextStaffEntry.VoiceEntries[idx];
-                        if (voiceEntry.ParentVoice === this.voice) {
-                            let candidateNote: Note = voiceEntry.Notes[0];
-                            if (candidateNote.Length.lte(new Fraction(1, 8))) {
-                                this.openBeam.addNoteToBeam(candidateNote);
-                                this.openBeam = undefined;
-                            } else {
-                                this.openBeam = undefined;
-                            }
-                        }
-                    }
-                }
-            } else {
+  }
+
+  /**
+   * Check for open [[Beam]]s at end of [[SourceMeasure]] and closes them explicity.
+   */
+  private handleOpenBeam(): void {
+    if (this.openBeam.Notes.length === 1) {
+      let beamNote: Note = this.openBeam.Notes[0];
+      beamNote.NoteBeam = undefined;
+      this.openBeam = undefined;
+      return;
+    }
+    if (this.currentNote === CollectionUtil.last(this.openBeam.Notes)) {
+      this.openBeam = undefined;
+    } else {
+      let beamLastNote: Note = CollectionUtil.last(this.openBeam.Notes);
+      let beamLastNoteStaffEntry: SourceStaffEntry = beamLastNote.ParentStaffEntry;
+      let horizontalIndex: number = this.currentMeasure.getVerticalContainerIndexByTimestamp(beamLastNoteStaffEntry.Timestamp);
+      let verticalIndex: number = beamLastNoteStaffEntry.VerticalContainerParent.StaffEntries.indexOf(beamLastNoteStaffEntry);
+      if (horizontalIndex < this.currentMeasure.VerticalSourceStaffEntryContainers.length - 1) {
+        let nextStaffEntry: SourceStaffEntry = this.currentMeasure.VerticalSourceStaffEntryContainers[horizontalIndex + 1].StaffEntries[verticalIndex];
+        if (nextStaffEntry !== undefined) {
+          for (let idx: number = 0, len: number = nextStaffEntry.VoiceEntries.length; idx < len; ++idx) {
+            let voiceEntry: VoiceEntry = nextStaffEntry.VoiceEntries[idx];
+            if (voiceEntry.ParentVoice === this.voice) {
+              let candidateNote: Note = voiceEntry.Notes[0];
+              if (candidateNote.Length.lte(new Fraction(1, 8))) {
+                this.openBeam.addNoteToBeam(candidateNote);
+                this.openBeam = undefined;
+              } else {
                 this.openBeam = undefined;
+              }
             }
+          }
         }
+      } else {
+        this.openBeam = undefined;
+      }
     }
-    private handleGraceNote(node: IXmlElement, note: Note): void {
-        let graceChord: boolean = false;
-        let type: string = "";
-        if (node.elements("type")) {
-            let typeNode: IXmlElement[] = node.elements("type");
-            if (typeNode) {
-                type = typeNode[0].value;
-                try {
-                    note.Length = this.getNoteDurationFromType(type);
-                    note.Length.Numerator = 1;
-                } catch (e) {
-                    let errorMsg: string = ITextTranslation.translateText(
-                        "ReaderErrorMessages/NoteDurationError", "Invalid note duration."
-                    );
-                    this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-                    throw new MusicSheetReadingException(errorMsg, e);
-                }
+  }
+
+  private handleGraceNote(node: IXmlElement, note: Note): void {
+    let graceChord: boolean = false;
+    let type: string = "";
+    if (node.elements("type")) {
+      let typeNode: IXmlElement[] = node.elements("type");
+      if (typeNode) {
+        type = typeNode[0].value;
+        try {
+          note.Length = this.getNoteDurationFromType(type);
+          note.Length.Numerator = 1;
+        } catch (e) {
+          let errorMsg: string = ITextTranslation.translateText(
+            "ReaderErrorMessages/NoteDurationError", "Invalid note duration."
+          );
+          this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+          throw new MusicSheetReadingException(errorMsg, e);
+        }
 
-            }
+      }
+    }
+    let graceNode: IXmlElement = node.element("grace");
+    if (graceNode !== undefined && graceNode.attributes()) {
+      if (graceNode.attribute("slash")) {
+        let slash: string = graceNode.attribute("slash").value;
+        if (slash === "yes") {
+          note.GraceNoteSlash = true;
         }
-        let graceNode: IXmlElement = node.element("grace");
-        if (graceNode !== undefined && graceNode.attributes()) {
-            if (graceNode.attribute("slash")) {
-                let slash: string = graceNode.attribute("slash").value;
-                if (slash === "yes") {
-                    note.GraceNoteSlash = true;
-                }
+      }
+    }
+    if (node.element("chord") !== undefined) {
+      graceChord = true;
+    }
+    let graceVoiceEntry: VoiceEntry = undefined;
+    if (!graceChord) {
+      graceVoiceEntry = new VoiceEntry(
+        new Fraction(0, 1), this.currentVoiceEntry.ParentVoice, this.currentStaffEntry
+      );
+      if (this.currentVoiceEntry.graceVoiceEntriesBefore === undefined) {
+        this.currentVoiceEntry.graceVoiceEntriesBefore = [];
+      }
+      this.currentVoiceEntry.graceVoiceEntriesBefore.push(graceVoiceEntry);
+    } else {
+      if (
+        this.currentVoiceEntry.graceVoiceEntriesBefore !== undefined
+        && this.currentVoiceEntry.graceVoiceEntriesBefore.length > 0
+      ) {
+        graceVoiceEntry = CollectionUtil.last(this.currentVoiceEntry.graceVoiceEntriesBefore);
+      }
+    }
+    if (graceVoiceEntry !== undefined) {
+      graceVoiceEntry.Notes.push(note);
+      note.ParentVoiceEntry = graceVoiceEntry;
+    }
+  }
+
+  /**
+   * Create a [[Tuplet]].
+   * @param node
+   * @param tupletNodeList
+   * @returns {number}
+   */
+  private addTuplet(node: IXmlElement, tupletNodeList: IXmlElement[]): number {
+    if (tupletNodeList !== undefined && tupletNodeList.length > 1) {
+      let timeModNode: IXmlElement = node.element("time-modification");
+      if (timeModNode !== undefined) {
+        timeModNode = timeModNode.element("actual-notes");
+      }
+      let tupletNodeListArr: IXmlElement[] = tupletNodeList;
+      for (let idx: number = 0, len: number = tupletNodeListArr.length; idx < len; ++idx) {
+        let tupletNode: IXmlElement = tupletNodeListArr[idx];
+        if (tupletNode !== undefined && tupletNode.attributes()) {
+          let type: string = tupletNode.attribute("type").value;
+          if (type === "start") {
+            let tupletNumber: number = 1;
+            if (tupletNode.attribute("number")) {
+              tupletNumber = parseInt(tupletNode.attribute("number").value, 10);
+            }
+            let tupletLabelNumber: number = 0;
+            if (timeModNode !== undefined) {
+              tupletLabelNumber = parseInt(timeModNode.value, 10);
+              if (isNaN(tupletLabelNumber)) {
+                let errorMsg: string = ITextTranslation.translateText(
+                  "ReaderErrorMessages/TupletNoteDurationError", "Invalid tuplet note duration."
+                );
+                this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                throw new MusicSheetReadingException(errorMsg, undefined);
+              }
+
+            }
+            let tuplet: Tuplet = new Tuplet(tupletLabelNumber);
+            if (this.tupletDict[tupletNumber] !== undefined) {
+              delete this.tupletDict[tupletNumber];
+              if (Object.keys(this.tupletDict).length === 0) {
+                this.openTupletNumber = 0;
+              } else if (Object.keys(this.tupletDict).length > 1) {
+                this.openTupletNumber--;
+              }
+            }
+            this.tupletDict[tupletNumber] = tuplet;
+            let subnotelist: Note[] = [];
+            subnotelist.push(this.currentNote);
+            tuplet.Notes.push(subnotelist);
+            tuplet.Fractions.push(this.getTupletNoteDurationFromType(node));
+            this.currentNote.NoteTuplet = tuplet;
+            this.openTupletNumber = tupletNumber;
+          } else if (type === "stop") {
+            let tupletNumber: number = 1;
+            if (tupletNode.attribute("number")) {
+              tupletNumber = parseInt(tupletNode.attribute("number").value, 10);
+            }
+            let tuplet: Tuplet = this.tupletDict[tupletNumber];
+            if (tuplet !== undefined) {
+              let subnotelist: Note[] = [];
+              subnotelist.push(this.currentNote);
+              tuplet.Notes.push(subnotelist);
+              tuplet.Fractions.push(this.getTupletNoteDurationFromType(node));
+              this.currentNote.NoteTuplet = tuplet;
+              delete this.tupletDict[tupletNumber];
+              if (Object.keys(this.tupletDict).length === 0) {
+                this.openTupletNumber = 0;
+              } else if (Object.keys(this.tupletDict).length > 1) {
+                this.openTupletNumber--;
+              }
             }
+          }
         }
-        if (node.element("chord") !== undefined) {
-            graceChord = true;
+      }
+    } else if (tupletNodeList[0] !== undefined) {
+      let n: IXmlElement = tupletNodeList[0];
+      if (n.hasAttributes) {
+        let type: string = n.attribute("type").value;
+        let tupletnumber: number = 1;
+        if (n.attribute("number")) {
+          tupletnumber = parseInt(n.attribute("number").value, 10);
         }
-        let graceVoiceEntry: VoiceEntry = undefined;
-        if (!graceChord) {
-            graceVoiceEntry = new VoiceEntry(
-                new Fraction(0, 1), this.currentVoiceEntry.ParentVoice, this.currentStaffEntry
-            );
-            if (this.currentVoiceEntry.graceVoiceEntriesBefore === undefined) {
-                this.currentVoiceEntry.graceVoiceEntriesBefore = [];
+        let noTupletNumbering: boolean = isNaN(tupletnumber);
+
+        if (type === "start") {
+          let tupletLabelNumber: number = 0;
+          let timeModNode: IXmlElement = node.element("time-modification");
+          if (timeModNode !== undefined) {
+            timeModNode = timeModNode.element("actual-notes");
+          }
+          if (timeModNode !== undefined) {
+            tupletLabelNumber = parseInt(timeModNode.value, 10);
+            if (isNaN(tupletLabelNumber)) {
+              let errorMsg: string = ITextTranslation.translateText(
+                "ReaderErrorMessages/TupletNoteDurationError", "Invalid tuplet note duration."
+              );
+              this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+              throw new MusicSheetReadingException(errorMsg);
             }
-            this.currentVoiceEntry.graceVoiceEntriesBefore.push(graceVoiceEntry);
-        } else {
-            if (
-                this.currentVoiceEntry.graceVoiceEntriesBefore !== undefined
-                && this.currentVoiceEntry.graceVoiceEntriesBefore.length > 0
-            ) {
-                graceVoiceEntry = CollectionUtil.last(this.currentVoiceEntry.graceVoiceEntriesBefore);
+
+          }
+          if (noTupletNumbering) {
+            this.openTupletNumber++;
+            tupletnumber = this.openTupletNumber;
+          }
+          let tuplet: Tuplet = this.tupletDict[tupletnumber];
+          if (tuplet === undefined) {
+            tuplet = this.tupletDict[tupletnumber] = new Tuplet(tupletLabelNumber);
+          }
+          let subnotelist: Note[] = [];
+          subnotelist.push(this.currentNote);
+          tuplet.Notes.push(subnotelist);
+          tuplet.Fractions.push(this.getTupletNoteDurationFromType(node));
+          this.currentNote.NoteTuplet = tuplet;
+          this.openTupletNumber = tupletnumber;
+        } else if (type === "stop") {
+          if (noTupletNumbering) {
+            tupletnumber = this.openTupletNumber;
+          }
+          let tuplet: Tuplet = this.tupletDict[this.openTupletNumber];
+          if (tuplet !== undefined) {
+            let subnotelist: Note[] = [];
+            subnotelist.push(this.currentNote);
+            tuplet.Notes.push(subnotelist);
+            tuplet.Fractions.push(this.getTupletNoteDurationFromType(node));
+            this.currentNote.NoteTuplet = tuplet;
+            if (Object.keys(this.tupletDict).length === 0) {
+              this.openTupletNumber = 0;
+            } else if (Object.keys(this.tupletDict).length > 1) {
+              this.openTupletNumber--;
             }
+            delete this.tupletDict[tupletnumber];
+          }
         }
-        if (graceVoiceEntry !== undefined) {
-            graceVoiceEntry.Notes.push(note);
-            note.ParentVoiceEntry = graceVoiceEntry;
+      }
+    }
+    return this.openTupletNumber;
+  }
+
+  /**
+   * This method handles the time-modification IXmlElement for the Tuplet case (tupletNotes not at begin/end of Tuplet).
+   * @param noteNode
+   */
+  private handleTimeModificationNode(noteNode: IXmlElement): void {
+    if (this.tupletDict[this.openTupletNumber] !== undefined) {
+      try {
+        // Tuplet should already be created
+        let tuplet: Tuplet = this.tupletDict[this.openTupletNumber];
+        let notes: Note[] = CollectionUtil.last(tuplet.Notes);
+        let lastTupletVoiceEntry: VoiceEntry = notes[0].ParentVoiceEntry;
+        let noteList: Note[];
+        if (lastTupletVoiceEntry.Timestamp.Equals(this.currentVoiceEntry.Timestamp)) {
+          noteList = notes;
+        } else {
+          noteList = [];
+          tuplet.Notes.push(noteList);
+          tuplet.Fractions.push(this.getTupletNoteDurationFromType(noteNode));
         }
+        noteList.push(this.currentNote);
+        this.currentNote.NoteTuplet = tuplet;
+      } catch (ex) {
+        let errorMsg: string = ITextTranslation.translateText(
+          "ReaderErrorMessages/TupletNumberError", "Invalid tuplet number."
+        );
+        this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+        throw ex;
+      }
+
+    } else if (this.currentVoiceEntry.Notes.length > 0) {
+      let firstNote: Note = this.currentVoiceEntry.Notes[0];
+      if (firstNote.NoteTuplet !== undefined) {
+        let tuplet: Tuplet = firstNote.NoteTuplet;
+        let notes: Note[] = CollectionUtil.last(tuplet.Notes);
+        notes.push(this.currentNote);
+        this.currentNote.NoteTuplet = tuplet;
+      }
     }
-
-    /**
-     * Create a [[Tuplet]].
-     * @param node
-     * @param tupletNodeList
-     * @returns {number}
-     */
-    private addTuplet(node: IXmlElement, tupletNodeList: IXmlElement[]): number {
-        if (tupletNodeList !== undefined && tupletNodeList.length > 1) {
-            let timeModNode: IXmlElement = node.element("time-modification");
-            if (timeModNode !== undefined) {
-                timeModNode = timeModNode.element("actual-notes");
-            }
-            let tupletNodeListArr: IXmlElement[] = tupletNodeList;
-            for (let idx: number = 0, len: number = tupletNodeListArr.length; idx < len; ++idx) {
-                let tupletNode: IXmlElement = tupletNodeListArr[idx];
-                if (tupletNode !== undefined && tupletNode.attributes()) {
-                    let type: string = tupletNode.attribute("type").value;
-                    if (type === "start") {
-                        let tupletNumber: number = 1;
-                        if (tupletNode.attribute("number")) {
-                            tupletNumber = parseInt(tupletNode.attribute("number").value, 10);
-                        }
-                        let tupletLabelNumber: number = 0;
-                        if (timeModNode !== undefined) {
-                            tupletLabelNumber = parseInt(timeModNode.value, 10);
-                            if (isNaN(tupletLabelNumber)) {
-                                let errorMsg: string = ITextTranslation.translateText(
-                                    "ReaderErrorMessages/TupletNoteDurationError", "Invalid tuplet note duration."
-                                );
-                                this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-                                throw new MusicSheetReadingException(errorMsg, undefined);
-                            }
-
-                        }
-                        let tuplet: Tuplet = new Tuplet(tupletLabelNumber);
-                        if (this.tupletDict[tupletNumber] !== undefined) {
-                            delete this.tupletDict[tupletNumber];
-                            if (Object.keys(this.tupletDict).length === 0) {
-                                this.openTupletNumber = 0;
-                            } else if (Object.keys(this.tupletDict).length > 1) {
-                                this.openTupletNumber--;
-                            }
-                        }
-                        this.tupletDict[tupletNumber] = tuplet;
-                        let subnotelist: Note[] = [];
-                        subnotelist.push(this.currentNote);
-                        tuplet.Notes.push(subnotelist);
-                        tuplet.Fractions.push(this.getTupletNoteDurationFromType(node));
-                        this.currentNote.NoteTuplet = tuplet;
-                        this.openTupletNumber = tupletNumber;
-                    } else if (type === "stop") {
-                        let tupletNumber: number = 1;
-                        if (tupletNode.attribute("number")) {
-                            tupletNumber = parseInt(tupletNode.attribute("number").value, 10);
-                        }
-                        let tuplet: Tuplet = this.tupletDict[tupletNumber];
-                        if (tuplet !== undefined) {
-                            let subnotelist: Note[] = [];
-                            subnotelist.push(this.currentNote);
-                            tuplet.Notes.push(subnotelist);
-                            tuplet.Fractions.push(this.getTupletNoteDurationFromType(node));
-                            this.currentNote.NoteTuplet = tuplet;
-                            delete this.tupletDict[tupletNumber];
-                            if (Object.keys(this.tupletDict).length === 0) {
-                                this.openTupletNumber = 0;
-                            } else if (Object.keys(this.tupletDict).length > 1) {
-                                this.openTupletNumber--;
-                            }
-                        }
+  }
+
+  private addTie(tieNodeList: IXmlElement[], measureStartAbsoluteTimestamp: Fraction, maxTieNoteFraction: Fraction): void {
+    if (tieNodeList !== undefined) {
+      if (tieNodeList.length === 1) {
+        let tieNode: IXmlElement = tieNodeList[0];
+        if (tieNode !== undefined && tieNode.attributes()) {
+          let type: string = tieNode.attribute("type").value;
+          try {
+            if (type === "start") {
+              let num: number = this.findCurrentNoteInTieDict(this.currentNote);
+              if (num < 0) {
+                delete this.openTieDict[num];
+              }
+              let newTieNumber: number = this.getNextAvailableNumberForTie();
+              let tie: Tie = new Tie(this.currentNote);
+              this.openTieDict[newTieNumber] = tie;
+              if (this.currentNote.NoteBeam !== undefined) {
+                if (this.currentNote.NoteBeam.Notes[0] === this.currentNote) {
+                  tie.BeamStartTimestamp = Fraction.plus(measureStartAbsoluteTimestamp, this.currentVoiceEntry.Timestamp);
+                } else {
+                  for (let idx: number = 0, len: number = this.currentNote.NoteBeam.Notes.length; idx < len; ++idx) {
+                    let note: Note = this.currentNote.NoteBeam.Notes[idx];
+                    if (note.NoteTie !== undefined && note.NoteTie !== tie && note.NoteTie.BeamStartTimestamp !== undefined) {
+                      tie.BeamStartTimestamp = note.NoteTie.BeamStartTimestamp;
+                      break;
                     }
+                  }
+                  if (this.currentNote === CollectionUtil.last(this.currentNote.NoteBeam.Notes)) {
+                    tie.BeamStartTimestamp = Fraction.plus(measureStartAbsoluteTimestamp, this.currentVoiceEntry.Timestamp);
+                  }
                 }
-            }
-        } else if (tupletNodeList[0] !== undefined) {
-            let n: IXmlElement = tupletNodeList[0];
-            if (n.hasAttributes) {
-                let type: string = n.attribute("type").value;
-                let tupletnumber: number = 1;
-                if (n.attribute("number")) {
-                    tupletnumber = parseInt(n.attribute("number").value, 10);
+              }
+            } else if (type === "stop") {
+              let tieNumber: number = this.findCurrentNoteInTieDict(this.currentNote);
+              let tie: Tie = this.openTieDict[tieNumber];
+              if (tie !== undefined) {
+                let tieStartNote: Note = tie.Start;
+                tieStartNote.NoteTie = tie;
+                tieStartNote.Length.Add(this.currentNote.Length);
+                tie.Fractions.push(this.currentNote.Length);
+                if (maxTieNoteFraction.lt(Fraction.plus(this.currentStaffEntry.Timestamp, this.currentNote.Length))) {
+                  maxTieNoteFraction = Fraction.plus(this.currentStaffEntry.Timestamp, this.currentNote.Length);
                 }
-                let noTupletNumbering: boolean = isNaN(tupletnumber);
-
-                if (type === "start") {
-                    let tupletLabelNumber: number = 0;
-                    let timeModNode: IXmlElement = node.element("time-modification");
-                    if (timeModNode !== undefined) {
-                        timeModNode = timeModNode.element("actual-notes");
-                    }
-                    if (timeModNode !== undefined) {
-                        tupletLabelNumber = parseInt(timeModNode.value, 10);
-                        if (isNaN(tupletLabelNumber)) {
-                            let errorMsg: string = ITextTranslation.translateText(
-                                "ReaderErrorMessages/TupletNoteDurationError", "Invalid tuplet note duration."
-                            );
-                            this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-                            throw new MusicSheetReadingException(errorMsg);
-                        }
-
-                    }
-                    if (noTupletNumbering) {
-                        this.openTupletNumber++;
-                        tupletnumber = this.openTupletNumber;
-                    }
-                    let tuplet: Tuplet = this.tupletDict[tupletnumber];
-                    if (tuplet === undefined) {
-                        tuplet = this.tupletDict[tupletnumber] = new Tuplet(tupletLabelNumber);
-                    }
-                    let subnotelist: Note[] = [];
-                    subnotelist.push(this.currentNote);
-                    tuplet.Notes.push(subnotelist);
-                    tuplet.Fractions.push(this.getTupletNoteDurationFromType(node));
-                    this.currentNote.NoteTuplet = tuplet;
-                    this.openTupletNumber = tupletnumber;
-                } else if (type === "stop") {
-                    if (noTupletNumbering) {
-                        tupletnumber = this.openTupletNumber;
-                    }
-                    let tuplet: Tuplet = this.tupletDict[this.openTupletNumber];
-                    if (tuplet !== undefined) {
-                        let subnotelist: Note[] = [];
-                        subnotelist.push(this.currentNote);
-                        tuplet.Notes.push(subnotelist);
-                        tuplet.Fractions.push(this.getTupletNoteDurationFromType(node));
-                        this.currentNote.NoteTuplet = tuplet;
-                        if (Object.keys(this.tupletDict).length === 0) {
-                            this.openTupletNumber = 0;
-                        } else if (Object.keys(this.tupletDict).length > 1) {
-                            this.openTupletNumber--;
-                        }
-                        delete this.tupletDict[tupletnumber];
+                let i: number = this.currentVoiceEntry.Notes.indexOf(this.currentNote);
+                if (i !== -1) {
+                  this.currentVoiceEntry.Notes.splice(i, 1);
+                }
+                if (
+                  this.currentVoiceEntry.Articulations.length === 1
+                  && this.currentVoiceEntry.Articulations[0] === ArticulationEnum.fermata
+                  && tieStartNote.ParentVoiceEntry.Articulations[ArticulationEnum.fermata] === undefined
+                ) {
+                  tieStartNote.ParentVoiceEntry.Articulations.push(ArticulationEnum.fermata);
+                }
+                if (this.currentNote.NoteBeam !== undefined) {
+                  let noteBeamIndex: number = this.currentNote.NoteBeam.Notes.indexOf(this.currentNote);
+                  if (noteBeamIndex === 0 && tie.BeamStartTimestamp === undefined) {
+                    tie.BeamStartTimestamp = Fraction.plus(measureStartAbsoluteTimestamp, this.currentVoiceEntry.Timestamp);
+                  }
+                  let noteBeam: Beam = this.currentNote.NoteBeam;
+                  noteBeam.Notes[noteBeamIndex] = tieStartNote;
+                  tie.TieBeam = noteBeam;
+                }
+                if (this.currentNote.NoteTuplet !== undefined) {
+                  let noteTupletIndex: number = this.currentNote.NoteTuplet.getNoteIndex(this.currentNote);
+                  let index: number = this.currentNote.NoteTuplet.Notes[noteTupletIndex].indexOf(this.currentNote);
+                  let noteTuplet: Tuplet = this.currentNote.NoteTuplet;
+                  noteTuplet.Notes[noteTupletIndex][index] = tieStartNote;
+                  tie.TieTuplet = noteTuplet;
+                }
+                for (let idx: number = 0, len: number = this.currentNote.NoteSlurs.length; idx < len; ++idx) {
+                  let slur: Slur = this.currentNote.NoteSlurs[idx];
+                  if (slur.StartNote === this.currentNote) {
+                    slur.StartNote = tie.Start;
+                    slur.StartNote.NoteSlurs.push(slur);
+                  }
+                  if (slur.EndNote === this.currentNote) {
+                    slur.EndNote = tie.Start;
+                    slur.EndNote.NoteSlurs.push(slur);
+                  }
+                }
+                let lyricsEntries: Dictionary<number, LyricsEntry> = this.currentVoiceEntry.LyricsEntries;
+                for (let lyricsEntry in lyricsEntries) {
+                  if (lyricsEntries.hasOwnProperty(lyricsEntry)) {
+                    let val: LyricsEntry = this.currentVoiceEntry.LyricsEntries[lyricsEntry];
+                    if (!tieStartNote.ParentVoiceEntry.LyricsEntries.hasOwnProperty(lyricsEntry)) {
+                      tieStartNote.ParentVoiceEntry.LyricsEntries[lyricsEntry] = val;
+                      val.Parent = tieStartNote.ParentVoiceEntry;
                     }
+                  }
                 }
+                delete this.openTieDict[tieNumber];
+              }
             }
-        }
-        return this.openTupletNumber;
-    }
+          } catch (err) {
+            let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/TieError", "Error while reading tie.");
+            this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+          }
 
-    /**
-     * This method handles the time-modification IXmlElement for the Tuplet case (tupletNotes not at begin/end of Tuplet).
-     * @param noteNode
-     */
-    private handleTimeModificationNode(noteNode: IXmlElement): void {
-        if (this.tupletDict[this.openTupletNumber] !== undefined) {
-            try {
-                // Tuplet should already be created
-                let tuplet: Tuplet = this.tupletDict[this.openTupletNumber];
-                let notes: Note[] = CollectionUtil.last(tuplet.Notes);
-                let lastTupletVoiceEntry: VoiceEntry = notes[0].ParentVoiceEntry;
-                let noteList: Note[];
-                if (lastTupletVoiceEntry.Timestamp.Equals(this.currentVoiceEntry.Timestamp)) {
-                    noteList = notes;
-                } else {
-                    noteList = [];
-                    tuplet.Notes.push(noteList);
-                    tuplet.Fractions.push(this.getTupletNoteDurationFromType(noteNode));
-                }
-                noteList.push(this.currentNote);
-                this.currentNote.NoteTuplet = tuplet;
-            } catch (ex) {
-                let errorMsg: string = ITextTranslation.translateText(
-                    "ReaderErrorMessages/TupletNumberError", "Invalid tuplet number."
-                );
-                this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-                throw ex;
+        }
+      } else if (tieNodeList.length === 2) {
+        let tieNumber: number = this.findCurrentNoteInTieDict(this.currentNote);
+        if (tieNumber >= 0) {
+          let tie: Tie = this.openTieDict[tieNumber];
+          let tieStartNote: Note = tie.Start;
+          tieStartNote.Length.Add(this.currentNote.Length);
+          tie.Fractions.push(this.currentNote.Length);
+          if (this.currentNote.NoteBeam !== undefined) {
+            let noteBeamIndex: number = this.currentNote.NoteBeam.Notes.indexOf(this.currentNote);
+            if (noteBeamIndex === 0 && tie.BeamStartTimestamp === undefined) {
+              tie.BeamStartTimestamp = Fraction.plus(measureStartAbsoluteTimestamp, this.currentVoiceEntry.Timestamp);
             }
-
-        } else if (this.currentVoiceEntry.Notes.length > 0) {
-            let firstNote: Note = this.currentVoiceEntry.Notes[0];
-            if (firstNote.NoteTuplet !== undefined) {
-                let tuplet: Tuplet = firstNote.NoteTuplet;
-                let notes: Note[] = CollectionUtil.last(tuplet.Notes);
-                notes.push(this.currentNote);
-                this.currentNote.NoteTuplet = tuplet;
+            let noteBeam: Beam = this.currentNote.NoteBeam;
+            noteBeam.Notes[noteBeamIndex] = tieStartNote;
+            tie.TieBeam = noteBeam;
+          }
+          for (let idx: number = 0, len: number = this.currentNote.NoteSlurs.length; idx < len; ++idx) {
+            let slur: Slur = this.currentNote.NoteSlurs[idx];
+            if (slur.StartNote === this.currentNote) {
+              slur.StartNote = tie.Start;
+              slur.StartNote.NoteSlurs.push(slur);
             }
-        }
-    }
-    private addTie(tieNodeList: IXmlElement[], measureStartAbsoluteTimestamp: Fraction, maxTieNoteFraction: Fraction): void {
-        if (tieNodeList !== undefined) {
-            if (tieNodeList.length === 1) {
-                let tieNode: IXmlElement = tieNodeList[0];
-                if (tieNode !== undefined && tieNode.attributes()) {
-                    let type: string = tieNode.attribute("type").value;
-                    try {
-                        if (type === "start") {
-                            let num: number = this.findCurrentNoteInTieDict(this.currentNote);
-                            if (num < 0) {
-                                delete this.openTieDict[num];
-                            }
-                            let newTieNumber: number = this.getNextAvailableNumberForTie();
-                            let tie: Tie = new Tie(this.currentNote);
-                            this.openTieDict[newTieNumber] = tie;
-                            if (this.currentNote.NoteBeam !== undefined) {
-                                if (this.currentNote.NoteBeam.Notes[0] === this.currentNote) {
-                                    tie.BeamStartTimestamp = Fraction.plus(measureStartAbsoluteTimestamp, this.currentVoiceEntry.Timestamp);
-                                } else {
-                                    for (let idx: number = 0, len: number = this.currentNote.NoteBeam.Notes.length; idx < len; ++idx) {
-                                        let note: Note = this.currentNote.NoteBeam.Notes[idx];
-                                        if (note.NoteTie !== undefined && note.NoteTie !== tie && note.NoteTie.BeamStartTimestamp !== undefined) {
-                                            tie.BeamStartTimestamp = note.NoteTie.BeamStartTimestamp;
-                                            break;
-                                        }
-                                    }
-                                    if (this.currentNote === CollectionUtil.last(this.currentNote.NoteBeam.Notes)) {
-                                        tie.BeamStartTimestamp = Fraction.plus(measureStartAbsoluteTimestamp, this.currentVoiceEntry.Timestamp);
-                                    }
-                                }
-                            }
-                        } else if (type === "stop") {
-                            let tieNumber: number = this.findCurrentNoteInTieDict(this.currentNote);
-                            let tie: Tie = this.openTieDict[tieNumber];
-                            if (tie !== undefined) {
-                                let tieStartNote: Note = tie.Start;
-                                tieStartNote.NoteTie = tie;
-                                tieStartNote.Length.Add(this.currentNote.Length);
-                                tie.Fractions.push(this.currentNote.Length);
-                                if (maxTieNoteFraction.lt(Fraction.plus(this.currentStaffEntry.Timestamp, this.currentNote.Length))) {
-                                    maxTieNoteFraction = Fraction.plus(this.currentStaffEntry.Timestamp, this.currentNote.Length);
-                                }
-                                let i: number = this.currentVoiceEntry.Notes.indexOf(this.currentNote);
-                                if (i !== -1) { this.currentVoiceEntry.Notes.splice(i, 1); }
-                                if (
-                                    this.currentVoiceEntry.Articulations.length === 1
-                                    && this.currentVoiceEntry.Articulations[0] === ArticulationEnum.fermata
-                                    && tieStartNote.ParentVoiceEntry.Articulations[ArticulationEnum.fermata] === undefined
-                                ) {
-                                    tieStartNote.ParentVoiceEntry.Articulations.push(ArticulationEnum.fermata);
-                                }
-                                if (this.currentNote.NoteBeam !== undefined) {
-                                    let noteBeamIndex: number = this.currentNote.NoteBeam.Notes.indexOf(this.currentNote);
-                                    if (noteBeamIndex === 0 && tie.BeamStartTimestamp === undefined) {
-                                        tie.BeamStartTimestamp = Fraction.plus(measureStartAbsoluteTimestamp, this.currentVoiceEntry.Timestamp);
-                                    }
-                                    let noteBeam: Beam = this.currentNote.NoteBeam;
-                                    noteBeam.Notes[noteBeamIndex] = tieStartNote;
-                                    tie.TieBeam = noteBeam;
-                                }
-                                if (this.currentNote.NoteTuplet !== undefined) {
-                                    let noteTupletIndex: number = this.currentNote.NoteTuplet.getNoteIndex(this.currentNote);
-                                    let index: number = this.currentNote.NoteTuplet.Notes[noteTupletIndex].indexOf(this.currentNote);
-                                    let noteTuplet: Tuplet = this.currentNote.NoteTuplet;
-                                    noteTuplet.Notes[noteTupletIndex][index] = tieStartNote;
-                                    tie.TieTuplet = noteTuplet;
-                                }
-                                for (let idx: number = 0, len: number = this.currentNote.NoteSlurs.length; idx < len; ++idx) {
-                                    let slur: Slur = this.currentNote.NoteSlurs[idx];
-                                    if (slur.StartNote === this.currentNote) {
-                                        slur.StartNote = tie.Start;
-                                        slur.StartNote.NoteSlurs.push(slur);
-                                    }
-                                    if (slur.EndNote === this.currentNote) {
-                                        slur.EndNote = tie.Start;
-                                        slur.EndNote.NoteSlurs.push(slur);
-                                    }
-                                }
-                                let lyricsEntries: Dictionary<number, LyricsEntry> = this.currentVoiceEntry.LyricsEntries;
-                                for (let lyricsEntry in lyricsEntries) {
-                                    if (lyricsEntries.hasOwnProperty(lyricsEntry)) {
-                                        let val: LyricsEntry = this.currentVoiceEntry.LyricsEntries[lyricsEntry];
-                                        if (!tieStartNote.ParentVoiceEntry.LyricsEntries.hasOwnProperty(lyricsEntry)) {
-                                            tieStartNote.ParentVoiceEntry.LyricsEntries[lyricsEntry] = val;
-                                            val.Parent = tieStartNote.ParentVoiceEntry;
-                                        }
-                                    }
-                                }
-                                delete this.openTieDict[tieNumber];
-                            }
-                        }
-                    } catch (err) {
-                        let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/TieError", "Error while reading tie.");
-                        this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-                    }
-
-                }
-            } else if (tieNodeList.length === 2) {
-                let tieNumber: number = this.findCurrentNoteInTieDict(this.currentNote);
-                if (tieNumber >= 0) {
-                    let tie: Tie = this.openTieDict[tieNumber];
-                    let tieStartNote: Note = tie.Start;
-                    tieStartNote.Length.Add(this.currentNote.Length);
-                    tie.Fractions.push(this.currentNote.Length);
-                    if (this.currentNote.NoteBeam !== undefined) {
-                        let noteBeamIndex: number = this.currentNote.NoteBeam.Notes.indexOf(this.currentNote);
-                        if (noteBeamIndex === 0 && tie.BeamStartTimestamp === undefined) {
-                            tie.BeamStartTimestamp = Fraction.plus(measureStartAbsoluteTimestamp, this.currentVoiceEntry.Timestamp);
-                        }
-                        let noteBeam: Beam = this.currentNote.NoteBeam;
-                        noteBeam.Notes[noteBeamIndex] = tieStartNote;
-                        tie.TieBeam = noteBeam;
-                    }
-                    for (let idx: number = 0, len: number = this.currentNote.NoteSlurs.length; idx < len; ++idx) {
-                        let slur: Slur = this.currentNote.NoteSlurs[idx];
-                        if (slur.StartNote === this.currentNote) {
-                            slur.StartNote = tie.Start;
-                            slur.StartNote.NoteSlurs.push(slur);
-                        }
-                        if (slur.EndNote === this.currentNote) {
-                            slur.EndNote = tie.Start;
-                            slur.EndNote.NoteSlurs.push(slur);
-                        }
-                    }
+            if (slur.EndNote === this.currentNote) {
+              slur.EndNote = tie.Start;
+              slur.EndNote.NoteSlurs.push(slur);
+            }
+          }
 
-                    this.currentVoiceEntry.LyricsEntries.forEach((key: number, value: LyricsEntry): void => {
-                        if (!tieStartNote.ParentVoiceEntry.LyricsEntries.containsKey(key)) {
-                            tieStartNote.ParentVoiceEntry.LyricsEntries.setValue(key, value);
-                            value.Parent = tieStartNote.ParentVoiceEntry;
-                        }
-                    });
-                    if (maxTieNoteFraction.lt(Fraction.plus(this.currentStaffEntry.Timestamp, this.currentNote.Length))) {
-                        maxTieNoteFraction = Fraction.plus(this.currentStaffEntry.Timestamp, this.currentNote.Length);
-                    }
-                    // delete currentNote from Notes:
-                    let i: number = this.currentVoiceEntry.Notes.indexOf(this.currentNote);
-                    if (i !== -1) { this.currentVoiceEntry.Notes.splice(i, 1); }
-                }
+          this.currentVoiceEntry.LyricsEntries.forEach((key: number, value: LyricsEntry): void => {
+            if (!tieStartNote.ParentVoiceEntry.LyricsEntries.containsKey(key)) {
+              tieStartNote.ParentVoiceEntry.LyricsEntries.setValue(key, value);
+              value.Parent = tieStartNote.ParentVoiceEntry;
             }
+          });
+          if (maxTieNoteFraction.lt(Fraction.plus(this.currentStaffEntry.Timestamp, this.currentNote.Length))) {
+            maxTieNoteFraction = Fraction.plus(this.currentStaffEntry.Timestamp, this.currentNote.Length);
+          }
+          // delete currentNote from Notes:
+          let i: number = this.currentVoiceEntry.Notes.indexOf(this.currentNote);
+          if (i !== -1) {
+            this.currentVoiceEntry.Notes.splice(i, 1);
+          }
         }
+      }
     }
-
-    /**
-     * Find the next free int (starting from 0) to use as key in TieDict.
-     * @returns {number}
-     */
-    private getNextAvailableNumberForTie(): number {
-        let keys: string[] = Object.keys(this.openTieDict);
-        if (keys.length === 0) { return 1; }
-        keys.sort((a, b) => (+a - +b)); // FIXME Andrea: test
-        for (let i: number = 0; i < keys.length; i++) {
-            if ("" + (i + 1) !== keys[i]) {
-                return i + 1;
-            }
+  }
+
+  /**
+   * Find the next free int (starting from 0) to use as key in TieDict.
+   * @returns {number}
+   */
+  private getNextAvailableNumberForTie(): number {
+    let keys: string[] = Object.keys(this.openTieDict);
+    if (keys.length === 0) {
+      return 1;
+    }
+    keys.sort((a, b) => (+a - +b)); // FIXME Andrea: test
+    for (let i: number = 0; i < keys.length; i++) {
+      if ("" + (i + 1) !== keys[i]) {
+        return i + 1;
+      }
+    }
+    return +(keys[keys.length - 1]) + 1;
+  }
+
+  /**
+   * Search the tieDictionary for the corresponding candidateNote to the currentNote (same FundamentalNote && Octave).
+   * @param candidateNote
+   * @returns {number}
+   */
+  private findCurrentNoteInTieDict(candidateNote: Note): number {
+    let openTieDict: { [_: number]: Tie; } = this.openTieDict;
+    for (let key in openTieDict) {
+      if (openTieDict.hasOwnProperty(key)) {
+        let tie: Tie = openTieDict[key];
+        if (tie.Start.Pitch.FundamentalNote === candidateNote.Pitch.FundamentalNote && tie.Start.Pitch.Octave === candidateNote.Pitch.Octave) {
+          return +key;
         }
-        return +(keys[keys.length - 1]) + 1;
+      }
     }
-
-    /**
-     * Search the tieDictionary for the corresponding candidateNote to the currentNote (same FundamentalNote && Octave).
-     * @param candidateNote
-     * @returns {number}
-     */
-    private findCurrentNoteInTieDict(candidateNote: Note): number {
-        let openTieDict: { [_: number]: Tie; } = this.openTieDict;
-        for (let key in openTieDict) {
-            if (openTieDict.hasOwnProperty(key)) {
-                let tie: Tie = openTieDict[key];
-                if (tie.Start.Pitch.FundamentalNote === candidateNote.Pitch.FundamentalNote && tie.Start.Pitch.Octave === candidateNote.Pitch.Octave) {
-                    return +key;
-                }
-            }
+    return -1;
+  }
+
+  /**
+   * Calculate the normal duration of a [[Tuplet]] note.
+   * @param xmlNode
+   * @returns {any}
+   */
+  private getTupletNoteDurationFromType(xmlNode: IXmlElement): Fraction {
+    if (xmlNode.element("type") !== undefined) {
+      let typeNode: IXmlElement = xmlNode.element("type");
+      if (typeNode !== undefined) {
+        let type: string = typeNode.value;
+        try {
+          return this.getNoteDurationFromType(type);
+        } catch (e) {
+          let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/NoteDurationError", "Invalid note duration.");
+          this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+          throw new MusicSheetReadingException("", e);
         }
-        return -1;
-    }
-
-    /**
-     * Calculate the normal duration of a [[Tuplet]] note.
-     * @param xmlNode
-     * @returns {any}
-     */
-    private getTupletNoteDurationFromType(xmlNode: IXmlElement): Fraction {
-        if (xmlNode.element("type") !== undefined) {
-            let typeNode: IXmlElement = xmlNode.element("type");
-            if (typeNode !== undefined) {
-                let type: string = typeNode.value;
-                try {
-                    return this.getNoteDurationFromType(type);
-                } catch (e) {
-                    let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/NoteDurationError", "Invalid note duration.");
-                    this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-                    throw new MusicSheetReadingException("", e);
-                }
 
-            }
-        }
-        return undefined;
+      }
     }
+    return undefined;
+  }
 }

+ 7 - 7
src/OSMD/OSMD.ts

@@ -170,23 +170,23 @@ export class OSMD {
     public setLogLevel(level: string): void {
         switch (level) {
             case "trace":
-                log.setLevel(log.levels.WARN);
+                log.setLevel(LogLevel.TRACE);
                 break;
             case "debug":
-                log.setLevel(log.levels.DEBUG);
+                log.setLevel(LogLevel.DEBUG);
                 break;
             case "info":
-                log.setLevel(log.levels.INFO);
+                log.setLevel(LogLevel.INFO);
                 break;
             case "warn":
-                log.setLevel(log.levels.WARN);
+                log.setLevel(LogLevel.WARN);
                 break;
             case "error":
-                log.setLevel(log.levels.ERROR);
+                log.setLevel(LogLevel.ERROR);
                 break;
             default:
                 log.warn(`Could not set log level to ${level}. Using warn instead.`);
-                log.setLevel(log.levels.WARN);
+                log.setLevel(LogLevel.WARN);
                 break;
         }
     }
@@ -243,7 +243,7 @@ export class OSMD {
             timeout = undefined;
             window.clearTimeout(timeout);
             if ((new Date()).getTime() - rtime < delta) {
-                timeout = window.setTimeout(resizeEnd, delta);
+                timeout = window.setTimeout(this.resizeEnd, delta);
             } else {
                 endCallback();
             }