Sfoglia il codice sorgente

Back merge from opensheetmusicdisplay

Benjamin Giesinger 8 anni fa
parent
commit
d7b664a3d0

+ 3 - 5
package.json

@@ -56,11 +56,11 @@
     "vexflow": "^1.2.53"
   },
   "devDependencies": {
-    "@types/chai": "^3.4.35",
+    "@types/chai": "^4.0.3",
     "@types/loglevel": "^1.4.29",
     "@types/mocha": "^2.2.40",
     "browserify": "^14.0.0",
-    "chai": "^3.5.0",
+    "chai": "^4.1.0",
     "cz-conventional-changelog": "^2.0.0",
     "grunt": "^1.0.1",
     "grunt-browserify": "^5.0.0",
@@ -91,9 +91,7 @@
     "tsify": "^3.0.0",
     "tslint": "^5.0.0",
     "typedoc": "^0.7.0",
-    "typescript": "^2.2.2",
-    "uglifyjs-webpack-plugin": "^0.4.3",
-    "webpack": "^2.5.1"
+    "typescript": "^2.2.2"
   },
   "config": {
     "commitizen": {

+ 378 - 338
src/Common/DataObjects/Fraction.ts

@@ -5,379 +5,419 @@
  * A class representing mathematical fractions, which have a numerator and a denominator.
  */
 export class Fraction {
-    private static maximumAllowedNumber: number = 46340;
-    private numerator: number = 0;
-    private denominator: number = 1;
-    private realValue: number;
-
-    /**
-     * Returns the maximum of two fractions (does not clone)
-     * @param f1
-     * @param f2
-     * @returns {Fraction}
-     */
-    public static max(f1: Fraction, f2: Fraction): Fraction {
-        if (f1.RealValue > f2.RealValue) {
-            return f1;
-        } else {
-            return f2;
-        }
+  private static maximumAllowedNumber: number = 46340; // sqrt(int.Max) --> signed int with 4 bytes (2^31)
+  private numerator: number = 0;
+  private denominator: number = 1;
+  private wholeValue: number = 0;
+  private realValue: number;
+
+  /**
+   * Returns the maximum of two fractions (does not clone)
+   * @param f1
+   * @param f2
+   * @returns {Fraction}
+   */
+  public static max(f1: Fraction, f2: Fraction): Fraction {
+    if (f1.RealValue > f2.RealValue) {
+      return f1;
+    } else {
+      return f2;
     }
-
-    public static Equal(f1: Fraction, f2: Fraction): boolean {
-        return f1.Denominator === f2.Denominator && f1.Numerator === f2.Numerator;
+  }
+
+  public static Equal(f1: Fraction, f2: Fraction): boolean {
+    return f1.wholeValue === f2.wholeValue && f1.Denominator === f2.Denominator && f1.Numerator === f2.Numerator;
+  }
+
+  /**
+   * The same as Fraction.clone
+   * @param fraction
+   * @returns {Fraction}
+   */
+  public static createFromFraction(fraction: Fraction): Fraction {
+    return new Fraction(fraction.numerator, fraction.denominator, fraction.wholeValue, false);
+  }
+
+  public static plus(f1: Fraction, f2: Fraction): Fraction {
+    let sum: Fraction = f1.clone();
+    sum.Add(f2);
+    return sum;
+  }
+
+  public static minus(f1: Fraction, f2: Fraction): Fraction {
+    let sum: Fraction = f1.clone();
+    sum.Sub(f2);
+    return sum;
+  }
+
+  private static greatestCommonDenominator(a: number, b: number): number {
+    if (a === 0) {
+      return b;
     }
 
-    /**
-     * The same as Fraction.clone
-     * @param fraction
-     * @returns {Fraction}
-     */
-    public static createFromFraction(fraction: Fraction): Fraction {
-        return new Fraction(fraction.numerator, fraction.denominator);
+    if (b === 1) {
+      return 1;
     }
 
-    public static plus (f1: Fraction, f2: Fraction): Fraction {
-        let sum: Fraction = f1.clone();
-        sum.Add(f2);
-        return sum;
+    while (b !== 0) {
+      if (a > b) {
+        a -= b;
+      } else {
+        b -= a;
+      }
     }
 
-    public static minus(f1: Fraction , f2: Fraction): Fraction {
-        let sum: Fraction = f1.clone();
-        sum.Sub(f2);
-        return sum;
+    return a;
+  }
+
+  /**
+   *
+   * @param numerator
+   * @param denominator
+   * @param wholeValue - the integer number, needed for values greater than 1
+   * @param simplify - If simplify is true, then the fraction is simplified
+   *      to make both the numerator and denominator coprime, and less than maximumAllowedNumber.
+   */
+  constructor(numerator: number = 0, denominator: number = 1, wholeValue: number = 0, simplify: boolean = true) {
+    this.numerator = numerator;
+    this.denominator = denominator;
+    this.wholeValue = wholeValue;
+
+    if (simplify) {
+      this.simplify();
     }
+    this.setRealValue();
+  }
 
-    private static greatestCommonDenominator(a: number, b: number): number {
-        if (a === 0) {
-            return b;
-        }
-
-        if (b === 1) {
-            return 1;
-        }
-
-        while (b !== 0) {
-            if (a > b) {
-                a -= b;
-            } else {
-                b -= a;
-            }
-        }
-
-        return a;
+  public toString(): string {
+    let result: string = this.numerator + "/" + this.denominator;
+    if (this.wholeValue !== 0) {
+      result = this.wholeValue + " " + result;
     }
 
-    /**
-     *
-     * @param numerator
-     * @param denominator
-     * @param simplify - If simplify is true, then the fraction is simplified
-     *      to make both the numerator and denominator coprime, and less than maximumAllowedNumber.
-     */
-    constructor(numerator: number = 0, denominator: number = 1, simplify: boolean = true) {
-        this.numerator = numerator;
-        this.denominator = denominator;
-
-        if (simplify) { this.simplify(); }
-        this.setRealValue();
-    }
+    return result;
+  }
 
-    public toString(): string {
-        return this.numerator + "/" + this.denominator;
-    }
+  public clone(): Fraction {
+    return new Fraction(this.numerator, this.denominator, this.wholeValue, false);
+  }
 
-    public clone(): Fraction {
-        return new Fraction(this.numerator, this.denominator, false);
-    }
+  public get Numerator(): number {
+    return this.numerator;
+  }
 
-    public get Numerator(): number {
-        return this.numerator;
+  public set Numerator(value: number) {
+    if (this.numerator !== value) {
+      this.numerator = value;
+      this.simplify();
+      this.setRealValue();
     }
+  }
 
-    public set Numerator(value: number) {
-        if (this.numerator !== value) {
-            this.numerator = value;
-            this.simplify();
-            this.setRealValue();
-        }
-    }
+  public get Denominator(): number {
+    return this.denominator;
+  }
 
-    public get Denominator(): number {
-        return this.denominator;
+  public set Denominator(value: number) {
+    if (this.denominator !== value) {
+      this.denominator = value;
+      if (this.numerator !== 0) {
+        this.simplify();
+      }
+      this.setRealValue();
     }
+  }
 
-    public set Denominator(value: number) {
-        if (this.denominator !== value) {
-            this.denominator = value;
-            if (this.numerator !== 0) {
-                this.simplify();
-            }
-            this.setRealValue();
-        }
-    }
+  public get WholeValue(): number {
+    return this.wholeValue;
+  }
 
-    public get RealValue(): number {
-        return this.realValue;
+  public set WholeValue(value: number) {
+    if (this.wholeValue !== value) {
+      this.wholeValue = value;
+      this.setRealValue();
     }
-
-    public multiplyWithFactor(factor: number): void {
-        this.numerator *= factor;
-        this.denominator *= factor;
+  }
+
+  public GetExpandedNumerator(): number {
+    return this.wholeValue * this.denominator + this.numerator;
+  }
+
+  public IsNegative(): boolean {
+    return this.realValue < 0;
+  }
+
+  public get RealValue(): number {
+    return this.realValue;
+  }
+
+  public expand(expansionValue: number): void {
+    this.numerator *= expansionValue;
+    this.denominator *= expansionValue;
+    if (this.wholeValue !== 0) {
+      this.numerator += this.wholeValue * this.denominator;
+      this.wholeValue = 0;
     }
-
-    public multiplyDenominatorWithFactor(factor: number): void {
-        this.denominator *= factor;
-        this.setRealValue();
+  }
+
+  // public multiplyDenominatorWithFactor(factor: number): void {
+  //   this.denominator *= factor;
+  //   this.setRealValue();
+  // }
+
+  public Add(fraction: Fraction): void {
+    this.numerator = (this.wholeValue * this.denominator + this.numerator) * fraction.denominator +
+      (fraction.wholeValue * fraction.denominator + fraction.numerator) * this.denominator;
+    this.denominator = this.denominator * fraction.denominator;
+    this.wholeValue = 0;
+    this.simplify();
+    this.setRealValue();
+  }
+
+  public Sub(fraction: Fraction): void {
+    this.numerator = (this.wholeValue * this.denominator + this.numerator) * fraction.denominator -
+      (fraction.wholeValue * fraction.denominator + fraction.numerator) * this.denominator;
+    this.denominator = this.denominator * fraction.denominator;
+    this.wholeValue = 0;
+    this.simplify();
+    this.setRealValue();
+  }
+
+  public Quantize(maxAllowedDenominator: number): Fraction {
+    if (this.denominator <= maxAllowedDenominator) {
+      return this;
     }
 
-    public Add(fraction: Fraction): void {
-        this.numerator = this.numerator * fraction.denominator + fraction.numerator * this.denominator;
-        this.denominator = this.denominator * fraction.denominator;
-        this.simplify();
-        this.setRealValue();
+    let upTestFraction: Fraction = new Fraction(this.numerator + 1, this.denominator, this.wholeValue);
 
+    while (upTestFraction.Denominator > maxAllowedDenominator) {
+      upTestFraction.Numerator++;
     }
 
-    public Sub(fraction: Fraction): void {
-        this.numerator = this.numerator * fraction.denominator - fraction.numerator * this.denominator;
-        this.denominator = this.denominator * fraction.denominator;
-        this.simplify();
-        this.setRealValue();
-    }
+    if (this.numerator > this.denominator) {
+      let downTestFraction: Fraction = new Fraction(this.numerator - 1, this.denominator, this.wholeValue);
 
-    public Quantize(maxAllowedDenominator: number): Fraction {
-        if (this.denominator <= maxAllowedDenominator) {
-            return this;
-        }
+      while (downTestFraction.Denominator > maxAllowedDenominator) {
+        downTestFraction.Numerator--;
+      }
 
-        let upTestFraction: Fraction = new Fraction(this.numerator + 1, this.denominator);
-
-        while (upTestFraction.Denominator > maxAllowedDenominator) {
-            upTestFraction.Numerator++;
-        }
-
-        if (this.numerator > this.denominator) {
-            let downTestFraction: Fraction = new Fraction(this.numerator - 1, this.denominator);
-
-            while (downTestFraction.Denominator > maxAllowedDenominator) {
-                downTestFraction.Numerator--;
-            }
-
-            if (downTestFraction.Denominator < upTestFraction.Denominator) {
-                return downTestFraction;
-            }
-        }
-        return upTestFraction;
+      if (downTestFraction.Denominator < upTestFraction.Denominator) {
+        return downTestFraction;
+      }
     }
-
-    public Equals(obj: Fraction): boolean {
-        return this.RealValue === obj.RealValue;
-    }
-
-    public CompareTo(obj: Fraction): number {
-        let diff: number = this.numerator * obj.Denominator - this.denominator * obj.Numerator;
-        // Return the sign of diff
-        return diff ? diff < 0 ? -1 : 1 : 0;
+    return upTestFraction;
+  }
+
+  public Equals(obj: Fraction): boolean {
+    return this.realValue === obj.realValue;
+  }
+
+  public CompareTo(obj: Fraction): number {
+    let diff: number = this.realValue - obj.realValue;
+    // Return the sign of diff
+    return diff ? diff < 0 ? -1 : 1 : 0;
+  }
+
+  public lt(frac: Fraction): boolean {
+    return this.realValue < frac.realValue;
+  }
+
+  public lte(frac: Fraction): boolean {
+    return this.realValue <= frac.realValue;
+  }
+
+  //public Equals(f: Fraction): boolean {
+  //    if (ReferenceEquals(this, f))
+  //        return true;
+  //    if (ReferenceEquals(f, undefined))
+  //        return false;
+  //    return <number>this.numerator * f.denominator === <number>f.numerator * this.denominator;
+  //}
+
+  private setRealValue(): void {
+    this.realValue = this.wholeValue + this.numerator / this.denominator;
+  }
+
+  private simplify(): void {
+    if (this.numerator === 0) {
+      this.denominator = 1;
+      return;
     }
 
-    public lt(frac: Fraction): boolean {
-        return (this.numerator * frac.Denominator - this.denominator * frac.Numerator) < 0;
-    }
-    public lte(frac: Fraction): boolean {
-        return (this.numerator * frac.Denominator - this.denominator * frac.Numerator) <= 0;
-    }
+    let i: number = Fraction.greatestCommonDenominator(Math.abs(this.numerator), Math.abs(this.denominator));
 
-    //public Equals(f: Fraction): boolean {
-    //    if (ReferenceEquals(this, f))
-    //        return true;
-    //    if (ReferenceEquals(f, undefined))
-    //        return false;
-    //    return <number>this.numerator * f.denominator === <number>f.numerator * this.denominator;
-    //}
+    this.numerator /= i;
+    this.denominator /= i;
 
-    public GetInversion(): Fraction {
-        return new Fraction(this.denominator, this.numerator);
+    let whole: number = Math.floor(this.numerator / this.denominator);
+    if (whole !== 0) {
+      this.wholeValue += whole;
+      this.numerator -= whole * this.denominator;
+      if (this.numerator === 0) {
+        this.denominator = 1;
+      }
     }
-
-    private setRealValue(): void {
-        this.realValue = this.numerator / this.denominator;
+    if (this.denominator > Fraction.maximumAllowedNumber) {
+      let factor: number = <number>this.denominator / Fraction.maximumAllowedNumber;
+      this.numerator = <number>Math.round(this.numerator / factor);
+      this.denominator = <number>Math.round(this.denominator / factor);
     }
-
-    private simplify(): void {
-        if (this.numerator === 0) {
-            this.denominator = 1;
-            return;
-        }
-
-        let i: number = Fraction.greatestCommonDenominator(Math.abs(this.numerator), Math.abs(this.denominator));
-
-        this.numerator /= i;
-        this.denominator /= i;
-
-        if (this.denominator > Fraction.maximumAllowedNumber) {
-            let factor: number = this.denominator / Fraction.maximumAllowedNumber;
-            this.numerator = Math.round(this.numerator / factor);
-            this.denominator = Math.round(this.denominator / factor);
-        }
-        if (this.numerator > Fraction.maximumAllowedNumber) {
-            let factor: number = this.numerator / Fraction.maximumAllowedNumber;
-            this.numerator = Math.round(this.numerator / factor);
-            this.denominator = Math.round(this.denominator / factor);
-        }
+    if (this.numerator > Fraction.maximumAllowedNumber) {
+      let factor: number = <number>this.numerator / Fraction.maximumAllowedNumber;
+      this.numerator = <number>Math.round(this.numerator / factor);
+      this.denominator = <number>Math.round(this.denominator / factor);
     }
-
-
-
-    //private static equals(f1: Fraction, f2: Fraction): boolean {
-    //    return <number>f1.numerator * f2.denominator === <number>f2.numerator * f1.denominator;
-    //}
-    //
-    //public static ApproximateFractionFromValue(value: number, epsilonForPrecision: number): Fraction {
-    //    let n: number = 1;
-    //    let d: number = 1;
-    //    let fraction: number = n / d;
-    //    while (Math.abs(fraction - value) > epsilonForPrecision) {
-    //        if (fraction < value) {
-    //            n++;
-    //        }
-    //        else {
-    //            d++;
-    //            n = <number>Math.round(value * d);
-    //        }
-    //        fraction = n / <number>d;
-    //    }
-    //    return new Fraction(n, d);
-    //}
-    //public static GetEarlierTimestamp(m1: Fraction, m2: Fraction): Fraction {
-    //    if (m1 < m2)
-    //        return m1;
-    //    else return m2;
-    //}
-
-    //public static getFraction(value: number, denominatorPrecision: number): Fraction {
-    //    let numerator: number = <number>Math.round(value / (1.0 / denominatorPrecision));
-    //    return new Fraction(numerator, denominatorPrecision);
-    //}
-    //public static fractionMin(f1: Fraction, f2: Fraction): Fraction {
-    //    if (f1 < f2)
-    //        return f1;
-    //    else return f2;
-    //}
-
-    //public static GetMaxValue(): Fraction {
-    //    return new Fraction(Fraction.maximumAllowedNumber, 1);
-    //}
-    //public static get MaxAllowedNumerator(): number {
-    //    return Fraction.maximumAllowedNumber;
-    //}
-    //public static get MaxAllowedDenominator(): number {
-    //    return Fraction.maximumAllowedNumber;
-    //}
-    //public ToFloatingString(): string {
-    //    return this.RealValue.ToString();
-    //}
-    //public Compare(x: Fraction, y: Fraction): number {
-    //    if (x > y)
-    //        return 1;
-    //    if (x < y)
-    //        return -1;
-    //    return 0;
-    //}
-
-    //#region operators
-    //
-    //    // operator overloads must always come in pairs
-    //    // operator overload +
-    //    public static Fraction operator + (Fraction f1, Fraction f2)
-    //{
-    //    Fraction sum = new Fraction(f1);
-    //    sum.Add(f2);
-    //    return sum;
-    //}
-    //
-    //// operator overload -
-    //public static Fraction operator - (Fraction f1, Fraction f2)
-    //{
-    //    Fraction diff = new Fraction(f1);
-    //    diff.Sub(f2);
-    //    return diff;
-    //}
-    //
-    //// operator overloads must always come in pairs
-    //// operator overload >
-    //public static bool operator > (Fraction f1, Fraction f2)
-    //{
-    //    //return (long) f1.Numerator*f2._denominator > (long) f2._numerator*f1._denominator;
-    //    return f1.RealValue > f2.RealValue;
-    //}
-    //
-    //// operator overload <
-    //public static bool operator < (Fraction f1, Fraction f2)
-    //{
-    //    //return (long) f1._numerator*f2._denominator < (long) f2._numerator*f1._denominator;
-    //    return f1.RealValue < f2.RealValue;
-    //}
-    //
-    //// operator overload ==
-    //public static bool operator === (Fraction f1, Fraction f2)
-    //{
-    //    // code enhanced for performance
-    //    // System.Object.ReferenceEquals(f1, undefined) is better than if (f1 === undefined)
-    //    // and comparisons between booleans are quick
-    //    bool f1IsNull = System.Object.ReferenceEquals(f1, undefined);
-    //    bool f2IsNull = System.Object.ReferenceEquals(f2, undefined);
-    //
-    //    // method returns true when both are undefined, false when only the first is undefined, otherwise the result of equals
-    //    if (f1IsNull !== f2IsNull)
-    //        return false;
-    //
-    //    if (f1IsNull /*&& f2IsNull*/)
-    //        return true;
-    //
-    //    return equals(f1, f2);
-    //}
-    //
-    //// operator overload !=
-    //public static bool operator !== (Fraction f1, Fraction f2)
-    //{
-    //    return (!(f1 === f2));
-    //}
-    //
-    //// operator overload >=
-    //public static bool operator >= (Fraction f1, Fraction f2)
-    //{
-    //    return (!(f1 < f2));
-    //}
-    //
-    //// operator overload <=
-    //public static bool operator <= (Fraction f1,Fraction f2)
-    //{
-    //    return (!(f1 > f2));
-    //}
-    //
-    //public static Fraction operator / (Fraction f, int i)
-    //{
-    //    return new Fraction(f._numerator, f._denominator *= i);
-    //}
-    //
-    //public static Fraction operator / (Fraction f1, Fraction f2)
-    //{
-    //    let res = new Fraction(f1.Numerator*f2.Denominator, f1.Denominator*f2.Numerator);
-    //    return res.Denominator === 0 ? new Fraction(0, 1) : res;
-    //}
-    //
-    //public static Fraction operator * (Fraction f1, Fraction f2)
-    //{
-    //    return new Fraction(f1.Numerator*f2.Numerator, f1.Denominator*f2.Denominator);
-    //}
-    //
-    //public static Fraction operator % (Fraction f1, Fraction f2)
-    //{
-    //    let a = f1/f2;
-    //    return new Fraction(a.Numerator%a.Denominator, a.Denominator)*f2;
-    //}
-    //
-    //#endregion operators
+  }
+
+
+  //private static equals(f1: Fraction, f2: Fraction): boolean {
+  //    return <number>f1.numerator * f2.denominator === <number>f2.numerator * f1.denominator;
+  //}
+  //
+  //public static ApproximateFractionFromValue(value: number, epsilonForPrecision: number): Fraction {
+  //    let n: number = 1;
+  //    let d: number = 1;
+  //    let fraction: number = n / d;
+  //    while (Math.abs(fraction - value) > epsilonForPrecision) {
+  //        if (fraction < value) {
+  //            n++;
+  //        }
+  //        else {
+  //            d++;
+  //            n = <number>Math.round(value * d);
+  //        }
+  //        fraction = n / <number>d;
+  //    }
+  //    return new Fraction(n, d);
+  //}
+  //public static GetEarlierTimestamp(m1: Fraction, m2: Fraction): Fraction {
+  //    if (m1 < m2)
+  //        return m1;
+  //    else return m2;
+  //}
+
+  //public static getFraction(value: number, denominatorPrecision: number): Fraction {
+  //    let numerator: number = <number>Math.round(value / (1.0 / denominatorPrecision));
+  //    return new Fraction(numerator, denominatorPrecision);
+  //}
+  //public static fractionMin(f1: Fraction, f2: Fraction): Fraction {
+  //    if (f1 < f2)
+  //        return f1;
+  //    else return f2;
+  //}
+
+  //public static GetMaxValue(): Fraction {
+  //    return new Fraction(Fraction.maximumAllowedNumber, 1);
+  //}
+  //public static get MaxAllowedNumerator(): number {
+  //    return Fraction.maximumAllowedNumber;
+  //}
+  //public static get MaxAllowedDenominator(): number {
+  //    return Fraction.maximumAllowedNumber;
+  //}
+  //public ToFloatingString(): string {
+  //    return this.RealValue.ToString();
+  //}
+  //public Compare(x: Fraction, y: Fraction): number {
+  //    if (x > y)
+  //        return 1;
+  //    if (x < y)
+  //        return -1;
+  //    return 0;
+  //}
+
+  //#region operators
+  //
+  //    // operator overloads must always come in pairs
+  //    // operator overload +
+  //    public static Fraction operator + (Fraction f1, Fraction f2)
+  //{
+  //    Fraction sum = new Fraction(f1);
+  //    sum.Add(f2);
+  //    return sum;
+  //}
+  //
+  //// operator overload -
+  //public static Fraction operator - (Fraction f1, Fraction f2)
+  //{
+  //    Fraction diff = new Fraction(f1);
+  //    diff.Sub(f2);
+  //    return diff;
+  //}
+  //
+  //// operator overloads must always come in pairs
+  //// operator overload >
+  //public static bool operator > (Fraction f1, Fraction f2)
+  //{
+  //    //return (long) f1.Numerator*f2._denominator > (long) f2._numerator*f1._denominator;
+  //    return f1.RealValue > f2.RealValue;
+  //}
+  //
+  //// operator overload <
+  //public static bool operator < (Fraction f1, Fraction f2)
+  //{
+  //    //return (long) f1._numerator*f2._denominator < (long) f2._numerator*f1._denominator;
+  //    return f1.RealValue < f2.RealValue;
+  //}
+  //
+  //// operator overload ==
+  //public static bool operator === (Fraction f1, Fraction f2)
+  //{
+  //    // code enhanced for performance
+  //    // System.Object.ReferenceEquals(f1, undefined) is better than if (f1 === undefined)
+  //    // and comparisons between booleans are quick
+  //    bool f1IsNull = System.Object.ReferenceEquals(f1, undefined);
+  //    bool f2IsNull = System.Object.ReferenceEquals(f2, undefined);
+  //
+  //    // method returns true when both are undefined, false when only the first is undefined, otherwise the result of equals
+  //    if (f1IsNull !== f2IsNull)
+  //        return false;
+  //
+  //    if (f1IsNull /*&& f2IsNull*/)
+  //        return true;
+  //
+  //    return equals(f1, f2);
+  //}
+  //
+  //// operator overload !=
+  //public static bool operator !== (Fraction f1, Fraction f2)
+  //{
+  //    return (!(f1 === f2));
+  //}
+  //
+  //// operator overload >=
+  //public static bool operator >= (Fraction f1, Fraction f2)
+  //{
+  //    return (!(f1 < f2));
+  //}
+  //
+  //// operator overload <=
+  //public static bool operator <= (Fraction f1,Fraction f2)
+  //{
+  //    return (!(f1 > f2));
+  //}
+  //
+  //public static Fraction operator / (Fraction f, int i)
+  //{
+  //    return new Fraction(f._numerator, f._denominator *= i);
+  //}
+  //
+  //public static Fraction operator / (Fraction f1, Fraction f2)
+  //{
+  //    let res = new Fraction(f1.Numerator*f2.Denominator, f1.Denominator*f2.Numerator);
+  //    return res.Denominator === 0 ? new Fraction(0, 1) : res;
+  //}
+  //
+  //public static Fraction operator * (Fraction f1, Fraction f2)
+  //{
+  //    return new Fraction(f1.Numerator*f2.Numerator, f1.Denominator*f2.Denominator);
+  //}
+  //
+  //public static Fraction operator % (Fraction f1, Fraction f2)
+  //{
+  //    let a = f1/f2;
+  //    return new Fraction(a.Numerator%a.Denominator, a.Denominator)*f2;
+  //}
+  //
+  //#endregion operators
 }

+ 28 - 3
src/MusicalScore/Graphical/BoundingBox.ts

@@ -14,9 +14,9 @@ export class BoundingBox {
     protected absolutePosition: PointF2D = new PointF2D();
     protected relativePosition: PointF2D = new PointF2D();
     protected size: SizeF2D = new SizeF2D();
-    protected marginSize: SizeF2D;
-    protected upperLeftCorner: PointF2D;
-    protected upperLeftMarginCorner: PointF2D;
+    protected marginSize: SizeF2D = new SizeF2D();
+    protected upperLeftCorner: PointF2D = new PointF2D();
+    protected upperLeftMarginCorner: PointF2D = new PointF2D();
     protected borderLeft: number = 0;
     protected borderRight: number = 0;
     protected borderTop: number = 0;
@@ -205,6 +205,20 @@ export class BoundingBox {
     }
 
     /**
+     * Calculate the the absolute position by adding up all relative positions of all parents (including the own rel. pos.)
+     */
+    public calculateAbsolutePosition(): void {
+      this.absolutePosition.x = this.relativePosition.x;
+      this.absolutePosition.y = this.relativePosition.y;
+      let parent: BoundingBox = this.parent;
+      while (parent !== undefined) {
+        this.absolutePosition.x += parent.relativePosition.x;
+        this.absolutePosition.y += parent.relativePosition.y;
+        parent = parent.parent;
+      }
+    }
+
+    /**
      * This method calculates the Absolute Positions recursively
      */
     public calculateAbsolutePositionsRecursiveWithoutTopelement(): void {
@@ -218,6 +232,7 @@ export class BoundingBox {
 
     /**
      * This method calculates the Absolute Positions recursively
+     * from the root element down to the leaf elements
      * @param x
      * @param y
      */
@@ -231,6 +246,16 @@ export class BoundingBox {
     }
 
     /**
+     * calculates the absolute positions of all children of this boundingBox
+     */
+    public calculateAbsolutePositionsOfChildren(): void {
+      for (let idx: number = 0, len: number = this.ChildElements.length; idx < len; ++idx) {
+        let child: BoundingBox = this.ChildElements[idx];
+        child.calculateAbsolutePositionsRecursive(this.absolutePosition.x, this.absolutePosition.y);
+      }
+    }
+
+    /**
      * This method calculates the BoundingBoxes
      */
     public calculateBoundingBox(): void {

+ 3 - 0
src/MusicalScore/Graphical/EngravingRules.ts

@@ -442,6 +442,9 @@ export class EngravingRules {
     public get SystemLabelsRightMargin(): number {
         return this.systemLabelsRightMargin;
     }
+    public set SystemLabelsRightMargin(value: number) {
+        this.systemLabelsRightMargin = value;
+    }
     public get MinimumAllowedDistanceBetweenSystems(): number {
         return this.minimumAllowedDistanceBetweenSystems;
     }

+ 9 - 4
src/MusicalScore/Graphical/GraphicalNote.ts

@@ -60,10 +60,15 @@ export class GraphicalNote extends GraphicalObject {
      * @returns {number}
      */
     private calculateNumberOfNeededDots(fraction: Fraction): number {
-        let dotCount: number = 0;
-        if (this.sourceNote === undefined || this.sourceNote.NoteTuplet === undefined) {
-            dotCount = Math.floor(Math.log(fraction.Numerator) / Math.LN2);
+      let num: number = 1;
+      let product: number = 2;
+      let expandedNumerator: number = fraction.GetExpandedNumerator();
+      if (this.sourceNote === undefined || this.sourceNote.NoteTuplet === undefined) {
+        while (product < expandedNumerator) {
+          num++;
+          product = <number>Math.pow(2, num);
         }
-        return Math.min(3, dotCount);
+      }
+      return Math.min(3, num - 1);
     }
 }

+ 2 - 2
src/MusicalScore/Graphical/GraphicalStaffEntry.ts

@@ -253,7 +253,7 @@ export abstract class GraphicalStaffEntry extends GraphicalObject {
             for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
                 let graphicalNote: GraphicalNote = graphicalNotes[idx2];
                 let calNoteLen: Fraction = graphicalNote.graphicalNoteLength;
-                if (calNoteLen.lt(minLength) && calNoteLen.Numerator > 0) {
+                if (calNoteLen.lt(minLength) && calNoteLen.GetExpandedNumerator() > 0) {
                     minLength = calNoteLen;
                 }
             }
@@ -268,7 +268,7 @@ export abstract class GraphicalStaffEntry extends GraphicalObject {
             for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
                 let graphicalNote: GraphicalNote = graphicalNotes[idx2];
                 let calNoteLen: Fraction = graphicalNote.graphicalNoteLength;
-                if (maxLength.lt(calNoteLen)  && calNoteLen.Numerator > 0) {
+                if (maxLength.lt(calNoteLen)  && calNoteLen.GetExpandedNumerator() > 0) {
                     maxLength = calNoteLen;
                 }
             }

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

@@ -19,6 +19,9 @@ 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";
+import {GraphicalLabel} from "../GraphicalLabel";
+import {EngravingRules} from "../EngravingRules";
 
 export class VexFlowGraphicalSymbolFactory implements IGraphicalSymbolFactory {
     /**
@@ -172,6 +175,15 @@ export class VexFlowGraphicalSymbolFactory implements IGraphicalSymbolFactory {
      * @param transposeHalftones
      */
     public createChordSymbol(sourceStaffEntry: SourceStaffEntry, graphicalStaffEntry: GraphicalStaffEntry, transposeHalftones: number): void {
-        return;
+      let graphicalChordSymbolContainer: GraphicalChordSymbolContainer =
+        new GraphicalChordSymbolContainer(sourceStaffEntry.ChordContainer,
+                                          graphicalStaffEntry.PositionAndShape,
+                                          EngravingRules.Rules.ChordSymbolTextHeight,
+                                          transposeHalftones);
+      let graphicalLabel: GraphicalLabel = graphicalChordSymbolContainer.GetGraphicalLabel;
+      graphicalLabel.setLabelPositionAndShapeBorders();
+      graphicalChordSymbolContainer.PositionAndShape.calculateBoundingBox();
+      graphicalStaffEntry.graphicalChordContainer = graphicalChordSymbolContainer;
+      graphicalStaffEntry.PositionAndShape.ChildElements.push(graphicalChordSymbolContainer.PositionAndShape);
     }
 }

+ 6 - 1
src/MusicalScore/Graphical/VexFlow/VexFlowMeasure.ts

@@ -297,7 +297,10 @@ export class VexFlowMeasure extends StaffMeasure {
                 for (let beam of this.beams[voiceID]) {
                     let notes: Vex.Flow.StaveNote[] = [];
                     for (let entry of beam[1]) {
-                        notes.push((<VexFlowStaffEntry>entry).vfNotes[voiceID]);
+                        let note: Vex.Flow.StaveNote = (<VexFlowStaffEntry>entry).vfNotes[voiceID];
+                        if (note !== undefined) {
+                          notes.push(note);
+                        }
                     }
                     if (notes.length > 1) {
                         vfbeams.push(new Vex.Flow.Beam(notes, true));
@@ -444,6 +447,8 @@ export class VexFlowMeasure extends StaffMeasure {
                 measure.ParentStaffLine.PositionAndShape.RelativePosition.x -
                 measure.parentMusicSystem.PositionAndShape.RelativePosition.x;
             gse.PositionAndShape.RelativePosition.x = x;
+            gse.PositionAndShape.calculateAbsolutePosition();
+            gse.PositionAndShape.calculateAbsolutePositionsOfChildren();
         }
     }
 }

+ 15 - 1
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer.ts

@@ -8,6 +8,8 @@ import {VexFlowConverter} from "./VexFlowConverter";
 import {VexFlowTextMeasurer} from "./VexFlowTextMeasurer";
 import {MusicSystem} from "../MusicSystem";
 import {GraphicalObject} from "../GraphicalObject";
+import {GraphicalLayers} from "../DrawingEnums";
+import {GraphicalStaffEntry} from "../GraphicalStaffEntry";
 
 /**
  * This is a global contant which denotes the height in pixels of the space between two lines of the stave
@@ -68,7 +70,19 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
             measure.PositionAndShape.AbsolutePosition.x * unitInPixels,
             measure.PositionAndShape.AbsolutePosition.y * unitInPixels
         );
-        return measure.draw(this.vfctx);
+        measure.draw(this.vfctx);
+
+        // Draw the StaffEntries
+        for (let staffEntry of measure.staffEntries){
+            this.drawStaffEntry(staffEntry);
+        }
+    }
+
+    private drawStaffEntry(staffEntry: GraphicalStaffEntry): void {
+        // Draw ChordSymbol
+        if (staffEntry.graphicalChordContainer !== undefined) {
+            this.drawLabel(staffEntry.graphicalChordContainer.GetGraphicalLabel, <number>GraphicalLayers.Notes);
+        }
     }
 
     protected drawInstrumentBrace(bracket: GraphicalObject, system: MusicSystem): void {

+ 1 - 1
src/MusicalScore/MusicSheet.ts

@@ -33,7 +33,7 @@ export class MusicSheet /*implements ISettableMusicSheet, IComparable<MusicSheet
         this.rules = EngravingRules.Rules;
         this.playbackSettings = new PlaybackSettings();
         // FIXME?
-        this.playbackSettings.rhythm = new Fraction(4, 4, false);
+        this.playbackSettings.rhythm = new Fraction(4, 4, 0, false);
         this.userStartTempoInBPM = 100;
         this.pageWidth = 120;
         this.MusicPartManager = new MusicPartManager(this);

+ 961 - 960
src/MusicalScore/ScoreIO/InstrumentReader.ts

@@ -19,6 +19,7 @@ import {IXmlAttribute} from "../../Common/FileIO/Xml";
 import {ChordSymbolContainer} from "../VoiceData/ChordSymbolContainer";
 import {Logging} from "../../Common/Logging";
 import {MidiInstrument} from "../VoiceData/Instructions/ClefInstruction";
+import {ChordSymbolReader} from "./MusicSymbolModules/ChordSymbolReader";
 //import Dictionary from "typescript-collections/dist/lib/Dictionary";
 
 // FIXME: The following classes are missing
@@ -54,1033 +55,1033 @@ export type RepetitionInstructionReader = any;
  */
 export class InstrumentReader {
 
-    constructor(repetitionInstructionReader: RepetitionInstructionReader, xmlMeasureList: IXmlElement[], instrument: Instrument) {
-        // (*) this.repetitionInstructionReader = repetitionInstructionReader;
-        this.xmlMeasureList = xmlMeasureList;
-        this.musicSheet = instrument.GetMusicSheet;
-        this.instrument = instrument;
-        this.activeClefs = new Array(instrument.Staves.length);
-        this.activeClefsHaveBeenInitialized = new Array(instrument.Staves.length);
-        for (let i: number = 0; i < instrument.Staves.length; i++) {
-            this.activeClefsHaveBeenInitialized[i] = false;
-        }
-        // FIXME createExpressionGenerators(instrument.Staves.length);
-        // (*) this.slurReader = MusicSymbolModuleFactory.createSlurReader(this.musicSheet);
-    }
-
-    // (*) private repetitionInstructionReader: RepetitionInstructionReader;
-    private xmlMeasureList: IXmlElement[];
-    private musicSheet: MusicSheet;
-    private slurReader: any; // (*) SlurReader;
-    private instrument: Instrument;
-    private voiceGeneratorsDict: { [n: number]: VoiceGenerator; } = {};
-    private staffMainVoiceGeneratorDict: { [staffId: number]: VoiceGenerator } = {};
-    private inSourceMeasureInstrumentIndex: number;
-    private divisions: number = 0;
-    private currentMeasure: SourceMeasure;
-    private previousMeasure: SourceMeasure;
-    private currentXmlMeasureIndex: number = 0;
-    private currentStaff: Staff;
-    private currentStaffEntry: SourceStaffEntry;
-    private activeClefs: ClefInstruction[];
-    private activeKey: KeyInstruction;
-    private activeRhythm: RhythmInstruction;
-    private activeClefsHaveBeenInitialized: boolean[];
-    private activeKeyHasBeenInitialized: boolean = false;
-    private abstractInstructions: [number, AbstractNotationInstruction][] = [];
-    private openChordSymbolContainer: ChordSymbolContainer;
-    // (*) private expressionReaders: ExpressionReader[];
-    private currentVoiceGenerator: VoiceGenerator;
-    //private openSlurDict: { [n: number]: Slur; } = {};
-    private maxTieNoteFraction: Fraction;
-
-    public get ActiveKey(): KeyInstruction {
-        return this.activeKey;
-    }
-
-    public get MaxTieNoteFraction(): Fraction {
-        return this.maxTieNoteFraction;
-    }
-
-    public get ActiveRhythm(): RhythmInstruction {
-        return this.activeRhythm;
-    }
+  constructor(repetitionInstructionReader: RepetitionInstructionReader, xmlMeasureList: IXmlElement[], instrument: Instrument) {
+      this.repetitionInstructionReader = repetitionInstructionReader;
+      this.xmlMeasureList = xmlMeasureList;
+      this.musicSheet = instrument.GetMusicSheet;
+      this.instrument = instrument;
+      this.activeClefs = new Array(instrument.Staves.length);
+      this.activeClefsHaveBeenInitialized = new Array(instrument.Staves.length);
+      for (let i: number = 0; i < instrument.Staves.length; i++) {
+        this.activeClefsHaveBeenInitialized[i] = false;
+      }
+      // FIXME createExpressionGenerators(instrument.Staves.length);
+      // (*) this.slurReader = MusicSymbolModuleFactory.createSlurReader(this.musicSheet);
+  }
 
-    public set ActiveRhythm(value: RhythmInstruction) {
-        this.activeRhythm = value;
-    }
+  private repetitionInstructionReader: RepetitionInstructionReader;
+  private xmlMeasureList: IXmlElement[];
+  private musicSheet: MusicSheet;
+  private slurReader: any; // (*) SlurReader;
+  private instrument: Instrument;
+  private voiceGeneratorsDict: { [n: number]: VoiceGenerator; } = {};
+  private staffMainVoiceGeneratorDict: { [staffId: number]: VoiceGenerator } = {};
+  private inSourceMeasureInstrumentIndex: number;
+  private divisions: number = 0;
+  private currentMeasure: SourceMeasure;
+  private previousMeasure: SourceMeasure;
+  private currentXmlMeasureIndex: number = 0;
+  private currentStaff: Staff;
+  private currentStaffEntry: SourceStaffEntry;
+  private activeClefs: ClefInstruction[];
+  private activeKey: KeyInstruction;
+  private activeRhythm: RhythmInstruction;
+  private activeClefsHaveBeenInitialized: boolean[];
+  private activeKeyHasBeenInitialized: boolean = false;
+  private abstractInstructions: [number, AbstractNotationInstruction][] = [];
+  private openChordSymbolContainer: ChordSymbolContainer;
+  // (*) private expressionReaders: ExpressionReader[];
+  private currentVoiceGenerator: VoiceGenerator;
+  //private openSlurDict: { [n: number]: Slur; } = {};
+  private maxTieNoteFraction: Fraction;
 
-    /**
-     * Main CreateSheet: read the next XML Measure and save all data to the given [[SourceMeasure]].
-     * @param currentMeasure
-     * @param measureStartAbsoluteTimestamp - Using this instead of currentMeasure.AbsoluteTimestamp as it isn't set yet
-     * @param guitarPro
-     * @returns {boolean}
-     */
-    public readNextXmlMeasure(currentMeasure: SourceMeasure, measureStartAbsoluteTimestamp: Fraction, guitarPro: boolean): boolean {
-        if (this.currentXmlMeasureIndex >= this.xmlMeasureList.length) {
-            return false;
-        }
-        this.currentMeasure = currentMeasure;
-        this.inSourceMeasureInstrumentIndex = this.musicSheet.getGlobalStaffIndexOfFirstStaff(this.instrument);
-        // (*) if (this.repetitionInstructionReader !== undefined) {
-        //  this.repetitionInstructionReader.prepareReadingMeasure(currentMeasure, this.currentXmlMeasureIndex);
-        //}
-        let currentFraction: Fraction = new Fraction(0, 1);
-        let previousFraction: Fraction = new Fraction(0, 1);
-        let divisionsException: boolean = false;
-        this.maxTieNoteFraction = new Fraction(0, 1);
-        let lastNoteWasGrace: boolean = false;
-        try {
-            let xmlMeasureListArr: IXmlElement[] = this.xmlMeasureList[this.currentXmlMeasureIndex].elements();
-            for (let xmlNode of xmlMeasureListArr) {
-                if (xmlNode.name === "note") {
-                    if (xmlNode.hasAttributes && xmlNode.attribute("print-object") && xmlNode.attribute("print-spacing")) {
-                        continue;
-                    }
-                    let noteStaff: number = 1;
-                    if (this.instrument.Staves.length > 1) {
-                        if (xmlNode.element("staff") !== undefined) {
-                            noteStaff = parseInt(xmlNode.element("staff").value, 10);
-                            if (isNaN(noteStaff)) {
-                                Logging.debug("InstrumentReader.readNextXmlMeasure.get staff number");
-                                noteStaff = 1;
-                            }
-                        }
-                    }
+  public get ActiveKey(): KeyInstruction {
+    return this.activeKey;
+  }
 
-                    this.currentStaff = this.instrument.Staves[noteStaff - 1];
-                    let isChord: boolean = xmlNode.element("chord") !== undefined;
-                    if (xmlNode.element("voice") !== undefined) {
-                        let noteVoice: number = parseInt(xmlNode.element("voice").value, 10);
-                        this.currentVoiceGenerator = this.getOrCreateVoiceGenerator(noteVoice, noteStaff - 1);
-                    } else {
-                        if (!isChord || this.currentVoiceGenerator === undefined) {
-                            this.currentVoiceGenerator = this.getOrCreateVoiceGenerator(1, noteStaff - 1);
-                        }
-                    }
-                    let noteDivisions: number = 0;
-                    let noteDuration: Fraction = new Fraction(0, 1);
-                    let isTuplet: boolean = false;
-                    if (xmlNode.element("duration") !== undefined) {
-                        noteDivisions = parseInt(xmlNode.element("duration").value, 10);
-                        if (!isNaN(noteDivisions)) {
-                            noteDuration = new Fraction(noteDivisions, 4 * this.divisions);
-                            if (noteDivisions === 0) {
-                                noteDuration = this.getNoteDurationFromTypeNode(xmlNode);
-                            }
-                            if (xmlNode.element("time-modification") !== undefined) {
-                                noteDuration = this.getNoteDurationForTuplet(xmlNode);
-                                isTuplet = true;
-                            }
-                        } else {
-                            let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/NoteDurationError", "Invalid Note Duration.");
-                            this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-                            Logging.debug("InstrumentReader.readNextXmlMeasure", errorMsg);
-                            continue;
-                        }
-                    }
+  public get MaxTieNoteFraction(): Fraction {
+    return this.maxTieNoteFraction;
+  }
 
-                    let restNote: boolean = xmlNode.element("rest") !== undefined;
-                    //Logging.log("New note found!", noteDivisions, noteDuration.toString(), restNote);
-                    let isGraceNote: boolean = xmlNode.element("grace") !== undefined || noteDivisions === 0 || isChord && lastNoteWasGrace;
-                    let musicTimestamp: Fraction = currentFraction.clone();
-                    if (isChord) {
-                        musicTimestamp = previousFraction.clone();
-                    }
-                    this.currentStaffEntry = this.currentMeasure.findOrCreateStaffEntry(
-                        musicTimestamp,
-                        this.inSourceMeasureInstrumentIndex + noteStaff - 1,
-                        this.currentStaff
-                    ).staffEntry;
-                    //Logging.log("currentStaffEntry", this.currentStaffEntry, this.currentMeasure.VerticalSourceStaffEntryContainers.length);
+  public get ActiveRhythm(): RhythmInstruction {
+    return this.activeRhythm;
+  }
 
-                    if (!this.currentVoiceGenerator.hasVoiceEntry() || (!isChord && !isGraceNote && !lastNoteWasGrace) || (!lastNoteWasGrace && isGraceNote)) {
-                        this.currentVoiceGenerator.createVoiceEntry(musicTimestamp, this.currentStaffEntry, !restNote);
-                    }
-                    if (!isGraceNote && !isChord) {
-                        previousFraction = currentFraction.clone();
-                        currentFraction.Add(noteDuration);
-                    }
-                    if (
-                        isChord &&
-                        this.currentStaffEntry !== undefined &&
-                        this.currentStaffEntry.ParentStaff !== this.currentStaff
-                    ) {
-                        this.currentStaffEntry = this.currentVoiceGenerator.checkForStaffEntryLink(
-                            this.inSourceMeasureInstrumentIndex + noteStaff - 1, this.currentStaff, this.currentStaffEntry, this.currentMeasure
-                        );
-                    }
-                    let beginOfMeasure: boolean = (
-                        this.currentStaffEntry !== undefined &&
-                        this.currentStaffEntry.Timestamp !== undefined &&
-                        this.currentStaffEntry.Timestamp.Equals(new Fraction(0, 1)) && !this.currentStaffEntry.hasNotes()
-                    );
-                    this.saveAbstractInstructionList(this.instrument.Staves.length, beginOfMeasure);
-                    if (this.openChordSymbolContainer !== undefined) {
-                        this.currentStaffEntry.ChordContainer = this.openChordSymbolContainer;
-                        this.openChordSymbolContainer = undefined;
-                    }
-                    if (this.activeRhythm !== undefined) {
-                        // (*) this.musicSheet.SheetPlaybackSetting.Rhythm = this.activeRhythm.Rhythm;
-                    }
-                    if (isTuplet) {
-                        this.currentVoiceGenerator.read(
-                            xmlNode, noteDuration.Numerator,
-                            noteDuration.Denominator, restNote, isGraceNote,
-                            this.currentStaffEntry, this.currentMeasure,
-                            measureStartAbsoluteTimestamp,
-                            this.maxTieNoteFraction, isChord, guitarPro
-                        );
-                    } else {
-                        this.currentVoiceGenerator.read(
-                            xmlNode, noteDivisions, 4 * this.divisions,
-                            restNote, isGraceNote, this.currentStaffEntry,
-                            this.currentMeasure, measureStartAbsoluteTimestamp,
-                            this.maxTieNoteFraction, isChord, guitarPro
-                        );
-                    }
-                    let notationsNode: IXmlElement = xmlNode.element("notations");
-                    if (notationsNode !== undefined && notationsNode.element("dynamics") !== undefined) {
-                        // (*) let expressionReader: ExpressionReader = this.expressionReaders[this.readExpressionStaffNumber(xmlNode) - 1];
-                        //if (expressionReader !== undefined) {
-                        //  expressionReader.readExpressionParameters(
-                        //    xmlNode, this.instrument, this.divisions, currentFraction, previousFraction, this.currentMeasure.MeasureNumber, false
-                        //  );
-                        //  expressionReader.read(
-                        //    xmlNode, this.currentMeasure, previousFraction
-                        //  );
-                        //}
-                    }
-                    lastNoteWasGrace = isGraceNote;
-                } else if (xmlNode.name === "attributes") {
-                    let divisionsNode: IXmlElement = xmlNode.element("divisions");
-                    if (divisionsNode !== undefined) {
-                        this.divisions = parseInt(divisionsNode.value, 10);
-                        if (isNaN(this.divisions)) {
-                            let errorMsg: string = ITextTranslation.translateText(  "ReaderErrorMessages/DivisionError",
-                                                                                    "Invalid divisions value at Instrument: ");
-                            Logging.debug("InstrumentReader.readNextXmlMeasure", errorMsg);
-                            this.divisions = this.readDivisionsFromNotes();
-                            if (this.divisions > 0) {
-                                this.musicSheet.SheetErrors.push(errorMsg + this.instrument.Name);
-                            } else {
-                                divisionsException = true;
-                                throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
-                            }
-                        }
+  public set ActiveRhythm(value: RhythmInstruction) {
+    this.activeRhythm = value;
+  }
 
-                    }
-                    if (
-                        xmlNode.element("divisions") === undefined &&
-                        this.divisions === 0 &&
-                        this.currentXmlMeasureIndex === 0
-                    ) {
-                        let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/DivisionError", "Invalid divisions value at Instrument: ");
-                        this.divisions = this.readDivisionsFromNotes();
-                        if (this.divisions > 0) {
-                            this.musicSheet.SheetErrors.push(errorMsg + this.instrument.Name);
-                        } else {
-                            divisionsException = true;
-                            throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
-                        }
-                    }
-                    this.addAbstractInstruction(xmlNode, guitarPro);
-                    if (currentFraction.Equals(new Fraction(0, 1)) &&
-                        this.isAttributesNodeAtBeginOfMeasure(this.xmlMeasureList[this.currentXmlMeasureIndex], xmlNode)) {
-                        this.saveAbstractInstructionList(this.instrument.Staves.length, true);
-                    }
-                    if (this.isAttributesNodeAtEndOfMeasure(this.xmlMeasureList[this.currentXmlMeasureIndex], xmlNode)) {
-                        this.saveClefInstructionAtEndOfMeasure();
-                    }
-                } else if (xmlNode.name === "forward") {
-                    let forFraction: number = parseInt(xmlNode.element("duration").value, 10);
-                    currentFraction.Add(new Fraction(forFraction, 4 * this.divisions));
-                } else if (xmlNode.name === "backup") {
-                    let backFraction: number = parseInt(xmlNode.element("duration").value, 10);
-                    currentFraction.Sub(new Fraction(backFraction, 4 * this.divisions));
-                    if (currentFraction.Numerator < 0) {
-                        currentFraction = new Fraction(0, 1);
-                    }
-                    previousFraction.Sub(new Fraction(backFraction, 4 * this.divisions));
-                    if (previousFraction.Numerator < 0) {
-                        previousFraction = new Fraction(0, 1);
-                    }
-                } else if (xmlNode.name === "direction") {
-                    // unused let directionTypeNode: IXmlElement = xmlNode.element("direction-type");
-                    // (*) MetronomeReader.readMetronomeInstructions(xmlNode, this.musicSheet, this.currentXmlMeasureIndex);
-                    let relativePositionInMeasure: number = Math.min(1, currentFraction.RealValue);
-                    if (this.activeRhythm !== undefined && this.activeRhythm.Rhythm !== undefined) {
-                        relativePositionInMeasure /= this.activeRhythm.Rhythm.RealValue;
-                    }
-                    // unused: let handeled: boolean = false;
-                    // (*) if (this.repetitionInstructionReader !== undefined) {
-                    //  handeled = this.repetitionInstructionReader.handleRepetitionInstructionsFromWordsOrSymbols(directionTypeNode,
-                    //                                                                                              relativePositionInMeasure);
-                    //}
-                    //if (!handeled) {
-                    //  let expressionReader: ExpressionReader = this.expressionReaders[0];
-                    //  let staffIndex: number = this.readExpressionStaffNumber(xmlNode) - 1;
-                    //  if (staffIndex < this.expressionReaders.length) {
-                    //    expressionReader = this.expressionReaders[staffIndex];
-                    //  }
-                    //  if (expressionReader !== undefined) {
-                    //    if (directionTypeNode.element("octave-shift") !== undefined) {
-                    //      expressionReader.readExpressionParameters(
-                    //        xmlNode, this.instrument, this.divisions, currentFraction, previousFraction, this.currentMeasure.MeasureNumber, true
-                    //      );
-                    //      expressionReader.addOctaveShift(xmlNode, this.currentMeasure, previousFraction.clone());
-                    //    }
-                    //    expressionReader.readExpressionParameters(
-                    //      xmlNode, this.instrument, this.divisions, currentFraction, previousFraction, this.currentMeasure.MeasureNumber, false
-                    //    );
-                    //    expressionReader.read(xmlNode, this.currentMeasure, currentFraction);
-                    //  }
-                    //}
-                } else if (xmlNode.name === "barline") {
-                    // (*)
-                    //if (this.repetitionInstructionReader !== undefined) {
-                    //  let measureEndsSystem: boolean = false;
-                    //  this.repetitionInstructionReader.handleLineRepetitionInstructions(xmlNode, measureEndsSystem);
-                    //  if (measureEndsSystem) {
-                    //    this.currentMeasure.BreakSystemAfter = true;
-                    //    this.currentMeasure.endsPiece = true;
-                    //  }
-                    //}
-                } else if (xmlNode.name === "sound") {
-                    // (*) MetronomeReader.readTempoInstruction(xmlNode, this.musicSheet, this.currentXmlMeasureIndex);
-                } else if (xmlNode.name === "harmony") {
-                    // (*) this.openChordSymbolContainer = ChordSymbolReader.readChordSymbol(xmlNode, this.musicSheet, this.activeKey);
-                }
-            }
-            for (let j in this.voiceGeneratorsDict) {
-                if (this.voiceGeneratorsDict.hasOwnProperty(j)) {
-                    let voiceGenerator: VoiceGenerator = this.voiceGeneratorsDict[j];
-                    voiceGenerator.checkForOpenBeam();
-                    voiceGenerator.checkForOpenGraceNotes();
-                }
+  /**
+   * Main CreateSheet: read the next XML Measure and save all data to the given [[SourceMeasure]].
+   * @param currentMeasure
+   * @param measureStartAbsoluteTimestamp - Using this instead of currentMeasure.AbsoluteTimestamp as it isn't set yet
+   * @param guitarPro
+   * @returns {boolean}
+   */
+  public readNextXmlMeasure(currentMeasure: SourceMeasure, measureStartAbsoluteTimestamp: Fraction, guitarPro: boolean): boolean {
+    if (this.currentXmlMeasureIndex >= this.xmlMeasureList.length) {
+      return false;
+    }
+    this.currentMeasure = currentMeasure;
+    this.inSourceMeasureInstrumentIndex = this.musicSheet.getGlobalStaffIndexOfFirstStaff(this.instrument);
+    // (*) if (this.repetitionInstructionReader !== undefined) {
+    //  this.repetitionInstructionReader.prepareReadingMeasure(currentMeasure, this.currentXmlMeasureIndex);
+    //}
+    let currentFraction: Fraction = new Fraction(0, 1);
+    let previousFraction: Fraction = new Fraction(0, 1);
+    let divisionsException: boolean = false;
+    this.maxTieNoteFraction = new Fraction(0, 1);
+    let lastNoteWasGrace: boolean = false;
+    try {
+      let xmlMeasureListArr: IXmlElement[] = this.xmlMeasureList[this.currentXmlMeasureIndex].elements();
+      for (let xmlNode of xmlMeasureListArr) {
+        if (xmlNode.name === "note") {
+          if (xmlNode.hasAttributes && xmlNode.attribute("print-object") && xmlNode.attribute("print-spacing")) {
+            continue;
+          }
+          let noteStaff: number = 1;
+          if (this.instrument.Staves.length > 1) {
+            if (xmlNode.element("staff") !== undefined) {
+              noteStaff = parseInt(xmlNode.element("staff").value, 10);
+              if (isNaN(noteStaff)) {
+                Logging.debug("InstrumentReader.readNextXmlMeasure.get staff number");
+                noteStaff = 1;
+              }
             }
-            if (this.currentXmlMeasureIndex === this.xmlMeasureList.length - 1) {
-                for (let i: number = 0; i < this.instrument.Staves.length; i++) {
-                    if (!this.activeClefsHaveBeenInitialized[i]) {
-                        this.createDefaultClefInstruction(this.musicSheet.getGlobalStaffIndexOfFirstStaff(this.instrument) + i);
-                    }
-                }
-                if (!this.activeKeyHasBeenInitialized) {
-                    this.createDefaultKeyInstruction();
-                }
-                // (*)
-                //for (let i: number = 0; i < this.expressionReaders.length; i++) {
-                //  let reader: ExpressionReader = this.expressionReaders[i];
-                //  if (reader !== undefined) {
-                //    reader.checkForOpenExpressions(this.currentMeasure, currentFraction);
-                //  }
-                //}
+          }
+
+          this.currentStaff = this.instrument.Staves[noteStaff - 1];
+          let isChord: boolean = xmlNode.element("chord") !== undefined;
+          if (xmlNode.element("voice") !== undefined) {
+            let noteVoice: number = parseInt(xmlNode.element("voice").value, 10);
+            this.currentVoiceGenerator = this.getOrCreateVoiceGenerator(noteVoice, noteStaff - 1);
+          } else {
+            if (!isChord || this.currentVoiceGenerator === undefined) {
+              this.currentVoiceGenerator = this.getOrCreateVoiceGenerator(1, noteStaff - 1);
             }
-        } catch (e) {
-            if (divisionsException) {
-                throw new MusicSheetReadingException(e.Message);
+          }
+          let noteDivisions: number = 0;
+          let noteDuration: Fraction = new Fraction(0, 1);
+          let isTuplet: boolean = false;
+          if (xmlNode.element("duration") !== undefined) {
+            noteDivisions = parseInt(xmlNode.element("duration").value, 10);
+            if (!isNaN(noteDivisions)) {
+              noteDuration = new Fraction(noteDivisions, 4 * this.divisions);
+              if (noteDivisions === 0) {
+                noteDuration = this.getNoteDurationFromTypeNode(xmlNode);
+              }
+              if (xmlNode.element("time-modification") !== undefined) {
+                noteDuration = this.getNoteDurationForTuplet(xmlNode);
+                isTuplet = true;
+              }
+            } else {
+              let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/NoteDurationError", "Invalid Note Duration.");
+              this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+              Logging.debug("InstrumentReader.readNextXmlMeasure", errorMsg);
+              continue;
             }
-            let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/MeasureError", "Error while reading Measure.");
-            this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-            Logging.debug("InstrumentReader.readNextXmlMeasure", errorMsg, e);
-        }
+          }
 
-        this.previousMeasure = this.currentMeasure;
-        this.currentXmlMeasureIndex += 1;
-        return true;
-    }
+          let restNote: boolean = xmlNode.element("rest") !== undefined;
+          //Logging.log("New note found!", noteDivisions, noteDuration.toString(), restNote);
+          let isGraceNote: boolean = xmlNode.element("grace") !== undefined || noteDivisions === 0 || isChord && lastNoteWasGrace;
+          let musicTimestamp: Fraction = currentFraction.clone();
+          if (isChord) {
+            musicTimestamp = previousFraction.clone();
+          }
+          this.currentStaffEntry = this.currentMeasure.findOrCreateStaffEntry(
+            musicTimestamp,
+            this.inSourceMeasureInstrumentIndex + noteStaff - 1,
+            this.currentStaff
+          ).staffEntry;
+          //Logging.log("currentStaffEntry", this.currentStaffEntry, this.currentMeasure.VerticalSourceStaffEntryContainers.length);
 
-    public doCalculationsAfterDurationHasBeenSet(): void {
-        for (let j in this.voiceGeneratorsDict) {
-            if (this.voiceGeneratorsDict.hasOwnProperty(j)) {
-                this.voiceGeneratorsDict[j].checkOpenTies();
+          if (!this.currentVoiceGenerator.hasVoiceEntry() || (!isChord && !isGraceNote && !lastNoteWasGrace) || (!lastNoteWasGrace && isGraceNote)) {
+            this.currentVoiceGenerator.createVoiceEntry(musicTimestamp, this.currentStaffEntry, !restNote);
+          }
+          if (!isGraceNote && !isChord) {
+            previousFraction = currentFraction.clone();
+            currentFraction.Add(noteDuration);
+          }
+          if (
+            isChord &&
+            this.currentStaffEntry !== undefined &&
+            this.currentStaffEntry.ParentStaff !== this.currentStaff
+          ) {
+            this.currentStaffEntry = this.currentVoiceGenerator.checkForStaffEntryLink(
+              this.inSourceMeasureInstrumentIndex + noteStaff - 1, this.currentStaff, this.currentStaffEntry, this.currentMeasure
+            );
+          }
+          let beginOfMeasure: boolean = (
+            this.currentStaffEntry !== undefined &&
+            this.currentStaffEntry.Timestamp !== undefined &&
+            this.currentStaffEntry.Timestamp.Equals(new Fraction(0, 1)) && !this.currentStaffEntry.hasNotes()
+          );
+          this.saveAbstractInstructionList(this.instrument.Staves.length, beginOfMeasure);
+          if (this.openChordSymbolContainer !== undefined) {
+            this.currentStaffEntry.ChordContainer = this.openChordSymbolContainer;
+            this.openChordSymbolContainer = undefined;
+          }
+          if (this.activeRhythm !== undefined) {
+            // (*) this.musicSheet.SheetPlaybackSetting.Rhythm = this.activeRhythm.Rhythm;
+          }
+          if (isTuplet) {
+            this.currentVoiceGenerator.read(
+              xmlNode, noteDuration, restNote, isGraceNote,
+              this.currentStaffEntry, this.currentMeasure,
+              measureStartAbsoluteTimestamp,
+              this.maxTieNoteFraction, isChord, guitarPro
+            );
+          } else {
+            this.currentVoiceGenerator.read(
+              xmlNode, new Fraction(noteDivisions, 4 * this.divisions),
+              restNote, isGraceNote, this.currentStaffEntry,
+              this.currentMeasure, measureStartAbsoluteTimestamp,
+              this.maxTieNoteFraction, isChord, guitarPro
+            );
+          }
+          let notationsNode: IXmlElement = xmlNode.element("notations");
+          if (notationsNode !== undefined && notationsNode.element("dynamics") !== undefined) {
+            // (*) let expressionReader: ExpressionReader = this.expressionReaders[this.readExpressionStaffNumber(xmlNode) - 1];
+            //if (expressionReader !== undefined) {
+            //  expressionReader.readExpressionParameters(
+            //    xmlNode, this.instrument, this.divisions, currentFraction, previousFraction, this.currentMeasure.MeasureNumber, false
+            //  );
+            //  expressionReader.read(
+            //    xmlNode, this.currentMeasure, previousFraction
+            //  );
+            //}
+          }
+          lastNoteWasGrace = isGraceNote;
+        } else if (xmlNode.name === "attributes") {
+          let divisionsNode: IXmlElement = xmlNode.element("divisions");
+          if (divisionsNode !== undefined) {
+            this.divisions = parseInt(divisionsNode.value, 10);
+            if (isNaN(this.divisions)) {
+              let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/DivisionError",
+                                                                    "Invalid divisions value at Instrument: ");
+              Logging.debug("InstrumentReader.readNextXmlMeasure", errorMsg);
+              this.divisions = this.readDivisionsFromNotes();
+              if (this.divisions > 0) {
+                this.musicSheet.SheetErrors.push(errorMsg + this.instrument.Name);
+              } else {
+                divisionsException = true;
+                throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
+              }
             }
-        }
-    }
 
-    /**
-     * Get or create the passing [[VoiceGenerator]].
-     * @param voiceId
-     * @param staffId
-     * @returns {VoiceGenerator}
-     */
-    private getOrCreateVoiceGenerator(voiceId: number, staffId: number): VoiceGenerator {
-        let staff: Staff = this.instrument.Staves[staffId];
-        let voiceGenerator: VoiceGenerator = this.voiceGeneratorsDict[voiceId];
-        if (voiceGenerator !== undefined) {
-            if (staff.Voices.indexOf(voiceGenerator.GetVoice) === -1) {
-                staff.Voices.push(voiceGenerator.GetVoice);
-            }
-        } else {
-            let mainVoiceGenerator: VoiceGenerator = this.staffMainVoiceGeneratorDict[staffId];
-            if (mainVoiceGenerator !== undefined) {
-                voiceGenerator = new VoiceGenerator(this.instrument, voiceId, this.slurReader, mainVoiceGenerator.GetVoice);
-                staff.Voices.push(voiceGenerator.GetVoice);
-                this.voiceGeneratorsDict[voiceId] = voiceGenerator;
+          }
+          if (
+            xmlNode.element("divisions") === undefined &&
+            this.divisions === 0 &&
+            this.currentXmlMeasureIndex === 0
+          ) {
+            let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/DivisionError", "Invalid divisions value at Instrument: ");
+            this.divisions = this.readDivisionsFromNotes();
+            if (this.divisions > 0) {
+              this.musicSheet.SheetErrors.push(errorMsg + this.instrument.Name);
             } else {
-                voiceGenerator = new VoiceGenerator(this.instrument, voiceId, this.slurReader);
-                staff.Voices.push(voiceGenerator.GetVoice);
-                this.voiceGeneratorsDict[voiceId] = voiceGenerator;
-                this.staffMainVoiceGeneratorDict[staffId] = voiceGenerator;
+              divisionsException = true;
+              throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
             }
+          }
+          this.addAbstractInstruction(xmlNode, guitarPro);
+          if (currentFraction.Equals(new Fraction(0, 1)) &&
+            this.isAttributesNodeAtBeginOfMeasure(this.xmlMeasureList[this.currentXmlMeasureIndex], xmlNode)) {
+            this.saveAbstractInstructionList(this.instrument.Staves.length, true);
+          }
+          if (this.isAttributesNodeAtEndOfMeasure(this.xmlMeasureList[this.currentXmlMeasureIndex], xmlNode)) {
+            this.saveClefInstructionAtEndOfMeasure();
+          }
+        } else if (xmlNode.name === "forward") {
+          let forFraction: number = parseInt(xmlNode.element("duration").value, 10);
+          currentFraction.Add(new Fraction(forFraction, 4 * this.divisions));
+        } else if (xmlNode.name === "backup") {
+          let backFraction: number = parseInt(xmlNode.element("duration").value, 10);
+          currentFraction.Sub(new Fraction(backFraction, 4 * this.divisions));
+          if (currentFraction.IsNegative()) {
+            currentFraction = new Fraction(0, 1);
+          }
+          previousFraction.Sub(new Fraction(backFraction, 4 * this.divisions));
+          if (previousFraction.IsNegative()) {
+            previousFraction = new Fraction(0, 1);
+          }
+        } else if (xmlNode.name === "direction") {
+          // unused let directionTypeNode: IXmlElement = xmlNode.element("direction-type");
+          // (*) MetronomeReader.readMetronomeInstructions(xmlNode, this.musicSheet, this.currentXmlMeasureIndex);
+          let relativePositionInMeasure: number = Math.min(1, currentFraction.RealValue);
+          if (this.activeRhythm !== undefined && this.activeRhythm.Rhythm !== undefined) {
+            relativePositionInMeasure /= this.activeRhythm.Rhythm.RealValue;
+          }
+                    // unused:
+                    // let handeled: boolean = false;
+                    // if (this.repetitionInstructionReader !== undefined) {
+          //  handeled = this.repetitionInstructionReader.handleRepetitionInstructionsFromWordsOrSymbols(directionTypeNode,
+          //                                                                                              relativePositionInMeasure);
+          //}
+          //if (!handeled) {
+          //  let expressionReader: ExpressionReader = this.expressionReaders[0];
+          //  let staffIndex: number = this.readExpressionStaffNumber(xmlNode) - 1;
+          //  if (staffIndex < this.expressionReaders.length) {
+          //    expressionReader = this.expressionReaders[staffIndex];
+          //  }
+          //  if (expressionReader !== undefined) {
+          //    if (directionTypeNode.element("octave-shift") !== undefined) {
+          //      expressionReader.readExpressionParameters(
+          //        xmlNode, this.instrument, this.divisions, currentFraction, previousFraction, this.currentMeasure.MeasureNumber, true
+          //      );
+          //      expressionReader.addOctaveShift(xmlNode, this.currentMeasure, previousFraction.clone());
+          //    }
+          //    expressionReader.readExpressionParameters(
+          //      xmlNode, this.instrument, this.divisions, currentFraction, previousFraction, this.currentMeasure.MeasureNumber, false
+          //    );
+          //    expressionReader.read(xmlNode, this.currentMeasure, currentFraction);
+          //  }
+          //}
+        } else if (xmlNode.name === "barline") {
+
+          //if (this.repetitionInstructionReader !== undefined) {
+          //  let measureEndsSystem: boolean = false;
+          //  this.repetitionInstructionReader.handleLineRepetitionInstructions(xmlNode, measureEndsSystem);
+          //  if (measureEndsSystem) {
+          //    this.currentMeasure.BreakSystemAfter = true;
+          //    this.currentMeasure.endsPiece = true;
+          //  }
+          //}
+        } else if (xmlNode.name === "sound") {
+          // (*) MetronomeReader.readTempoInstruction(xmlNode, this.musicSheet, this.currentXmlMeasureIndex);
+        } else if (xmlNode.name === "harmony") {
+                    this.openChordSymbolContainer = ChordSymbolReader.readChordSymbol(xmlNode, this.musicSheet, this.activeKey);
+        }
+      }
+      for (let j in this.voiceGeneratorsDict) {
+        if (this.voiceGeneratorsDict.hasOwnProperty(j)) {
+          let voiceGenerator: VoiceGenerator = this.voiceGeneratorsDict[j];
+          voiceGenerator.checkForOpenBeam();
+          voiceGenerator.checkForOpenGraceNotes();
         }
-        return voiceGenerator;
+      }
+      if (this.currentXmlMeasureIndex === this.xmlMeasureList.length - 1) {
+        for (let i: number = 0; i < this.instrument.Staves.length; i++) {
+          if (!this.activeClefsHaveBeenInitialized[i]) {
+            this.createDefaultClefInstruction(this.musicSheet.getGlobalStaffIndexOfFirstStaff(this.instrument) + i);
+          }
+        }
+        if (!this.activeKeyHasBeenInitialized) {
+          this.createDefaultKeyInstruction();
+        }
+        // (*)
+        //for (let i: number = 0; i < this.expressionReaders.length; i++) {
+        //  let reader: ExpressionReader = this.expressionReaders[i];
+        //  if (reader !== undefined) {
+        //    reader.checkForOpenExpressions(this.currentMeasure, currentFraction);
+        //  }
+        //}
+      }
+    } catch (e) {
+      if (divisionsException) {
+        throw new MusicSheetReadingException(e.Message);
+      }
+      let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/MeasureError", "Error while reading Measure.");
+      this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+      Logging.debug("InstrumentReader.readNextXmlMeasure", errorMsg, e);
     }
 
+    this.previousMeasure = this.currentMeasure;
+    this.currentXmlMeasureIndex += 1;
+    return true;
+  }
 
-    //private createExpressionGenerators(numberOfStaves: number): void {
-    //  // (*)
-    //  //this.expressionReaders = new Array(numberOfStaves);
-    //  //for (let i: number = 0; i < numberOfStaves; i++) {
-    //  //  this.expressionReaders[i] = MusicSymbolModuleFactory.createExpressionGenerator(this.musicSheet, this.instrument, i + 1);
-    //  //}
-    //}
+  public doCalculationsAfterDurationHasBeenSet(): void {
+    for (let j in this.voiceGeneratorsDict) {
+      if (this.voiceGeneratorsDict.hasOwnProperty(j)) {
+        this.voiceGeneratorsDict[j].checkOpenTies();
+      }
+    }
+  }
 
-    /**
-     * Create the default [[ClefInstruction]] for the given staff index.
-     * @param staffIndex
-     */
-    private createDefaultClefInstruction(staffIndex: number): void {
-        let first: SourceMeasure;
-        if (this.musicSheet.SourceMeasures.length > 0) {
-            first = this.musicSheet.SourceMeasures[0];
-        } else {
-            first = this.currentMeasure;
-        }
-        let clefInstruction: ClefInstruction = new ClefInstruction(ClefEnum.G, 0, 2);
-        let firstStaffEntry: SourceStaffEntry;
-        if (first.FirstInstructionsStaffEntries[staffIndex] === undefined) {
-            firstStaffEntry = new SourceStaffEntry(undefined, undefined);
-            first.FirstInstructionsStaffEntries[staffIndex] = firstStaffEntry;
-        } else {
-            firstStaffEntry = first.FirstInstructionsStaffEntries[staffIndex];
-            firstStaffEntry.removeFirstInstructionOfTypeClefInstruction();
-        }
-        clefInstruction.Parent = firstStaffEntry;
-        firstStaffEntry.Instructions.splice(0, 0, clefInstruction);
+  /**
+   * Get or create the passing [[VoiceGenerator]].
+   * @param voiceId
+   * @param staffId
+   * @returns {VoiceGenerator}
+   */
+  private getOrCreateVoiceGenerator(voiceId: number, staffId: number): VoiceGenerator {
+    let staff: Staff = this.instrument.Staves[staffId];
+    let voiceGenerator: VoiceGenerator = this.voiceGeneratorsDict[voiceId];
+    if (voiceGenerator !== undefined) {
+      if (staff.Voices.indexOf(voiceGenerator.GetVoice) === -1) {
+        staff.Voices.push(voiceGenerator.GetVoice);
+      }
+    } else {
+      let mainVoiceGenerator: VoiceGenerator = this.staffMainVoiceGeneratorDict[staffId];
+      if (mainVoiceGenerator !== undefined) {
+        voiceGenerator = new VoiceGenerator(this.instrument, voiceId, this.slurReader, mainVoiceGenerator.GetVoice);
+        staff.Voices.push(voiceGenerator.GetVoice);
+        this.voiceGeneratorsDict[voiceId] = voiceGenerator;
+      } else {
+        voiceGenerator = new VoiceGenerator(this.instrument, voiceId, this.slurReader);
+        staff.Voices.push(voiceGenerator.GetVoice);
+        this.voiceGeneratorsDict[voiceId] = voiceGenerator;
+        this.staffMainVoiceGeneratorDict[staffId] = voiceGenerator;
+      }
     }
+    return voiceGenerator;
+  }
+
 
-    /**
-     * Create the default [[KeyInstruction]] in case no [[KeyInstruction]] is given in the whole [[Instrument]].
-     */
-    private createDefaultKeyInstruction(): void {
-        let first: SourceMeasure;
-        if (this.musicSheet.SourceMeasures.length > 0) {
-            first = this.musicSheet.SourceMeasures[0];
+  //private createExpressionGenerators(numberOfStaves: number): void {
+  //  // (*)
+  //  //this.expressionReaders = new Array(numberOfStaves);
+  //  //for (let i: number = 0; i < numberOfStaves; i++) {
+  //  //  this.expressionReaders[i] = MusicSymbolModuleFactory.createExpressionGenerator(this.musicSheet, this.instrument, i + 1);
+  //  //}
+  //}
+
+  /**
+   * Create the default [[ClefInstruction]] for the given staff index.
+   * @param staffIndex
+   */
+  private createDefaultClefInstruction(staffIndex: number): void {
+    let first: SourceMeasure;
+    if (this.musicSheet.SourceMeasures.length > 0) {
+      first = this.musicSheet.SourceMeasures[0];
+    } else {
+      first = this.currentMeasure;
+    }
+    let clefInstruction: ClefInstruction = new ClefInstruction(ClefEnum.G, 0, 2);
+    let firstStaffEntry: SourceStaffEntry;
+    if (first.FirstInstructionsStaffEntries[staffIndex] === undefined) {
+      firstStaffEntry = new SourceStaffEntry(undefined, undefined);
+      first.FirstInstructionsStaffEntries[staffIndex] = firstStaffEntry;
+    } else {
+      firstStaffEntry = first.FirstInstructionsStaffEntries[staffIndex];
+      firstStaffEntry.removeFirstInstructionOfTypeClefInstruction();
+    }
+    clefInstruction.Parent = firstStaffEntry;
+    firstStaffEntry.Instructions.splice(0, 0, clefInstruction);
+  }
+
+  /**
+   * Create the default [[KeyInstruction]] in case no [[KeyInstruction]] is given in the whole [[Instrument]].
+   */
+  private createDefaultKeyInstruction(): void {
+    let first: SourceMeasure;
+    if (this.musicSheet.SourceMeasures.length > 0) {
+      first = this.musicSheet.SourceMeasures[0];
+    } else {
+      first = this.currentMeasure;
+    }
+    let keyInstruction: KeyInstruction = new KeyInstruction(undefined, 0, KeyEnum.major);
+    for (let j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + this.instrument.Staves.length; j++) {
+      if (first.FirstInstructionsStaffEntries[j] === undefined) {
+        let firstStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
+        first.FirstInstructionsStaffEntries[j] = firstStaffEntry;
+        keyInstruction.Parent = firstStaffEntry;
+        firstStaffEntry.Instructions.push(keyInstruction);
+      } else {
+        let firstStaffEntry: SourceStaffEntry = first.FirstInstructionsStaffEntries[j];
+        keyInstruction.Parent = firstStaffEntry;
+        firstStaffEntry.removeFirstInstructionOfTypeKeyInstruction();
+        if (firstStaffEntry.Instructions[0] instanceof ClefInstruction) {
+          firstStaffEntry.Instructions.splice(1, 0, keyInstruction);
         } else {
-            first = this.currentMeasure;
-        }
-        let keyInstruction: KeyInstruction = new KeyInstruction(undefined, 0, KeyEnum.major);
-        for (let j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + this.instrument.Staves.length; j++) {
-            if (first.FirstInstructionsStaffEntries[j] === undefined) {
-                let firstStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
-                first.FirstInstructionsStaffEntries[j] = firstStaffEntry;
-                keyInstruction.Parent = firstStaffEntry;
-                firstStaffEntry.Instructions.push(keyInstruction);
-            } else {
-                let firstStaffEntry: SourceStaffEntry = first.FirstInstructionsStaffEntries[j];
-                keyInstruction.Parent = firstStaffEntry;
-                firstStaffEntry.removeFirstInstructionOfTypeKeyInstruction();
-                if (firstStaffEntry.Instructions[0] instanceof ClefInstruction) {
-                    firstStaffEntry.Instructions.splice(1, 0, keyInstruction);
-                } else {
-                    firstStaffEntry.Instructions.splice(0, 0, keyInstruction);
-                }
-            }
+          firstStaffEntry.Instructions.splice(0, 0, keyInstruction);
         }
+      }
     }
+  }
 
-    /**
-     * Check if the given attributesNode is at the begin of a XmlMeasure.
-     * @param parentNode
-     * @param attributesNode
-     * @returns {boolean}
-     */
-    private isAttributesNodeAtBeginOfMeasure(parentNode: IXmlElement, attributesNode: IXmlElement): boolean {
-        let children: IXmlElement[] = parentNode.elements();
-        let attributesNodeIndex: number = children.indexOf(attributesNode); // FIXME | 0
-        if (attributesNodeIndex > 0 && children[attributesNodeIndex - 1].name === "backup") {
-            return true;
-        }
-        let firstNoteNodeIndex: number = -1;
-        for (let i: number = 0; i < children.length; i++) {
-            if (children[i].name === "note") {
-                firstNoteNodeIndex = i;
-                break;
-            }
-        }
-        return (attributesNodeIndex < firstNoteNodeIndex && firstNoteNodeIndex > 0) || (firstNoteNodeIndex < 0);
+  /**
+   * Check if the given attributesNode is at the begin of a XmlMeasure.
+   * @param parentNode
+   * @param attributesNode
+   * @returns {boolean}
+   */
+  private isAttributesNodeAtBeginOfMeasure(parentNode: IXmlElement, attributesNode: IXmlElement): boolean {
+    let children: IXmlElement[] = parentNode.elements();
+    let attributesNodeIndex: number = children.indexOf(attributesNode); // FIXME | 0
+    if (attributesNodeIndex > 0 && children[attributesNodeIndex - 1].name === "backup") {
+      return true;
     }
+    let firstNoteNodeIndex: number = -1;
+    for (let i: number = 0; i < children.length; i++) {
+      if (children[i].name === "note") {
+        firstNoteNodeIndex = i;
+        break;
+      }
+    }
+    return (attributesNodeIndex < firstNoteNodeIndex && firstNoteNodeIndex > 0) || (firstNoteNodeIndex < 0);
+  }
 
-    /**
-     * Check if the given attributesNode is at the end of a XmlMeasure.
-     * @param parentNode
-     * @param attributesNode
-     * @returns {boolean}
-     */
-    private isAttributesNodeAtEndOfMeasure(parentNode: IXmlElement, attributesNode: IXmlElement): boolean {
-        let childs: IXmlElement[] = parentNode.elements().slice();
-        let attributesNodeIndex: number = 0;
-        for (let i: number = 0; i < childs.length; i++) {
-            if (childs[i] === attributesNode) {
-                attributesNodeIndex = i;
-                break;
-            }
-        }
-        let nextNoteNodeIndex: number = 0;
-        for (let i: number = attributesNodeIndex; i < childs.length; i++) {
-            if (childs[i].name === "note") {
-                nextNoteNodeIndex = i;
-                break;
-            }
-        }
-        return attributesNodeIndex > nextNoteNodeIndex;
+  /**
+   * Check if the given attributesNode is at the end of a XmlMeasure.
+   * @param parentNode
+   * @param attributesNode
+   * @returns {boolean}
+   */
+  private isAttributesNodeAtEndOfMeasure(parentNode: IXmlElement, attributesNode: IXmlElement): boolean {
+    let childs: IXmlElement[] = parentNode.elements().slice();
+    let attributesNodeIndex: number = 0;
+    for (let i: number = 0; i < childs.length; i++) {
+      if (childs[i] === attributesNode) {
+        attributesNodeIndex = i;
+        break;
+      }
     }
+    let nextNoteNodeIndex: number = 0;
+    for (let i: number = attributesNodeIndex; i < childs.length; i++) {
+      if (childs[i].name === "note") {
+        nextNoteNodeIndex = i;
+        break;
+      }
+    }
+    return attributesNodeIndex > nextNoteNodeIndex;
+  }
 
-    /**
-     * Called only when no noteDuration is given in XML.
-     * @param xmlNode
-     * @returns {Fraction}
-     */
-    private getNoteDurationFromTypeNode(xmlNode: IXmlElement): Fraction {
-        if (xmlNode.element("type") !== undefined) {
-            let typeNode: IXmlElement = xmlNode.element("type");
-            if (typeNode !== undefined) {
-                let type: string = typeNode.value;
-                return this.currentVoiceGenerator.getNoteDurationFromType(type);
-            }
-        }
-        return new Fraction(0, 4 * this.divisions);
+  /**
+   * Called only when no noteDuration is given in XML.
+   * @param xmlNode
+   * @returns {Fraction}
+   */
+  private getNoteDurationFromTypeNode(xmlNode: IXmlElement): Fraction {
+    if (xmlNode.element("type") !== undefined) {
+      let typeNode: IXmlElement = xmlNode.element("type");
+      if (typeNode !== undefined) {
+        let type: string = typeNode.value;
+        return this.currentVoiceGenerator.getNoteDurationFromType(type);
+      }
     }
+    return new Fraction(0, 4 * this.divisions);
+  }
+
+  /**
+   * Add (the three basic) Notation Instructions to a list
+   * @param node
+   * @param guitarPro
+   */
+  private addAbstractInstruction(node: IXmlElement, guitarPro: boolean): void {
+    if (node.element("divisions") !== undefined) {
+      if (node.elements().length === 1) {
+        return;
+      }
+    }
+    let transposeNode: IXmlElement = node.element("transpose");
+    if (transposeNode !== undefined) {
+      let chromaticNode: IXmlElement = transposeNode.element("chromatic");
+      if (chromaticNode !== undefined) {
+        this.instrument.PlaybackTranspose = parseInt(chromaticNode.value, 10);
+      }
+    }
+    let clefList: IXmlElement[] = node.elements("clef");
+    let errorMsg: string;
+    if (clefList.length > 0) {
+      for (let idx: number = 0, len: number = clefList.length; idx < len; ++idx) {
+        let nodeList: IXmlElement = clefList[idx];
+        let clefEnum: ClefEnum = ClefEnum.G;
+        let line: number = 2;
+        let staffNumber: number = 1;
+        let clefOctaveOffset: number = 0;
+        let lineNode: IXmlElement = nodeList.element("line");
+        if (lineNode !== undefined) {
+          try {
+            line = parseInt(lineNode.value, 10);
+          } catch (ex) {
+            errorMsg = ITextTranslation.translateText(
+              "ReaderErrorMessages/ClefLineError",
+              "Invalid clef line given -> using default clef line."
+            );
+            this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+            line = 2;
+            Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
+          }
 
-    /**
-     * Add (the three basic) Notation Instructions to a list
-     * @param node
-     * @param guitarPro
-     */
-    private addAbstractInstruction(node: IXmlElement, guitarPro: boolean): void {
-        if (node.element("divisions") !== undefined) {
-            if (node.elements().length === 1) {
-                return;
-            }
         }
-        let transposeNode: IXmlElement = node.element("transpose");
-        if (transposeNode !== undefined) {
-            let chromaticNode: IXmlElement = transposeNode.element("chromatic");
-            if (chromaticNode !== undefined) {
-                this.instrument.PlaybackTranspose = parseInt(chromaticNode.value, 10);
+        let signNode: IXmlElement = nodeList.element("sign");
+        if (signNode !== undefined) {
+          try {
+            clefEnum = ClefEnum[signNode.value];
+            if (!ClefInstruction.isSupportedClef(clefEnum)) {
+              if (clefEnum === ClefEnum.TAB && guitarPro) {
+                clefOctaveOffset = -1;
+              }
+              errorMsg = ITextTranslation.translateText(
+                "ReaderErrorMessages/ClefError",
+                "Unsupported clef found -> using default clef."
+              );
+              this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+              clefEnum = ClefEnum.G;
+              line = 2;
             }
-        }
-        let clefList: IXmlElement[] = node.elements("clef");
-        let errorMsg: string;
-        if (clefList.length > 0) {
-            for (let idx: number = 0, len: number = clefList.length; idx < len; ++idx) {
-                let nodeList: IXmlElement = clefList[idx];
-                let clefEnum: ClefEnum = ClefEnum.G;
-                let line: number = 2;
-                let staffNumber: number = 1;
-                let clefOctaveOffset: number = 0;
-                let lineNode: IXmlElement = nodeList.element("line");
-                if (lineNode !== undefined) {
-                    try {
-                        line = parseInt(lineNode.value, 10);
-                    } catch (ex) {
-                        errorMsg = ITextTranslation.translateText(
-                            "ReaderErrorMessages/ClefLineError",
-                            "Invalid clef line given -> using default clef line."
-                        );
-                        this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-                        line = 2;
-                        Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
-                    }
-
-                }
-                let signNode: IXmlElement = nodeList.element("sign");
-                if (signNode !== undefined) {
-                    try {
-                        clefEnum = ClefEnum[signNode.value];
-                        if (!ClefInstruction.isSupportedClef(clefEnum)) {
-                            if (clefEnum === ClefEnum.TAB && guitarPro) {
-                                clefOctaveOffset = -1;
-                            }
-                            errorMsg = ITextTranslation.translateText(
-                                "ReaderErrorMessages/ClefError",
-                                "Unsupported clef found -> using default clef."
-                            );
-                            this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-                            clefEnum = ClefEnum.G;
-                            line = 2;
-                        }
-                    } catch (e) {
-                        errorMsg = ITextTranslation.translateText(
-                            "ReaderErrorMessages/ClefError",
-                            "Invalid clef found -> using default clef."
-                        );
-                        this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-                        clefEnum = ClefEnum.G;
-                        line = 2;
-                        Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, e);
-                    }
+          } catch (e) {
+            errorMsg = ITextTranslation.translateText(
+              "ReaderErrorMessages/ClefError",
+              "Invalid clef found -> using default clef."
+            );
+            this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+            clefEnum = ClefEnum.G;
+            line = 2;
+            Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, e);
+          }
 
-                }
-                let clefOctaveNode: IXmlElement = nodeList.element("clef-octave-change");
-                if (clefOctaveNode !== undefined) {
-                    try {
-                        clefOctaveOffset = parseInt(clefOctaveNode.value, 10);
-                    } catch (e) {
-                        errorMsg = ITextTranslation.translateText(
-                            "ReaderErrorMessages/ClefOctaveError",
-                            "Invalid clef octave found -> using default clef octave."
-                        );
-                        this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-                        clefOctaveOffset = 0;
-                    }
+        }
+        let clefOctaveNode: IXmlElement = nodeList.element("clef-octave-change");
+        if (clefOctaveNode !== undefined) {
+          try {
+            clefOctaveOffset = parseInt(clefOctaveNode.value, 10);
+          } catch (e) {
+            errorMsg = ITextTranslation.translateText(
+              "ReaderErrorMessages/ClefOctaveError",
+              "Invalid clef octave found -> using default clef octave."
+            );
+            this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+            clefOctaveOffset = 0;
+          }
 
-                }
-                if (nodeList.hasAttributes && nodeList.attributes()[0].name === "number") {
-                    try {
-                        staffNumber = parseInt(nodeList.attributes()[0].value, 10);
-                    } catch (err) {
-                        errorMsg = ITextTranslation.translateText(
-                            "ReaderErrorMessages/ClefError",
-                            "Invalid clef found -> using default clef."
-                        );
-                        this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-                        staffNumber = 1;
-                    }
-                }
+        }
+        if (nodeList.hasAttributes && nodeList.attributes()[0].name === "number") {
+          try {
+            staffNumber = parseInt(nodeList.attributes()[0].value, 10);
+          } catch (err) {
+            errorMsg = ITextTranslation.translateText(
+              "ReaderErrorMessages/ClefError",
+              "Invalid clef found -> using default clef."
+            );
+            this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+            staffNumber = 1;
+          }
+        }
 
-                let clefInstruction: ClefInstruction = new ClefInstruction(clefEnum, clefOctaveOffset, line);
-                this.abstractInstructions.push([staffNumber, clefInstruction]);
-            }
+        let clefInstruction: ClefInstruction = new ClefInstruction(clefEnum, clefOctaveOffset, line);
+        this.abstractInstructions.push([staffNumber, clefInstruction]);
+      }
+    }
+    if (node.element("key") !== undefined && this.instrument.MidiInstrumentId !== MidiInstrument.Percussion) {
+      let key: number = 0;
+      let keyNode: IXmlElement = node.element("key").element("fifths");
+      if (keyNode !== undefined) {
+        try {
+          key = parseInt(keyNode.value, 10);
+        } catch (ex) {
+          errorMsg = ITextTranslation.translateText(
+            "ReaderErrorMessages/KeyError",
+            "Invalid key found -> set to default."
+          );
+          this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+          key = 0;
+          Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
         }
-        if (node.element("key") !== undefined && this.instrument.MidiInstrumentId !== MidiInstrument.Percussion) {
-            let key: number = 0;
-            let keyNode: IXmlElement = node.element("key").element("fifths");
-            if (keyNode !== undefined) {
-                try {
-                    key = parseInt(keyNode.value, 10);
-                } catch (ex) {
-                    errorMsg = ITextTranslation.translateText(
-                        "ReaderErrorMessages/KeyError",
-                        "Invalid key found -> set to default."
-                    );
-                    this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-                    key = 0;
-                    Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
-                }
 
-            }
-            let keyEnum: KeyEnum = KeyEnum.none;
-            let modeNode: IXmlElement = node.element("key");
-            if (modeNode !== undefined) {
-                modeNode = modeNode.element("mode");
-            }
-            if (modeNode !== undefined) {
-                try {
-                    keyEnum = KeyEnum[modeNode.value];
-                } catch (ex) {
-                    errorMsg = ITextTranslation.translateText(
-                        "ReaderErrorMessages/KeyError",
-                        "Invalid key found -> set to default."
-                    );
-                    this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-                    keyEnum = KeyEnum.major;
-                    Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
-                }
+      }
+      let keyEnum: KeyEnum = KeyEnum.none;
+      let modeNode: IXmlElement = node.element("key");
+      if (modeNode !== undefined) {
+        modeNode = modeNode.element("mode");
+      }
+      if (modeNode !== undefined) {
+        try {
+          keyEnum = KeyEnum[modeNode.value];
+        } catch (ex) {
+          errorMsg = ITextTranslation.translateText(
+            "ReaderErrorMessages/KeyError",
+            "Invalid key found -> set to default."
+          );
+          this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+          keyEnum = KeyEnum.major;
+          Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
+        }
 
-            }
-            let keyInstruction: KeyInstruction = new KeyInstruction(undefined, key, keyEnum);
-            this.abstractInstructions.push([1, keyInstruction]);
+      }
+      let keyInstruction: KeyInstruction = new KeyInstruction(undefined, key, keyEnum);
+      this.abstractInstructions.push([1, keyInstruction]);
+    }
+    if (node.element("time") !== undefined) {
+      let symbolEnum: RhythmSymbolEnum = RhythmSymbolEnum.NONE;
+      let timeNode: IXmlElement = node.element("time");
+      if (timeNode !== undefined && timeNode.hasAttributes) {
+        let firstAttr: IXmlAttribute = timeNode.firstAttribute;
+        if (firstAttr.name === "symbol") {
+          if (firstAttr.value === "common") {
+            symbolEnum = RhythmSymbolEnum.COMMON;
+          } else if (firstAttr.value === "cut") {
+            symbolEnum = RhythmSymbolEnum.CUT;
+          }
         }
-        if (node.element("time") !== undefined) {
-            let symbolEnum: RhythmSymbolEnum = RhythmSymbolEnum.NONE;
-            let timeNode: IXmlElement = node.element("time");
-            if (timeNode !== undefined && timeNode.hasAttributes) {
-                let firstAttr: IXmlAttribute = timeNode.firstAttribute;
-                if (firstAttr.name === "symbol") {
-                    if (firstAttr.value === "common") {
-                        symbolEnum = RhythmSymbolEnum.COMMON;
-                    } else if (firstAttr.value === "cut") {
-                        symbolEnum = RhythmSymbolEnum.CUT;
-                    }
+      }
+      let num: number = 0;
+      let denom: number = 0;
+      let senzaMisura: boolean = (timeNode !== undefined && timeNode.element("senza-misura") !== undefined);
+      let timeList: IXmlElement[] = node.elements("time");
+      let beatsList: IXmlElement[] = [];
+      let typeList: IXmlElement[] = [];
+      for (let idx: number = 0, len: number = timeList.length; idx < len; ++idx) {
+        let xmlNode: IXmlElement = timeList[idx];
+        beatsList.push.apply(beatsList, xmlNode.elements("beats"));
+        typeList.push.apply(typeList, xmlNode.elements("beat-type"));
+      }
+      if (!senzaMisura) {
+        try {
+          if (beatsList !== undefined && beatsList.length > 0 && typeList !== undefined && beatsList.length === typeList.length) {
+            let length: number = beatsList.length;
+            let fractions: Fraction[] = new Array(length);
+            let maxDenom: number = 0;
+            for (let i: number = 0; i < length; i++) {
+              let s: string = beatsList[i].value;
+              let n: number = 0;
+              let d: number = 0;
+              if (s.indexOf("+") !== -1) {
+                let numbers: string[] = s.split("+");
+                for (let idx: number = 0, len: number = numbers.length; idx < len; ++idx) {
+                  n += parseInt(numbers[idx], 10);
                 }
+              } else {
+                n = parseInt(s, 10);
+              }
+              d = parseInt(typeList[i].value, 10);
+              maxDenom = Math.max(maxDenom, d);
+              fractions[i] = new Fraction(n, d, 0, false);
             }
-            let num: number = 0;
-            let denom: number = 0;
-            let senzaMisura: boolean = (timeNode !== undefined && timeNode.element("senza-misura") !== undefined);
-            let timeList: IXmlElement[] = node.elements("time");
-            let beatsList: IXmlElement[] = [];
-            let typeList: IXmlElement[] = [];
-            for (let idx: number = 0, len: number = timeList.length; idx < len; ++idx) {
-                let xmlNode: IXmlElement = timeList[idx];
-                beatsList.push.apply(beatsList, xmlNode.elements("beats"));
-                typeList.push.apply(typeList, xmlNode.elements("beat-type"));
+            for (let i: number = 0; i < length; i++) {
+              if (fractions[i].Denominator === maxDenom) {
+                num += fractions[i].Numerator;
+              } else {
+                num += (maxDenom / fractions[i].Denominator) * fractions[i].Numerator;
+              }
             }
-            if (!senzaMisura) {
-                try {
-                    if (beatsList !== undefined && beatsList.length > 0 && typeList !== undefined && beatsList.length === typeList.length) {
-                        let length: number = beatsList.length;
-                        let fractions: Fraction[] = new Array(length);
-                        let maxDenom: number = 0;
-                        for (let i: number = 0; i < length; i++) {
-                            let s: string = beatsList[i].value;
-                            let n: number = 0;
-                            let d: number = 0;
-                            if (s.indexOf("+") !== -1) {
-                                let numbers: string[] = s.split("+");
-                                for (let idx: number = 0, len: number = numbers.length; idx < len; ++idx) {
-                                    n += parseInt(numbers[idx], 10);
-                                }
-                            } else {
-                                n = parseInt(s, 10);
-                            }
-                            d = parseInt(typeList[i].value, 10);
-                            maxDenom = Math.max(maxDenom, d);
-                            fractions[i] = new Fraction(n, d, false);
-                        }
-                        for (let i: number = 0; i < length; i++) {
-                            if (fractions[i].Denominator === maxDenom) {
-                                num += fractions[i].Numerator;
-                            } else {
-                                num += (maxDenom / fractions[i].Denominator) * fractions[i].Numerator;
-                            }
-                        }
-                        denom = maxDenom;
-                    } else {
-                        num = parseInt(node.element("time").element("beats").value, 10);
-                        denom = parseInt(node.element("time").element("beat-type").value, 10);
-                    }
-                } catch (ex) {
-                    errorMsg = ITextTranslation.translateText("ReaderErrorMessages/RhythmError", "Invalid rhythm found -> set to default.");
-                    this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
-                    num = 4;
-                    denom = 4;
-                    Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
-                }
+            denom = maxDenom;
+          } else {
+            num = parseInt(node.element("time").element("beats").value, 10);
+            denom = parseInt(node.element("time").element("beat-type").value, 10);
+          }
+        } catch (ex) {
+          errorMsg = ITextTranslation.translateText("ReaderErrorMessages/RhythmError", "Invalid rhythm found -> set to default.");
+          this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+          num = 4;
+          denom = 4;
+          Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
+        }
 
-                if ((num === 4 && denom === 4) || (num === 2 && denom === 2)) {
-                    symbolEnum = RhythmSymbolEnum.NONE;
-                }
-                this.abstractInstructions.push([1, new RhythmInstruction(
-                    new Fraction(num, denom, false), num, denom, symbolEnum
-                )]);
-            } else {
-                this.abstractInstructions.push([1, new RhythmInstruction(new Fraction(4, 4, false), 4, 4, RhythmSymbolEnum.NONE)]);
-            }
+        if ((num === 4 && denom === 4) || (num === 2 && denom === 2)) {
+          symbolEnum = RhythmSymbolEnum.NONE;
         }
+        this.abstractInstructions.push([1, new RhythmInstruction(
+          new Fraction(num, denom, 0, false), symbolEnum
+        )]);
+      } else {
+        this.abstractInstructions.push([1, new RhythmInstruction(new Fraction(4, 4, 0, false), RhythmSymbolEnum.NONE)]);
+      }
     }
+  }
 
-    /**
-     * Save the current AbstractInstructions to the corresponding [[StaffEntry]]s.
-     * @param numberOfStaves
-     * @param beginOfMeasure
-     */
-    private saveAbstractInstructionList(numberOfStaves: number, beginOfMeasure: boolean): void {
-        for (let i: number = this.abstractInstructions.length - 1; i >= 0; i--) {
-            let pair: [number, AbstractNotationInstruction] = this.abstractInstructions[i];
-            let key: number = pair[0];
-            let value: AbstractNotationInstruction = pair[1];
-            if (value instanceof ClefInstruction) {
-                let clefInstruction: ClefInstruction = <ClefInstruction>value;
-                if (this.currentXmlMeasureIndex === 0 || (key <= this.activeClefs.length && clefInstruction !== this.activeClefs[key - 1])) {
-                    if (!beginOfMeasure && this.currentStaffEntry !== undefined && !this.currentStaffEntry.hasNotes() && key - 1
-                        === this.instrument.Staves.indexOf(this.currentStaffEntry.ParentStaff)) {
-                        let newClefInstruction: ClefInstruction = clefInstruction;
-                        newClefInstruction.Parent = this.currentStaffEntry;
-                        this.currentStaffEntry.removeFirstInstructionOfTypeClefInstruction();
-                        this.currentStaffEntry.Instructions.push(newClefInstruction);
-                        this.activeClefs[key - 1] = clefInstruction;
-                        this.abstractInstructions.splice(i, 1);
-                    } else if (beginOfMeasure) {
-                        let firstStaffEntry: SourceStaffEntry;
-                        if (this.currentMeasure !== undefined) {
-                            let newClefInstruction: ClefInstruction = clefInstruction;
-                            let sseIndex: number = this.inSourceMeasureInstrumentIndex + key - 1;
-                            let firstSse: SourceStaffEntry = this.currentMeasure.FirstInstructionsStaffEntries[sseIndex];
-                            if (this.currentXmlMeasureIndex === 0) {
-                                if (firstSse === undefined) {
-                                    firstStaffEntry = new SourceStaffEntry(undefined, undefined);
-                                    this.currentMeasure.FirstInstructionsStaffEntries[sseIndex] = firstStaffEntry;
-                                    newClefInstruction.Parent = firstStaffEntry;
-                                    firstStaffEntry.Instructions.push(newClefInstruction);
-                                    this.activeClefsHaveBeenInitialized[key - 1] = true;
-                                } else if (this.currentMeasure.FirstInstructionsStaffEntries[sseIndex]
-                                    !==
-                                    undefined && !(firstSse.Instructions[0] instanceof ClefInstruction)) {
-                                    firstStaffEntry = firstSse;
-                                    newClefInstruction.Parent = firstStaffEntry;
-                                    firstStaffEntry.removeFirstInstructionOfTypeClefInstruction();
-                                    firstStaffEntry.Instructions.splice(0, 0, newClefInstruction);
-                                    this.activeClefsHaveBeenInitialized[key - 1] = true;
-                                } else {
-                                    let lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
-                                    this.currentMeasure.LastInstructionsStaffEntries[sseIndex] = lastStaffEntry;
-                                    newClefInstruction.Parent = lastStaffEntry;
-                                    lastStaffEntry.Instructions.push(newClefInstruction);
-                                }
-                            } else if (!this.activeClefsHaveBeenInitialized[key - 1]) {
-                                let first: SourceMeasure = this.musicSheet.SourceMeasures[0];
-                                if (first.FirstInstructionsStaffEntries[sseIndex] === undefined) {
-                                    firstStaffEntry = new SourceStaffEntry(undefined, undefined);
-                                } else {
-                                    firstStaffEntry = first.FirstInstructionsStaffEntries[sseIndex];
-                                    firstStaffEntry.removeFirstInstructionOfTypeClefInstruction();
-                                }
-                                newClefInstruction.Parent = firstStaffEntry;
-                                firstStaffEntry.Instructions.splice(0, 0, newClefInstruction);
-                                this.activeClefsHaveBeenInitialized[key - 1] = true;
-                            } else {
-                                let lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
-                                this.previousMeasure.LastInstructionsStaffEntries[sseIndex] = lastStaffEntry;
-                                newClefInstruction.Parent = lastStaffEntry;
-                                lastStaffEntry.Instructions.push(newClefInstruction);
-                            }
-                            this.activeClefs[key - 1] = clefInstruction;
-                            this.abstractInstructions.splice(i, 1);
-                        }
-                    }
-                } else if (key <= this.activeClefs.length && clefInstruction === this.activeClefs[key - 1]) {
-                    this.abstractInstructions.splice(i, 1);
+  /**
+   * Save the current AbstractInstructions to the corresponding [[StaffEntry]]s.
+   * @param numberOfStaves
+   * @param beginOfMeasure
+   */
+  private saveAbstractInstructionList(numberOfStaves: number, beginOfMeasure: boolean): void {
+    for (let i: number = this.abstractInstructions.length - 1; i >= 0; i--) {
+      let pair: [number, AbstractNotationInstruction] = this.abstractInstructions[i];
+      let key: number = pair[0];
+      let value: AbstractNotationInstruction = pair[1];
+      if (value instanceof ClefInstruction) {
+        let clefInstruction: ClefInstruction = <ClefInstruction>value;
+        if (this.currentXmlMeasureIndex === 0 || (key <= this.activeClefs.length && clefInstruction !== this.activeClefs[key - 1])) {
+          if (!beginOfMeasure && this.currentStaffEntry !== undefined && !this.currentStaffEntry.hasNotes() && key - 1
+            === this.instrument.Staves.indexOf(this.currentStaffEntry.ParentStaff)) {
+            let newClefInstruction: ClefInstruction = clefInstruction;
+            newClefInstruction.Parent = this.currentStaffEntry;
+            this.currentStaffEntry.removeFirstInstructionOfTypeClefInstruction();
+            this.currentStaffEntry.Instructions.push(newClefInstruction);
+            this.activeClefs[key - 1] = clefInstruction;
+            this.abstractInstructions.splice(i, 1);
+          } else if (beginOfMeasure) {
+            let firstStaffEntry: SourceStaffEntry;
+            if (this.currentMeasure !== undefined) {
+              let newClefInstruction: ClefInstruction = clefInstruction;
+              let sseIndex: number = this.inSourceMeasureInstrumentIndex + key - 1;
+              let firstSse: SourceStaffEntry = this.currentMeasure.FirstInstructionsStaffEntries[sseIndex];
+              if (this.currentXmlMeasureIndex === 0) {
+                if (firstSse === undefined) {
+                  firstStaffEntry = new SourceStaffEntry(undefined, undefined);
+                  this.currentMeasure.FirstInstructionsStaffEntries[sseIndex] = firstStaffEntry;
+                  newClefInstruction.Parent = firstStaffEntry;
+                  firstStaffEntry.Instructions.push(newClefInstruction);
+                  this.activeClefsHaveBeenInitialized[key - 1] = true;
+                } else if (this.currentMeasure.FirstInstructionsStaffEntries[sseIndex]
+                  !==
+                  undefined && !(firstSse.Instructions[0] instanceof ClefInstruction)) {
+                  firstStaffEntry = firstSse;
+                  newClefInstruction.Parent = firstStaffEntry;
+                  firstStaffEntry.removeFirstInstructionOfTypeClefInstruction();
+                  firstStaffEntry.Instructions.splice(0, 0, newClefInstruction);
+                  this.activeClefsHaveBeenInitialized[key - 1] = true;
+                } else {
+                  let lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
+                  this.currentMeasure.LastInstructionsStaffEntries[sseIndex] = lastStaffEntry;
+                  newClefInstruction.Parent = lastStaffEntry;
+                  lastStaffEntry.Instructions.push(newClefInstruction);
                 }
-            }
-            if (value instanceof KeyInstruction) {
-                let keyInstruction: KeyInstruction = <KeyInstruction>value;
-                if (this.activeKey === undefined || this.activeKey.Key !== keyInstruction.Key) {
-                    this.activeKey = keyInstruction;
-                    this.abstractInstructions.splice(i, 1);
-                    let sourceMeasure: SourceMeasure;
-                    if (!this.activeKeyHasBeenInitialized) {
-                        this.activeKeyHasBeenInitialized = true;
-                        if (this.currentXmlMeasureIndex > 0) {
-                            sourceMeasure = this.musicSheet.SourceMeasures[0];
-                        } else {
-                            sourceMeasure = this.currentMeasure;
-                        }
-                    } else {
-                        sourceMeasure = this.currentMeasure;
-                    }
-                    if (sourceMeasure !== undefined) {
-                        for (let j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + numberOfStaves; j++) {
-                            let newKeyInstruction: KeyInstruction = keyInstruction;
-                            if (sourceMeasure.FirstInstructionsStaffEntries[j] === undefined) {
-                                let firstStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
-                                sourceMeasure.FirstInstructionsStaffEntries[j] = firstStaffEntry;
-                                newKeyInstruction.Parent = firstStaffEntry;
-                                firstStaffEntry.Instructions.push(newKeyInstruction);
-                            } else {
-                                let firstStaffEntry: SourceStaffEntry = sourceMeasure.FirstInstructionsStaffEntries[j];
-                                newKeyInstruction.Parent = firstStaffEntry;
-                                firstStaffEntry.removeFirstInstructionOfTypeKeyInstruction();
-                                if (firstStaffEntry.Instructions.length === 0) {
-                                    firstStaffEntry.Instructions.push(newKeyInstruction);
-                                } else {
-                                    if (firstStaffEntry.Instructions[0] instanceof ClefInstruction) {
-                                        firstStaffEntry.Instructions.splice(1, 0, newKeyInstruction);
-                                    } else {
-                                        firstStaffEntry.Instructions.splice(0, 0, newKeyInstruction);
-                                    }
-                                }
-                            }
-                        }
-                    }
+              } else if (!this.activeClefsHaveBeenInitialized[key - 1]) {
+                let first: SourceMeasure = this.musicSheet.SourceMeasures[0];
+                if (first.FirstInstructionsStaffEntries[sseIndex] === undefined) {
+                  firstStaffEntry = new SourceStaffEntry(undefined, undefined);
                 } else {
-                    this.abstractInstructions.splice(i, 1);
+                  firstStaffEntry = first.FirstInstructionsStaffEntries[sseIndex];
+                  firstStaffEntry.removeFirstInstructionOfTypeClefInstruction();
                 }
+                newClefInstruction.Parent = firstStaffEntry;
+                firstStaffEntry.Instructions.splice(0, 0, newClefInstruction);
+                this.activeClefsHaveBeenInitialized[key - 1] = true;
+              } else {
+                let lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
+                this.previousMeasure.LastInstructionsStaffEntries[sseIndex] = lastStaffEntry;
+                newClefInstruction.Parent = lastStaffEntry;
+                lastStaffEntry.Instructions.push(newClefInstruction);
+              }
+              this.activeClefs[key - 1] = clefInstruction;
+              this.abstractInstructions.splice(i, 1);
+            }
+          }
+        } else if (key <= this.activeClefs.length && clefInstruction === this.activeClefs[key - 1]) {
+          this.abstractInstructions.splice(i, 1);
+        }
+      }
+      if (value instanceof KeyInstruction) {
+        let keyInstruction: KeyInstruction = <KeyInstruction>value;
+        if (this.activeKey === undefined || this.activeKey.Key !== keyInstruction.Key) {
+          this.activeKey = keyInstruction;
+          this.abstractInstructions.splice(i, 1);
+          let sourceMeasure: SourceMeasure;
+          if (!this.activeKeyHasBeenInitialized) {
+            this.activeKeyHasBeenInitialized = true;
+            if (this.currentXmlMeasureIndex > 0) {
+              sourceMeasure = this.musicSheet.SourceMeasures[0];
+            } else {
+              sourceMeasure = this.currentMeasure;
             }
-            if (value instanceof RhythmInstruction) {
-                let rhythmInstruction: RhythmInstruction = <RhythmInstruction>value;
-                if (this.activeRhythm === undefined || this.activeRhythm !== rhythmInstruction) {
-                    this.activeRhythm = rhythmInstruction;
-                    this.abstractInstructions.splice(i, 1);
-                    if (this.currentMeasure !== undefined) {
-                        for (let j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + numberOfStaves; j++) {
-                            let newRhythmInstruction: RhythmInstruction = rhythmInstruction;
-                            let firstStaffEntry: SourceStaffEntry;
-                            if (this.currentMeasure.FirstInstructionsStaffEntries[j] === undefined) {
-                                firstStaffEntry = new SourceStaffEntry(undefined, undefined);
-                                this.currentMeasure.FirstInstructionsStaffEntries[j] = firstStaffEntry;
-                            } else {
-                                firstStaffEntry = this.currentMeasure.FirstInstructionsStaffEntries[j];
-                                firstStaffEntry.removeFirstInstructionOfTypeRhythmInstruction();
-                            }
-                            newRhythmInstruction.Parent = firstStaffEntry;
-                            firstStaffEntry.Instructions.push(newRhythmInstruction);
-                        }
-                    }
+          } else {
+            sourceMeasure = this.currentMeasure;
+          }
+          if (sourceMeasure !== undefined) {
+            for (let j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + numberOfStaves; j++) {
+              let newKeyInstruction: KeyInstruction = keyInstruction;
+              if (sourceMeasure.FirstInstructionsStaffEntries[j] === undefined) {
+                let firstStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
+                sourceMeasure.FirstInstructionsStaffEntries[j] = firstStaffEntry;
+                newKeyInstruction.Parent = firstStaffEntry;
+                firstStaffEntry.Instructions.push(newKeyInstruction);
+              } else {
+                let firstStaffEntry: SourceStaffEntry = sourceMeasure.FirstInstructionsStaffEntries[j];
+                newKeyInstruction.Parent = firstStaffEntry;
+                firstStaffEntry.removeFirstInstructionOfTypeKeyInstruction();
+                if (firstStaffEntry.Instructions.length === 0) {
+                  firstStaffEntry.Instructions.push(newKeyInstruction);
                 } else {
-                    this.abstractInstructions.splice(i, 1);
+                  if (firstStaffEntry.Instructions[0] instanceof ClefInstruction) {
+                    firstStaffEntry.Instructions.splice(1, 0, newKeyInstruction);
+                  } else {
+                    firstStaffEntry.Instructions.splice(0, 0, newKeyInstruction);
+                  }
                 }
+              }
+            }
+          }
+        } else {
+          this.abstractInstructions.splice(i, 1);
+        }
+      }
+      if (value instanceof RhythmInstruction) {
+        let rhythmInstruction: RhythmInstruction = <RhythmInstruction>value;
+        if (this.activeRhythm === undefined || this.activeRhythm !== rhythmInstruction) {
+          this.activeRhythm = rhythmInstruction;
+          this.abstractInstructions.splice(i, 1);
+          if (this.currentMeasure !== undefined) {
+            for (let j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + numberOfStaves; j++) {
+              let newRhythmInstruction: RhythmInstruction = rhythmInstruction;
+              let firstStaffEntry: SourceStaffEntry;
+              if (this.currentMeasure.FirstInstructionsStaffEntries[j] === undefined) {
+                firstStaffEntry = new SourceStaffEntry(undefined, undefined);
+                this.currentMeasure.FirstInstructionsStaffEntries[j] = firstStaffEntry;
+              } else {
+                firstStaffEntry = this.currentMeasure.FirstInstructionsStaffEntries[j];
+                firstStaffEntry.removeFirstInstructionOfTypeRhythmInstruction();
+              }
+              newRhythmInstruction.Parent = firstStaffEntry;
+              firstStaffEntry.Instructions.push(newRhythmInstruction);
             }
+          }
+        } else {
+          this.abstractInstructions.splice(i, 1);
         }
+      }
     }
+  }
 
-    /**
-     * Save any ClefInstruction given - exceptionally - at the end of the currentMeasure.
-     */
-    private saveClefInstructionAtEndOfMeasure(): void {
-        for (let i: number = this.abstractInstructions.length - 1; i >= 0; i--) {
-            let key: number = this.abstractInstructions[i][0];
-            let value: AbstractNotationInstruction = this.abstractInstructions[i][1];
-            if (value instanceof ClefInstruction) {
-                let clefInstruction: ClefInstruction = <ClefInstruction>value;
-                if (
-                    (this.activeClefs[key - 1] === undefined) ||
-                    (clefInstruction.ClefType !== this.activeClefs[key - 1].ClefType || (
-                        clefInstruction.ClefType === this.activeClefs[key - 1].ClefType &&
-                        clefInstruction.Line !== this.activeClefs[key - 1].Line
-                    ))) {
-                    let lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
-                    this.currentMeasure.LastInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + key - 1] = lastStaffEntry;
-                    let newClefInstruction: ClefInstruction = clefInstruction;
-                    newClefInstruction.Parent = lastStaffEntry;
-                    lastStaffEntry.Instructions.push(newClefInstruction);
-                    this.activeClefs[key - 1] = clefInstruction;
-                    this.abstractInstructions.splice(i, 1);
-                }
-            }
+  /**
+   * Save any ClefInstruction given - exceptionally - at the end of the currentMeasure.
+   */
+  private saveClefInstructionAtEndOfMeasure(): void {
+    for (let i: number = this.abstractInstructions.length - 1; i >= 0; i--) {
+      let key: number = this.abstractInstructions[i][0];
+      let value: AbstractNotationInstruction = this.abstractInstructions[i][1];
+      if (value instanceof ClefInstruction) {
+        let clefInstruction: ClefInstruction = <ClefInstruction>value;
+        if (
+          (this.activeClefs[key - 1] === undefined) ||
+          (clefInstruction.ClefType !== this.activeClefs[key - 1].ClefType || (
+            clefInstruction.ClefType === this.activeClefs[key - 1].ClefType &&
+            clefInstruction.Line !== this.activeClefs[key - 1].Line
+          ))) {
+          let lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
+          this.currentMeasure.LastInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + key - 1] = lastStaffEntry;
+          let newClefInstruction: ClefInstruction = clefInstruction;
+          newClefInstruction.Parent = lastStaffEntry;
+          lastStaffEntry.Instructions.push(newClefInstruction);
+          this.activeClefs[key - 1] = clefInstruction;
+          this.abstractInstructions.splice(i, 1);
         }
+      }
     }
+  }
 
-    /**
-     * In case of a [[Tuplet]], read NoteDuration from type.
-     * @param xmlNode
-     * @returns {Fraction}
-     */
-    private getNoteDurationForTuplet(xmlNode: IXmlElement): Fraction {
-        let duration: Fraction = new Fraction(0, 1);
-        let typeDuration: Fraction = this.getNoteDurationFromTypeNode(xmlNode);
-        if (xmlNode.element("time-modification") !== undefined) {
-            let time: IXmlElement = xmlNode.element("time-modification");
-            if (time !== undefined) {
-                if (time.element("actual-notes") !== undefined && time.element("normal-notes") !== undefined) {
-                    let actualNotes: IXmlElement = time.element("actual-notes");
-                    let normalNotes: IXmlElement = time.element("normal-notes");
-                    if (actualNotes !== undefined && normalNotes !== undefined) {
-                        let actual: number = parseInt(actualNotes.value, 10);
-                        let normal: number = parseInt(normalNotes.value, 10);
-                        duration = new Fraction(normal * typeDuration.Numerator, actual * typeDuration.Denominator);
-                    }
-                }
-            }
+  /**
+   * In case of a [[Tuplet]], read NoteDuration from type.
+   * @param xmlNode
+   * @returns {Fraction}
+   */
+  private getNoteDurationForTuplet(xmlNode: IXmlElement): Fraction {
+    let duration: Fraction = new Fraction(0, 1);
+    let typeDuration: Fraction = this.getNoteDurationFromTypeNode(xmlNode);
+    if (xmlNode.element("time-modification") !== undefined) {
+      let time: IXmlElement = xmlNode.element("time-modification");
+      if (time !== undefined) {
+        if (time.element("actual-notes") !== undefined && time.element("normal-notes") !== undefined) {
+          let actualNotes: IXmlElement = time.element("actual-notes");
+          let normalNotes: IXmlElement = time.element("normal-notes");
+          if (actualNotes !== undefined && normalNotes !== undefined) {
+            let actual: number = parseInt(actualNotes.value, 10);
+            let normal: number = parseInt(normalNotes.value, 10);
+            duration = new Fraction(normal * typeDuration.Numerator, actual * typeDuration.Denominator);
+          }
         }
-        return duration;
+      }
     }
+    return duration;
+  }
 
-    //private readExpressionStaffNumber(xmlNode: IXmlElement): number {
-    //  let directionStaffNumber: number = 1;
-    //  if (xmlNode.element("staff") !== undefined) {
-    //    let staffNode: IXmlElement = xmlNode.element("staff");
-    //    if (staffNode !== undefined) {
-    //      try {
-    //        directionStaffNumber = parseInt(staffNode.value, 10);
-    //      } catch (ex) {
-    //        let errorMsg: string = ITextTranslation.translateText(
-    //          "ReaderErrorMessages/ExpressionStaffError", "Invalid Expression staff number -> set to default."
-    //        );
-    //        this.musicSheet.SheetErrors.pushTemp(errorMsg);
-    //        directionStaffNumber = 1;
-    //        logging.debug("InstrumentReader.readExpressionStaffNumber", errorMsg, ex);
-    //      }
-    //
-    //    }
-    //  }
-    //  return directionStaffNumber;
-    //}
+  //private readExpressionStaffNumber(xmlNode: IXmlElement): number {
+  //  let directionStaffNumber: number = 1;
+  //  if (xmlNode.element("staff") !== undefined) {
+  //    let staffNode: IXmlElement = xmlNode.element("staff");
+  //    if (staffNode !== undefined) {
+  //      try {
+  //        directionStaffNumber = parseInt(staffNode.value, 10);
+  //      } catch (ex) {
+  //        let errorMsg: string = ITextTranslation.translateText(
+  //          "ReaderErrorMessages/ExpressionStaffError", "Invalid Expression staff number -> set to default."
+  //        );
+  //        this.musicSheet.SheetErrors.pushTemp(errorMsg);
+  //        directionStaffNumber = 1;
+  //        logging.debug("InstrumentReader.readExpressionStaffNumber", errorMsg, ex);
+  //      }
+  //
+  //    }
+  //  }
+  //  return directionStaffNumber;
+  //}
 
-    /**
-     * Calculate the divisions value from the type and duration of the first MeasureNote that makes sense
-     * (meaning itself hasn't any errors and it doesn't belong to a [[Tuplet]]).
-     *
-     * If all the MeasureNotes belong to a [[Tuplet]], then we read the next XmlMeasure (and so on...).
-     * If we have reached the end of the [[Instrument]] and still the divisions aren't set, we throw an exception
-     * @returns {number}
-     */
-    private readDivisionsFromNotes(): number {
-        let divisionsFromNote: number = 0;
-        let xmlMeasureIndex: number = this.currentXmlMeasureIndex;
-        let read: boolean = false;
-        while (!read) {
-            let xmlMeasureListArr: IXmlElement[] = this.xmlMeasureList[xmlMeasureIndex].elements();
-            for (let idx: number = 0, len: number = xmlMeasureListArr.length; idx < len; ++idx) {
-                let xmlNode: IXmlElement = xmlMeasureListArr[idx];
-                if (xmlNode.name === "note" && xmlNode.element("time-modification") === undefined) {
-                    if (xmlNode.element("duration") !== undefined && xmlNode.element("type") !== undefined) {
-                        let durationNode: IXmlElement = xmlNode.element("duration");
-                        let typeNode: IXmlElement = xmlNode.element("type");
-                        if (durationNode !== undefined && typeNode !== undefined) {
-                            let type: string = typeNode.value;
-                            let noteDuration: number = 0;
-                            try {
-                                noteDuration = parseInt(durationNode.value, 10);
-                            } catch (ex) {
-                                Logging.debug("InstrumentReader.readDivisionsFromNotes", ex);
-                                continue;
-                            }
+  /**
+   * Calculate the divisions value from the type and duration of the first MeasureNote that makes sense
+   * (meaning itself hasn't any errors and it doesn't belong to a [[Tuplet]]).
+   *
+   * If all the MeasureNotes belong to a [[Tuplet]], then we read the next XmlMeasure (and so on...).
+   * If we have reached the end of the [[Instrument]] and still the divisions aren't set, we throw an exception
+   * @returns {number}
+   */
+  private readDivisionsFromNotes(): number {
+    let divisionsFromNote: number = 0;
+    let xmlMeasureIndex: number = this.currentXmlMeasureIndex;
+    let read: boolean = false;
+    while (!read) {
+      let xmlMeasureListArr: IXmlElement[] = this.xmlMeasureList[xmlMeasureIndex].elements();
+      for (let idx: number = 0, len: number = xmlMeasureListArr.length; idx < len; ++idx) {
+        let xmlNode: IXmlElement = xmlMeasureListArr[idx];
+        if (xmlNode.name === "note" && xmlNode.element("time-modification") === undefined) {
+          if (xmlNode.element("duration") !== undefined && xmlNode.element("type") !== undefined) {
+            let durationNode: IXmlElement = xmlNode.element("duration");
+            let typeNode: IXmlElement = xmlNode.element("type");
+            if (durationNode !== undefined && typeNode !== undefined) {
+              let type: string = typeNode.value;
+              let noteDuration: number = 0;
+              try {
+                noteDuration = parseInt(durationNode.value, 10);
+              } catch (ex) {
+                Logging.debug("InstrumentReader.readDivisionsFromNotes", ex);
+                continue;
+              }
 
-                            switch (type) {
-                                case "1024th":
-                                    divisionsFromNote = (noteDuration / 4) * 1024;
-                                    break;
-                                case "512th":
-                                    divisionsFromNote = (noteDuration / 4) * 512;
-                                    break;
-                                case "256th":
-                                    divisionsFromNote = (noteDuration / 4) * 256;
-                                    break;
-                                case "128th":
-                                    divisionsFromNote = (noteDuration / 4) * 128;
-                                    break;
-                                case "64th":
-                                    divisionsFromNote = (noteDuration / 4) * 64;
-                                    break;
-                                case "32nd":
-                                    divisionsFromNote = (noteDuration / 4) * 32;
-                                    break;
-                                case "16th":
-                                    divisionsFromNote = (noteDuration / 4) * 16;
-                                    break;
-                                case "eighth":
-                                    divisionsFromNote = (noteDuration / 4) * 8;
-                                    break;
-                                case "quarter":
-                                    divisionsFromNote = (noteDuration / 4) * 4;
-                                    break;
-                                case "half":
-                                    divisionsFromNote = (noteDuration / 4) * 2;
-                                    break;
-                                case "whole":
-                                    divisionsFromNote = (noteDuration / 4);
-                                    break;
-                                case "breve":
-                                    divisionsFromNote = (noteDuration / 4) / 2;
-                                    break;
-                                case "long":
-                                    divisionsFromNote = (noteDuration / 4) / 4;
-                                    break;
-                                case "maxima":
-                                    divisionsFromNote = (noteDuration / 4) / 8;
-                                    break;
-                                default:
-                                    break;
-                            }
-                        }
-                    }
-                }
-                if (divisionsFromNote > 0) {
-                    read = true;
-                    break;
-                }
-            }
-            if (divisionsFromNote === 0) {
-                xmlMeasureIndex++;
-                if (xmlMeasureIndex === this.xmlMeasureList.length) {
-                    let errorMsg: string = ITextTranslation.translateText("ReaderErrorMEssages/DivisionsError", "Invalid divisions value at Instrument: ");
-                    throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
-                }
+              switch (type) {
+                case "1024th":
+                  divisionsFromNote = (noteDuration / 4) * 1024;
+                  break;
+                case "512th":
+                  divisionsFromNote = (noteDuration / 4) * 512;
+                  break;
+                case "256th":
+                  divisionsFromNote = (noteDuration / 4) * 256;
+                  break;
+                case "128th":
+                  divisionsFromNote = (noteDuration / 4) * 128;
+                  break;
+                case "64th":
+                  divisionsFromNote = (noteDuration / 4) * 64;
+                  break;
+                case "32nd":
+                  divisionsFromNote = (noteDuration / 4) * 32;
+                  break;
+                case "16th":
+                  divisionsFromNote = (noteDuration / 4) * 16;
+                  break;
+                case "eighth":
+                  divisionsFromNote = (noteDuration / 4) * 8;
+                  break;
+                case "quarter":
+                  divisionsFromNote = (noteDuration / 4) * 4;
+                  break;
+                case "half":
+                  divisionsFromNote = (noteDuration / 4) * 2;
+                  break;
+                case "whole":
+                  divisionsFromNote = (noteDuration / 4);
+                  break;
+                case "breve":
+                  divisionsFromNote = (noteDuration / 4) / 2;
+                  break;
+                case "long":
+                  divisionsFromNote = (noteDuration / 4) / 4;
+                  break;
+                case "maxima":
+                  divisionsFromNote = (noteDuration / 4) / 8;
+                  break;
+                default:
+                  break;
+              }
             }
+          }
+        }
+        if (divisionsFromNote > 0) {
+          read = true;
+          break;
+        }
+      }
+      if (divisionsFromNote === 0) {
+        xmlMeasureIndex++;
+        if (xmlMeasureIndex === this.xmlMeasureList.length) {
+          let errorMsg: string = ITextTranslation.translateText("ReaderErrorMEssages/DivisionsError", "Invalid divisions value at Instrument: ");
+          throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
         }
-        return divisionsFromNote;
+      }
     }
+    return divisionsFromNote;
+  }
 }

+ 3 - 3
src/MusicalScore/ScoreIO/MusicSheetReader.ts

@@ -279,7 +279,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
             }
         }
         if (rhythmInstructions.length === 0 && this.currentMeasure === this.musicSheet.SourceMeasures[0]) {
-            let rhythmInstruction: RhythmInstruction = new RhythmInstruction(new Fraction(4, 4, false), 4, 4, RhythmSymbolEnum.NONE);
+            let rhythmInstruction: RhythmInstruction = new RhythmInstruction(new Fraction(4, 4, 0, false), RhythmSymbolEnum.NONE);
             for (let i: number = 0; i < this.completeNumberOfStaves; i++) {
                 if (this.currentMeasure.FirstInstructionsStaffEntries[i] === undefined) {
                     this.currentMeasure.FirstInstructionsStaffEntries[i] = new SourceStaffEntry(undefined, undefined);
@@ -345,7 +345,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
             instrumentsMaxTieNoteFractions.push(instrumentReader.MaxTieNoteFraction);
             let activeRythmMeasure: Fraction = instrumentReader.ActiveRhythm.Rhythm;
             if (activeRhythm.lt(activeRythmMeasure)) {
-                activeRhythm = new Fraction(activeRythmMeasure.Numerator, activeRythmMeasure.Denominator, false);
+                activeRhythm = new Fraction(activeRythmMeasure.Numerator, activeRythmMeasure.Denominator, 0, false);
             }
         }
         let instrumentsDurations: Fraction[] = this.currentMeasure.calculateInstrumentsDuration(this.musicSheet, instrumentsMaxTieNoteFractions);
@@ -400,7 +400,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
     private checkFractionsForEquivalence(maxInstrumentDuration: Fraction, activeRhythm: Fraction): void {
         if (activeRhythm.Denominator > maxInstrumentDuration.Denominator) {
             let factor: number = activeRhythm.Denominator / maxInstrumentDuration.Denominator;
-            maxInstrumentDuration.multiplyWithFactor(factor);
+            maxInstrumentDuration.expand(factor);
         }
     }
 

+ 145 - 0
src/MusicalScore/ScoreIO/MusicSymbolModules/ChordSymbolReader.ts

@@ -0,0 +1,145 @@
+import {IXmlElement} from "../../../Common/FileIO/Xml";
+import {MusicSheet} from "../../MusicSheet";
+import {ChordDegreeText, ChordSymbolContainer, ChordSymbolEnum, Degree} from "../../VoiceData/ChordSymbolContainer";
+import {AccidentalEnum, NoteEnum, Pitch} from "../../../Common/DataObjects/Pitch";
+import {KeyInstruction} from "../../VoiceData/Instructions/KeyInstruction";
+import {ITextTranslation} from "../../Interfaces/ITextTranslation";
+import {Logging} from "../../../Common/Logging";
+export class ChordSymbolReader {
+    public static readChordSymbol(xmlNode: IXmlElement, musicSheet: MusicSheet, activeKey: KeyInstruction): ChordSymbolContainer {
+        let root: IXmlElement = xmlNode.element("root");
+        let kind: IXmlElement = xmlNode.element("kind");
+
+        // must be always present
+        if (root === undefined || kind === undefined) {
+          return undefined;
+        }
+
+        let rootStep: IXmlElement = root.element("root-step");
+        let rootAlter: IXmlElement = root.element("root-alter");
+
+        // a valid NoteEnum value should be present
+        if (rootStep === undefined) {
+            return undefined;
+        }
+        let rootNote: NoteEnum;
+        try {
+            rootNote = NoteEnum[rootStep.value.trim()];
+        } catch (ex) {
+            let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                  "Invalid chord symbol");
+            musicSheet.SheetErrors.pushMeasureError(errorMsg);
+            Logging.error(LogLevel.DEBUG, "InstrumentReader.readChordSymbol", errorMsg, ex);
+            return undefined;
+        }
+
+        // an alteration value isn't necessary
+        let rootAlteration: AccidentalEnum = AccidentalEnum.NONE;
+        if (rootAlter !== undefined) {
+            try {
+                rootAlteration = <AccidentalEnum>parseInt(rootAlter.value, undefined);
+            } catch (ex) {
+                let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                      "Invalid chord symbol");
+                musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                Logging.error(LogLevel.DEBUG, "InstrumentReader.readChordSymbol", errorMsg, ex);
+            }
+
+        }
+        // using default octave value, to be changed later
+        let rootPitch: Pitch = new Pitch(rootNote, 1, rootAlteration);
+        let kindValue: string = kind.value.trim().replace("-", "");
+        let chordKind: ChordSymbolEnum;
+        try {
+            chordKind = ChordSymbolEnum[kindValue];
+        } catch (ex) {
+            let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                  "Invalid chord symbol");
+            musicSheet.SheetErrors.pushMeasureError(errorMsg);
+            Logging.error(LogLevel.DEBUG, "InstrumentReader.readChordSymbol", errorMsg, ex);
+            return undefined;
+        }
+
+        // bass is optional
+        let bassPitch: Pitch = undefined;
+        let bass: IXmlElement = xmlNode.element("bass");
+        if (bass !== undefined) {
+            let bassStep: IXmlElement = bass.element("bass-step");
+            let bassAlter: IXmlElement = bass.element("bass-alter");
+            let bassNote: NoteEnum = NoteEnum.C;
+            if (bassStep !== undefined) {
+                try {
+                    bassNote = NoteEnum[bassStep.value.trim()];
+                } catch (ex) {
+                    let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                          "Invalid chord symbol");
+                    musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                    Logging.error(LogLevel.DEBUG, "InstrumentReader.readChordSymbol", errorMsg, ex);
+                    return undefined;
+                }
+
+            }
+            let bassAlteration: AccidentalEnum = AccidentalEnum.NONE;
+            if (bassAlter !== undefined) {
+                try {
+                    bassAlteration = <AccidentalEnum>parseInt(bassAlter.value, undefined);
+                } catch (ex) {
+                    let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                          "Invalid chord symbol");
+                    musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                    Logging.error(LogLevel.DEBUG, "InstrumentReader.readChordSymbol", errorMsg, ex);
+                }
+
+            }
+            bassPitch = new Pitch(bassNote, 1, bassAlteration);
+        }
+
+        // degree is optional
+        let degree: Degree = undefined;
+        let degreeNode: IXmlElement = xmlNode.element("degree");
+        if (degreeNode !== undefined) {
+            let degreeValue: IXmlElement = degreeNode.element("degree-value");
+            let degreeAlter: IXmlElement = degreeNode.element("degree-alter");
+            let degreeType: IXmlElement = degreeNode.element("degree-type");
+            if (degreeValue === undefined || degreeAlter === undefined || degreeType === undefined) {
+              return undefined;
+            }
+
+            let value: number;
+            try {
+                value = parseInt(degreeValue.value.trim(), undefined);
+            } catch (ex) {
+                let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                      "Invalid chord symbol");
+                musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                Logging.error(LogLevel.DEBUG, "InstrumentReader.readChordSymbol", errorMsg, ex);
+                return undefined;
+            }
+
+            let alter: AccidentalEnum;
+            try {
+                alter = <AccidentalEnum>parseInt(degreeAlter.value, undefined);
+            } catch (ex) {
+                let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                      "Invalid chord symbol");
+                musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                Logging.error(LogLevel.DEBUG, "InstrumentReader.readChordSymbol", errorMsg, ex);
+                return undefined;
+            }
+
+            let text: ChordDegreeText;
+            try {
+                text = ChordDegreeText[degreeType.value.trim().toLowerCase()];
+            } catch (ex) {
+                let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                      "Invalid chord symbol");
+                musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                Logging.error(LogLevel.DEBUG, "InstrumentReader.readChordSymbol", errorMsg, ex);
+                return undefined;
+            }
+
+            degree = new Degree(value, alter, text);
+        }
+        return new ChordSymbolContainer(rootPitch, chordKind, bassPitch, degree, activeKey);
+    }
+}

+ 7 - 7
src/MusicalScore/ScoreIO/VoiceGenerator.ts

@@ -106,7 +106,7 @@ export class VoiceGenerator {
      * @returns {Note}
      */
     public read(
-        noteNode: IXmlElement, noteDuration: number, divisions: number, restNote: boolean, graceNote: boolean,
+        noteNode: IXmlElement, noteDuration: Fraction, restNote: boolean, graceNote: boolean,
         parentStaffEntry: SourceStaffEntry, parentMeasure: SourceMeasure,
         measureStartAbsoluteTimestamp: Fraction, maxTieNoteFraction: Fraction, chord: boolean, guitarPro: boolean
     ): Note {
@@ -115,8 +115,8 @@ export class VoiceGenerator {
         //Logging.debug("read called:", restNote);
         try {
             this.currentNote = restNote
-                ? this.addRestNote(noteDuration, divisions)
-                : this.addSingleNote(noteNode, noteDuration, divisions, graceNote, chord, guitarPro);
+                ? this.addRestNote(noteDuration)
+                : this.addSingleNote(noteNode, noteDuration, graceNote, chord, guitarPro);
             // (*)
             //if (this.lyricsReader !== undefined && noteNode.element("lyric") !== undefined) {
             //    this.lyricsReader.addLyricEntry(noteNode, this.currentVoiceEntry);
@@ -321,7 +321,7 @@ export class VoiceGenerator {
      * @returns {Note}
      */
     private addSingleNote(
-        node: IXmlElement, noteDuration: number, divisions: number, graceNote: boolean, chord: boolean, guitarPro: boolean
+        node: IXmlElement, noteDuration: Fraction, graceNote: boolean, chord: boolean, guitarPro: boolean
     ): Note {
         //Logging.debug("addSingleNote called");
         let noteAlter: AccidentalEnum = AccidentalEnum.NONE;
@@ -396,7 +396,7 @@ export class VoiceGenerator {
 
         noteOctave -= Pitch.OctaveXmlDifference;
         let pitch: Pitch = new Pitch(noteStep, noteOctave, noteAlter);
-        let noteLength: Fraction = new Fraction(noteDuration, divisions);
+        let noteLength: Fraction = Fraction.createFromFraction(noteDuration);
         let note: Note = new Note(this.currentVoiceEntry, this.currentStaffEntry, noteLength, pitch);
         note.PlaybackInstrumentId = playbackInstrumentId;
         if (!graceNote) {
@@ -416,8 +416,8 @@ export class VoiceGenerator {
      * @param divisions
      * @returns {Note}
      */
-    private addRestNote(noteDuration: number, divisions: number): Note {
-        let restFraction: Fraction = new Fraction(noteDuration, divisions);
+    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) {

+ 4 - 4
src/MusicalScore/VoiceData/Instructions/RhythmInstruction.ts

@@ -5,11 +5,11 @@ import {Fraction} from "../../../Common/DataObjects/Fraction";
  * A [[RhythmInstruction]] is the time signature which specifies the number of beats in each bar, and the value of one beat.
  */
 export class RhythmInstruction extends AbstractNotationInstruction {
-    constructor(rhythm: Fraction, numerator: number, denominator: number, rhythmSymbolEnum: RhythmSymbolEnum) {
+    constructor(rhythm: Fraction, rhythmSymbolEnum: RhythmSymbolEnum) {
         super(undefined); // FIXME no parent SourceStaffEntry
         this.rhythm = rhythm;
-        this.numerator = numerator;
-        this.denominator = denominator;
+        this.numerator = rhythm.Numerator;
+        this.denominator = rhythm.Denominator;
         this.symbolEnum = rhythmSymbolEnum;
     }
 
@@ -35,7 +35,7 @@ export class RhythmInstruction extends AbstractNotationInstruction {
     }
 
     public clone(): RhythmInstruction {
-        return new RhythmInstruction(this.rhythm.clone(), this.numerator, this.denominator, this.symbolEnum);
+        return new RhythmInstruction(this.rhythm.clone(), this.symbolEnum);
     }
 
     public OperatorEquals(rhythm2: RhythmInstruction): boolean {

+ 133 - 133
src/OSMD/Cursor.ts

@@ -10,150 +10,150 @@ import {GraphicalMusicSheet} from "../MusicalScore/Graphical/GraphicalMusicSheet
  * A cursor which can iterate through the music sheet.
  */
 export class Cursor {
-    constructor(container: HTMLElement, osmd: OSMD) {
-        this.container = container;
-        this.osmd = osmd;
-        let curs: HTMLElement = document.createElement("img");
-        curs.style.position = "absolute";
-        curs.style.zIndex = "-1";
-        this.cursorElement = <HTMLImageElement>curs;
-        container.appendChild(curs);
-    }
+  constructor(container: HTMLElement, osmd: OSMD) {
+    this.container = container;
+    this.osmd = osmd;
+    let curs: HTMLElement = document.createElement("img");
+    curs.style.position = "absolute";
+    curs.style.zIndex = "-1";
+    this.cursorElement = <HTMLImageElement>curs;
+    container.appendChild(curs);
+  }
 
-    private container: HTMLElement;
-    private osmd: OSMD;
-    private manager: MusicPartManager;
-    private iterator: MusicPartManagerIterator;
-    private graphic: GraphicalMusicSheet;
-    private hidden: boolean = true;
-    private cursorElement: HTMLImageElement;
+  private container: HTMLElement;
+  private osmd: OSMD;
+  private manager: MusicPartManager;
+  private iterator: MusicPartManagerIterator;
+  private graphic: GraphicalMusicSheet;
+  private hidden: boolean = true;
+  private cursorElement: HTMLImageElement;
 
-    public init(manager: MusicPartManager, graphic: GraphicalMusicSheet): void {
-        this.manager = manager;
-        this.reset();
-        this.graphic = graphic;
-        this.hidden = true;
-        this.hide();
-    }
+  public init(manager: MusicPartManager, graphic: GraphicalMusicSheet): void {
+    this.manager = manager;
+    this.reset();
+    this.graphic = graphic;
+    this.hidden = true;
+    this.hide();
+  }
+
+  /**
+   * Make the cursor visible
+   */
+  public show(): void {
+    this.hidden = false;
+    this.update();
+    // Forcing the sheet to re-render is not necessary anymore,
+    // since the cursor is an HTML element.
+    // this.osmd.render();
+  }
 
-    /**
-     * Make the cursor visible
-     */
-    public show(): void {
-        this.hidden = false;
-        this.update();
-        // Forcing the sheet to re-render is not necessary anymore,
-        // since the cursor is an HTML element.
-        // this.osmd.render();
+  public update(): void {
+    // Warning! This should NEVER call this.osmd.render()
+    if (this.hidden) {
+      return;
     }
+    this.graphic.Cursors.length = 0;
+    let iterator: MusicPartManagerIterator = this.iterator;
+    if (iterator.EndReached || iterator.CurrentVoiceEntries === undefined || iterator.CurrentVoiceEntries.length === 0) {
+      return;
+    }
+    let x: number = 0, y: number = 0, height: number = 0;
 
-    public update(): void {
-        // Warning! This should NEVER call this.osmd.render()
-        if (this.hidden) {
-            return;
-        }
-        this.graphic.Cursors.length = 0;
-        let iterator: MusicPartManagerIterator = this.iterator;
-        if  (iterator.EndReached || iterator.CurrentVoiceEntries === undefined) {
-            return;
-        }
-        let x: number = 0, y: number = 0, height: number = 0;
-        for (let idx: number = 0, len: number = iterator.CurrentVoiceEntries.length; idx < len; ++idx) {
-            let voiceEntry: VoiceEntry = iterator.CurrentVoiceEntries[idx];
-            let measureIndex: number = voiceEntry.ParentSourceStaffEntry.VerticalContainerParent.ParentMeasure.measureListIndex;
-            let staffIndex: number = voiceEntry.ParentSourceStaffEntry.ParentStaff.idInMusicSheet;
-            let gse: VexFlowStaffEntry =
-                <VexFlowStaffEntry>this.graphic.findGraphicalStaffEntryFromMeasureList(staffIndex, measureIndex, voiceEntry.ParentSourceStaffEntry);
-            if (idx === 0) {
-                x = gse.getX();
-                let musicSystem: MusicSystem = gse.parentMeasure.parentMusicSystem;
-                y = musicSystem.PositionAndShape.AbsolutePosition.y + musicSystem.StaffLines[0].PositionAndShape.RelativePosition.y;
-                let endY: number = musicSystem.PositionAndShape.AbsolutePosition.y +
-                    musicSystem.StaffLines[musicSystem.StaffLines.length - 1].PositionAndShape.RelativePosition.y + 4.0;
-                height = endY - y;
-            }
-            // The following code is not necessary (for now, but it could come useful later):
-            // it highlights the notes under the cursor.
-            //let vfNotes: { [voiceID: number]: Vex.Flow.StaveNote; } = gse.vfNotes;
-            //for (let voiceId in vfNotes) {
-            //    if (vfNotes.hasOwnProperty(voiceId)) {
-            //        vfNotes[voiceId].setStyle({
-            //            fillStyle: "red",
-            //            strokeStyle: "red",
-            //        });
-            //    }
-            //}
-        }
-        // Update the graphical cursor
-        // The following is the legacy cursor rendered on the canvas:
-        // // let cursor: GraphicalLine = new GraphicalLine(new PointF2D(x, y), new PointF2D(x, y + height), 3, OutlineAndFillStyleEnum.PlaybackCursor);
+    let voiceEntry: VoiceEntry = iterator.CurrentVoiceEntries[0];
+    let measureIndex: number = voiceEntry.ParentSourceStaffEntry.VerticalContainerParent.ParentMeasure.measureListIndex;
+    let staffIndex: number = voiceEntry.ParentSourceStaffEntry.ParentStaff.idInMusicSheet;
+    let gse: VexFlowStaffEntry =
+      <VexFlowStaffEntry>this.graphic.findGraphicalStaffEntryFromMeasureList(staffIndex, measureIndex, voiceEntry.ParentSourceStaffEntry);
 
-        // This the current HTML Cursor:
-        let cursorElement: HTMLImageElement = this.cursorElement;
-        cursorElement.style.top = (y * 10.0 * this.osmd.zoom) + "px";
-        cursorElement.style.left = ((x - 1.5) * 10.0 * this.osmd.zoom) + "px";
-        cursorElement.height = (height * 10.0 * this.osmd.zoom);
-        let newWidth: number = 3 * 10.0 * this.osmd.zoom;
-        if (newWidth !== cursorElement.width) {
-            cursorElement.width = newWidth;
-            this.updateStyle(newWidth);
-        }
+    x = gse.PositionAndShape.AbsolutePosition.x;
+    let musicSystem: MusicSystem = gse.parentMeasure.parentMusicSystem;
+    y = musicSystem.PositionAndShape.AbsolutePosition.y + musicSystem.StaffLines[0].PositionAndShape.RelativePosition.y;
+    let endY: number = musicSystem.PositionAndShape.AbsolutePosition.y +
+      musicSystem.StaffLines[musicSystem.StaffLines.length - 1].PositionAndShape.RelativePosition.y + 4.0;
+    height = endY - y;
 
-        // Show cursor
-        // // Old cursor: this.graphic.Cursors.push(cursor);
-        this.cursorElement.style.display = "";
-    }
+    // The following code is not necessary (for now, but it could come useful later):
+    // it highlights the notes under the cursor.
+    //let vfNotes: { [voiceID: number]: Vex.Flow.StaveNote; } = gse.vfNotes;
+    //for (let voiceId in vfNotes) {
+    //    if (vfNotes.hasOwnProperty(voiceId)) {
+    //        vfNotes[voiceId].setStyle({
+    //            fillStyle: "red",
+    //            strokeStyle: "red",
+    //        });
+    //    }
+    //}
 
-    /**
-     * Hide the cursor
-     */
-    public hide(): void {
-        // Hide the actual cursor element
-        this.cursorElement.style.display = "none";
-        //this.graphic.Cursors.length = 0;
-        // Forcing the sheet to re-render is not necessary anymore
-        //if (!this.hidden) {
-        //    this.osmd.render();
-        //}
-        this.hidden = true;
-    }
+    // Update the graphical cursor
+    // The following is the legacy cursor rendered on the canvas:
+    // // let cursor: GraphicalLine = new GraphicalLine(new PointF2D(x, y), new PointF2D(x, y + height), 3, OutlineAndFillStyleEnum.PlaybackCursor);
 
-    /**
-     * Go to next entry
-     */
-    public next(): void {
-        this.iterator.moveToNext();
-        if (!this.hidden) {
-            this.show();
-        }
+    // This the current HTML Cursor:
+    let cursorElement: HTMLImageElement = this.cursorElement;
+    cursorElement.style.top = (y * 10.0 * this.osmd.zoom) + "px";
+    cursorElement.style.left = ((x - 1.5) * 10.0 * this.osmd.zoom) + "px";
+    cursorElement.height = (height * 10.0 * this.osmd.zoom);
+    let newWidth: number = 3 * 10.0 * this.osmd.zoom;
+    if (newWidth !== cursorElement.width) {
+      cursorElement.width = newWidth;
+      this.updateStyle(newWidth);
     }
 
-    /**
-     * Go to next entry
-     */
-    public reset(): void {
-        this.iterator = this.manager.getIterator();
-        this.iterator.moveToNext();
-        this.update();
-    }
+    // Show cursor
+    // // Old cursor: this.graphic.Cursors.push(cursor);
+    this.cursorElement.style.display = "";
+  }
+
+  /**
+   * Hide the cursor
+   */
+  public hide(): void {
+    // Hide the actual cursor element
+    this.cursorElement.style.display = "none";
+    //this.graphic.Cursors.length = 0;
+    // Forcing the sheet to re-render is not necessary anymore
+    //if (!this.hidden) {
+    //    this.osmd.render();
+    //}
+    this.hidden = true;
+  }
 
-    private updateStyle(width: number, color: string = "#33e02f"): void {
-        // Create a dummy canvas to generate the gradient for the cursor
-        // FIXME This approach needs to be improved
-        let c: HTMLCanvasElement = document.createElement("canvas");
-        c.width = this.cursorElement.width;
-        c.height = 1;
-        let ctx: CanvasRenderingContext2D = c.getContext("2d");
-        ctx.globalAlpha = 0.5;
-        // Generate the gradient
-        let gradient: CanvasGradient = ctx.createLinearGradient(0, 0, this.cursorElement.width, 0);
-        gradient.addColorStop(0, "white"); // it was: "transparent"
-        gradient.addColorStop(0.2, color);
-        gradient.addColorStop(0.8, color);
-        gradient.addColorStop(1, "white"); // it was: "transparent"
-        ctx.fillStyle = gradient;
-        ctx.fillRect(0, 0, width, 1);
-        // Set the actual image
-        this.cursorElement.src = c.toDataURL("image/png");
+  /**
+   * Go to next entry
+   */
+  public next(): void {
+    this.iterator.moveToNext();
+    if (!this.hidden) {
+      this.show();
     }
+  }
+
+  /**
+   * reset cursor to start
+   */
+  public reset(): void {
+    this.iterator = this.manager.getIterator();
+    this.iterator.moveToNext();
+    this.update();
+  }
+
+  private updateStyle(width: number, color: string = "#33e02f"): void {
+    // Create a dummy canvas to generate the gradient for the cursor
+    // FIXME This approach needs to be improved
+    let c: HTMLCanvasElement = document.createElement("canvas");
+    c.width = this.cursorElement.width;
+    c.height = 1;
+    let ctx: CanvasRenderingContext2D = c.getContext("2d");
+    ctx.globalAlpha = 0.5;
+    // Generate the gradient
+    let gradient: CanvasGradient = ctx.createLinearGradient(0, 0, this.cursorElement.width, 0);
+    gradient.addColorStop(0, "white"); // it was: "transparent"
+    gradient.addColorStop(0.2, color);
+    gradient.addColorStop(0.8, color);
+    gradient.addColorStop(1, "white"); // it was: "transparent"
+    ctx.fillStyle = gradient;
+    ctx.fillRect(0, 0, width, 1);
+    // Set the actual image
+    this.cursorElement.src = c.toDataURL("image/png");
+  }
 }

+ 0 - 33
test/Common/DataObjects/Fraction_Test.ts

@@ -2,8 +2,6 @@
  * Created by Oliver on 16.03.2016.
  */
 import { Fraction } from "../../../src/Common/DataObjects/Fraction";
-import Dictionary from "typescript-collections/dist/lib/Dictionary";
-import {Logging} from "../../../src/Common/Logging";
 
 describe("Fraction Unit Tests:", () => {
     describe("Construct Fraction, check properties", () => {
@@ -35,35 +33,4 @@ describe("Fraction Unit Tests:", () => {
         done();
       });
     });
-    // Todo: remove when typescript porting phase 2 is done an project is compiling properly again
-    describe("blablabla", () => {
-        let dict: Dictionary<Fraction, Fraction> = new Dictionary<Fraction, Fraction>();
-        //     new Collections.Dictionary<Fraction, Fraction>(
-        //     function(f: Fraction): string {
-        //         return f.toString();
-        // });
-
-        let keys: Fraction[] = [];
-        let values: Fraction[] = [];
-
-        for (let i: number = 0; i < 10; ++i) {
-            keys.push(new Fraction(1, i));
-            values.push(new Fraction(i, 1));
-            dict.setValue(keys[i], values[i]);
-        }
-
-        it("retrieved fractions should be equal", (done: MochaDone) => {
-            for (let i: number = 9; i > -1; --i) {
-                let key: Fraction = keys[i];
-                let value: Fraction = values[i];
-
-                //console.log(values[i].toString() + "== " + dict.getValue(key));
-                Logging.debug(values[i].toString() + "== " + dict.getValue(new Fraction(key.Numerator, key.Denominator)));
-                // chai.expect(dict.getValue(key)).to.equal(value);
-                chai.expect(dict.getValue(new Fraction(key.Numerator, key.Denominator))).to.equal(value);
-            }
-
-            done();
-        });
-    });
 });